На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Перед отправкой сообщения внимательно прочтите правила раздела!!!
1. Запрещается обсуждать написание вирусов, троянов и других вредоносных программ!
2. Помните, что у нас есть FAQ раздела Assembler и Полезные ссылки. Посмотрите, возможно, там уже имеется решение вашего вопроса.

3. Настоятельно рекомендуем обратить особое внимание на правила форума, которые нарушаются чаще всего:
  3.1. Заголовок темы должен кратко отражать её суть. Темы с заголовками типа "Срочно помогите!" или "Ассемблер" будут отправляться в Корзину для мусора.
  3.2. Исходники программ обязательно выделяйте тегами [code]...[/code] (одиночные инструкции можно не выделять).
  3.3. Нежелательно поднимать старые темы (не обновлявшиеся более года) без веской на то причины.

Не забывайте также про главные Правила форума!

Добро пожаловать и приятного вам общения!!! ;)
 
Модераторы: Jin X, Qraizer
Страницы: (2) 1 [2]  все  ( Перейти к последнему сообщению )  
> Измерение времени выполнения кода, как средство профилирования
    Цитата JoeUser @
    А именно! QPC не точнее лишь потому, что там - API,

    не совсем так..
    Чтобы получить реальное время, нужно иметь счётчик и частоту, на которой этот счётчик работает. Например если взять счётчик процессора TSC и разделить его не на частоту процессора, а частоту таймера HPET, то получим не правильное время. Именно поэтому пара QPC+QPF должны всегда ходить вместе. Если замерить, сколько раз простучит QPC в течении одной секунды, то непременно получим значение, которое вернёт нам QPF. Это-же касается и пары RDTSC+CPUfreq.

    Цитата Qraizer @
    поправь-таки код.

    да.. он кривой, т.к. я его набросал на коленке. Спасибо вот Jin X поправил. ;)

    Цитата Pavia @
    А х32- программах индусы всё же сделали что'бы они не плавали.

    я имел в виду, что индусы точили набор функций NtCreateProfile(), с которыми я кстати так и разобрался до конца.

    Цитата Pavia @
    Там не 100 Мгц, а частота RDTSC. Только младшие биты 4-5 бит они не контролируют.

    вполне возможно, только эта частота у меня всегда совпадает с физической частотой системной шины, без множителя CPU.

    Цитата Jin X @
    Это что, так Invariant TSC работает?

    именно так он и работает!
    На новых чипсетах TSC выделен в отдельный домен, и идёт напрямую от системного клокера, - овер биоса на неё не влияет.
    Прикреплённый файлПрикреплённый файлtscp.png (9,88 Кбайт, скачиваний: 24)
    Сообщение отредактировано: core-i7 -
    Бог знает суть. Подробности нашёптывает дьявол.
      Цитата core-i7 @
      овер биоса на неё не влияет
      А на ВМ проц типа стартует сразу с разогнанной частоты, поэтому и показывает её?

      Добавлено
      Цитата core-i7 @
      Спасибо вот Jin X поправил.
      Я в том году поинтереснее код для теста начал писать, но не доделал. Хотя, осталось чуть-чуть.
      Я вот только думаю, есть ли смысл выравнивать тестовый код по 16 байтам? :rolleyes:
      Как я понял, основная фишка этого выравнивания в том, чтобы весь код попал в один 16-байтный блок. Т.е. если код занимает, скажем, 8 байт (ну или 24), то он может начинаться с любого адреса от 0 до 7 (в младшем полубайте), разницы не будет никакой.

      update: Вот инфа по этому поводу. Получается, что так и есть.
      Прикреплённый файлПрикреплённый файлcode_align.png (101,79 Кбайт, скачиваний: 19)
      Сообщение отредактировано: Jin X -
      aeskeygenassist bndstx cmpxchg16b dpps endbr64 f2xm1 gf2p8affineinvqb haddps incsspq jrcxz kxnorw ldmxcsr mpsadbw nop orpd pclmulhqlqdq qword rdpmc sha256rnds2 tzcnt unpcklpd vp4dpwssds wrfsbase xgetbv yword zword
        Доделал вроде как вполне приличную тестилку скорости кода.
        Пока только под 64 бита.
        ExpandedWrap disabled
          format  PE64 Console 5.0
          include 'win64axp.inc'
           
          ;-- CODE SECTION -------------------------------------------------------------------------------------------------------
           
          .code
           
          entry:
           
          frame
                  ; -1 is handle of current process (GetCurrentProcess), -2 is handle of current thread (GetCurrentThread)
                  invoke  SetProcessAffinityMask, -1, 1 ; to aviod CPU migration
                  invoke  SetPriorityClass, -1, REALTIME_PRIORITY_CLASS ; available only when running with administrator rights
                  invoke  SetThreadPriority, -2, THREAD_PRIORITY_TIME_CRITICAL
           
                  stdcall SpeedTestInit, -1
                  stdcall SpeedTestMsg, test1, 'Testing 1...', <' %llu ticks%s',10>, ' (CPU migration is detected)'
                  stdcall SpeedTestMsg, test2, 'Testing 2...', <' %llu ticks%s',10>, ' (CPU migration is detected)'
                  stdcall SpeedTestMsg, test3, 'Testing 3...', <' %llu ticks%s',10>, ' (CPU migration is detected)'
           
                  invoke  SetThreadPriority, -2, THREAD_PRIORITY_NORMAL
                  invoke  SetPriorityClass, -1, NORMAL_PRIORITY_CLASS
           
                  cinvoke printf, 'Press a key to exit...'
                  cinvoke getch
           
                  invoke  ExitProcess, 0
          endf
           
          align 16
          test1:
                  xor eax,eax
                  cpuid
                  ret
           
          align 16
          test2:
                  mov ecx,65536
              @@: dec ecx
                  jnz @B
                  ret
           
          align 16
          test3:
                  mov ecx,65536
                  loop    $
                  ret
           
          ;-- SPEED TEST PROCEDURES ----------------------------------------------------------------------------------------------
           
          ; Speed-test procedures for Windows x64, v1.00a
          ; (c) 2020 by Jin X (jin_x@list.ru)
           
          SPEEDTEST_REPEATS = 256         ; number of code execution repeats (must be power of two!!!)
          SPEEDTEST_WARMUPS = 1 shl (bsr SPEEDTEST_REPEATS / 2) ; number of warming-up executions
           
          assert SPEEDTEST_WARMUPS >= 0 & SPEEDTEST_REPEATS > 0 & bsf SPEEDTEST_REPEATS = bsr SPEEDTEST_REPEATS
           
          ; Initialize speed-test and show message if needed (via printf)
          ; Parameters: ecx = show message flags: bit 0 - when rdtscp is NOT supported, bit 1 - when invariant TSC is NOT supported, bit 2 - when everything's ok (ecx = -1 - all messages)
          ; Returns: rax = unsupported feature flags: bit 0 - rdtscp is NOT supported, bit 1 - invariant TSC is NOT supported (eax = 0 - both features are supported)
          proc        SpeedTestInit   uses rbx, MsgFlags
          frame
                  mov r8b,3       ; temp result
                  mov r9d,ecx     ; show message flags
           
                  mov eax,0x80000000
                  cpuid
                  mov r10d,eax    ; max extended cpuid leaf level
           
                  ; RDTSCP instruction support check
                  mov eax,0x80000001
                  cmp r10d,eax
                  jb  .no_inv     ; both features are NOT supported
                  cpuid
                  bt  edx,27      ; rdtscp support bit
                  jnc .no_rdtscp
                  and r8b,not 1   ; mark as supported
                  mov [SpeedTestGetTSC],SpeedTestRDTSCP ; use RDTSC instruction
              .no_rdtscp:
           
                  ; Invariant TSC support check
                  mov eax,0x80000007
                  cmp r10d,eax
                  jb  .no_inv
                  cpuid
                  bt  edx,8       ; invariant TSC support bit
                  jnc .no_inv
                  and r8b,not 2   ; mark as supported
              .no_inv:
                  mov bl,r8b
                  mov bh,bl       ; save result mask
                  test    bl,bl
                  setz    cl
                  shl cl,2
                  or  bl,cl       ; set bit 2 in r8d if both features are supported
                  and bl,r9b      ; bit mask for messages
           
                  ; Messages
                  test    bl,1
                  jz  @F
                  cinvoke printf, <"Warning: RDTSCP instruction is not supported, RDTSC will be used instead (CPU migration can't be detected)!", 10>
              @@: test    bl,2
                  jz  @F
                  cinvoke printf, <"Warning: invariant TSC is not supported (results may be inaccurate)!", 10>
              @@: test    bl,4
                  jz  @F
                  cinvoke printf, <"Success: both RDTSCP instruction and invariant TSC are supported.", 10>
              @@:
                  ; Measure overhead
                  xor eax,eax
                  mov [SpeedTestOverhead],rax
                  stdcall SpeedTest, SpeedTestEmptyFunc ; overhead test
                  mov [SpeedTestOverhead],rax
           
                  movzx   eax,bh      ; results
                  ret
          endf
          endp ; SpeedTestInit
           
          ; Measure procedure speed and show message (via printf)
          ; Parameters:
          ;   * rcx = proc address
          ;   * rdx = starting message (0 - no message, -1 - 'Testing...' message);
          ;   * r8 = result message (0 - no message, -1 - just a number of ticks and new line), should contain '%llu' for result TSC count and then '%s' (optional) for CPU migration message (specified by r9);
          ;   * r9 = CPU migration message (optional, should be used only is r8 message contains '%s').
          ; Returns: rax = TSC count (always positive value), zf = 1 if no CPU migration is occured
          proc        SpeedTestMsg    ProcAddr, PreMsg, ResultMsg, MigMsg
          SpeedTestMsg% = 0   ; turn off parameter count check
          frame
                  mov [ProcAddr],rcx
                  mov [ResultMsg],r8
                  mov [MigMsg],r9
           
                  ; Starting message
                  test    rdx,rdx
                  jz  .no_start
                  cmp rdx,-1
                  jne @F
                  mov rdx,.testing_msg
              @@: cinvoke printf, '%s', rdx
              .no_start:
           
                  ; Test speed
                  stdcall SpeedTest, [ProcAddr]
                  mov [ProcAddr],rax
                  setz    byte [PreMsg]   ; save zf
           
                  ; Result message
                  mov r8,.no_message
                  jz  @F      ; jump if no CPU migration
                  mov r8,[MigMsg]
              @@: mov rcx,[ResultMsg]
                  test    rcx,rcx
                  jz  .no_results
                  cmp rcx,-1
                  jne @F
                  mov rcx,.just_ticks
              @@: cinvoke printf, rcx, rax, r8
              .no_results:
           
                  ; Return values
                  mov rax,[ProcAddr]
                  dec byte [PreMsg]   ; restore zf
                  ret
          endf
          .testing_msg    db  'Testing...',0
          .just_ticks db  ' %llu',10
          .no_message db  0
          endp ; SpeedTestMsg
           
          ; Measure procedure speed
          ; Parameters: rcx = proc address
          ; Returns: rax = TSC count (always positive value), zf = 1 if no CPU migration is occured
          proc        SpeedTest   uses rbx rsi rdi r12 r13 r14 r15, ProcAddr
          frame
                  mov r12,rcx
           
                  ; Warming-up calls
            if SPEEDTEST_WARMUPS > 0
                  mov esi,SPEEDTEST_WARMUPS
              @@: stdcall r12
                  dec esi
                  jnz @B
            end if
                  ; Main tests
                  cld
                  mov rdi,SpeedTestResults
                  xor r15d,r15d
                  mov esi,SPEEDTEST_REPEATS
              @@:;    invoke  SwitchToThread  ; try to update thread time slice
                  invoke  SpeedTestGetTSC ; get ticks in rax, CPU id in ecx
                  mov r13,rax
                  mov r14d,ecx
                  stdcall r12     ; main call
                  invoke  SpeedTestGetTSC ; get ticks in rax, CPU id in ecx
                  sub rax,r13
                  sub rax,[SpeedTestOverhead] ; result TSC count
                  stosq           ; store to SpeedTestResults
                  sub ecx,r14d    ; detect CPU migration
                  or  r15d,ecx    ; migration flag for all tests
                  dec esi
                  jnz @B
           
            if SPEEDTEST_REPEATS > 2
                  ; Sort results
                  mov rcx,SpeedTestResults
                  mov rdx,SPEEDTEST_REPEATS
                  stdcall InsertionSort64
            end if
                  ; Calculate average CPU ticks
            if SPEEDTEST_REPEATS <= 2
                  mov ecx,SPEEDTEST_REPEATS
            else
                  mov ecx,SPEEDTEST_REPEATS/2 ; use only 50% of results from array middle (assuming that 25% at the start and end are errors)
            end if
                  xor eax,eax
                  xor edx,edx
              @@: add rax,[SpeedTestResults+(SPEEDTEST_REPEATS/4)*8 + rdx*8] ; sum of all relevant results
                  inc edx
                  dec ecx
                  jnz @B
           
            if SPEEDTEST_REPEATS > 2
                  sar rax,bsr (SPEEDTEST_REPEATS/2) ; average value
            else if SPEEDTEST_REPEATS = 2
                  sar rax,bsr SPEEDTEST_REPEATS ; average value
                  test    rax,rax
            end if
                  cmovs   eax,ecx     ; zero result if negative
                  test    r15d,r15d   ; zf = 1 if no CPU migration is occured
                  ret
          endf
          endp ; SpeedTest
           
          ; Read TSC via RDTSC [for internal use]
          ; Returns: rax = current TSC counter value, ecx = 0 (processor id detection is not supported)
          ; Changes ebx !!!
          if used SpeedTestRDTSC
          SpeedTestRDTSC:
                  xor eax,eax     ; cpuid execution time may vary depending on eax value
                  cpuid           ; serialization
                  xor ecx,ecx
                  rdtsc
                  shl rdx,32
                  or  rax,rdx
                  mfence
          SpeedTestEmptyFunc:
                  ret
          end if ; used SpeedTestRDTSC
           
          ; Read TSC via RDTSCP [for internal use]
          ; Returns: rax = current TSC counter value, ecx = processor id
          if used SpeedTestRDTSCP
          SpeedTestRDTSCP:
                  rdtscp
                  shl rdx,32
                  or  rax,rdx
                  mfence
                  ret
          end if ; used SpeedTestRDTSCP
           
          if used InsertionSort64
          ; Insertion sort of 64-bit elements
          ; Parameters: rcx = array address, rdx = number of elements
          InsertionSort64:
                  mov r8d,1           ; start key_index
                  cmp rdx,r8
                  jle .exit           ; jump if number of element <= 1
              .loop1:
                  mov rax,[rcx+r8*8]      ; key
                  mov r9,r8           ; el_index
              .loop2:
                  mov r10,[rcx+(r9-1)*8]  ; prev_el
                  cmp r10,rax         ; prev_el <=> key ?
                  jng @F
                  mov [rcx+r9*8],r10      ; if (prev_el > key) el = prev_el
                  dec r9          ; --el_index
                  jnz .loop2          ; repeat if el_index > 0
              @@:
                  mov [rcx+r9*8],rax      ; el = key
           
                  inc r8          ; ++key_index
                  cmp r8,rdx
                  jb  .loop1          ; repeat if key_index < number of elements
              .exit:
                  ret
          end if ; used InsertionSort64
           
          ;-- DATA SECTION -------------------------------------------------------------------------------------------------------
           
          .data
           
          if used SpeedTestInit
          SpeedTestGetTSC dq  SpeedTestRDTSC      ; TSC read procedure
          SpeedTestOverhead rq    1           ; TSC read overhead tick count
          SpeedTestResults rq SPEEDTEST_REPEATS   ; Temporary result array
          end if ; used SpeedTestInit
           
          ;-- IMPORT SECTION -----------------------------------------------------------------------------------------------------
           
          section '.idata' import data readable
           
          library kernel32, 'kernel32.dll',\
              msvcrt, 'msvcrt.dll'
           
              import_kernel32
              all_api
           
          import  msvcrt,\
              printf, 'printf',\
              getch, '_getch'

        Прикреплённый файлПрикреплённый файлspeedtest64.fasm (8,73 Кбайт, скачиваний: 9)
        Сообщение отредактировано: Jin X -
        aeskeygenassist bndstx cmpxchg16b dpps endbr64 f2xm1 gf2p8affineinvqb haddps incsspq jrcxz kxnorw ldmxcsr mpsadbw nop orpd pclmulhqlqdq qword rdpmc sha256rnds2 tzcnt unpcklpd vp4dpwssds wrfsbase xgetbv yword zword
          Цитата Jin X @
          А на ВМ проц типа стартует сразу с разогнанной частоты, поэтому и показывает её?

          ..имхо на вирту вообще не нужно делать ставки, поскольку она живёт своей жизнью

          Цитата Jin X @
          Доделал вроде как вполне приличную тестилку скорости кода

          прикольно получилось - зачёт! :good:
          Сообщение отредактировано: core-i7 -
          Бог знает суть. Подробности нашёптывает дьявол.
            Цитата core-i7 @
            прикольно получилось - зачёт!
            Я там косякнул кое-где (с цифровыми параметрами для SpeedTestMsg) :(
            Сейчас исправил, сообщение обновил ;)
            aeskeygenassist bndstx cmpxchg16b dpps endbr64 f2xm1 gf2p8affineinvqb haddps incsspq jrcxz kxnorw ldmxcsr mpsadbw nop orpd pclmulhqlqdq qword rdpmc sha256rnds2 tzcnt unpcklpd vp4dpwssds wrfsbase xgetbv yword zword
              И снова исправлен косячок, добавленный в результате предыдущего исправления: прога всегда показывала CPU migration <_<
              Файлы обновлены.

              Сообщения были разделены в тему "Определение микроархитектуры CPU"
              aeskeygenassist bndstx cmpxchg16b dpps endbr64 f2xm1 gf2p8affineinvqb haddps incsspq jrcxz kxnorw ldmxcsr mpsadbw nop orpd pclmulhqlqdq qword rdpmc sha256rnds2 tzcnt unpcklpd vp4dpwssds wrfsbase xgetbv yword zword
                core-i7, ты знаешь, всё-таки QPC использует не HPET, даже при значениях QPF = 10 млн.
                Я тут почитал кое-что. Во-первых, для HPET нужно идти в ядро, а QPC этого не делает (по крайней мере, у меня на 10-ке точно, да и на 7-ке, насколько я помню, было так же). Во-вторых, он читает RDTSCP и дальше выполняет какие-то хитрые арифметические операции, в результате чего преобразует это значение в QPC-счётчик. Причём, он выполняет не только деление (через умножение), но и зачем-то добавляет какие-то числа, ибо отношение RDTSCP/QPC постепенно растёт.
                aeskeygenassist bndstx cmpxchg16b dpps endbr64 f2xm1 gf2p8affineinvqb haddps incsspq jrcxz kxnorw ldmxcsr mpsadbw nop orpd pclmulhqlqdq qword rdpmc sha256rnds2 tzcnt unpcklpd vp4dpwssds wrfsbase xgetbv yword zword
                  Цитата Jin X @
                  Во-вторых, он читает RDTSCP и дальше выполняет какие-то хитрые арифметические операции

                  тогда QPF должна быть привязана к частоте процессора чтоли? (ведь QPF и QPC работают синхронно)
                  к примеру у меня CPU=1.1 GHz и QPF возвращает 10 MHz,
                  ты говоришь, что у тебя тоже 10 MHz, а частота процессора какая?
                  и почему тогда, если НРЕТ не поддерживается чипсетом, то QPF в аккурат равна частоте ACPI-таймера 3.579545 MHz - где параллель с TSC ???
                  Бог знает суть. Подробности нашёптывает дьявол.
                    Не исключено, что занижение частоты связано со всякими там Spectre. Хотя и верится несколько с трудом, т.к. занижение QPF выполнено гораздо раньше, чем сообщено о той же Spectre. Ну или о Spectre было уже давно известно, гораздо раньше публикаций.
                    Одни с годами умнеют, другие становятся старше.
                      Цитата core-i7 @
                      тогда QPF должна быть привязана к частоте процессора чтоли?
                      Нет.
                      Как я понял, винда на старте проверяет наличие invariant TSC. Если он присутствует, то вычисляет кол-во циклов в секунду и определяет делитель (обратный множитель).
                      А вот время вызова QPC проверяется выбранный на старте режим (HPET или TSC), и если используется TSC, читает его, добавляет что-то ещё зачем-то и делит на этот делитель, подгоняя таким образом к частоте 10 МГц.

                      Цитата core-i7 @
                      и почему тогда, если НРЕТ не поддерживается чипсетом, то QPF в аккурат равна частоте ACPI-таймера 3.579545 MHz - где параллель с TSC ???
                      Подозреваю, что там, где используется APCI-таймер, винда не самая свежая, либо нет ни invariant TSC, ни HPET.

                      Добавлено
                      Цитата Qraizer @
                      Не исключено, что занижение частоты связано со всякими там Spectre.
                      Сомневаюсь, что кто-то будет использовать QPC для тестов кэша :)
                      Ну и да, эта канитель никогда на частоте проца не работала, насколько я понимаю.
                      aeskeygenassist bndstx cmpxchg16b dpps endbr64 f2xm1 gf2p8affineinvqb haddps incsspq jrcxz kxnorw ldmxcsr mpsadbw nop orpd pclmulhqlqdq qword rdpmc sha256rnds2 tzcnt unpcklpd vp4dpwssds wrfsbase xgetbv yword zword
                      1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                      0 пользователей:


                      Рейтинг@Mail.ru
                      [ Script Execution time: 0,1393 ]   [ 17 queries used ]   [ Generated: 5.08.20, 01:38 GMT ]