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

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

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

Добро пожаловать и приятного вам общения!!! ;)
 
Модераторы: Jin X, Qraizer
  
> Измерение времени выполнения кода , как средство профилирования
    Имхо замерять время выполнения всей программы наоборот не имеет смысла - если снимать профайл, то с отдельных её участков. Если вместо связки QPC/QPF использовать RDTSC/CPU.freq, то это позволит вычислять время вплоть до нано/секунд, т.е. даже единичные инструкции (например узнать, насколько в цикле лучше DEC,чем LOOP).

    Сейчас-же, всё зависит от частоты таймера QPerfFrequency(), макс.значение которого всего 14 MHz (и то, если задействован HPET, а так 3). Поэтому логичней, взять за основу сразу частоту CPU 1..3 GHz, и его счётчик тактов TSC. Бонусом, не помешала-бы и сериализация на входе/выходе через инструкцию LFENCE.. т.е. учитывать спекулятивное выполнение кода процессором.

    А вообще, для таких случаев в составе Ntdll.dll имеется набор спец.функций NtCreateProfile(), которые в качестве метронома используют таймер локального контролёра LAPIC. Этот таймер работает на частоте шины FSB/DMI (100..200 MHz), а значит и он уступает связке RDTSC+CPUfreq. Однако эти функции точились индусами специально для профайлеров, так-что сбрасывать их со-счетов было-бы глупо.

    Эта тема была разделена из темы "КТЗ!"
      Цитата core-i7 @
      Поэтому логичней, взять за основу сразу частоту CPU 1..3 GHz, и его счётчик тактов TSC. Бонусом, не помешала-бы и сериализация на входе/выходе через инструкцию LFENCE.. т.е. учитывать спекулятивное выполнение кода процессором.

      А можно пример кода, как это запрограммить?
        ..что-то в этом роде:

        ExpandedWrap disabled
          ;====== Частота процессора
                  mov      ecx,2
          @@:     push     ecx
                  lfence
                  rdtsc
                  push     eax
                  invoke   Sleep,500
                  rdtsc
                  pop      ebx
                  sub      eax,ebx
                  mov      ebx,500000
                  cdq
                  div      ebx
                  pop      ecx
                  dec      ecx
                  jnz      @b
                  mov      [cpuFreq],eax     ; запомнить
                 cinvoke   printf,<10,' CPU freq..: %d MHz',0>,eax
           
          ;====== Частота таймера
                  invoke   QueryPerformanceFrequency,qpf
                  mov      eax,[qpf]
                  mov      ebx,1000000
                  cdq
                  div      ebx
                 cinvoke   printf,<10,' Timer freq: %d.%d MHz',0>,eax,edx
           
          ;====== Погрешность = 2 инструкции: сериализация LFENCE, и чтение TSC
                  lfence
                  rdtsc
                  push     eax
                  lfence
                  rdtsc
                  pop      ebx
                  sub      eax,ebx
                  mov      [fix],eax    ; запомнить    
           
          ;***************************
          ; Профайлер
          ;***************************
                  lfence
                  rdtsc
                  push     eax
           
          ;<----- Сюда вставляем профилируемые инструкции
           
                  lfence
                  rdtsc
                  pop      ebx        
                  sub      eax,ebx
                  sub      eax,[fix]
                  push     eax
           
                  fild     dword[esp]    ; такты
                  fidiv    [cpuFreq]     ; разделить на частоту процессора
                  fstp     [fpuBuff]     ; время в нано/секундах
           
                  pop      eax
                 cinvoke   printf,<10,'%u Takt = %.3f Micro/sec',0>,\
                                          eax, dword[fpuBuff], dword[fpuBuff+4]

        Здесь я вывел частоту таймера QPF, чтобы сравнить её с частотой процессора. Если QPF возвратит 3.5 MHz, значит система использует в качестве основного ACPI-таймер (3.579545 MHz), если больше 10 MHz - HPET (в идеале 14). В любом случае, QPF в десятки раз отстаёт от процессора.
          core-i7, привет, Тимур ;)
          Хм... я всегда думал, что QPC тоже использует использует rdtsc или rdtscp (по крайней мере, эта инструкция там есть) и сдвигает результат на 10 бит, но QPF выдал 10 млн, что наводит на размышления.
          Зачем же тогда там эти rdtsc? :huh:

          Т.к. lfence ставит барьер только на чтение и не гарантирует, что перед rdtsc влезет одна из последующих инструкций, я бы делал так всё же:
          ExpandedWrap disabled
            mfence
            rdtsc
            mfence

          Вот хорошая дока по этой теме:
          http://www.mkurnosov.net/uploads/Main/mkur...-rdtsc-2014.pdf

          А есть ещё инструкция rdpmc, которая как раз для профайлинга предназначена, но она сложнее в использовании и не всегда нужна. К тому же, она привилегированная (в винде, в линуксе, видимо, тоже), нужно драйвер писать, хотя у Агнера Фога уже есть: https://www.agner.org/optimize/#testp

          Добавлено
          Можно ещё приоритет потока выставлять по максимуму, кстати.
            Женя, салам!
            Цитата Jin X @
            но QPF выдал 10 млн, что наводит на размышления.
            Зачем же тогда там эти rdtsc?

            10 илн, это значит 10 MHz чтоли? (т.к. там в наносек блоках)
            У меня на буке тоже не подымается выше 10-ти, хотя это HPET и частота его 14 MHz.
            а rdtsc наверное там для какой-нибудь калибровки.
              [cut по просьбе автора]
              Лично мне вот интересно, предложения core-i7 смогут ли улучшить точность С++ шного std::chrono::high_resolution_clock? И чуйка мне подсказывает "несомненно" (я всегда надеюсь на лучшее, прогрессивное и спортивное)!
              [cut по просьбе автора]

              Цитата Jin X @
              Хм... я всегда думал, что QPC тоже использует использует rdtsc или rdtscp

              В качестве антиоффтопика ... когда я увидел код от core-i7, сразу побежал интересоваться незнакомыми мне командами :) Статья-за-статьей, статья-за-статьей ... и у меня есть ответ на твой вопрос (частично). А именно! QPC не точнее кода от core-i7 лишь потому, что там - API, и под капотом у которого стопицот индусов, которых погоняют 10 брахманов (даже если они используют rdtsc или rdtscp). А у core-i7 в примере - только инструкции камня. Ну это чисто мое ИМХО. Мнений конечно дохрена, но я пока вот такое выбрал за истину.
              Сообщение отредактировано: Jin X -
                Цитата core-i7 @
                10 илн, это значит 10 MHz чтоли? (т.к. там в наносек блоках)
                QFP выдаёт частоту, т.е. 10 млн - это 10 МГц. При чём тут наносекунды?
                  Скрытый текст
                  Эх ... удалил такое искреннее сообщение от себя :wall: За два года модерства - расслабился, потерял чуйку! :wall:

                  Добавлено
                  Цитата Jin X @
                  т.к. оно включает в себя больше всего, нежели замер времени.

                  Ну мож быть ... тебе виднее - но я заметил именно профилирование. Но спорить не хочу совсем - мне диалог дальнейший интересен. Мое мнение ... та-сяк ... слушать интереснее, особенно если собеседники плотно в теме.
                    Цитата JoeUser @
                    Эх ... удалил такое искреннее сообщение от себя За два года модерства - расслабился, потерял чуйку!
                    Не понимаю, о чём ты?
                    Если надо, можно найти сообщение (отредактированное, удалённое). Но с этим лучше в Л.С., чтобы не засорять обсуждение.

                    Цитата JoeUser @
                    Ну мож быть ... тебе виднее - но я заметил именно профилирование.
                    Не в заголовке суть, а в великих речах, глаголящих истину :P
                      Что любопытно, XP (виртуальная) выдаёт 3ГГц, а 7ка уже 10МГц

                      Добавлено
                      core-i7, поправь-таки код. Частота путает уменьшаемое и вычитаемое, все замеры путают знаковую и беззнаковую арифметику, а целочисленную арифметику замени на 64-битную, ибо странно наблюдать отрицательные Micro/sec
                        Цитата Qraizer @
                        Что любопытно, XP (виртуальная) выдаёт 3ГГц, а 7ка уже 10МГц
                        В 98 вообще 1.19 МГц :)
                        Там таймер 8254 используется :)
                          Подкину дровишек.
                          1) Для виртуализации TSC сохраняется в контексте процесса и после загружается обратно. Причем виндоус использует это всегда.
                          2)
                          Цитата
                          е RDTSC+CPUfreq. Однако эти функции точились индусами специально для профайлеров,
                          В давние времена да.
                          Суть в том что если делать x64 программы то там эта комбинация плавает в отрицательные области. А х32- программах индусы всё же сделали что'бы они не плавали.

                          3)
                          Цитата
                          таймер локального контролёра LAPIC. Этот таймер работает на частоте шины FSB/DMI (100..200 MHz),

                          Там не 100 Мгц, а частота RDTSC. Только младшие биты 4-5 бит они не контролируют.
                          4) Для профилирования есть PerformanceCounter нужен драйвер. У интела есть IntelPerformanceCounterMonitor-PCM-V2.10 нужно только GUI или API прекрутить.
                            Цитата Qraizer @
                            core-i7, поправь-таки код
                            Как вариант:
                            Скрытый текст
                            ExpandedWrap disabled
                              format  PE Console 4.0
                              entry   start
                               
                              include 'win32axp.inc'
                               
                              ;-- CODE SECTION -------------------------------------------------------------------------------------------------------
                               
                              macro   ReadTSC
                              {
                                      mfence
                                      rdtsc
                                      mfence
                              }
                               
                              .code
                               
                              start:
                                      invoke   SetThreadPriority, -2, THREAD_PRIORITY_TIME_CRITICAL
                               
                              ;====== Частота процессора
                                      ReadTSC
                                      push     eax
                                      push     edx
                                      invoke   Sleep,1000
                                      ReadTSC
                                      pop      ecx
                                      pop      ebx
                                      sub      eax,ebx
                                      sbb      edx,ecx
                                      push     edx
                                      push     eax
                                      fild     qword[esp]
                                      add      esp,8
                                      fidiv    [N1M]
                                      fistp    [cpuFreq]
                                     cinvoke   printf,<10,'  CPU freq: %d MHz',0>,[cpuFreq]
                               
                              ;====== Частота таймера
                                      invoke   QueryPerformanceFrequency,qpf
                                      fild     [qpf]
                                      fidiv    [N1M]
                                      fstp    [fpuBuff]
                                     cinvoke   printf,<10,'Timer freq: %f MHz',0>,dword[fpuBuff],dword[fpuBuff+4]
                               
                              ;====== Погрешность = 2 инструкции: сериализация LFENCE, и чтение TSC
                                      ReadTSC
                                      push     eax
                                      ReadTSC
                                      pop      ebx
                                      sub      eax,ebx
                                      mov      [fix],eax    ; запомнить    
                               
                              ;***************************
                              ; Профайлер
                              ;***************************
                                      ReadTSC
                                      push     eax
                               
                              ;<----- Сюда вставляем профилируемые инструкции
                               
                                      ReadTSC
                                      pop      ebx
                                      sub      eax,ebx
                                      sub      eax,[fix]
                                      push     eax
                               
                                      fild     dword [esp]   ; такты
                                      fidiv    [cpuFreq]     ; разделить на частоту процессора
                                      fstp     [fpuBuff]     ; время в микросекундах
                               
                                      pop      eax
                                     cinvoke   printf,<10,'%i ticks = %f microsec',0>,\
                                                              eax, dword[fpuBuff], dword[fpuBuff+4]
                                     cinvoke   getch
                                      invoke   ExitProcess, 0
                               
                              ;-- DATA SECTION -------------------------------------------------------------------------------------------------------
                               
                              .data
                               
                              N1M     dd       1000000
                              cpuFreq dd       ?
                              fix     dd       ?
                              qpf     dq       ?
                              fpuBuff dq       ?
                               
                              ;-- IMPORT SECTION -----------------------------------------------------------------------------------------------------
                               
                              section '.idata' import data readable
                               
                              library kernel32, 'kernel32.dll',\
                                      msvcrt, 'msvcrt.dll'
                               
                                      import_kernel32
                                      all_api
                               
                              import  msvcrt,\
                                      printf, 'printf',\
                                      getch, '_getch'
                              Скрытый текст
                              Цитата Jin X @
                              Не понимаю, о чём ты?

                              Это и хорошо! 30 гратусов тов. Цельсия в тени меня сводят с ума - и я уже кидаюсь на всех аки собака Баскервили)
                                Цитата Jin X @
                                Как вариант
                                У меня этот код в виртуальной Win98 показывает время пустого кода минус несколько тысяч тактов, в 10-ке в районе -20 (в среднем), на домашнем около нуля (+/-). Любопытненько, однако...
                                И ещё на домашнем частота 3300 измеряется, на вирт. 3700. Хотя всякие там CPU-Z показывают 3700. На самом деле у меня небольшой штатный разгон: 3300 -> 3700.
                                Это что, так Invariant TSC работает?

                                Цитата Pavia @
                                1) Для виртуализации TSC сохраняется в контексте процесса и после загружается обратно. Причем виндоус использует это всегда.
                                А если поподробнее?
                                  Цитата 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 Кбайт, скачиваний: 1027)
                                  Сообщение отредактировано: core-i7 -
                                    Цитата core-i7 @
                                    овер биоса на неё не влияет
                                    А на ВМ проц типа стартует сразу с разогнанной частоты, поэтому и показывает её?

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

                                    update: Вот инфа по этому поводу. Получается, что так и есть.
                                    Прикреплённый файлПрикреплённый файлcode_align.png (101,79 Кбайт, скачиваний: 1191)
                                    Сообщение отредактировано: 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 Кбайт, скачиваний: 738)
                                      Сообщение отредактировано: 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,0830 ]   [ 19 queries used ]   [ Generated: 16.04.24, 16:01 GMT ]