Y_Mur Во-первых, насчет rdtsc это ты в огород Booster-a помидоры кидай Во-вторых, я не понял на каком основании ты сделал вывод, что частота QueryPerformance "гуляет в соответствии со SpeedStep" - может еще и в твоем огородике стоит покопаться ?
leo Покопайся - аттач там прилагается ) Меня тоже удивла такая пляска результатов - особенно если сравнить результат работы с "лишними" циклами @@: loop @B и без них - такое впечатление что заполняя память процессор норовит подремать, снизив частоту и QueryPerformance следует за ним, хотя по документации и не должна
Сделал всё как советовал leo. Вот такие результаты: P4 2400 DDR1 400MHz Код (Text): ======================================= Read BlockSize = 16777216 byte time = 0.0224953 sec. bandwidth = 711.259 Mb/sec dword time = 0.00938471 sec. bandwidth = 1704.9 Mb/sec movq time = 0.00828569 sec. bandwidth = 1931.04 Mb/sec movapd time = 0.00715705 sec. bandwidth = 2235.56 Mb/sec ======================================= Write BlockSize = 16777216 byte time = 0.0213225 sec. bandwidth = 750.38 Mb/sec dword time = 0.0189502 sec. bandwidth = 844.319 Mb/sec movq time = 0.018913 sec. bandwidth = 845.978 Mb/sec movntq time = 0.00676147 sec. bandwidth = 2366.35 Mb/sec movntpd time = 0.00676371 sec. bandwidth = 2365.57 Mb/sec Core 2 Duo E8500 3.16, DDR3 1333 Mhz. Код (Text): ======================================= Read BlockSize = 16777216 byte time = 0.0158343 sec. bandwidth = 1010.46 Mb/sec dword time = 0.00599797 sec. bandwidth = 2667.57 Mb/sec movq time = 0.00534237 sec. bandwidth = 2994.93 Mb/sec movapd time = 0.00550196 sec. bandwidth = 2908.06 Mb/sec ======================================= Write BlockSize = 16777216 byte time = 0.0158951 sec. bandwidth = 1006.6 Mb/sec dword time = 0.0137417 sec. bandwidth = 1164.34 Mb/sec movq time = 0.013822 sec. bandwidth = 1157.57 Mb/sec movntq time = 0.00620149 sec. bandwidth = 2580.03 Mb/sec movntpd time = 0.00588545 sec. bandwidth = 2718.57 Mb/sec Как я и предполагал, не особо сильно повлияли все эти ухищрения. Кора быстрее, но насколько! Тестилка в аттаче вместе с сурсом.
Хм, у меня кора (2х ядерная) помедленнее и память ддр2 но результаты получше Athlon 64 X2 Turion Mobile (1.6ггц) \ DDR2-4300 266мгц: Код (Text): Read BlockSize = 16777216 byte time = 0.0248015 sec. bandwidth = 645.123 Mb/sec dword time = 0.00865613 sec. bandwidth = 1848.4 Mb/sec movq time = 0.00735485 sec. bandwidth = 2175.44 Mb/sec movapd time = 0.00708358 sec. bandwidth = 2258.74 Mb/sec ======================================= Write BlockSize = 16777216 byte time = 0.0319686 sec. bandwidth = 500.491 Mb/sec dword time = 0.0138752 sec. bandwidth = 1153.13 Mb/sec movq time = 0.0118082 sec. bandwidth = 1354.99 Mb/sec movntq time = 0.00418684 sec. bandwidth = 3821.49 Mb/sec movntpd time = 0.0041902 sec. bandwidth = 3818.44 Mb/sec Core 2 Duo E6750 (3.0ггц) \ DDR2-6400 475мгц Код (Text): Read BlockSize = 16777216 byte time = 0.00618647 sec. bandwidth = 2586.29 Mb/sec dword time = 0.00251093 sec. bandwidth = 6372.13 Mb/sec movq time = 0.00234297 sec. bandwidth = 6828.95 Mb/sec movapd time = 0.00214252 sec. bandwidth = 7467.84 Mb/sec ======================================= Write BlockSize = 16777216 byte time = 0.00692707 sec. bandwidth = 2309.78 Mb/sec dword time = 0.00606879 sec. bandwidth = 2636.44 Mb/sec movq time = 0.00597646 sec. bandwidth = 2677.17 Mb/sec movntq time = 0.00244242 sec. bandwidth = 6550.88 Mb/sec movntpd time = 0.00242559 sec. bandwidth = 6596.34 Mb/sec Сore 2 Quad Q9300 (2.5ггц) \ DDR2-5300 333мгц Код (Text): Read BlockSize = 16777216 byte time = 0.00949639 sec. bandwidth = 1684.85 Mb/sec dword time = 0.00397963 sec. bandwidth = 4020.48 Mb/sec movq time = 0.00359864 sec. bandwidth = 4446.12 Mb/sec movapd time = 0.00349171 sec. bandwidth = 4582.28 Mb/sec ======================================= Write BlockSize = 16777216 byte time = 0.00842523 sec. bandwidth = 1899.06 Mb/sec dword time = 0.00705991 sec. bandwidth = 2266.32 Mb/sec movq time = 0.006842 sec. bandwidth = 2338.5 Mb/sec movntq time = 0.0024001 sec. bandwidth = 6666.4 Mb/sec movntpd time = 0.00239688 sec. bandwidth = 6675.34 Mb/sec
Да похоже у Booster-a висла с TimePeriod=1 дурит А вот почему у атлонов чтение так сильно отстает не очень понятно. Или префетчер хреноватый, или организация L1 (эксклюзивный и всего 2-way) или все вместе ?
Я думаю именно поблемы с организацией L1 - I-Cache, D-Cache, по 2 way каждый. Интересно? что выдает их новый Phenom II X4. Врядли они не могут префетчер создать.
Интересно всё таки из-за чего эта байда? TermoSINteZ предположил что из-за Thermal Throttling-а, то есть снижения частоты проца из-за перегрева. Надо будет потестить тот комп. более детально. Может ещё есть идеи на этот счёт?
Хочу поблагодарить TermoSINteZ-а за помощь в тестах. С помощью них удалось получить более-менее ясную картину. Видимо у Athlon 64 X2 Turion просто не работает аппаратный prefetch. С помощью инструкции prefetchnta со значениями 512-1024, на нём удалось поднять чтение с примерно 2.5 Гб до почти 4Гб. На Intel это тоже даёт эффект, хотя в процентном отношении и не такой большой, но всё же позволяет поднять примерно на 0.5Гб/сек. Вот такой кодес работает очень быстро для чтения: Код (Text): mov esi, pMem mov ecx, count shr ecx, 3 l1: prefetchnta 512[esi] movq mm0, qword ptr [esi] add esi, 8 dec ecx jnz l1 Возможно AMD это сделала намеренно, так как имеет смысл не префетчить ненужные данные в случае непоследовательного доступа. Но как это работает на непоследовательном доступе я пока не знаю. Также имеет смысл использовать SSE, оно или даёт некоторый прирост или по крайней мере не хуже MMX. Развёртка цикла не слишком себя оправдала, хотя и не хуже не развёрнутого варианта. В операциях копирования программный префетч дал немного на атлоне, хотя SSE(movntpd) находится рядом. А на коре это почти ничего не дало. Соответствующие стандарные си функции здорово проигрывают, чего конечно и стоило ожидать.
t00x Такие: Сore 2 Quad Код (Text): Запись: memset time = 0.00370836 sec. bandwidth = 4314.57 Mb/sec mmx(movntq) time = 0.00240883 sec. bandwidth = 6642.24 Mb/sec sse(movntpd) time = 0.00240687 sec. bandwidth = 6647.64 Mb/sec Копирование: memcpy time = 0.00953627 sec. bandwidth = 1677.81 Mb/sec mmx(movq/movntq) time = 0.00690192 sec. bandwidth = 2318.19 Mb/sec sse(movapd/movntpd) time = 0.00630967 sec. bandwidth = 2535.79 Mb/sec
С проблемой низкой пропускной способности разобрался, настройки компа стояли в Safe, откуда частота FSB и процессора были занижены в несколько раз. Теперь меня интересуют другие вещи. Почему инициализация страницы памяти всего в несколько раз медленнее полного её чтения, отъедая десятки тысяч тактов? Как вообще происходит механизм инициализации? Ещё наткнулся на PAGE_WRITECOMBINE. Для затравки можно почитать это - Fast copy video memory Мои комменты в конце под ником Flame. Пока чтение видео памяти не тестил. Тестил запись в PAGE_WRITECOMBINE память с помощью обычных mov и повышения производительности не обнаружил. Вообще была мысль для процев где отсутствуют SSE4, при чтении видопамяти, временно убирать атрибут PAGE_WRITECOMBINE, но при смене атрибута памяти происходит довольно существенная задержка, что тоже для меня не ясно.
По-моему эта PAGE_WRITECOMBINE просто фикция. Сравнил скорость чтения/записи памяти c различными атрибутами памяти и использования разных инструкций. Результаты: BlockSize: 100mb, CPU: Core 2 Duo E8500 3.16, Memory: DDR3 1333Mhz. Код (Text): write: PAGE_READWRITE, mov time = 0.0341194 sec. bandwidth = 2813.65 Mb/sec PAGE_READWRITE|PAGE_WRITECOMBINE, mov time = 0.0142017 sec. bandwidth = 6759.77 Mb/sec PAGE_READWRITE, movntq time = 0.0150171 sec. bandwidth = 6392.73 Mb/sec PAGE_READWRITE|PAGE_WRITECOMBINE, movntq time = 0.015053 sec. bandwidth = 6377.48 Mb/sec read: PAGE_READWRITE, mov time = 0.0152392 sec. bandwidth = 6299.53 Mb/sec PAGE_READWRITE|PAGE_WRITECOMBINE, mov time = 0.577456 sec. bandwidth = 166.246 Mb/sec PAGE_READWRITE, movntdqa time = 0.0141081 sec. bandwidth = 6804.58 Mb/sec PAGE_READWRITE|PAGE_WRITECOMBINE, movntdqa time = 0.0858824 sec. bandwidth = 1117.81 Mb/sec Вообщем не очень понятно зачем был нужен весь этот огород с PAGE_WRITECOMBINE. Да, видимо при записи она немного опережает movntq, но стоило ли оно того, что при чтении даже с современной movntdqa наблюдается шестикрантоное падение по сравнению с чтением PAGE_READWRITE(про mov вообще молчу). По-моему это очень сомнительно. К тому же movntdqa только начиная с SSE 4.1. И заюзать это самостоятельно при чтении видеопамяти не выйдет, так как API возвращает уже скопированную из промапленной памяти указатель, с атрибутом PAGE_READWRITE. Так что надеемся на драйверописателей и удивляемся кривизне интела. Зачем на скорость чтения PCI-Express 2.0 8 Гб?
Это не фикция, а специальный вид памяти для девайсов. PAGE_NOCACHE вообще запрещает кэширование данных процессором, как на чтение так и на запись, а PAGE_WRITECOMBINE - запрещает кэширование, но разрешает при записи объединять данные в более крупные пакеты (до 64 байт = размер линейки кэша). Поэтому и получается, что скорость записи в такую память сравнима с movntq (используются одни и те же WC-буферы записи), а при чтении она ведет себя как некэшируемая UC память - сколько байт запросил, столько и читает напрямую из ОЗУ без всякого префетча. Чем больше размер запрашиваемых данных, тем меньше вклад накладных расходов на передачу запросов и соотв-но тем выше скорость чтения. Процессор читает WB данные в кэш 64 или 128 байт, а UC\WC максимум по 16 байт (movdqa и т.п.) - отсюда и значительная разница в скорости чтения. Так было "всегда" (по кр.мере со времен PPro\PII), и только в SSE 4 ребята наконец-то реализовали "потоковое чтение" (streaming load) WC памяти до 64 байт за раз на movntdqa. По идее movntdqa при правильном использовании должна приближать скорость чтения WC-памяти до скорости обычного кэшируемого чтения. Почему у тебя существенно отстает - не знаю
может быть PAGE_WRITECOMBINE из msdn и Write Combining из "Volume 3A: 10.3 METHODS OF CACHING AVAILABLE" не одно и то же?
leo Что такое PAGE_WRITECOMBINE и как оно работает я в курсе, благо не один день это изучаю. Мне не понятно почему возникают такие проблемы при работе в видеопамятью, когда скорость шины уже стала 16 Гб в одну сторону. Применение этого атрибута в данном случае полумера, к тому же нафик не нужная в случае movntq, поэтому и написал - фикция. Почему при чтении в драйвере память мапится на PAGE_WRITECOMBINE? Разве нельзя при чтении/записи мапить на разные участки? Или использовать movntq? Или проблема сбросить кэш при чтении? На счёт скорости movntdqa, по тестам получается примерно в 7 раз, что сходится с результатами этой статьи - http://software.intel.com/ru-ru/blogs/2009/05/07/2001208/ Да и где написано, что скорость чтения кешируемой памяти должна быть равна скорости PAGE_WRITECOMBINE через movntdqa? А то что интел наконец-то придумали как решить проблему, которая была уже хрен знает сколько времени, за это им респект.
Как-то у тебя все с ног на голову . Во-первых, "16 Гб в одну сторону" - это как раз и есть "фикция" Точнее сказать это скорость пакетной передачи данных, достигаемая разными схемотехническими ухищрениями типа считывания всей строки RAM за раз + удвоение\учетверение скорости передачи по шине. А латентность доступа к памяти как была на уровне единиц наносекунд (~150-200МГц) так и осталась и никаких кардинальных улучшений в ближайшее время тут не придвидится. Поэтому все эти Гб/с достигаются только при чтении\записи пакетов данных в 64\128 и более байт + префетч для распараллеливания посылки запросов с передачей данных. Поэтому и WB-память с кэшированием и HW\SW-префетчем рулит. Во-вторых, UC-память в принципе не кэшируется по определению, и соотв-но по шине гоняется столько байт сколько указано в команде movXXX, и соотв-но скорость передачи оказывается крайне низкой из-за больших накладных расходов. Для USWC-памяти, опять же по определению, допускается объединение записываемых данных в пакеты. Размер пакета определяется железом и составляет 64 байта = размеру одной кэш-линейки. Объединение при записи достигается за счет использования внутренних 64-байтных WC-буферов еще со времен PPro\PII, когда никаких movntq и в помине не было. Если память имеет атрибут WC, то процессор копит данные в WC-буферах независимо от того какие команды записи используются - mov или movnt, и соотв-но для записи в WC не обязательно юзать асм или intrinsic'и, можно и на сях\паскалях кодить. Т.е. понятие WC-памяти с хардварной поддержкой "потоковой записи" является первичной фичей процессора, а то, что в SSE (в PIII) дали возможность юзать movntq для записи в обычную WB-память - это дополнительная фича, и нужно сказать за это разаработчикам спасибо, а не наезжать на WC-атрибут, который существовал и существует сам по себе независимо от наличия\отсутствия movntq. А вот с "потоковым чтением" USWC несколько иная ситуация, т.к. такой фичи в определении WC-памяти вообще нет, поэтому в SSE4 просто добавили команду movntdqa - хочешь юзай, не хочешь - грузи по старинке обычными мувами, с нехилыми тормозами Во-первых, не равна, а близка. Во-вторых, как осторожно подметил t00x - если виндусовый PAGE_WRITECOMBINE это действительно установка атрибута WC в MTRR\PAT, то и теоретически скорость чтения WC через movntdqa должна быть одного порядка с чтением обычной WB без HW-префетча (т.к. movntdqa инициирует чтение 64 байт за раз во внутренний буфер проца), и эспериментальные цифирьки от интел об этом говорят, см.например тут (правда они не мегабайты гоняли, а 4К по кругу, т.к. для некэшируемой памяти размер блока не должен играть существенной роли, видимо...)
leo Я вчера просто не выспался, всю ночь кошмары снились, вот и маленько не то написал, что хотел. ^) Конечно WC память не фикция, просто мне не совсем понятно почему такой геморой с чтением видеопамяти. Ведь наверняка уже давно можно было решить эту проблему. Технологии требующие чтения видеопамяти, появились не вчера. Это понятно, но как правило с видеопамяти запрашивается не по одному байту. Я это и подразумевал, всё равно аппаратный префетч в кэш, на интеле должен быть быстрее, так у них вроде поболее 64 байт префетчится. Тестирую такой функцией Код (Text): int testRead(char* pMem, size_t count) { int _count = count/0x40; volatile int c = 0; _asm { pushad mov ecx, _count mov eax, pMem1 l1: MOVNTDQA(0, 0); MOVNTDQA(1, 0x10); MOVNTDQA(2, 0x20); MOVNTDQA(3, 0x30); add eax, 40h dec ecx jne l1 mov c, ecx popad } return c; } MOVNTDQA(0, 0); - Это макрос, где первый параметр номер xmm регистра, второй смещение - [eax+offset], так как 2005 студия не понимате SSE4. Тут вообще одно чтение, без какой-либо обработки. Просто интересная ситуация, передача по шине очень быстра, а процессор не способен быстро её скопировать. Один из вариантов: при чтении мепировать на READWRITE и в начале копирования новых при данных сбрасывать кэш в invalid, не думаю что это очень сложно. Наверно можно было даже сделать отдельный атрибут памяти.