Googling i ack
-ing się skończyły! Mam odpowiedź.
Ale najpierw pozwól, że wyjaśnię nieco cel pytania: chcę wyraźnie odróżnić niezależne procesy w systemie i ich liczniki wydajności. Na przykład rdzeń procesora, urządzenie uncore (o tym niedawno się dowiedziałem), jądro lub aplikacja użytkownika na procesorze, magistrala (= kontroler magistrali), dysk twardy są niezależnymi procesami, nie są synchronizowane przez zegar . I obecnie prawdopodobnie każdy z nich ma jakiś licznik monitorowania procesu (PMC). Chciałbym zrozumieć, z których procesów pochodzą te liczniki. (Jest to również pomocne w googlowaniu: „sprzedawca” rzeczy zeruje to lepiej.)
Również sprzętu wykorzystywanego do szukania: Ubuntu 14.04
, linux 3.13.0-103-generic
, procesor Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz
(z /proc/cpuinfo
, posiada 2 rdzenie fizyczne i 4 wirtualne - fizyczne materii tutaj).
Terminologia, rzeczy, które obejmuje pytanie
Od Intela:
procesor to core
urządzenie (to 1 urządzenie / proces) i kilka uncore
urządzeń , core
to, co uruchamia program (zegar, ALU, rejestry itp.), uncore
są urządzeniami umieszczanymi na matrycy, blisko procesora ze względu na szybkość i małe opóźnienia (prawdziwy powód to „ponieważ producent może to zrobić”); jak zrozumiałem, jest to w zasadzie mostek północny, jak na płycie głównej komputera, plus pamięci podręczne; a AMD faktycznie nazywa te urządzenia NorthBridge instead of
uncore`;
ubox
co pojawia się w moim sysfs
$ find /sys/devices/ -type d -name events
/sys/devices/cpu/events
/sys/devices/uncore_cbox_0/events
/sys/devices/uncore_cbox_1/events
- jest uncore
urządzeniem, które zarządza pamięcią podręczną ostatniego poziomu (LLC, ostatnia przed uderzeniem w pamięć RAM); Mam 2 rdzenie, a więc 2 LLC i 2 ubox
;
Processor Monitoring Unit (PMU) to oddzielne urządzenie, które monitoruje operacje procesora i zapisuje je w liczniku monitorowania procesora (PMC) (zlicza błędy pamięci podręcznej, cykle procesora itp.); one istnieć core
i uncore
urządzeń; z core
nich są dostępne z rdpmc
(czytaj PMC) pouczenie; uncore
, ponieważ urządzenia te zależą od rzeczywistego procesorów w parze są dostępne poprzez modele rejestrów szczególne (MSR) poprzez rdmsr
(naturalny);
najwyraźniej przepływ pracy z nimi odbywa się za pomocą par rejestrów - 1 rejestr ustawia zdarzenia, które liczy licznik, 2 rejestr jest wartością w liczniku; licznik można skonfigurować tak, aby zwiększał wartość po kilku zdarzeniach, nie tylko 1; + w tych licznikach występują interupty / zauważające przepełnienie technologiczne;
więcej można znaleźć w „Intel IA-32 Software Developer's Manual Vol. 3B” rozdział 18 „MONITOROWANIE WYDAJNOŚCI”;
także format MSR konkretnie dla tych uncore
PMC dla wersji „Architectural Performance Monitoring Version 1” (istnieją wersje 1-4 w instrukcji, nie wiem, który to mój procesor) jest opisany na „Rysunek 18-1. MSR IA32_PERFEVTSELx ”(strona 18-3 w kopalni) oraz sekcja„ 18.2.1.2 Wstępnie zdefiniowane zdarzenia wydajności architektonicznej ”w„ Tabeli 18-1. UMask i kodowanie wybranych zdarzeń dla wstępnie zdefiniowanych zdarzeń wydajności architektonicznej ”, która pokazuje wydarzenia, które pojawiają się jak Hardware event
w perf list
.
Z jądra Linux:
jądro ma system (abstrakcja / warstwa) do zarządzania licznikami wydajności różnego pochodzenia, zarówno oprogramowania (jądra), jak i sprzętu, co opisano w linux-source-3.13.0/tools/perf/design.txt
; zdarzenie w tym systemie jest zdefiniowane jako struct perf_event_attr
(plik linux-source-3.13.0/include/uapi/linux/perf_event.h
), którego główna część jest prawdopodobnie __u64 config
polowa - może zawierać zarówno definicję zdarzenia specyficzną dla procesora (64-bitowe słowo w formacie opisanym na tych liczbach Intela), jak i zdarzenie jądra
MSB słowa konfiguracyjnego oznacza, że reszta zawiera [nieprzetworzone zdarzenie procesora lub jądra]
zdarzenie jądra zdefiniowane za pomocą 7 bitów dla typu i 56 dla identyfikatora zdarzenia, które są enum
-s w kodzie, które w moim przypadku to:
$ ak PERF_TYPE linux-source-3.13.0/include/
...
linux-source-3.13.0/include/uapi/linux/perf_event.h
29: PERF_TYPE_HARDWARE = 0,
30: PERF_TYPE_SOFTWARE = 1,
31: PERF_TYPE_TRACEPOINT = 2,
32: PERF_TYPE_HW_CACHE = 3,
33: PERF_TYPE_RAW = 4,
34: PERF_TYPE_BREAKPOINT = 5,
36: PERF_TYPE_MAX, /* non-ABI */
( ak
to mój pseudonim na ack-grep
, który nazywa się ack
na Debianie; i ack
jest niesamowity);
w kodzie źródłowym jądra widać operacje takie jak „rejestruj wszystkie PMU odkryte w systemie” i typy struktur struct pmu
, które są przekazywane do czegoś podobnego int perf_pmu_register(struct pmu *pmu, const char *name, int type)
- w ten sposób można nazwać ten system „PMU jądra”, co byłoby agregacją wszystkich PMU w systemie; ale ta nazwa może być interpretowana jako system monitorowania operacji jądra, co byłoby mylące;
nazwijmy ten podsystem perf_events
dla jasności;
jak każdy podsystem jądra, ten podsystem można wyeksportować do sysfs
(który jest przeznaczony do eksportu podsystemów jądra do użytku przez ludzi); i to są te events
katalogi w moim /sys/
- eksportowanym (częściach) perf_events
podsystemie;
ponadto narzędzie przestrzeni użytkownika perf
(wbudowane w system Linux) jest nadal osobnym programem i ma własne „abstrakcje”; reprezentuje zdarzenie wymagane do monitorowania przez użytkownika jako perf_evsel
(pliki linux-source-3.13.0/tools/perf/util/evsel.{h,c}
) - ta struktura ma pole struct perf_event_attr attr;
, ale także pole podobne do struct cpu_map *cpus;
tego, w jaki sposób perf
narzędzie przypisuje zdarzenie do wszystkich lub poszczególnych procesorów.
Odpowiedź
Rzeczywiście, Hardware cache event
są to „skróty” do zdarzeń urządzeń pamięci podręcznej (urządzeń ubox
Intela uncore
), które są specyficzne dla procesora i można uzyskać do nich dostęp za pośrednictwem protokołu Raw hardware event descriptor
. I Hardware event
są bardziej stabilne w architekturze, która, jak rozumiem, nazywa zdarzenia z core
urządzenia. W moim jądrze nie ma innych „skrótów” 3.13
do niektórych innych uncore
zdarzeń i liczników. Cała reszta - Software
i Tracepoints
- są zdarzeniami jądra.
Zastanawiam się, czy core
„s Hardware event
s są dostępne za pośrednictwem tego samego Raw hardware event descriptor
protokołu. Mogą nie - ponieważ licznik / PMU jest włączony core
, być może dostęp do niego jest inny. Na przykład z tą rdpmu
instrukcją, zamiast rdmsr
, która uzyskuje dostęp uncore
. Ale to nie jest takie ważne.
Kernel PMU event
są tylko wydarzeniami, na które są eksportowane sysfs
. Nie wiem, jak to się robi (automatycznie przez jądro wszystkie wykryte PMC w systemie lub po prostu coś na stałe zakodowanego, a jeśli dodam kprobe
- czy to jest eksportowane? Itp.). Ale najważniejsze jest to, że są to te same zdarzenia, które Hardware event
występują w systemie wewnętrznym perf_event
.
I nie wiem co to
$ ls /sys/devices/uncore_cbox_0/events
clockticks
są.
Szczegóły dotyczące Kernel PMU event
Przeszukiwanie kodu prowadzi do:
$ ak "Kernel PMU" linux-source-3.13.0/tools/perf/
linux-source-3.13.0/tools/perf/util/pmu.c
629: printf(" %-50s [Kernel PMU event]\n", aliases[j]);
- co dzieje się w funkcji
void print_pmu_events(const char *event_glob, bool name_only) {
...
while ((pmu = perf_pmu__scan(pmu)) != NULL)
list_for_each_entry(alias, &pmu->aliases, list) {...}
...
/* b.t.w. list_for_each_entry is an iterator
* apparently, it takes a block of {code} and runs over some lost
* Ruby built in kernel!
*/
// then there is a loop over these aliases and
loop{ ... printf(" %-50s [Kernel PMU event]\n", aliases[j]); ... }
}
i perf_pmu__scan
znajduje się w tym samym pliku:
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) {
...
pmu_read_sysfs(); // that's what it calls
}
- który również znajduje się w tym samym pliku:
/* Add all pmus in sysfs to pmu list: */
static void pmu_read_sysfs(void) {...}
Otóż to.
Szczegóły dotyczące Hardware event
iHardware cache event
Najwyraźniej Hardware event
pochodzą od tego, co Intel nazywa „wstępnie zdefiniowanymi zdarzeniami dotyczącymi wydajności architektonicznej”, 18.2.1.2 w IA-32 Software Developer's Manual tom 3B. I „PRZEGLĄD MONITOROWANIA WYDAJNOŚCI 18.1” instrukcji opisuje je jako:
Druga klasa możliwości monitorowania wydajności jest określana jako monitorowanie wydajności architektury. Ta klasa obsługuje takie same sposoby liczenia i próbkowania zdarzeń w oparciu o przerwanie, z mniejszym zestawem dostępnych zdarzeń. Widoczne zachowanie architektonicznych zdarzeń wydajnościowych jest spójne we wszystkich implementacjach procesorów. Dostępność funkcji monitorowania wydajności architektury jest wyliczana przy użyciu CPUID.0AH. Wydarzenia te zostały omówione w rozdziale 18.2.
- drugi typ to:
Począwszy od procesorów Intel Core Solo i Intel Core Duo, istnieją dwie klasy możliwości monitorowania wydajności. Pierwsza klasa obsługuje zdarzenia do monitorowania wydajności przy użyciu liczenia lub próbkowania zdarzeń na podstawie przerwania. Te zdarzenia nie mają charakteru architektonicznego i różnią się w zależności od modelu procesora ...
I te zdarzenia są po prostu linkami do podstawowych „surowych” zdarzeń sprzętowych, do których można uzyskać dostęp za pomocą perf
narzędzia as Raw hardware event descriptor
.
Aby to sprawdzić, spójrz na linux-source-3.13.0/arch/x86/kernel/cpu/perf_event_intel.c
:
/*
* Intel PerfMon, used on Core and later.
*/
static u64 intel_perfmon_event_map[PERF_COUNT_HW_MAX] __read_mostly =
{
[PERF_COUNT_HW_CPU_CYCLES] = 0x003c,
[PERF_COUNT_HW_INSTRUCTIONS] = 0x00c0,
[PERF_COUNT_HW_CACHE_REFERENCES] = 0x4f2e,
[PERF_COUNT_HW_CACHE_MISSES] = 0x412e,
...
}
- i dokładnie 0x412e
znajduje się w „Tabeli 18-1. UMask i kodowanie wyboru zdarzeń dla wstępnie zdefiniowanych zdarzeń wydajności architektonicznej” dla „Braków LLC”:
Bit Position CPUID.AH.EBX | Event Name | UMask | Event Select
...
4 | LLC Misses | 41H | 2EH
- H
dotyczy heksa. Wszystkie 7 są w strukturze, plus [PERF_COUNT_HW_REF_CPU_CYCLES] = 0x0300, /* pseudo-encoding *
. (Nazewnictwo jest nieco inne, adresy są takie same).
Zatem Hardware cache event
s są w strukturach takich jak (w tym samym pliku):
static __initconst const u64 snb_hw_cache_extra_regs
[PERF_COUNT_HW_CACHE_MAX]
[PERF_COUNT_HW_CACHE_OP_MAX]
[PERF_COUNT_HW_CACHE_RESULT_MAX] =
{...}
- który powinien być na piaszczysty most?
Jeden z nich - snb_hw_cache_extra_regs[LL][OP_WRITE][RESULT_ACCESS]
jest wypełniony SNB_DMND_WRITE|SNB_L3_ACCESS
, gdzie z def-s powyżej:
#define SNB_L3_ACCESS SNB_RESP_ANY
#define SNB_RESP_ANY (1ULL << 16)
#define SNB_DMND_WRITE (SNB_DMND_RFO|SNB_LLC_RFO)
#define SNB_DMND_RFO (1ULL << 1)
#define SNB_LLC_RFO (1ULL << 8)
co powinno być równe 0x00010102
, ale nie wiem, jak to sprawdzić za pomocą jakiejś tabeli.
A to daje wyobrażenie o tym, jak jest używany w perf_events
:
$ ak hw_cache_extra_regs linux-source-3.13.0/arch/x86/kernel/cpu/
linux-source-3.13.0/arch/x86/kernel/cpu/perf_event.c
50:u64 __read_mostly hw_cache_extra_regs
292: attr->config1 = hw_cache_extra_regs[cache_type][cache_op][cache_result];
linux-source-3.13.0/arch/x86/kernel/cpu/perf_event.h
521:extern u64 __read_mostly hw_cache_extra_regs
linux-source-3.13.0/arch/x86/kernel/cpu/perf_event_intel.c
272:static __initconst const u64 snb_hw_cache_extra_regs
567:static __initconst const u64 nehalem_hw_cache_extra_regs
915:static __initconst const u64 slm_hw_cache_extra_regs
2364: memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
2365: sizeof(hw_cache_extra_regs));
2407: memcpy(hw_cache_extra_regs, slm_hw_cache_extra_regs,
2408: sizeof(hw_cache_extra_regs));
2424: memcpy(hw_cache_extra_regs, nehalem_hw_cache_extra_regs,
2425: sizeof(hw_cache_extra_regs));
2452: memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
2453: sizeof(hw_cache_extra_regs));
2483: memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs,
2484: sizeof(hw_cache_extra_regs));
2516: memcpy(hw_cache_extra_regs, snb_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
$
Do memcpy
s wykonywane są w __init int intel_pmu_init(void) {... case:...}
.
To tylko attr->config1
trochę dziwne. Ale jest tam, w perf_event_attr
(ten sam linux-source-3.13.0/include/uapi/linux/perf_event.h
plik):
...
union {
__u64 bp_addr;
__u64 config1; /* extension of config */
};
union {
__u64 bp_len;
__u64 config2; /* extension of config1 */
};
...
Są rejestrowane w perf_events
systemie jądra za pomocą wywołań int perf_pmu_register(struct pmu *pmu, const char *name, int type)
(zdefiniowanych w linux-source-3.13.0/kernel/events/core.c:
):
static int __init init_hw_perf_events(void)
(plik arch/x86/kernel/cpu/perf_event.c
) z połączeniemperf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
(plik arch/x86/kernel/cpu/perf_event_intel_uncore.c
, są też arch/x86/kernel/cpu/perf_event_amd_uncore.c
) z połączeniemret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
Wreszcie wszystkie zdarzenia pochodzą ze sprzętu i wszystko jest w porządku. Ale tutaj można zauważyć: dlaczego mamy LLC-loads
na perf list
nie ubox1 LLC-loads
, ponieważ są to wydarzenia HW i one właściwie pochodzą z ubox
es?
Jest to rzecz związana z perf
narzędziem i jego perf_evsel
strukturą: kiedy zażądasz od zdarzenia HW perf
, zdefiniuj zdarzenie, z którego procesorów chcesz je uzyskać (domyślnie jest to wszystko), i ustawia perf_evsel
żądane zdarzenie i procesory, a następnie agregacja jest sumuje liczniki ze wszystkich procesorów w perf_evsel
(lub robi z nimi inne statystyki).
Widać to w tools/perf/builtin-stat.c
:
/*
* Read out the results of a single counter:
* aggregate counts across CPUs in system-wide mode
*/
static int read_counter_aggr(struct perf_evsel *counter)
{
struct perf_stat *ps = counter->priv;
u64 *count = counter->counts->aggr.values;
int i;
if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter),
thread_map__nr(evsel_list->threads), scale) < 0)
return -1;
for (i = 0; i < 3; i++)
update_stats(&ps->res_stats[i], count[i]);
if (verbose) {
fprintf(output, "%s: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n",
perf_evsel__name(counter), count[0], count[1], count[2]);
}
/*
* Save the full runtime - to allow normalization during printout:
*/
update_shadow_stats(counter, count);
return 0;
}
(Tak więc dla narzędzia perf
„pojedynczy licznik” nie jest nawet a perf_event_attr
, co jest formą ogólną, pasującą zarówno do zdarzeń SW, jak i HW, jest to zdarzenie z zapytania - te same zdarzenia mogą pochodzić z różnych urządzeń i są agregowane .)
Uwaga: struct perf_evsel
zawiera tylko 1 struct perf_evevent_attr
, ale ma także pole struct perf_evsel *leader;
- jest zagnieżdżone. Istnieje funkcja „(hierarchicznych) grup zdarzeń”, w perf_events
których można wysyłać kilka liczników razem, aby można je było porównywać ze sobą i tak dalej. Nie wiem, jak to działa z niezależnych wydarzeń z kernel
, core
, ubox
. Ale to jest zagnieżdżanie perf_evsel
. I najprawdopodobniej w ten sposób perf
zarządza kwerendą kilku zdarzeń razem.