суботу, 12 серпня 2017 р.

Огляд (CPU) performance counters API

Схема процесора M68000. Взято тут.
Сучасні процесори надають доступ до різноманітної інформації, пов'язаної із їх роботою -- кількість кеш-промахів та кеш-попадань, кількість виконаних переходів та кількість не вгаданих branch-предиктором переходів, кількість виконаних команд різних видів і т.д. і т.п.

Звичайно, до цієї інформації можна доступатися безпосередньо -- якщо ОС надає відповідні права працювати із моделе-специфічними регістрами процесора (MSR) або є можливість завантажити відповідний драйвер. Однак, це складно -- набір регістрів прив'язаний не тільки до архітектури процесора (x86 чи ARM), але й виробника (Intel vs AMD) і конкретної моделі процесора. Код виходить дуже непортабельним, або дуже громіздким. Зате все під контролем. Детальніше про такий підхід -- див., наприклад, сайт славнозвісного Агнера Фога: "Test programs for measuring clock cycles and performance monitoring". 

Однак, розвинені ОС надають і звичайним програмам доступ до цих інструментів. Про відповідні API MS Windows трішки говорилося в попередньому пості. Для повноти коротко (дуже коротко!) розглянемо спеціалізоване API для POSIX систем -- PAPI та кросплатформову бібліотеку від Intel Processor Counter Monitor (PCM).
Як бачимо, повної кросплатформовості немає -- або тільки POSIX (з обмовками), або тільки процесори Intel, при тому -- достатньо сучасні (конкретніше -- див. далі).


Linux -- PAPI


PAPI (Performance API) -- бібліотека читання performance counter-ів процесорів, яка з часом навчилася також працювати із іншими підсистемами -- мережею, вводом-виводом, тощо. Портабельна, існує під багато POSIX-систем, старіші версії (3.7) вміли працювати під Windows, хоч і обмежено.

Щоб заінсталювати під Linux, шукайте у вашому менеджері пакетів пакети типу libpapi-dev (Debian), чи papi-delev (RedHat). У деяких дистрибутивах може бути окремий пакет типу papi-tools (Debian), із command-line інструментами. Див. також офіційний сайт.

Існує у варіантах для С та для Fortran. Із С++, відповідно, проблем немає, а для інших мов будуть потрібні прив'язки -- bindings. 

Бібліотека підраховує кількість якихось подій системи. Ідентифікуються події іменами та внутрішніми кодами (є функції трансляції одного в інше і назад). Події поділяються на "нативні" (native events) -- присутні у конкретному процесорі і задані наперед (preset events) -- події, інформація про яких може бути корисна всім, і які є узагальненням більш низькорівневих нативних подій. Наприклад, "Total L1 Cache Misses" (PAPI_L1_TCM) -- сумарна кількість промахів кешу першого рівня на одних процесорах може відображатися на нативну подію (вміст якогось MSR, грубо кажучи), а на інших розраховуватися з кількості промахів кешу інструкцій і кешу даних. 

Є відповідні функції API для перевірки, чи конкретні події підтримуються:

1
2
3
int PAPI_query_event( int EventCode )
int PAPI_get_event_info( int EventCode, PAPI_event_info_t *info )
int PAPI_enum_event( int *EventCode, int modifier )
Також є утилітка papi_avail, яка виводить інформацію про події, підтримувані даною реалізацією.

Приклад її роботи на Raspberry Pi 3:

root@pi3:~# papi_avail | grep Yes

    Name        Code    Avail Deriv Description (Note)             # Copied later
PAPI_L1_DCM  0x80000000  Yes   Yes  Level 1 data cache misses
PAPI_L1_ICM  0x80000001  Yes   No   Level 1 instruction cache misses
PAPI_L2_DCM  0x80000002  Yes   No   Level 2 data cache misses
PAPI_TLB_DM  0x80000014  Yes   No   Data translation lookaside buffer misses
PAPI_TLB_IM  0x80000015  Yes   No   Instruction translation lookaside buffer misses
PAPI_HW_INT  0x80000029  Yes   No   Hardware interrupts
PAPI_BR_MSP  0x8000002e  Yes   No   Conditional branch instructions mispredicted
PAPI_TOT_INS 0x80000032  Yes   No   Instructions completed
PAPI_LD_INS  0x80000035  Yes   No   Load instructions
PAPI_SR_INS  0x80000036  Yes   No   Store instructions
PAPI_BR_INS  0x80000037  Yes   No   Branch instructions
PAPI_TOT_CYC 0x8000003b  Yes   No   Total cycles
PAPI_L1_DCA  0x80000040  Yes   No   Level 1 data cache accesses
PAPI_L2_DCA  0x80000041  Yes   No   Level 2 data cache accesses

Якись-там x86-64 (від моделі процесора та, можливо, версії ядра, результати змінюються):

[root@west papi_test]# papi_avail | grep Yes
    Name        Code    Avail Deriv Description (Note)             # Copied later
PAPI_L1_DCM  0x80000000  Yes   No   Level 1 data cache misses
PAPI_L1_ICM  0x80000001  Yes   No   Level 1 instruction cache misses
PAPI_L2_DCM  0x80000002  Yes   Yes  Level 2 data cache misses
PAPI_L2_ICM  0x80000003  Yes   No   Level 2 instruction cache misses
PAPI_L1_TCM  0x80000006  Yes   No   Level 1 cache misses
PAPI_L2_TCM  0x80000007  Yes   No   Level 2 cache misses
PAPI_CA_SHR  0x8000000a  Yes   No   Requests for exclusive access to shared cache line
PAPI_CA_CLN  0x8000000b  Yes   No   Requests for exclusive access to clean cache line
PAPI_CA_ITV  0x8000000d  Yes   No   Requests for cache line intervention
PAPI_TLB_DM  0x80000014  Yes   No   Data translation lookaside buffer misses
PAPI_TLB_IM  0x80000015  Yes   No   Instruction translation lookaside buffer misses
PAPI_L1_LDM  0x80000017  Yes   No   Level 1 load misses
PAPI_L1_STM  0x80000018  Yes   No   Level 1 store misses
PAPI_L2_LDM  0x80000019  Yes   Yes  Level 2 load misses
PAPI_L2_STM  0x8000001a  Yes   No   Level 2 store misses
PAPI_HW_INT  0x80000029  Yes   No   Hardware interrupts
PAPI_BR_CN   0x8000002b  Yes   No   Conditional branch instructions
PAPI_BR_TKN  0x8000002c  Yes   No   Conditional branch instructions taken
PAPI_BR_NTK  0x8000002d  Yes   No   Conditional branch instructions not taken
PAPI_BR_MSP  0x8000002e  Yes   No   Conditional branch instructions mispredicted
PAPI_BR_PRC  0x8000002f  Yes   Yes  Conditional branch instructions correctly predicted
PAPI_TOT_IIS 0x80000031  Yes   No   Instructions issued
PAPI_TOT_INS 0x80000032  Yes   No   Instructions completed
PAPI_FP_INS  0x80000034  Yes   No   Floating point instructions
PAPI_LD_INS  0x80000035  Yes   No   Load instructions
PAPI_SR_INS  0x80000036  Yes   No   Store instructions
PAPI_BR_INS  0x80000037  Yes   No   Branch instructions
PAPI_VEC_INS 0x80000038  Yes   No   Vector/SIMD instructions (could include integer)
PAPI_RES_STL 0x80000039  Yes   No   Cycles stalled on any resource
PAPI_TOT_CYC 0x8000003b  Yes   No   Total cycles
PAPI_L1_DCH  0x8000003e  Yes   Yes  Level 1 data cache hits
PAPI_L1_DCA  0x80000040  Yes   No   Level 1 data cache accesses
PAPI_L2_DCA  0x80000041  Yes   Yes  Level 2 data cache accesses
PAPI_L2_DCR  0x80000044  Yes   No   Level 2 data cache reads
PAPI_L2_DCW  0x80000047  Yes   No   Level 2 data cache writes
PAPI_L1_ICH  0x80000049  Yes   Yes  Level 1 instruction cache hits
PAPI_L2_ICH  0x8000004a  Yes   Yes  Level 2 instruction cache hits
PAPI_L1_ICA  0x8000004c  Yes   No   Level 1 instruction cache accesses
PAPI_L2_ICA  0x8000004d  Yes   No   Level 2 instruction cache accesses
PAPI_L2_TCH  0x80000056  Yes   Yes  Level 2 total cache hits
PAPI_L1_TCA  0x80000058  Yes   Yes  Level 1 total cache accesses
PAPI_L2_TCA  0x80000059  Yes   No   Level 2 total cache accesses
PAPI_L2_TCR  0x8000005c  Yes   Yes  Level 2 total cache reads
PAPI_L2_TCW  0x8000005f  Yes   No   Level 2 total cache writes
PAPI_FML_INS 0x80000061  Yes   No   Floating point multiply instructions
PAPI_FDV_INS 0x80000063  Yes   No   Floating point divide instructions
PAPI_FP_OPS  0x80000066  Yes   No   Floating point operations
PAPI_SP_OPS  0x80000067  Yes   Yes  Floating point operations; optimized to count scaled single precision vector operations
PAPI_DP_OPS  0x80000068  Yes   Yes  Floating point operations; optimized to count scaled double precision vector operations
PAPI_VEC_SP  0x80000069  Yes   No   Single precision vector/SIMD instructions
PAPI_VEC_DP  0x8000006a  Yes   No   Double precision vector/SIMD instructions
PAPI_REF_CYC 0x8000006b  Yes   No   Reference clock cycles


(Результати відфільтровано, по замовчуванню показує повний список подій, біля багатьох із яких пише No -- не підтримується, але у текстах вище додано оригінальний заголовок).

Інші утиліти:
  • papi_mem_info виводить інформацію  про архітектуру пам'яті -- розмір кешів, TLB, тощо.
  • papi_clockres -- роздільна здатність доступних таймерів.
  • papi_command_line -- отримання інформації про події із командного рядка.
  • Та багато інших. Детальніше див. документацію.
 Для ініціалізації слід викликати функцію  PAPI_library_init().

Обробка помилок  описана тут: "PAPI Error Handling". Ідея наступна -- функція повертає код завершення, якщо він не рівний PAPI_OK, сталася та чи інша помилка. Список є за посиланням вище, а її текстовий опис можна отримати викликом PAPI_perror() чи PAPI_strerror().

Підтримуються потоки, однак, кожен потік повинен ініціалізувати підтримку підрахунку подій самостійно. Для ввімкнення підтримки потоків, слід викликати PAPI_thread_init(pthread_self), а кожен потік реєструвати викликом PAPI_register_thread(). Підтримується також MPI! Детальніше див. "Using PAPI with Parallel Programs".

Можна оголошувати групи подій (event sets) для подій, які слід вимірювати одночасно. Детальніше див. "EVENT SETS".

Кількість лічильників, які можна використовувати, обмежена апаратно. (Є можливість мультиплексування, як спосіб обійти це обмеження). Взнати їх кількість можна за допомогою функції PAPI_num_counters(). Однак, тут є важливий нюанс -- для деяких подій треба зразу декілька апаратних лічильників, тому ще що їх у вас 6 не означає, що вдасться спостерігати за 6-ма довільними подіями зразу.

Приклад, як цим всім користуватися, можна побачити в репозиторії до цієї серії постів. Код виглядає якось так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
    int ret = PAPI_library_init(PAPI_VER_CURRENT);
    
    if (ret != PAPI_VER_CURRENT) {
        cout << "PAPI library init error!" << endl;
        exit(1);
    }

 int Events[] = {PAPI_L1_DCM, PAPI_L1_ICM};
 const size_t NUM_EVENTS = sizeof(Events)/sizeof(Events[0]);
 long_long values[NUM_EVENTS];
 
    if ( (ret = PAPI_start_counters(Events, NUM_EVENTS)) != PAPI_OK)
    {
      cout << "Error starting counters, code: " << ret << ", " << PAPI_strerror(ret) << endl;
      return 1;
    }

 ...................code............................................
 
    if ( (ret = PAPI_read_counters(values, NUM_EVENTS)) != PAPI_OK)
    {
      cout << "Err  code: " << ret << ", " <<     PAPI_strerror(ret) << endl;
      return 1;
    }

 char EventCodeStr[PAPI_MAX_STR_LEN];
 for(size_t i = 0; i<NUM_EVENTS; ++i)
 {
  cout << "Event code " << hex << SupportedEvents[i] << dec;
  if (PAPI_event_code_to_name(Events[i], EventCodeStr) == PAPI_OK)
  {
   cout << ", " << EventCodeStr;
  }
  cout << ": " << values[i];
  PAPI_event_info_t info;
  if (PAPI_get_event_info(Events[i], &info) == PAPI_OK)
  {
   cout << "\t" << info.long_descr;
  }else{
   cout << "\t" << "No description";
  }
  cout << endl;  
 } 

Через обмеження часу і мізерну кількість апаратних лічильників, код у репозиторії дещо дивний -- він випадковим чином вибирає декілька подій, і намагається їх підраховувати. Якщо лічильників для цієї комбінації бракує -- виводить повідомлення про помилку і завершується. Адекватним рішення було б або хитро взяти 1-2 події, щоб лічильників завжди вистачало, або використати мультплексування, але перше -- не весело, а на друге згаданого часу не вистачило.

Processor Counter Monitor (PCM)

PCM, як вже згадувалося -- кросплатформова бібліотека роботи із подіями процесорів та деяких інших системних метрик.  Правда, лише від Intel. На жаль, потребує зовсім нових процесорів:
Error: unsupported processor. Only Intel(R) processors are supported (Atom(R) and microarchitecture codename Nehalem/Nehalem-EP, Atom(tm), Westmere/Clarkdale, Sandy Bridge, Westmere-EP, Sandy Bridge-EP/Jaketown, Nehalem-EX, Westmere-EX, Ivy Bridge, Haswell, Broadwell, Ivy Bridge-EP/EN/EX/Ivytown, Haswell-EP/EN/EX, Broadwell-EP/EX, Skylake-SP, Broadwell-DE, Knights Landing, Skylake, Kabylake). CPU model number: 23 Brand: "Intel(R) Xeon(R) CPU E5405 @ 2.00GHz"
Як і PAPI, включає багато готових утиліт (точніше, навпаки, бібліотека була написана для їх підтримки, але придатна для незалежного використання):
  • pcm -- загальний моніторинг процесора (кількість виконаних команд,  тактова частота, пропускна здатність QPI (Quick Path Interconnect),  і т.д. і т.п.
  • pcm-memory -- пропускна здатність пам'яті.
  • pcm-pcie і pcm-iio  -- моніторинг PCIe.
  • pcm-numa -- відстеження локальних та нелокальних звертань на NUMA-системах.
  • pcm-core і pmu-query -- відстежування довільних подій процесорів.
  • Та пара інших.
"Інсталяція" проста:

git clone https://github.com/opcm/pcm
cd pcm
make

Можна пробувати запускати. На моїх системах часто з'являється повідомлення:

[root@computer pcm]# ./pcm-core.x
Error: NMI watchdog is enabled. This consumes one hw-PMU counter
 to disable NMI watchdog please run under root: echo 0 > /proc/sys/kernel/nmi_watchdog
 or to disable it permanently: echo 'kernel.nmi_watchdog=0' >> /etc/sysctl.conf

 Processor Counter Monitor: Core Monitoring Utility

Access to Processor Counter Monitor has denied (no MSR or PCI CFG space access).

Про NMI Watchog можна почитати окремо, але вказана в повідомленні інструкція діє, даючи можливість запускати згадані утиліти.

Для ілюстрації -- приклад виводу pcm-numa на системі із 24 логічними ядрами:

Core | IPC  | Instructions | Cycles  |  Local DRAM accesses | Remote DRAM Accesses
   0   0.48        835 K     1728 K       133                 130
   1   0.20         88 K      432 K        17                  20
   2   0.15         43 K      287 K        20                  17
   3   0.22        154 K      703 K        73                  44
   4   0.27        114 K      422 K        41                  87
   5   0.23        101 K      441 K        31                  85
   6   0.27        108 K      399 K        19                  20
   7   0.24        178 K      749 K        58                 103
   8   0.33        149 K      454 K        46                  34
   9   0.30        182 K      617 K        37                  56
  10   0.27         91 K      344 K        29                  45
  11   0.22         83 K      377 K        56                  90
  12   0.27        174 K      657 K        10                  21
  13   0.24        219 K      920 K        98                 241
  14   0.33        134 K      411 K        40                  58
  15   0.31        231 K      737 K        56                  27
  16   0.26         67 K      265 K        21                  14
  17   0.23         88 K      378 K        21                  94
  18   0.31        195 K      632 K        90                  93
  19   0.30        237 K      804 K        27                  57
  20   0.24         60 K      254 K        28                  47
  21   0.28        119 K      421 K        24                  38
  22   0.33        105 K      324 K        40                  41
  23   0.30        153 K      505 K        41                  68
-------------------------------------------------------------------------------------------------------------------
   *   0.30       3920 K       13 M      1056                1530


Якщо ваші програми скаржаться багато-багато раз на:

Error while reading perf data. Result is 0
Check if you run other competing Linux perf clients.

варто скомпілювати,прибравши із Makefile наступні рядки, вказавши не використовувати perf:

ifneq ($(wildcard /usr/include/linux/perf_event.h),)
CXXFLAGS += -DPCM_USE_PERF
endif


Правда, при цьому доведеться іноді безпосередньо перевантажувати PMU (Performance Monitoring Unit), див. код далі. Чому йому іноді perf API не подобається -- не знаю, за безпосередньої роботи із ним проблем немає.

За допомогою проектів Visual Studio, вдалося зібрати бібліотеку і під Windows. Правда, не без напильника -- воно скаржилося на опції, несумісні із /clr (хоча останнє якраз не ввімкнене, якщо вірити GUI!), то довелося забрати /Gm i ввімкнути /RTC1.

Використання у власному коді може виглядати якось так:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include <iostream>

#include "cpucounters.h"

using namespace std;
int main() {
    PCM * m = PCM::getInstance();
    PCM::ErrorCode returnResult = m->program();
 
    switch (returnResult)
    {
        case PCM::Success:
            break;
        case PCM::MSRAccessDenied:
            cerr << "MSRAccessDenied." << endl;
            exit(EXIT_FAILURE);
        case PCM::PMUBusy:
            cerr << "Looks like Performance Monitoring Unit is occupied by other application" << endl;
            cerr << "Reset it? (y/n)" << endl;
            char yn;
            std::cin >> yn;
            if ('y' == yn)
            {
                m->resetPMU();
                cerr << "PMU configuration has been reset. Try to rerun the program again." << endl;
            }
            exit(EXIT_FAILURE);
        default:
            cerr << "Unknown error." << endl;
            exit(EXIT_FAILURE);
    }

    SystemCounterState before_sstate = getSystemCounterState();

 ........................Code.for.testing...............................

    SystemCounterState after_sstate = getSystemCounterState();

 std::cout << fixed << left;
 int w = 35;
    std::cout << setw(w) << "Core cycles:" << getCycles(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) << "Average retired instructions:" << getExecUsage(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) << "Retired instructions:" << getInstructionsRetired(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Invariant TSC:" << getInvariantTSC(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Referen clock cycles:" << getRefCycles(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Instructions per clock cycle:" << getIPC(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Average core frequency:" << getAverageFrequency(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Average relative core frequency:" << getRelativeFrequency(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Core cycles lost due to L3 cache misses:" << getCyclesLostDueL3CacheMisses(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Core cycles lost due to L2 cache misses:" << getCyclesLostDueL2CacheMisses(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Core cycles lost due to L2 cache misses:" << getCyclesLostDueL2CacheMisses(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "L2 cache hit ratio:" << getL2CacheHitRatio(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "L2 cache hits:" << getL2CacheHits(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "L2 cache misses:" << getL2CacheMisses(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "L3 cache hit ratio:" << getL3CacheHitRatio(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "L3 cache hits:" << getL3CacheHits(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "L3 cache misses:" << getL3CacheMisses(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "L3 cache occupancy before:" << getL3CacheOccupancy(before_sstate) << std::endl;
    std::cout << setw(w) <<  "L3 cache occupancy after:" << getL3CacheOccupancy(after_sstate) << std::endl;
 
    std::cout << setw(w) <<  "SMI interrupts:" << getSMICount(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Local Memory Bandwidth:" << getLocalMemoryBW(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Remote Memory Bandwidth:" << getRemoteMemoryBW(before_sstate,after_sstate) << std::endl;
 
    std::cout << setw(w) <<  "Bytes read from RAM:" << getBytesReadFromMC(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Bytes written to RAM:" << getBytesWrittenToMC(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "I/O Bytes:" << getIORequestBytesFromMC(before_sstate,after_sstate) << std::endl;

    std::cout << setw(w) <<  "Consumed by CPU energy (Joules):" << getConsumedJoules(before_sstate,after_sstate) << std::endl;
    std::cout << setw(w) <<  "Consumed by DRAM energy (Joules):" << getDRAMConsumedJoules(before_sstate,after_sstate) << std::endl;
    m->cleanup();
}
Якщо не викликати cleanup(), при наступному запуску скаржитиметься: "Looks like Performance Monitoring Unit is occupied by other application. Reset it? (y/n)" -- якщо відповісти `y`, при наступному запуску програма має шанс успішно відпрацювати. (Звичайно, так само скаржитиметься, якщо лічильниками користується хтось інший!)

Згідно офіційної документації, компілюється програма, що використовує PCM, трохи нетривіально:

g++ -std=c++11 -I<pcm-path> <pcm-path>/cpucounters.o <pcm-path>/pci.o <pcm-path>/msr.o <pcm-path>/client_bw.o  -lpthread  pcm_test.cpp -o pcm_test

де список об'єктних файлів -- файли, що входять в PCM. Але окрема ціль побудови бібліотеки існує, якщо зробити:

make libPCM.a

Файл libPCM.a з'явиться, і з ним можна буде успішно лінкуватися:

g++ -std=c++11 -I<pcm-path> -L<pcm-path> -lPCM -lpthread  pcm_test.cpp -o pcm_test

Вивід буде якимось таким:

[root@compute-0-5 pcm]# g++ -std=c++11 -I. -L. cpucounters.o pci.o msr.o client_bw.o  -lpthread  sample.cpp -o pcm_test && ./pcm_test
Number of physical cores: 12
Number of logical cores: 24
Number of online logical cores: 24
Threads (logical cores) per physical core: 2
Num sockets: 2
Physical cores per socket: 6
Core PMU (perfmon) version: 3
Number of core PMU generic (programmable) counters: 4
Width of generic (programmable) counters: 48 bits
Number of core PMU fixed counters: 3
Width of fixed counters: 48 bits
Nominal core frequency: 2100000000 Hz
Package thermal spec power: 80 Watt; Package minimum power: 51 Watt; Package maximum power: 110 Watt;
ERROR: QPI LL monitoring device (0:7f:8:2) is missing. The QPI statistics will be incomplete or missing.
ERROR: QPI LL monitoring device (0:7f:9:2) is missing. The QPI statistics will be incomplete or missing.
Socket 0: 1 memory controllers detected with total number of 4 channels. 0 QPI ports detected.
ERROR: QPI LL monitoring device (0:ff:8:2) is missing. The QPI statistics will be incomplete or missing.
ERROR: QPI LL monitoring device (0:ff:9:2) is missing. The QPI statistics will be incomplete or missing.
Socket 1: 1 memory controllers detected with total number of 4 channels. 0 QPI ports detected.
Core cycles:                            4048298393
Average retired instructions:           0.053560
Retired instructions:                   4318553674
Invariant TSC:                          80630013261
Referen clock cycles:                   3396284619
Instructions per clock cycle:           1.066758
Average core frequency:                 105437495.065030
Average relative core frequency:        0.050208
Core cycles lost due to L3 cache misses:0.004025
Core cycles lost due to L2 cache misses:0.000733
Core cycles lost due to L2 cache misses:0.000733
L2 cache hit ratio:                     0.171535
L2 cache hits:                          35214
L2 cache misses:                        170074
L3 cache hit ratio:                     0.467785
L3 cache hits:                          79558
L3 cache misses:                        90516
L3 cache occupancy before:              0
L3 cache occupancy after:               0
SMI interrupts:                         0
Local Memory Bandwidth:                 0
Remote Memory Bandwidth:                0
Bytes read from RAM:                    117596096
Bytes written to RAM:                   111231296
I/O Bytes:                              0
Consumed by CPU energy (Joules):        71.988235
Consumed by DRAM energy (Joules):       23.961838

Зауважте "преамбулу", яку виводить сама бібліотека.

На загал, хоча інструмент потужний, враження від нього неоднозначні... Треба буде поспостерігати за розвитком.

Додатково, див. "Intel Performance Counter Monitor".

А на разі,

Дякую за увагу!



Немає коментарів:

Дописати коментар