Оптимизированный доступ к памяти.

Тема в разделе "WASM.A&O", создана пользователем Booster, 27 май 2009.

  1. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Y_Mur
    Во-первых, насчет rdtsc это ты в огород Booster-a помидоры кидай ;)
    Во-вторых, я не понял на каком основании ты сделал вывод, что частота QueryPerformance "гуляет в соответствии со SpeedStep" - может еще и в твоем огородике стоит покопаться ? ;)
     
  2. Y_Mur

    Y_Mur Active Member

    Публикаций:
    0
    Регистрация:
    6 сен 2006
    Сообщения:
    2.494
    leo
    Покопайся - аттач там прилагается :)) Меня тоже удивла такая пляска результатов - особенно если сравнить результат работы с "лишними" циклами @@: loop @B и без них - такое впечатление что заполняя память процессор норовит подремать, снизив частоту и QueryPerformance следует за ним, хотя по документации и не должна ;)
     
  3. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Сделал всё как советовал leo.

    Вот такие результаты:
    P4 2400 DDR1 400MHz

    Код (Text):
    1. =======================================
    2. Read BlockSize = 16777216
    3.  
    4. byte
    5. time = 0.0224953 sec. bandwidth = 711.259 Mb/sec
    6.  
    7. dword
    8. time = 0.00938471 sec. bandwidth = 1704.9 Mb/sec
    9.  
    10. movq
    11. time = 0.00828569 sec. bandwidth = 1931.04 Mb/sec
    12.  
    13. movapd
    14. time = 0.00715705 sec. bandwidth = 2235.56 Mb/sec
    15.  
    16. =======================================
    17. Write BlockSize = 16777216
    18.  
    19. byte
    20. time = 0.0213225 sec. bandwidth = 750.38 Mb/sec
    21.  
    22. dword
    23. time = 0.0189502 sec. bandwidth = 844.319 Mb/sec
    24.  
    25. movq
    26. time = 0.018913 sec. bandwidth = 845.978 Mb/sec
    27.  
    28. movntq
    29. time = 0.00676147 sec. bandwidth = 2366.35 Mb/sec
    30.  
    31. movntpd
    32. time = 0.00676371 sec. bandwidth = 2365.57 Mb/sec
    Core 2 Duo E8500 3.16, DDR3 1333 Mhz.

    Код (Text):
    1. =======================================
    2. Read BlockSize = 16777216
    3.  
    4. byte
    5. time = 0.0158343 sec. bandwidth = 1010.46 Mb/sec
    6.  
    7. dword
    8. time = 0.00599797 sec. bandwidth = 2667.57 Mb/sec
    9.  
    10. movq
    11. time = 0.00534237 sec. bandwidth = 2994.93 Mb/sec
    12.  
    13. movapd
    14. time = 0.00550196 sec. bandwidth = 2908.06 Mb/sec
    15.  
    16. =======================================
    17. Write BlockSize = 16777216
    18.  
    19. byte
    20. time = 0.0158951 sec. bandwidth = 1006.6 Mb/sec
    21.  
    22. dword
    23. time = 0.0137417 sec. bandwidth = 1164.34 Mb/sec
    24.  
    25. movq
    26. time = 0.013822 sec. bandwidth = 1157.57 Mb/sec
    27.  
    28. movntq
    29. time = 0.00620149 sec. bandwidth = 2580.03 Mb/sec
    30.  
    31. movntpd
    32. time = 0.00588545 sec. bandwidth = 2718.57 Mb/sec
    Как я и предполагал, не особо сильно повлияли все эти ухищрения. Кора быстрее, но насколько! Тестилка в аттаче вместе с сурсом.
     
  4. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.552
    Адрес:
    Russia
    Хм, у меня кора (2х ядерная) помедленнее и память ддр2 но результаты получше :)

    Athlon 64 X2 Turion Mobile (1.6ггц) \ DDR2-4300 266мгц:


    Код (Text):
    1. Read BlockSize = 16777216
    2.  
    3. byte
    4. time = 0.0248015 sec. bandwidth = 645.123 Mb/sec
    5.  
    6. dword
    7. time = 0.00865613 sec. bandwidth = 1848.4 Mb/sec
    8.  
    9. movq
    10. time = 0.00735485 sec. bandwidth = 2175.44 Mb/sec
    11.  
    12. movapd
    13. time = 0.00708358 sec. bandwidth = 2258.74 Mb/sec
    14.  
    15. =======================================
    16. Write BlockSize = 16777216
    17.  
    18. byte
    19. time = 0.0319686 sec. bandwidth = 500.491 Mb/sec
    20.  
    21. dword
    22. time = 0.0138752 sec. bandwidth = 1153.13 Mb/sec
    23.  
    24. movq
    25. time = 0.0118082 sec. bandwidth = 1354.99 Mb/sec
    26.  
    27. movntq
    28. time = 0.00418684 sec. bandwidth = 3821.49 Mb/sec
    29.  
    30. movntpd
    31. time = 0.0041902 sec. bandwidth = 3818.44 Mb/sec
    Core 2 Duo E6750 (3.0ггц) \ DDR2-6400 475мгц

    Код (Text):
    1. Read BlockSize = 16777216
    2.  
    3. byte
    4. time = 0.00618647 sec. bandwidth = 2586.29 Mb/sec
    5.  
    6. dword
    7. time = 0.00251093 sec. bandwidth = 6372.13 Mb/sec
    8.  
    9. movq
    10. time = 0.00234297 sec. bandwidth = 6828.95 Mb/sec
    11.  
    12. movapd
    13. time = 0.00214252 sec. bandwidth = 7467.84 Mb/sec
    14.  
    15. =======================================
    16. Write BlockSize = 16777216
    17.  
    18. byte
    19. time = 0.00692707 sec. bandwidth = 2309.78 Mb/sec
    20.  
    21. dword
    22. time = 0.00606879 sec. bandwidth = 2636.44 Mb/sec
    23.  
    24. movq
    25. time = 0.00597646 sec. bandwidth = 2677.17 Mb/sec
    26.  
    27. movntq
    28. time = 0.00244242 sec. bandwidth = 6550.88 Mb/sec
    29.  
    30. movntpd
    31. time = 0.00242559 sec. bandwidth = 6596.34 Mb/sec
    Сore 2 Quad Q9300 (2.5ггц) \ DDR2-5300 333мгц

    Код (Text):
    1. Read BlockSize = 16777216
    2.  
    3. byte
    4. time = 0.00949639 sec. bandwidth = 1684.85 Mb/sec
    5.  
    6. dword
    7. time = 0.00397963 sec. bandwidth = 4020.48 Mb/sec
    8.  
    9. movq
    10. time = 0.00359864 sec. bandwidth = 4446.12 Mb/sec
    11.  
    12. movapd
    13. time = 0.00349171 sec. bandwidth = 4582.28 Mb/sec
    14.  
    15. =======================================
    16. Write BlockSize = 16777216
    17.  
    18. byte
    19. time = 0.00842523 sec. bandwidth = 1899.06 Mb/sec
    20.  
    21. dword
    22. time = 0.00705991 sec. bandwidth = 2266.32 Mb/sec
    23.  
    24. movq
    25. time = 0.006842 sec. bandwidth = 2338.5 Mb/sec
    26.  
    27. movntq
    28. time = 0.0024001 sec. bandwidth = 6666.4 Mb/sec
    29.  
    30. movntpd
    31. time = 0.00239688 sec. bandwidth = 6675.34 Mb/sec
     
  5. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Да похоже у Booster-a висла с TimePeriod=1 дурит ;)

    А вот почему у атлонов чтение так сильно отстает не очень понятно. Или префетчер хреноватый, или организация L1 (эксклюзивный и всего 2-way) или все вместе ?
     
  6. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.552
    Адрес:
    Russia
    Я думаю именно поблемы с организацией L1 - I-Cache, D-Cache, по 2 way каждый. Интересно? что выдает их новый Phenom II X4. Врядли они не могут префетчер создать.
     
  7. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.552
    Адрес:
    Russia
    Кстати коры тестил на MS WinVista x64 Sp1. А вот Athlon на MS WinXP x86 SP2
     
  8. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Интересно всё таки из-за чего эта байда? TermoSINteZ предположил что из-за Thermal Throttling-а, то есть снижения частоты проца из-за перегрева. Надо будет потестить тот комп. более детально. Может ещё есть идеи на этот счёт?
     
  9. t00x

    t00x New Member

    Публикаций:
    0
    Регистрация:
    15 фев 2007
    Сообщения:
    1.921
    Booster
    мм?, из-за перегрева "северного моста" )
    это ведь чтение/запись из/в память.
     
  10. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    t00x
    Тогда какого она так медленно работает? (
     
  11. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    Хочу поблагодарить TermoSINteZ-а за помощь в тестах. С помощью них удалось получить более-менее ясную картину. Видимо у Athlon 64 X2 Turion просто не работает аппаратный prefetch. С помощью инструкции prefetchnta со значениями 512-1024, на нём удалось поднять чтение с примерно 2.5 Гб до почти 4Гб. На Intel это тоже даёт эффект, хотя в процентном отношении и не такой большой, но всё же позволяет поднять примерно на 0.5Гб/сек.
    Вот такой кодес работает очень быстро для чтения:
    Код (Text):
    1. mov esi, pMem
    2. mov ecx, count
    3. shr ecx, 3
    4. l1:
    5. prefetchnta 512[esi]
    6. movq mm0, qword ptr [esi]
    7. add esi, 8
    8. dec ecx
    9. jnz l1
    Возможно AMD это сделала намеренно, так как имеет смысл не префетчить ненужные данные в случае непоследовательного доступа. Но как это работает на непоследовательном доступе я пока не знаю. Также имеет смысл использовать SSE, оно или даёт некоторый прирост или по крайней мере не хуже MMX. Развёртка цикла не слишком себя оправдала, хотя и не хуже не развёрнутого варианта. В операциях копирования программный префетч дал немного на атлоне, хотя SSE(movntpd) находится рядом. А на коре это почти ничего не дало. Соответствующие стандарные си функции здорово проигрывают, чего конечно и стоило ожидать.
     
  12. t00x

    t00x New Member

    Публикаций:
    0
    Регистрация:
    15 фев 2007
    Сообщения:
    1.921
    Booster
    имеются в виду какие функции?
     
  13. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    t00x
    Такие:
    Сore 2 Quad
    Код (Text):
    1. Запись:
    2. memset
    3. time = 0.00370836 sec. bandwidth = 4314.57 Mb/sec
    4.  
    5. mmx(movntq)
    6. time = 0.00240883 sec. bandwidth = 6642.24 Mb/sec
    7.  
    8. sse(movntpd)
    9. time = 0.00240687 sec. bandwidth = 6647.64 Mb/sec
    10.  
    11.  
    12. Копирование:
    13. memcpy
    14. time = 0.00953627 sec. bandwidth = 1677.81 Mb/sec
    15.  
    16. mmx(movq/movntq)
    17. time = 0.00690192 sec. bandwidth = 2318.19 Mb/sec
    18.  
    19. sse(movapd/movntpd)
    20. time = 0.00630967 sec. bandwidth = 2535.79 Mb/sec
     
  14. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    С проблемой низкой пропускной способности разобрался, настройки компа стояли в Safe, откуда частота FSB и процессора были занижены в несколько раз. Теперь меня интересуют другие вещи.

    Почему инициализация страницы памяти всего в несколько раз медленнее полного её чтения, отъедая десятки тысяч тактов? Как вообще происходит механизм инициализации?

    Ещё наткнулся на PAGE_WRITECOMBINE. Для затравки можно почитать это - Fast copy video memory Мои комменты в конце под ником Flame. Пока чтение видео памяти не тестил. Тестил запись в PAGE_WRITECOMBINE память с помощью обычных mov и повышения производительности не обнаружил. Вообще была мысль для процев где отсутствуют SSE4, при чтении видопамяти, временно убирать атрибут PAGE_WRITECOMBINE, но при смене атрибута памяти происходит довольно существенная задержка, что тоже для меня не ясно.
     
  15. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    По-моему эта PAGE_WRITECOMBINE просто фикция. Сравнил скорость чтения/записи памяти c различными атрибутами памяти и использования разных инструкций. Результаты:

    BlockSize: 100mb, CPU: Core 2 Duo E8500 3.16, Memory: DDR3 1333Mhz.
    Код (Text):
    1. write:
    2. PAGE_READWRITE, mov
    3. time = 0.0341194 sec. bandwidth = 2813.65 Mb/sec
    4.  
    5. PAGE_READWRITE|PAGE_WRITECOMBINE, mov
    6. time = 0.0142017 sec. bandwidth = 6759.77 Mb/sec
    7.  
    8. PAGE_READWRITE, movntq
    9. time = 0.0150171 sec. bandwidth = 6392.73 Mb/sec
    10.  
    11. PAGE_READWRITE|PAGE_WRITECOMBINE, movntq
    12. time = 0.015053 sec. bandwidth = 6377.48 Mb/sec
    13.  
    14. read:
    15. PAGE_READWRITE, mov
    16. time = 0.0152392 sec. bandwidth = 6299.53 Mb/sec
    17.  
    18. PAGE_READWRITE|PAGE_WRITECOMBINE, mov
    19. time = 0.577456 sec. bandwidth = 166.246 Mb/sec
    20.  
    21. PAGE_READWRITE, movntdqa
    22. time = 0.0141081 sec. bandwidth = 6804.58 Mb/sec
    23.  
    24. PAGE_READWRITE|PAGE_WRITECOMBINE, movntdqa
    25. 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 Гб?
     
  16. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Это не фикция, а специальный вид памяти для девайсов. 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-памяти до скорости обычного кэшируемого чтения. Почему у тебя существенно отстает - не знаю
     
  17. t00x

    t00x New Member

    Публикаций:
    0
    Регистрация:
    15 фев 2007
    Сообщения:
    1.921
    может быть PAGE_WRITECOMBINE из msdn и Write Combining из "Volume 3A: 10.3 METHODS OF CACHING AVAILABLE" не одно и то же?
     
  18. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    leo
    Что такое PAGE_WRITECOMBINE и как оно работает я в курсе, благо не один день это изучаю. Мне не понятно почему возникают такие проблемы при работе в видеопамятью, когда скорость шины уже стала 16 Гб в одну сторону. Применение этого атрибута в данном случае полумера, к тому же нафик не нужная в случае movntq, поэтому и написал - фикция. Почему при чтении в драйвере память мапится на PAGE_WRITECOMBINE? Разве нельзя при чтении/записи мапить на разные участки? Или использовать movntq? Или проблема сбросить кэш при чтении? На счёт скорости movntdqa, по тестам получается примерно в 7 раз, что сходится с результатами этой статьи - http://software.intel.com/ru-ru/blogs/2009/05/07/2001208/ Да и где написано, что скорость чтения кешируемой памяти должна быть равна скорости PAGE_WRITECOMBINE через movntdqa? А то что интел наконец-то придумали как решить проблему, которая была уже хрен знает сколько времени, за это им респект.
     
  19. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Как-то у тебя все с ног на голову ;) .
    Во-первых, "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К по кругу, т.к. для некэшируемой памяти размер блока не должен играть существенной роли, видимо...)
     
  20. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    leo
    Я вчера просто не выспался, всю ночь кошмары снились, вот и маленько не то написал, что хотел. ^) Конечно WC память не фикция, просто мне не совсем понятно почему такой геморой с чтением видеопамяти. Ведь наверняка уже давно можно было решить эту проблему. Технологии требующие чтения видеопамяти, появились не вчера.

    Это понятно, но как правило с видеопамяти запрашивается не по одному байту.

    Я это и подразумевал, всё равно аппаратный префетч в кэш, на интеле должен быть быстрее, так у них вроде поболее 64 байт префетчится.

    Тестирую такой функцией
    Код (Text):
    1. int testRead(char* pMem, size_t count)
    2. {
    3.     int _count = count/0x40;
    4.     volatile int c = 0;
    5.    _asm
    6.     {
    7.     pushad
    8.     mov ecx, _count
    9.     mov eax, pMem1
    10.     l1:
    11.     MOVNTDQA(0, 0);
    12.     MOVNTDQA(1, 0x10);
    13.     MOVNTDQA(2, 0x20);
    14.     MOVNTDQA(3, 0x30);
    15.     add eax, 40h
    16.     dec ecx
    17.     jne l1
    18.     mov c, ecx
    19.     popad
    20.      }
    21.      return c;
    22. }
    MOVNTDQA(0, 0); - Это макрос, где первый параметр номер xmm регистра, второй смещение - [eax+offset], так как 2005 студия не понимате SSE4. Тут вообще одно чтение, без какой-либо обработки.

    Просто интересная ситуация, передача по шине очень быстра, а процессор не способен быстро её скопировать. Один из вариантов: при чтении мепировать на READWRITE и в начале копирования новых при данных сбрасывать кэш в invalid, не думаю что это очень сложно. Наверно можно было даже сделать отдельный атрибут памяти.