Перейти к содержанию
    

измерение скорости работы sgdma

Собрал 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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сразу возникает подозрение, что 78 мкс - какой-то квант времени системы. Что есть CLOCK_PROCESS_CPUTIME_ID по сути?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

8 hours ago, alexadmin said:

И что же возвращает clock_getres() в вашем случае?

Вызов возвращает значение равное 1 нс.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Еще один тест:

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 мкс.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Другое странное поведение:

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 мкс через нс

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вероятно linux-specifix. Проделки шедулера ОС какие-нибудь. То есть если бы это было baremetal, то точно чудо, а так черт знает, эксперт по линуксам нужен.

PS Сразу вспоминаются процессоры AMD начала 2000'х, у которых внутренние таймеры в разных ядрах считали по разному из-за чего ОС сходила с ума ;)

PPS А клоки процессора правильно проинициализированы, т.е. он точно работает на запланированной частоте, а не какой-нибудь стартовой в 150МГц?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, alexadmin said:

Вероятно linux-specifix. Проделки шедулера ОС какие-нибудь. То есть если бы это было baremetal, то точно чудо, а так черт знает, эксперт по линуксам нужен.

PS Сразу вспоминаются процессоры AMD начала 2000'х, у которых внутренние таймеры в разных ядрах считали по разному из-за чего ОС сходила с ума ;)

PPS А клоки процессора правильно проинициализированы, т.е. он точно работает на запланированной частоте, а не какой-нибудь стартовой в 150МГц?

Я подключился к отдельному DDR порту и подаю клок на него от отдельной PLL. Частота 108 МГц.

Запись и чтение данных происходит правильно.

Плата de10nano

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Тонкие замеры на гране наносек требуют тепличных условий.

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нс на не старых системах.

Изменено пользователем new123

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

После проведения множества тестов с измерением средствами Linux, было решено перейти к решению на основе счетчика, реализованного в части логики. Такой подход показывает результаты лучше, чем предыдущий и уже можно ориентироваться на результаты измерений. Но есть проблема с тем, что в избранном API (https://github.com/digibird1/Cyclone-V-SoC-system_Base/blob/master/SoC_Memory_2/sgdma.h) все равно присутствует функция остановки (nanosleep). Если функцию waitFinish() там реализовать просто как while, который ожидает условие, то ничего не передается, т.к. постоянно опрашивается модуль. Если оставить функцию printf(), то все измеряется, но это также идет в счет измеряемого времени. Есть ли какие-либо способы обойти момент с вызовом доп. функций в while'е?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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);

 

Изменено пользователем new123

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...