На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА 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 Кбайт, скачиваний: 1025)
    Сообщение отредактировано: core-i7 -
      Цитата core-i7 @
      овер биоса на неё не влияет
      А на ВМ проц типа стартует сразу с разогнанной частоты, поэтому и показывает её?

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

      update: Вот инфа по этому поводу. Получается, что так и есть.
      Прикреплённый файлПрикреплённый файлcode_align.png (101,79 Кбайт, скачиваний: 1189)
      Сообщение отредактировано: Jin X -
        Доделал вроде как вполне приличную тестилку скорости кода.
        Пока только под 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 Кбайт, скачиваний: 737)
        Сообщение отредактировано: Jin X -
          Цитата Jin X @
          А на ВМ проц типа стартует сразу с разогнанной частоты, поэтому и показывает её?

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

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

          прикольно получилось - зачёт! :good:
          Сообщение отредактировано: core-i7 -
            Цитата core-i7 @
            прикольно получилось - зачёт!
            Я там косякнул кое-где (с цифровыми параметрами для SpeedTestMsg) :(
            Сейчас исправил, сообщение обновил ;)
              И снова исправлен косячок, добавленный в результате предыдущего исправления: прога всегда показывала CPU migration <_<
              Файлы обновлены.

              Сообщения были разделены в тему "Определение микроархитектуры CPU"
                core-i7, ты знаешь, всё-таки QPC использует не HPET, даже при значениях QPF = 10 млн.
                Я тут почитал кое-что. Во-первых, для HPET нужно идти в ядро, а QPC этого не делает (по крайней мере, у меня на 10-ке точно, да и на 7-ке, насколько я помню, было так же). Во-вторых, он читает RDTSCP и дальше выполняет какие-то хитрые арифметические операции, в результате чего преобразует это значение в QPC-счётчик. Причём, он выполняет не только деление (через умножение), но и зачем-то добавляет какие-то числа, ибо отношение RDTSCP/QPC постепенно растёт.
                  Цитата 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 для тестов кэша :)
                      Ну и да, эта канитель никогда на частоте проца не работала, насколько я понимаю.
                      0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                      0 пользователей:


                      Рейтинг@Mail.ru
                      [ Script execution time: 0,0486 ]   [ 18 queries used ]   [ Generated: 28.03.24, 08:23 GMT ]