Maverick_ 15 10 декабря, 2019 Опубликовано 10 декабря, 2019 · Жалоба Собрал qsys систему для SoC (вложение). Написал под линукс программу управления на базе API. Модуль sgdma переписывает данные из DDR памяти в блочную память. Измерение времени работает с такой же функцией что по ссылке У меня выходит чтение из ddr и запись в блочную память 78 мкс. Но это же время получается не зависимо что переписываю 100 32битных слов что 2048 32битных слов. Одно и тоже время и такое большое. Не могу понять почему??? Программа управления: //Scatter Gather DMA controller 2 printf( "\n\n------------- Scatter DMA 2---------------\n\n" ); //create descriptors in the mapped memory struct alt_avalon_sgdma_packed *sgdma_desc01=sdram_16MB_add; struct alt_avalon_sgdma_packed *sgdma_desc02=sdram_16MB_add+sizeof(struct alt_avalon_sgdma_packed); struct alt_avalon_sgdma_packed *sgdma_desc03=sdram_16MB_add+2*sizeof(struct alt_avalon_sgdma_packed); struct alt_avalon_sgdma_packed *sgdma_desc_empty0=sdram_16MB_add+3*sizeof(struct alt_avalon_sgdma_packed); //Address to the physical space void* sgdma_desc1_phys0=(void*)SDRAM_16_BASE; void* sgdma_desc2_phys0=(void*)SDRAM_16_BASE+sizeof(struct alt_avalon_sgdma_packed); void* sgdma_desc3_phys0=(void*)SDRAM_16_BASE+2*sizeof(struct alt_avalon_sgdma_packed); void* sgdma_desc_empty_phys0=(void*)SDRAM_16_BASE+3*sizeof(struct alt_avalon_sgdma_packed); //configure the descriptor initDescriptor(sgdma_desc01,(void*)SDRAM_64_BASE,(void*)(ONCHIP_MEMORY2_1_BASE), sgdma_desc_empty_phys0,4*2048, //sgdma_desc2_phys ( _SGDMA_DESC_CTRMAP_OWNED_BY_HW)); initDescriptor(sgdma_desc_empty0,NULL,NULL, sgdma_desc_empty_phys0,0, (_SGDMA_DESC_CTRMAP_WRITE_FIXED_ADDRESS)); //map memory of the control register h2p_lw_sgdma_addr=virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + 0x100 ) & ( unsigned long)( HW_REGS_MASK ) ); ////fill the data space for (long int i=0;i<2048; i++){ *((uint32_t *)sdram_64MB_add+i)= 2048 - i; } //init the SGDMA controller init_sgdma(_SGDMA_CTR_IE_CHAIN_COMPLETED); debugPrintRegister(); //set the address of the descriptor setDescriptor(sgdma_desc1_phys0); // start measurement struct timespec start1, stop1; //clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start); clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start1); ///////////////////////////////////////////////// //start the transfer setControlReg(_SGDMA_CTR_IE_CHAIN_COMPLETED|_SGDMA_CTR_RUN); //debugPrintRegister(); usleep(100); //wait until transfer is complete waitFinish(); //for (long int i=0;i<256; i++){ //printf( "%d\n", *((uint32_t *)sdram_64MB_add+i)); // } //debugPrintDescriptorStatus(sgdma_desc01); //stop the core by clearing the run register setControlReg(_SGDMA_CTR_IE_CHAIN_COMPLETED); setvbuf(stdout, NULL, _IONBF, 0); clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop1); printf("Stop - %d\n", stop1.tv_nsec); printf("Start - %d\n", start1.tv_nsec); double result = (stop1.tv_sec - start1.tv_sec) * 1e6 + (stop1.tv_nsec - start1.tv_nsec) / 1e3; printf("Time of SDRAM operation - %.6f \n", result); //debugPrintDescriptorStatus(sgdma_desc01); printf( "/*///////////////////*/////////////////*/ \n"); for (long int i=0;i<256; i++){ printf( "%d\n", *((uint32_t *)sdram_64MB_add+i)); } printf( "////////////////////////////////////// \n"); for (int i=0;i<100;i++){ printf( "%d\n", *((uint32_t*)h2p_rom1_addr+i)); } // read results from block RAM for (int i = 0; i < 100; i++) { uint32_t val = *((uint32_t*)(h2p_rom1_addr+i)); if (val != (100-i)) printf("Error at iteration %d - the value is %d while %d expected\n", i, val, (100-i)); } soc_system.qsys Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexadmin 0 11 декабря, 2019 Опубликовано 11 декабря, 2019 · Жалоба Сразу возникает подозрение, что 78 мкс - какой-то квант времени системы. Что есть CLOCK_PROCESS_CPUTIME_ID по сути? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 11 декабря, 2019 Опубликовано 11 декабря, 2019 · Жалоба 2 hours ago, alexadmin said: Сразу возникает подозрение, что 78 мкс - какой-то квант времени системы. Что есть CLOCK_PROCESS_CPUTIME_ID по сути? Возможно, да: resolution depends on the implementation, so do not always expect to get nanosecond precision. The clock_getres system call returns the resolution of the specified clock. This is informational data since you do not need to apply any scaling factors to data returned by clock_gettime: the values are in seconds and nanoseconds. http://www.zonevii.com/416/notes/c-tutorials/gettime.html Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexadmin 0 11 декабря, 2019 Опубликовано 11 декабря, 2019 · Жалоба И что же возвращает clock_getres() в вашем случае? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 11 декабря, 2019 Опубликовано 11 декабря, 2019 · Жалоба 8 hours ago, alexadmin said: И что же возвращает clock_getres() в вашем случае? Вызов возвращает значение равное 1 нс. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 11 декабря, 2019 Опубликовано 11 декабря, 2019 · Жалоба Еще один тест: clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start1); usleep(100); сlock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop1); result = (stop1.tv_sec - start1.tv_sec) * 1e6 + (stop1.tv_nsec - start1.tv_nsec) / 1e3; printf("Time of sleep operation - %.6f \n", result); возвращает Time of sleep operation - 14.140000, т.е. 14 мкс. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 11 декабря, 2019 Опубликовано 11 декабря, 2019 · Жалоба Другое странное поведение: clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start1); //usleep(100); struct timespec temp; temp.tv_sec=0; temp.tv_nsec=1000000; nanosleep(&temp, NULL); clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &stop1); result = (stop1.tv_sec - start1.tv_sec) * 1e6 + (stop1.tv_nsec - start1.tv_nsec) / 1e3; printf("Time of sleep operation - %.6f \n", result); показывает Time of sleep operation - 15.620000 т.е. 15 мкс, хотя задано 1000 мкс через нс Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
alexadmin 0 12 декабря, 2019 Опубликовано 12 декабря, 2019 · Жалоба Вероятно linux-specifix. Проделки шедулера ОС какие-нибудь. То есть если бы это было baremetal, то точно чудо, а так черт знает, эксперт по линуксам нужен. PS Сразу вспоминаются процессоры AMD начала 2000'х, у которых внутренние таймеры в разных ядрах считали по разному из-за чего ОС сходила с ума ;) PPS А клоки процессора правильно проинициализированы, т.е. он точно работает на запланированной частоте, а не какой-нибудь стартовой в 150МГц? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 12 декабря, 2019 Опубликовано 12 декабря, 2019 · Жалоба 1 hour ago, alexadmin said: Вероятно linux-specifix. Проделки шедулера ОС какие-нибудь. То есть если бы это было baremetal, то точно чудо, а так черт знает, эксперт по линуксам нужен. PS Сразу вспоминаются процессоры AMD начала 2000'х, у которых внутренние таймеры в разных ядрах считали по разному из-за чего ОС сходила с ума ;) PPS А клоки процессора правильно проинициализированы, т.е. он точно работает на запланированной частоте, а не какой-нибудь стартовой в 150МГц? Я подключился к отдельному DDR порту и подаю клок на него от отдельной PLL. Частота 108 МГц. Запись и чтение данных происходит правильно. Плата de10nano Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
new123 0 12 декабря, 2019 Опубликовано 12 декабря, 2019 (изменено) · Жалоба Тонкие замеры на гране наносек требуют тепличных условий. 1) Посадить процесс в отдельное ядро (taskset -c ...). 2) Убрать создание переменных внутри замеров. Компилятор конечно умный и разместит их в кеше проца, но вдруг разместит их в памяти, это сильные просадки по времени. 3) слипы в замерах лучше убрать. Если ядро заснет, не факт, что просыпается через заданно кол-во времени. Лучше сделать ждуна на основе while 4) CLOCK_PROCESS_CPUTIME_ID лучше CLOCK_REALTIME 6) Любая лишняя операция с памятью потянет за собой микросеки. 7) Добавлю. Если прям вообще точно вымерить, нужно настроить ядро линукса, чтобы проц не засыпал, Чтобы он находился в C0 STATE 100% времени. Это нужно внести конфиг в grub. Иначе ядро подзасыпает, особенно во время sleep и приехали. Утилита i7z показывает частоты и состояние ядер реалтайм. On 12/11/2019 at 12:34 PM, Maverick_ said: Возможно, да: resolution depends on the implementation, Вызовите два подряда clock_gettime и поймете тот самый квант времени. На CLOCK_REALTIME это порядка 25-30нс на не старых системах. Изменено 12 декабря, 2019 пользователем new123 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Maverick_ 15 19 декабря, 2019 Опубликовано 19 декабря, 2019 · Жалоба После проведения множества тестов с измерением средствами Linux, было решено перейти к решению на основе счетчика, реализованного в части логики. Такой подход показывает результаты лучше, чем предыдущий и уже можно ориентироваться на результаты измерений. Но есть проблема с тем, что в избранном API (https://github.com/digibird1/Cyclone-V-SoC-system_Base/blob/master/SoC_Memory_2/sgdma.h) все равно присутствует функция остановки (nanosleep). Если функцию waitFinish() там реализовать просто как while, который ожидает условие, то ничего не передается, т.к. постоянно опрашивается модуль. Если оставить функцию printf(), то все измеряется, но это также идет в счет измеряемого времени. Есть ли какие-либо способы обойти момент с вызовом доп. функций в while'е? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
new123 0 20 декабря, 2019 Опубликовано 20 декабря, 2019 (изменено) · Жалоба 16 hours ago, Maverick_ said: Есть ли какие-либо способы обойти момент с вызовом доп. функций в while'е? вы комментируйте мой коммент, чтобы мне на почту приходило уведомление и я быстрее буду заходить. =) да, постоянно лучше не долбить, а то не даст изменениям примениться. вместо sleep есть такой подход int64_t operator - (struct timespec tm1, struct timespec tm2) { return (tm1.tv_sec * 1000000000 + tm1.tv_nsec) - (tm2.tv_sec * 1000000000 + tm2.tv_nsec); }; ... struct timespec ts_1, ts_now; ... clock_gettime(CLOCK_REALTIME, &ts_1); clock_gettime(CLOCK_REALTIME, &ts_now); /*Например ждать 100нс*/ while (ts_now - ts_1 < 100) clock_gettime(CLOCK_REALTIME, &ts_now); Если оператор объявлять лень, то struct timespec ts_1, ts_now; ... clock_gettime(CLOCK_REALTIME, &ts_1); clock_gettime(CLOCK_REALTIME, &ts_now); /*Например ждать 100нс*/ while ((ts_now.tv_sec * 1000000000 + ts_now.tv_nsec) - (ts_1.tv_sec * 1000000000 + ts_1.tv_nsec) < 100) clock_gettime(CLOCK_REALTIME, &ts_now); Изменено 20 декабря, 2019 пользователем new123 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться