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 ofuncore`;
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 อย่างเป็นรูปธรรมสำหรับuncorePMCs เหล่านี้สำหรับรุ่น "การตรวจสอบประสิทธิภาพสถาปัตยกรรมรุ่น 1" (มีรุ่น 1-4 ในคู่มือฉันไม่รู้ว่าตัวประมวลผลตัวใดของฉัน) อธิบายไว้ใน "รูปที่ 18-1 ของ IA32_PERFEVTSELx MSRs "(หน้า 18-3 ในของฉัน) และส่วน" 18.2.1.2 เหตุการณ์ประสิทธิภาพสถาปัตยกรรมที่กำหนดไว้ล่วงหน้า "กับ" ตารางที่ 18-1 UMask และเหตุการณ์เลือกการเข้ารหัสสำหรับเหตุการณ์สถาปัตยกรรมประสิทธิภาพที่กำหนดไว้ล่วงหน้า "ซึ่งแสดง เหตุการณ์ที่เกิดขึ้นซึ่งแสดงเป็นในHardware eventperf 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 events จะเข้าถึงได้ผ่านทางเดียวกันRaw hardware event descriptorโปรโตคอล พวกเขาอาจจะไม่ - เนื่องจากตัวนับ / PMU ตั้งอยู่บนcoreอาจจะมีการเข้าถึงที่แตกต่างกัน ยกตัวอย่างเช่นกับrdpmuการเรียนการสอนแทนซึ่งการเข้าถึงrdmsr uncoreแต่มันก็ไม่สำคัญ
Kernel PMU eventsysfsเป็นเพียงเหตุการณ์ที่เกิดขึ้นซึ่งมีการส่งออก ฉันไม่รู้ว่าจะทำอย่างไร (โดยเคอร์เนลทั้งหมดที่ค้นพบ 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 มีความสามารถในการตรวจสอบประสิทธิภาพสองระดับ คลาสเฟิร์สคลาสรองรับเหตุการณ์สำหรับการตรวจสอบประสิทธิภาพโดยใช้การนับหรือการใช้การสุ่มตัวอย่างเหตุการณ์แบบอินเตอร์รัปต์ เหตุการณ์เหล่านี้ไม่ใช่สถาปัตยกรรมและแตกต่างจากรุ่นโปรเซสเซอร์หนึ่งไปยังอีก ...
และเหตุการณ์เหล่านี้เป็นจริงเพียงแค่การเชื่อมโยงไปอ้างอิง "ดิบ" เหตุการณ์ฮาร์ดแวร์ซึ่งสามารถเข้าถึงได้ผ่านทางยูทิลิตี้เป็นperfRaw 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 events อยู่ในโครงสร้างเช่น (ในไฟล์เดียวกัน):
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));
$
memcpys __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 และพวกเขาจริงมาจากuboxES?
นั่นคือสิ่งที่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จัดการแบบสอบถามหลาย ๆ เหตุการณ์ด้วยกัน