Googling และack
-ing จบแล้ว! ฉันได้รับคำตอบ
แต่ก่อนอื่นให้ฉันอธิบายจุดประสงค์ของคำถามอีกเล็กน้อย: ฉันต้องการแยกความแตกต่างของกระบวนการที่เป็นอิสระในระบบและตัวนับประสิทธิภาพ ตัวอย่างเช่นแกนประมวลผล, อุปกรณ์ uncore (เรียนรู้เกี่ยวกับมันล่าสุด), เคอร์เนลหรือแอปพลิเคชันผู้ใช้บนโปรเซสเซอร์, บัส (= บัสคอนโทรลเลอร์), ฮาร์ดไดรฟ์เป็นกระบวนการอิสระทั้งหมดพวกเขาจะไม่ตรงกันโดยนาฬิกา . และทุกวันนี้พวกเขาทั้งหมดอาจมี Process Monitoring Counter (PMC) อยู่บ้าง ฉันต้องการเข้าใจว่ากระบวนการใดบ้างที่เคาน์เตอร์มาจาก (นอกจากนี้ยังมีประโยชน์ใน googling: "ผู้ขาย" ของสิ่งที่เป็นศูนย์จะดีกว่า)
นอกจากนี้เฟืองที่ใช้สำหรับการค้นหา: Ubuntu 14.04
,, linux 3.13.0-103-generic
โปรเซสเซอร์Intel(R) Core(TM) i5-3317U CPU @ 1.70GHz
(จาก/proc/cpuinfo
นั้นมี 2 คอร์ทางกายภาพและ 4 เสมือน - เรื่องทางกายภาพที่นี่)
คำศัพท์สิ่งที่คำถามเกี่ยวข้อง
จาก Intel:
โปรเซสเซอร์เป็นcore
อุปกรณ์ (เป็น 1 อุปกรณ์ / กระบวนการ) และuncore
อุปกรณ์มากมายcore
เป็นสิ่งที่รันโปรแกรม (นาฬิกา, ALU, รีจิสเตอร์ ฯลฯ ), uncore
เป็นอุปกรณ์ที่ตาย, ใกล้กับโปรเซสเซอร์สำหรับความเร็วและความหน่วงต่ำ (เหตุผลที่แท้จริง คือ "เพราะผู้ผลิตสามารถทำได้"); ที่ฉันเข้าใจว่ามันเป็น Northbridge โดยทั่วไปเช่นบนเมนบอร์ดพีซีและแคช; และ AMD เรียกอุปกรณ์เหล่านี้ว่า NorthBridge instead of
uncore`;
ubox
ซึ่งปรากฏในของฉัน sysfs
$ find /sys/devices/ -type d -name events
/sys/devices/cpu/events
/sys/devices/uncore_cbox_0/events
/sys/devices/uncore_cbox_1/events
- เป็นuncore
อุปกรณ์ที่จัดการแคชระดับสุดท้าย (LLC อุปกรณ์สุดท้ายก่อนที่จะกดปุ่ม RAM) ฉันมี 2 แกนดังนั้น 2 LLC และ 2 ubox
;
หน่วยประมวลผลการตรวจสอบหน่วยประมวลผล (PMU) เป็นอุปกรณ์แยกต่างหากที่ตรวจสอบการทำงานของหน่วยประมวลผลและบันทึกไว้ในหน่วยประมวลผลการตรวจสอบเคาน์เตอร์ (PMC) (นับแคชคิดถึง, รอบการประมวลผล ฯลฯ ); มีอยู่ในcore
และuncore
อุปกรณ์ core
คนที่มีการเข้าถึงด้วยrdpmc
(อ่าน PMC) การเรียนการสอน uncore
เนื่องจากอุปกรณ์เหล่านี้ขึ้นอยู่กับหน่วยประมวลผลที่เกิดขึ้นจริงที่อยู่ในมือจะเข้าถึงได้ผ่านทางรุ่น Registers เฉพาะ (MSR) ผ่านrdmsr
(ธรรมชาติ);
เห็นได้ชัดว่าเวิร์กโฟลว์กับพวกเขาจะทำผ่านคู่ของการลงทะเบียน - 1 ชุดลงทะเบียนที่เหตุการณ์นับนับ 2 ลงทะเบียนเป็นมูลค่าในเคาน์เตอร์; ตัวนับสามารถกำหนดค่าให้เพิ่มขึ้นหลังจากเหตุการณ์หลายอย่างไม่ใช่แค่ 1; + มีบางส่วนขัดจังหวะ / เทคโนโลยีสังเกตเห็นล้นในเคาน์เตอร์เหล่านี้;
มีอีกหนึ่งสามารถพบได้ใน "คู่มือผู้พัฒนาซอฟต์แวร์ IA-32 เล่ม 3B ของ Intel" บทที่ 18 "การตรวจสอบประสิทธิภาพ"
นอกจากนี้รูปแบบของ MSR อย่างเป็นรูปธรรมสำหรับuncore
PMCs เหล่านี้สำหรับรุ่น "การตรวจสอบประสิทธิภาพสถาปัตยกรรมรุ่น 1" (มีรุ่น 1-4 ในคู่มือฉันไม่รู้ว่าตัวประมวลผลตัวใดของฉัน) อธิบายไว้ใน "รูปที่ 18-1 ของ IA32_PERFEVTSELx MSRs "(หน้า 18-3 ในของฉัน) และส่วน" 18.2.1.2 เหตุการณ์ประสิทธิภาพสถาปัตยกรรมที่กำหนดไว้ล่วงหน้า "กับ" ตารางที่ 18-1 UMask และเหตุการณ์เลือกการเข้ารหัสสำหรับเหตุการณ์สถาปัตยกรรมประสิทธิภาพที่กำหนดไว้ล่วงหน้า "ซึ่งแสดง เหตุการณ์ที่เกิดขึ้นซึ่งแสดงเป็นในHardware event
perf list
จากเคอร์เนล linux:
เคอร์เนลมีระบบ (นามธรรม / เลเยอร์) สำหรับการจัดการตัวนับประสิทธิภาพของแหล่งกำเนิดที่แตกต่างกันทั้งซอฟต์แวร์ (เคอร์เนล) และฮาร์ดแวร์อธิบายไว้ในlinux-source-3.13.0/tools/perf/design.txt
; เหตุการณ์ในระบบนี้ถูกกำหนดเป็นstruct perf_event_attr
(ไฟล์linux-source-3.13.0/include/uapi/linux/perf_event.h
) ส่วนหลักซึ่งอาจเป็น__u64 config
ฟิลด์ - มันสามารถเก็บทั้งคำจำกัดความเหตุการณ์เฉพาะ CPU (คำ 64 บิตในรูปแบบที่อธิบายไว้ในตัวเลขของ Intel) หรือเหตุการณ์ของเคอร์เนล
MSB ของคำว่า config หมายถึงถ้าส่วนที่เหลือมี [raw CPU's หรือ kernel ของเหตุการณ์]
เหตุการณ์ของเคอร์เนลที่กำหนดด้วย 7 บิตสำหรับประเภทและ 56 สำหรับตัวระบุเหตุการณ์ซึ่งเป็นenum
-s ในรหัสซึ่งในกรณีของฉันคือ:
$ 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
เป็นนามแฝงของฉันack-grep
ซึ่งเป็นชื่อสำหรับack
บนเดเบียนและยอดเยี่ยมack
)
ในซอร์สโค้ดของเคอร์เนลเราสามารถเห็นการทำงานเช่น "ลงทะเบียน PMUs ทั้งหมดที่ถูก dicovered บนระบบ" และประเภทโครงสร้างstruct pmu
ซึ่งถูกส่งผ่านไปยังสิ่งที่ต้องการint perf_pmu_register(struct pmu *pmu, const char *name, int type)
- ดังนั้นเราสามารถเรียกระบบนี้ว่า "PMU ของเคอร์เนล" ซึ่งจะเป็นการรวมตัว ของ PMU ทั้งหมดบนระบบ; แต่ชื่อนี้สามารถตีความได้ว่าเป็นระบบการตรวจสอบการทำงานของเคอร์เนลซึ่งจะทำให้เข้าใจผิด;
ลองเรียกระบบย่อยนี้perf_events
เพื่อความชัดเจน
เช่นเดียวกับระบบย่อยเคอร์เนลระบบย่อยนี้สามารถส่งออกไปยังsysfs
(ซึ่งทำเพื่อเอ็กซ์พอร์ตระบบย่อยเคอร์เนลเพื่อให้ผู้ใช้ใช้); และนั่นคือสิ่งที่events
ไดเรกทอรีเหล่านั้นในระบบย่อย/sys/
ส่งออกของฉัน(ส่วนของ?) perf_events
;
นอกจากนี้ยูทิลิตี้ผู้ใช้พื้นที่perf
(สร้างขึ้นในลินุกซ์) ยังคงเป็นโปรแกรมที่แยกต่างหากและมี 'นามธรรมของตัวเอง; มันแสดงให้เห็นถึงเหตุการณ์ที่ร้องขอสำหรับการตรวจสอบโดยผู้ใช้เป็นperf_evsel
(ไฟล์linux-source-3.13.0/tools/perf/util/evsel.{h,c}
) - โครงสร้างนี้มีเขตข้อมูลstruct perf_event_attr attr;
แต่ยังมีฟิลด์เช่นนี้struct cpu_map *cpus;
เป็นวิธีที่perf
ยูทิลิตี้กำหนดกิจกรรมให้กับซีพียูทั้งหมดหรือเฉพาะ
ตอบ
แท้จริงแล้วHardware cache event
คือ "ทางลัด" กับเหตุการณ์ของอุปกรณ์แคช ( ubox
ของอินเทลuncore
อุปกรณ์) Raw hardware event descriptor
ซึ่งเป็นโปรเซสเซอร์ที่เฉพาะเจาะจงและสามารถเข้าถึงได้ผ่านทางโปรโตคอล และHardware event
มีความเสถียรมากกว่าในสถาปัตยกรรมซึ่งอย่างที่ฉันเข้าใจแล้วตั้งชื่อเหตุการณ์จากcore
อุปกรณ์ ไม่มี "ทางลัด" อื่น ๆ ในเคอร์เนลของฉัน3.13
สำหรับuncore
เหตุการณ์และตัวนับอื่น ๆ ส่วนที่เหลือทั้งหมด - Software
และTracepoints
- เป็นกิจกรรมของเคอร์เนล
ผมสงสัยว่าถ้าcore
's Hardware event
s จะเข้าถึงได้ผ่านทางเดียวกันRaw hardware event descriptor
โปรโตคอล พวกเขาอาจจะไม่ - เนื่องจากตัวนับ / PMU ตั้งอยู่บนcore
อาจจะมีการเข้าถึงที่แตกต่างกัน ยกตัวอย่างเช่นกับrdpmu
การเรียนการสอนแทนซึ่งการเข้าถึงrdmsr
uncore
แต่มันก็ไม่สำคัญ
Kernel PMU event
sysfs
เป็นเพียงเหตุการณ์ที่เกิดขึ้นซึ่งมีการส่งออก ฉันไม่รู้ว่าจะทำอย่างไร (โดยเคอร์เนลทั้งหมดที่ค้นพบ PMCs บนระบบหรือเพียงบางสิ่งบางอย่างที่เข้ารหัสยากและถ้าฉันเพิ่มkprobe
- มันจะถูกส่งออกหรือไม่?) แต่ประเด็นหลักคือสิ่งเหล่านี้เป็นเหตุการณ์เดียวกันHardware event
หรือเหตุการณ์อื่น ๆ ในperf_event
ระบบภายใน
และฉันไม่รู้ว่ามันคืออะไร
$ ls /sys/devices/uncore_cbox_0/events
clockticks
เป็น
รายละเอียดเกี่ยวกับ Kernel PMU event
การค้นหารหัสจะนำไปสู่:
$ 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]);
- ซึ่งเกิดขึ้นในฟังก์ชั่น
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]); ... }
}
และperf_pmu__scan
อยู่ในไฟล์เดียวกัน:
struct perf_pmu *perf_pmu__scan(struct perf_pmu *pmu) {
...
pmu_read_sysfs(); // that's what it calls
}
- ซึ่งอยู่ในไฟล์เดียวกัน:
/* Add all pmus in sysfs to pmu list: */
static void pmu_read_sysfs(void) {...}
แค่นั้นแหละ.
รายละเอียดเกี่ยวกับHardware event
และHardware cache event
เห็นได้ชัดว่าHardware event
มาจากสิ่งที่ Intel เรียกว่า "เหตุการณ์สถาปัตยกรรมประสิทธิภาพที่กำหนดไว้ล่วงหน้า", 18.2.1.2 ในคู่มือนักพัฒนาซอฟต์แวร์ IA-32 เล่ม 3B และ "18.1 ประสิทธิภาพการตรวจสอบภาพรวม" ของคู่มืออธิบายพวกเขาเป็น:
ความสามารถในการตรวจสอบประสิทธิภาพระดับที่สองเรียกว่าการตรวจสอบประสิทธิภาพสถาปัตยกรรม คลาสนี้รองรับการสุ่มตัวอย่างเหตุการณ์การนับและการอินเตอร์รัปต์แบบเดียวกันพร้อมชุดกิจกรรมที่มีขนาดเล็กกว่า พฤติกรรมที่มองเห็นได้ของเหตุการณ์ประสิทธิภาพสถาปัตยกรรมมีความสอดคล้องกันระหว่างการใช้งานโปรเซสเซอร์ ความพร้อมใช้งานของความสามารถในการตรวจสอบประสิทธิภาพสถาปัตยกรรมนั้นใช้ CPUID.0AH เหตุการณ์เหล่านี้ถูกกล่าวถึงในส่วน 18.2
- ประเภทอื่นคือ:
เริ่มต้นด้วยโปรเซสเซอร์ Intel Core Solo และ Intel Core Duo มีความสามารถในการตรวจสอบประสิทธิภาพสองระดับ คลาสเฟิร์สคลาสรองรับเหตุการณ์สำหรับการตรวจสอบประสิทธิภาพโดยใช้การนับหรือการใช้การสุ่มตัวอย่างเหตุการณ์แบบอินเตอร์รัปต์ เหตุการณ์เหล่านี้ไม่ใช่สถาปัตยกรรมและแตกต่างจากรุ่นโปรเซสเซอร์หนึ่งไปยังอีก ...
และเหตุการณ์เหล่านี้เป็นจริงเพียงแค่การเชื่อมโยงไปอ้างอิง "ดิบ" เหตุการณ์ฮาร์ดแวร์ซึ่งสามารถเข้าถึงได้ผ่านทางยูทิลิตี้เป็นperf
Raw hardware event descriptor
หากต้องการตรวจสอบสิ่งนี้ดูที่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,
...
}
- และ0x412e
สามารถพบได้ใน "ตารางที่ 18-1 การเข้ารหัส UMask และการเลือกเหตุการณ์สำหรับเหตุการณ์ประสิทธิภาพสถาปัตยกรรมที่กำหนดไว้ล่วงหน้า" สำหรับ "LLC Misses":
Bit Position CPUID.AH.EBX | Event Name | UMask | Event Select
...
4 | LLC Misses | 41H | 2EH
- H
สำหรับเลขฐานสิบหก ทั้งหมด 7 [PERF_COUNT_HW_REF_CPU_CYCLES] = 0x0300, /* pseudo-encoding *
อยู่ในโครงสร้างบวก (การตั้งชื่อแตกต่างกันเล็กน้อยที่อยู่เหมือนกัน)
ดังนั้นHardware cache event
s อยู่ในโครงสร้างเช่น (ในไฟล์เดียวกัน):
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] =
{...}
- สะพานไหนดีสำหรับทราย?
หนึ่งในเหล่านี้ - snb_hw_cache_extra_regs[LL][OP_WRITE][RESULT_ACCESS]
เต็มไปด้วยSNB_DMND_WRITE|SNB_L3_ACCESS
ซึ่งมาจาก def-s ข้างต้น:
#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)
ซึ่งควรเท่ากับ0x00010102
แต่ฉันไม่รู้วิธีตรวจสอบด้วยตารางบางอย่าง
และสิ่งนี้จะช่วยให้ความคิดวิธีการที่จะใช้ใน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));
$
memcpy
s __init int intel_pmu_init(void) {... case:...}
จะทำใน
เพียงattr->config1
แปลกนิดหน่อย แต่มันอยู่ที่นั่นในperf_event_attr
( linux-source-3.13.0/include/uapi/linux/perf_event.h
ไฟล์เดียวกัน):
...
union {
__u64 bp_addr;
__u64 config1; /* extension of config */
};
union {
__u64 bp_len;
__u64 config2; /* extension of config1 */
};
...
พวกเขาจะลงทะเบียนในperf_events
ระบบของเคอร์เนลด้วยการเรียกไปที่int perf_pmu_register(struct pmu *pmu, const char *name, int type)
(กำหนดไว้ในlinux-source-3.13.0/kernel/events/core.c:
):
static int __init init_hw_perf_events(void)
(ไฟล์arch/x86/kernel/cpu/perf_event.c
) พร้อมการโทรperf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
static int __init uncore_pmu_register(struct intel_uncore_pmu *pmu)
(ไฟล์arch/x86/kernel/cpu/perf_event_intel_uncore.c
ยังมีarch/x86/kernel/cpu/perf_event_amd_uncore.c
) กับการโทรret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
ในที่สุดเหตุการณ์ทั้งหมดมาจากฮาร์ดแวร์และทุกอย่างก็โอเค แต่ที่นี่ใครจะสังเกตเห็น: ทำไมเรามีLLC-loads
ในperf list
และไม่ได้ubox1 LLC-loads
ตั้งแต่เหล่านี้เป็นเหตุการณ์ที่เกิดขึ้น HW และพวกเขาจริงมาจากubox
ES?
นั่นคือสิ่งที่perf
ยูทิลิตี้และperf_evsel
โครงสร้าง' : เมื่อคุณร้องขอเหตุการณ์ HW จากperf
คุณกำหนดเหตุการณ์ซึ่งโปรเซสเซอร์ที่คุณต้องการ (เริ่มต้นคือทั้งหมด) และมันตั้งค่าperf_evsel
กับเหตุการณ์ที่ร้องขอและโปรเซสเซอร์แล้วที่รวมเป็น สรุปตัวนับจากตัวประมวลผลทั้งหมดในperf_evsel
(หรือทำสถิติอื่น ๆ ด้วย)
หนึ่งสามารถดูได้ใน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;
}
(ดังนั้นสำหรับยูทิลิตี้perf
"เคาน์เตอร์เดียว" ไม่ได้เป็นperf_event_attr
ซึ่งเป็นรูปแบบทั่วไปที่เหมาะสมทั้งเหตุการณ์ SW และ HW มันเป็นเหตุการณ์ของแบบสอบถามของคุณ - เหตุการณ์เดียวกันอาจมาจากอุปกรณ์ที่แตกต่างกันและพวกเขาจะรวม .)
ประกาศอีกด้วย: struct perf_evsel
มีเพียง 1 รายการstruct perf_evevent_attr
แต่มีเขตข้อมูลด้วยstruct perf_evsel *leader;
- ซ้อนกัน มีคุณสมบัติของ "กลุ่มเหตุการณ์ (ลำดับชั้น)" ในperf_events
เมื่อคุณสามารถจัดส่งเคาน์เตอร์จำนวนมากเข้าด้วยกันเพื่อให้สามารถเปรียบเทียบกันและอื่น ๆ ได้ ไม่แน่ใจว่าจะทำงานร่วมกับเหตุการณ์ที่เป็นอิสระจากkernel
, ,core
ubox
แต่การทำรังแบบperf_evsel
นี้มันคืออะไร และเป็นไปได้มากว่านั่นเป็นวิธีperf
จัดการแบบสอบถามหลาย ๆ เหตุการณ์ด้วยกัน