|
О производительности memcpy, Навеяно темой "jpeg на at91sam9g20" |
|
|
|
Aug 22 2010, 04:30
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(AlexandrY @ Aug 22 2010, 01:41)  Надо будет проверить влияние этого на производительность. Проверил интереса для. Должен сказать, что результаты вышли довольно любопытные, поэтому решил изложить их здесь. В ходе эксперимента измерялась скорость копирования 256 блоков по одному мегабайту с различными смещениями источника и приемника данных. В качестве тестовой платформы использовался процессор EP9312 (ARM920T, FCLK = 200MHz, BCLK = 100MHz). Первое число в квадратных скобках - смещение приемника, второе - источника, скорость приводится в мегабайтах в секунду: Код copy[0][0]: 60.674 copy[1][0]: 45.506 copy[2][0]: 45.506 copy[3][0]: 45.506
copy[0][1]: 46.397 copy[1][1]: 55.246 copy[2][1]: 45.506 copy[3][1]: 45.506
copy[0][2]: 46.397 copy[1][2]: 46.397 copy[2][2]: 55.245 copy[3][2]: 45.506
copy[0][3]: 46.397 copy[1][3]: 46.397 copy[2][3]: 46.397 copy[3][3]: 55.245 Примечательны два обстоятельства: 1. Относительно небольшое против ожидаемого снижение скорости при работе с неодинаковыми смещениями у источника и приемника 2. Заметное падение скорости в условиях, казалось бы близких к идеальным (n, n; при n > 0). Объяснение первому эффекту находится достаточно просто: 60 МБайт/с - это ограничение, накладываемое производительностью контроллера памяти. И если снизить частоту ядра, оставив частоту шины на том же уровне (FCLK = BCLK = 100MHz), то разница в результатах получается более значительной: Код copy[0][0]: 60.672 copy[1][0]: 32.233 copy[2][0]: 32.233 copy[3][0]: 32.233
copy[0][1]: 32.233 copy[1][1]: 53.933 copy[2][1]: 32.233 copy[3][1]: 32.233 ... Второй эффект куда любопытнее. Доподлинно установить его происхождение не удалось. Можно только определенно сказать, что он не связан напрямую с работой кэша и буфера записи. Наиболее логичным представляется предположение, что смещение данных на слово ломает где-то burst-передачи, создавая тем самым некоторый оверхед. Скорее всего это особенность данного конкретного процессора и его контроллера памяти. Зависимость скорости копирования от смещения данных, число в квадратных скобках - смещение в 32-битных словах: Код copy[0w]: 60.674102 copy[1w]: 55.245381 copy[2w]: 55.226639 copy[3w]: 52.582269 copy[4w]: 60.672306 copy[5w]: 55.246603 copy[6w]: 55.211088 copy[7w]: 52.584118 copy[8w]: 60.674150 ... И, наконец, последняя табличка. Она показывает скорость копирования при расположении источника и приемника данных в разных банках SDRAM. Код copy[0w]: 91.010796 copy[1w]: 79.629958 copy[2w]: 79.629988 copy[3w]: 73.539810 copy[4w]: 91.006777 copy[5w]: 79.630088 copy[6w]: 79.630112 copy[7w]: 73.539468 copy[8w]: 91.011220 ... Если резюмировать, то для эффективного копирования надо: 1. Выравнивать данные, причем иногда бывает мало и границы слова. Логичным представляется выравнивание по границе строки кэша. 2. По возможности располагать источник и приемник в разных банках SDRAM. Это позволит контроллеру памяти дольше держать банки открытыми (т.е. сэкономить на precharge).
|
|
|
|
|
 |
Ответов
|
Aug 22 2010, 14:02
|

embarrassed systems engineer
    
Группа: Свой
Сообщений: 1 083
Регистрация: 24-10-05
Из: Осокорки
Пользователь №: 10 038

|
Цитата(AlexandrY @ Aug 22 2010, 16:30)  Почему вы решили что все пишут на GCC? Ни в IAR, Надо признать, резон в замечании есть. Тут дело не столько в GCC, сколько в том, что memcpy() лично для меня функция важная и тщательно изученная не для одной архитектуры. Вот я и решил что все ее код "знают в лицо". Был неправ, что сказать . BTW, для IAR Full версии исходники доступны, и это они зря - там грустно  Цитата(AlexandrY @ Aug 22 2010, 16:30)  Никто бы не стал тестировать memcpy если б были исходники этой функции. Исходники (ессно, в нормальном варианте) там бывают довольно любопытные - иногда я много нового узнаю  . ИМХО, тестировать memcpy() следует потому что на современных системах производительность зависит не только (далеко не только) от того что написано в исходнике этой функции. Лично я всегда при помощи тестов memcpy() (своей имплементации RTL) тюнингую настройки контроллера DRAM, арбитра шины и прочие подобные мелочи. Цитата(zltigo @ Aug 22 2010, 16:48)  ибо в IAR 4x был мрак с memcpy(), но IAR - для 4x и 5.x день и ночь по результатам. Э-э-э-э, то есть 5-ый еще хуже чем 4-ый? Да куда ж там дальше-то. Я последний раз IAR-овские исходники смотрел в 4.30 - правда мрак.
|
|
|
|
|
Aug 22 2010, 14:13
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
QUOTE (VslavX @ Aug 22 2010, 16:02)  IAR Full версии исходники доступны, и это они зря - там грустно  Э,то что Вам показалось исходниками, это не они, это какая-то заглушка. Исходников нет и в полной. QUOTE Э-э-э-э, то есть 5-ый еще хуже чем 4-ый? Да куда ж там дальше-то. Вообще-то я хотел сказать, что совсем наоборот, и вроде так и сказал? Вот, то, что использовал вместо штатного memcpy() в 4x IAR: CODE //--------------------------------------------------------------------------- // Fast memcpy() & memove() For IAR ARM ANSI C/C++ Compiler //---------------------------------------------------------------------------
NAME memcpy
RSEG CSTACK:DATA:NOROOT(2)
MULTWEAK ??memcpy??rT MULTWEAK ??memmove??rT PUBLIC memcpy PUBLIC memmove
memcpy SYMBOL "memcpy" ??memcpy??rT SYMBOL "??rT", memcpy
memmove SYMBOL "memmove" ??memmove??rT SYMBOL "??rT", memmove
RSEG CODE:CODE:NOROOT(2) THUMB ??memcpy??rT: BX PC Nop REQUIRE memcpy
RSEG CODE:CODE:NOROOT(2) ARM
#ifndef configUSE_MEMCPY8W #define WORDS8_TRANSFER 0 #else #if configUSE_MEMCPY8W == 1 #define WORDS8_TRANSFER 1 #else #define WORDS8_TRANSFER 0 #endif #endif
//--------------------------------------------------------------------------- // void *(memcpy)(void *p1, const void *p2, size_t n) // Copy char p2[n] to p1[n] //--------------------------------------------------------------------------- memcpy: teq r2,#0 // Is p1 == 0 ? bxeq lr // If p1 == 0, return
stmdb sp!,{lr} // Push return address mov r12,r0 // Copy pointer p1 cmp r2,#8 // Is buffer long or short? ble byteserial // Jump if n <= 8
sub r3,r0,r1 // Compare pointers p1, p2 tst r3,#3 // Strings aligned same? bne byteserial // Jump if buffers not aligned
// Both strings are similarly aligned WRT word boundaries. // At least a portion of the data can be copied an entire // word at a time, which is faster than copying bytes. wordserial: ands r3,r0,#3 // Check byte alignment beq wordaligned // Jump if p1, p2 word-aligned
rsb r3,r3,#4 // m = no. of odd initial bytes sub r2,r2,r3 // n = n - m
// If the two buffers do not begin on word boundaries, begin // by copying the odd bytes that precede the first full word. preloop: ldrb lr,[r1],#1 // Read byte from source subs r3,r3,#1 // --m (decrement loop count) strb lr,[r12],#1 // Write byte to destination bne preloop // Loop if more bytes to move
wordaligned: #if WORDS8_TRANSFER == 1 movs r3,r2,asr #5 // Any chunks of 8 words? beq octsdone // Jump if no 8-word chunks
and r2,r2,#0x1F // Subtract chunks from n stmdb sp!,{r4-r10} // Save registers on stack
// The strings are long enough that we can transfer at least // some portion of the data in 8-word chunks. octloop: ldmia r1!,{r4-r10,lr} // Load 8 words from source subs r3,r3,#1 // More 8-word chunks to move? stmia r12!,{r4-r10,lr} // Write 8 words to destination bne octloop // Loop if more chunks
ldmia sp!,{r4-r10} // Restore registers from stack
octsdone: #endif movs r3,r2,asr #2 // Any more whole words to move? beq wordsdone // Jump if no more whole words
// Copy as much of the remaining data as possible one word at // a time. wordloop2: ldr lr,[r1],#4 // Read next word from source subs r3,r3,#1 // Decrement word count str lr,[r12],#4 // Write next word to destination bne wordloop2 // Loop while more words to move
wordsdone: ands r2,r2,#3 // Any last bytes to transfer? beq theend // Return if already done
// The two strings do not end on word boundaries. // Copy the remaining data one byte at a time. byteserial: ldrb lr,[r1],#1 // Read byte from source subs r2,r2,#1 // --n (decrement loop count) strb lr,[r12],#1 // Write byte to destination bne byteserial // Loop if more bytes to move
theend: ldmia sp!,{lr} // Return bx lr
//--------------------------------------------------------------------------- RSEG CODE:CODE:NOROOT(2) THUMB ??memmove??rT: BX PC Nop REQUIRE memmove
RSEG CODE:CODE:NOROOT(2) ARM
//--------------------------------------------------------------------------- // Safely copy c bytes from source s to destination d. // void *memmove(void *d, const void *s, unsigned c); //--------------------------------------------------------------------------- memmove: cmp r0,r1 // Is d > s ? bls memcpy // Jump to memcpy if d <= s
// Need to copy backwards, starting at tail ends of source and // destination arrays. Copy a word or a byte at a time? orr r3,r1,r0 // tmp = s | d orr r3,r3,r2 // tmp = s | d | c ands r3,r3,#3 // Is tmp even multiple of 4?
add r1,r1,r2 // s + c (end of source buffer) add r2,r2,r0 // d + c (end of dest'n buffer) beq move1 // Jump if tmp is multiple of 4 b move2
// Because the source and destination arrays are not aligned to even // word boundaries in memory, transfer only a byte at a time. move3: ldrb r3,[r1,#-1]! // Load next byte from source strb r3,[r2,#-1]! // Store next byte to dest'n move2: teq r0,r2 // More bytes to move? bne move3 // Jump if more bytes bx lr // All done
// Because count c is an even multiple of 4 and the source // and destination arrays begin on even word boundaries, move // an entire word at a time from source to destination. move4: ldr r3,[r1,#-4]! // Load next word from source str r3,[r2,#-4]! // Store next word to dest'n move1: teq r0,r2 // More words to move? bne move4 // Jump if more words
bx lr // All done
END Есть еще один сишный memcpy(). Интересно?
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
Сообщений в этой теме
aaarrr О производительности memcpy Aug 22 2010, 04:30   zltigo QUOTE (AlexandrY @ Aug 22 2010, 15:30) Ни... Aug 22 2010, 13:48     VslavX Цитата(zltigo @ Aug 22 2010, 17:13) Э,то ... Aug 22 2010, 14:53 aaarrr Цитата(VslavX @ Aug 22 2010, 16:39) aaarr... Aug 22 2010, 15:05 AlexandrY Цитата(aaarrr @ Aug 22 2010, 18:05) Пожал... Aug 22 2010, 15:18  aaarrr Цитата(AlexandrY @ Aug 22 2010, 19:18) По... Aug 22 2010, 15:47 igorsk RE: О производительности memcpy Aug 22 2010, 18:47 sergeeff Самый шустрый memcpy для всех случаев выравненных/... Aug 22 2010, 19:08 aaarrr RE: О производительности memcpy Aug 22 2010, 20:32 sergeeff ЦитатаНо данные все равно лучше выравнивать.
Это ... Aug 23 2010, 06:16 MrYuran Цитата(sergeeff @ Aug 23 2010, 10:16) Это... Aug 23 2010, 06:25 AlexandrY Цитата(sergeeff @ Aug 23 2010, 09:16) Это... Aug 23 2010, 06:45 sergeeff х86 всю свою "жизнь" аппаратно это тоже ... Aug 23 2010, 07:13 AlexandrY Цитата(sergeeff @ Aug 23 2010, 10:13) х86... Aug 23 2010, 07:50  MrYuran Цитата(AlexandrY @ Aug 23 2010, 11:50) Ес... Aug 23 2010, 08:07
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|