/* Sample period value taken from perf sample must match with expected value. */ staticint period_equal(unsignedlong exp_period, unsignedlong act_period)
{ return exp_period == act_period ? 0 : -1;
}
/* * Sample period value taken from perf sample must be >= minimum sample period * supported by IBS HW.
*/ staticint period_higher(unsignedlong min_period, unsignedlong act_period)
{ return min_period <= act_period ? 0 : -1;
}
staticint rb_drain_samples(struct perf_event_mmap_page *rb, unsignedlong exp_period, int *nr_samples, int (*callback)(unsignedlong, unsignedlong))
{ struct perf_event_header hdr; unsignedlong period; int ret = 0;
pr_debug("Fetch PMU tests:\n"); for (i = 0; i < ARRAY_SIZE(fetch_configs); i++) {
nr_samples = 0;
r = __ibs_config_test(IBS_FETCH, &(fetch_configs[i]), &nr_samples);
if (fetch_configs[i].fd == FD_ERROR) {
pr_debug("0x%-16lx: %-4s\n", fetch_configs[i].config,
!r ? "Ok" : "Fail");
} else { /* * Although nr_samples == 0 is reported as Fail here, * the failure status is not cascaded up because, we * can not decide whether test really failed or not * without actual samples.
*/
pr_debug("0x%-16lx: %-4s (nr samples: %d)\n", fetch_configs[i].config,
(!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples);
}
ret |= r;
}
pr_debug("Op PMU tests:\n"); for (i = 0; i < ARRAY_SIZE(op_configs); i++) {
nr_samples = 0;
r = __ibs_config_test(IBS_OP, &(op_configs[i]), &nr_samples);
if (op_configs[i].fd == FD_ERROR) {
pr_debug("0x%-16lx: %-4s\n", op_configs[i].config,
!r ? "Ok" : "Fail");
} else { /* * Although nr_samples == 0 is reported as Fail here, * the failure status is not cascaded up because, we * can not decide whether test really failed or not * without actual samples.
*/
pr_debug("0x%-16lx: %-4s (nr samples: %d)\n", op_configs[i].config,
(!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples);
}
ret |= r;
}
return ret;
}
struct ibs_period { /* Input */ int freq; unsignedlong sample_freq;
staticint __ibs_period_constraint_test(int ibs_type, struct ibs_period *period, int *nr_samples)
{ struct perf_event_attr attr; int ret = 0; void *rb; int fd;
if (period->freq && period->sample_freq > perf_event_max_sample_rate)
period->ret = FD_ERROR;
staticint ibs_period_constraint_test(void)
{ unsignedlong i; int nr_samples; int ret = 0; int r;
pr_debug("\nIBS sample period constraint tests:\n");
pr_debug("-----------------------------------\n");
pr_debug("Fetch PMU test:\n"); for (i = 0; i < ARRAY_SIZE(fetch_period); i++) {
nr_samples = 0;
r = __ibs_period_constraint_test(IBS_FETCH, &fetch_period[i],
&nr_samples);
if (fetch_period[i].ret == FD_ERROR) {
pr_debug("freq %d, sample_freq %9ld: %-4s\n",
fetch_period[i].freq, fetch_period[i].sample_freq,
!r ? "Ok" : "Fail");
} else { /* * Although nr_samples == 0 is reported as Fail here, * the failure status is not cascaded up because, we * can not decide whether test really failed or not * without actual samples.
*/
pr_debug("freq %d, sample_freq %9ld: %-4s (nr samples: %d)\n",
fetch_period[i].freq, fetch_period[i].sample_freq,
(!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples);
}
ret |= r;
}
pr_debug("Op PMU test:\n"); for (i = 0; i < ARRAY_SIZE(op_period); i++) {
nr_samples = 0;
r = __ibs_period_constraint_test(IBS_OP, &op_period[i],
&nr_samples);
if (op_period[i].ret == FD_ERROR) {
pr_debug("freq %d, sample_freq %9ld: %-4s\n",
op_period[i].freq, op_period[i].sample_freq,
!r ? "Ok" : "Fail");
} else { /* * Although nr_samples == 0 is reported as Fail here, * the failure status is not cascaded up because, we * can not decide whether test really failed or not * without actual samples.
*/
pr_debug("freq %d, sample_freq %9ld: %-4s (nr samples: %d)\n",
op_period[i].freq, op_period[i].sample_freq,
(!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples);
}
ret |= r;
}
return ret;
}
struct ibs_ioctl { /* Input */ int freq; unsignedlong period;
staticint __ibs_l3missonly_test(char *perf, int ibs_type, int *nr_samples, struct ibs_l3missonly *l3missonly)
{ struct perf_event_attr attr; int ret = 0; void *rb; int fd;
if (l3missonly->sample_freq > perf_event_max_sample_rate)
l3missonly->ret = FD_ERROR;
staticint ibs_l3missonly_test(char *perf)
{ int nr_samples = 0; int ret = 0; int r = 0;
pr_debug("\nIBS L3MissOnly test: (takes a while)\n");
pr_debug("--------------------\n");
if (perf_pmu__has_format(fetch_pmu, "l3missonly")) {
nr_samples = 0;
r = __ibs_l3missonly_test(perf, IBS_FETCH, &nr_samples, &fetch_l3missonly); if (fetch_l3missonly.ret == FD_ERROR) {
pr_debug("Fetch L3MissOnly: %-4s\n", !r ? "Ok" : "Fail");
} else { /* * Although nr_samples == 0 is reported as Fail here, * the failure status is not cascaded up because, we * can not decide whether test really failed or not * without actual samples.
*/
pr_debug("Fetch L3MissOnly: %-4s (nr_samples: %d)\n",
(!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples);
}
ret |= r;
}
if (perf_pmu__has_format(op_pmu, "l3missonly")) {
nr_samples = 0;
r = __ibs_l3missonly_test(perf, IBS_OP, &nr_samples, &op_l3missonly); if (op_l3missonly.ret == FD_ERROR) {
pr_debug("Op L3MissOnly: %-4s\n", !r ? "Ok" : "Fail");
} else { /* * Although nr_samples == 0 is reported as Fail here, * the failure status is not cascaded up because, we * can not decide whether test really failed or not * without actual samples.
*/
pr_debug("Op L3MissOnly: %-4s (nr_samples: %d)\n",
(!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples);
}
ret |= r;
}
fp = fopen("/proc/sys/kernel/perf_event_max_sample_rate", "r"); if (!fp) {
pr_debug("Can't open perf_event_max_sample_rate. Assuming %d\n",
max_sample_rate); goto out;
}
ret = fscanf(fp, "%d", &max_sample_rate); if (ret == EOF) {
pr_debug("Can't read perf_event_max_sample_rate. Assuming 100000\n");
max_sample_rate = 100000;
}
fclose(fp);
out: return max_sample_rate;
}
/* * Bunch of IBS sample period fixes that this test exercise went in v6.15. * Skip the test on older kernels to distinguish between test failure due * to a new bug vs known failure due to older kernel.
*/ staticbool kernel_v6_15_or_newer(void)
{ struct utsname utsname; char *endptr = NULL; long major, minor;
if (uname(&utsname) < 0) {
pr_debug("uname() failed. [%m]"); returnfalse;
}
major = strtol(utsname.release, &endptr, 10);
endptr++;
minor = strtol(endptr, NULL, 10);
return major >= 6 && minor >= 15;
}
int test__amd_ibs_period(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
{ char perf[PATH_MAX] = {'\0'}; int ret = TEST_OK;
page_size = sysconf(_SC_PAGESIZE);
/* * Reading perf_event_max_sample_rate only once _might_ cause some * of the test to fail if kernel changes it after reading it here.
*/
perf_event_max_sample_rate = get_perf_event_max_sample_rate();
fetch_pmu = perf_pmus__find("ibs_fetch");
op_pmu = perf_pmus__find("ibs_op");
if (!x86__is_amd_cpu() || !fetch_pmu || !op_pmu) return TEST_SKIP;
if (!kernel_v6_15_or_newer()) {
pr_debug("Need v6.15 or newer kernel. Skipping.\n"); return TEST_SKIP;
}
perf_exe(perf, sizeof(perf));
if (sched_affine(0)) return TEST_FAIL;
/* * Perf event can be opened in two modes: * 1 Freq mode * perf_event_attr->freq = 1, ->sample_freq = <frequency> * 2 Sample period mode * perf_event_attr->freq = 0, ->sample_period = <period> * * Instead of using above interface, IBS event in 'sample period mode' * can also be opened by passing <period> value directly in a MaxCnt * bitfields of perf_event_attr->config. Test this IBS specific special * interface.
*/ if (ibs_config_test())
ret = TEST_FAIL;
/* * IBS Fetch and Op PMUs have HW constraints on minimum sample period. * Also, sample period value must be in multiple of 0x10. Test that IBS * driver honors HW constraints for various possible values in Freq as * well as Sample Period mode IBS events.
*/ if (ibs_period_constraint_test())
ret = TEST_FAIL;
/* * Test ioctl() with various sample period values for IBS event.
*/ if (ibs_ioctl_test())
ret = TEST_FAIL;
/* * Test that opening of freq mode IBS event fails when the freq value * is passed through ->config, not explicitly in ->sample_freq. Also * use high freq value (beyond perf_event_max_sample_rate) to test IBS * driver do not bypass perf_event_max_sample_rate checks.
*/ if (ibs_freq_neg_test())
ret = TEST_FAIL;
/* * L3MissOnly is a post-processing filter, i.e. IBS HW checks for L3 * Miss at the completion of the tagged uOp. The sample is discarded * if the tagged uOp did not cause L3Miss. Also, IBS HW internally * resets CurCnt to a small pseudo-random value and resumes counting. * A new uOp is tagged once CurCnt reaches to MaxCnt. But the process * repeats until the tagged uOp causes an L3 Miss. * * With the freq mode event, the next sample period is calculated by * generic kernel on every sample to achieve desired freq of samples. * * Since the number of times HW internally reset CurCnt and the pseudo- * random value of CurCnt for all those occurrences are not known to SW, * the sample period adjustment by kernel goes for a toes for freq mode * IBS events. Kernel will set very small period for the next sample if * the window between current sample and prev sample is too high due to * multiple samples being discarded internally by IBS HW. * * Test that IBS sample period constraints are honored when L3MissOnly * is ON.
*/ if (ibs_l3missonly_test(perf))
ret = TEST_FAIL;
return ret;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.