1 // SPDX-License-Identifier: GPL-2.0 2 #include <sched.h> 3 #include <sys/syscall.h> 4 #include <sys/mman.h> 5 #include <sys/ioctl.h> 6 #include <sys/utsname.h> 7 #include <string.h> 8 9 #include "arch-tests.h" 10 #include "linux/perf_event.h" 11 #include "linux/zalloc.h" 12 #include "tests/tests.h" 13 #include "../perf-sys.h" 14 #include "pmu.h" 15 #include "pmus.h" 16 #include "debug.h" 17 #include "util.h" 18 #include "strbuf.h" 19 #include "../util/env.h" 20 21 static int page_size; 22 23 #define PERF_MMAP_DATA_PAGES 32L 24 #define PERF_MMAP_DATA_SIZE (PERF_MMAP_DATA_PAGES * page_size) 25 #define PERF_MMAP_DATA_MASK (PERF_MMAP_DATA_SIZE - 1) 26 #define PERF_MMAP_TOTAL_PAGES (PERF_MMAP_DATA_PAGES + 1) 27 #define PERF_MMAP_TOTAL_SIZE (PERF_MMAP_TOTAL_PAGES * page_size) 28 29 #define rmb() asm volatile("lfence":::"memory") 30 31 enum { 32 FD_ERROR, 33 FD_SUCCESS, 34 }; 35 36 enum { 37 IBS_FETCH, 38 IBS_OP, 39 }; 40 41 struct perf_pmu *fetch_pmu; 42 struct perf_pmu *op_pmu; 43 unsigned int perf_event_max_sample_rate; 44 45 /* Dummy workload to generate IBS samples. */ 46 static int dummy_workload_1(unsigned long count) 47 { 48 int (*func)(void); 49 int ret = 0; 50 char *p; 51 char insn1[] = { 52 0xb8, 0x01, 0x00, 0x00, 0x00, /* mov 1,%eax */ 53 0xc3, /* ret */ 54 0xcc, /* int 3 */ 55 }; 56 57 char insn2[] = { 58 0xb8, 0x02, 0x00, 0x00, 0x00, /* mov 2,%eax */ 59 0xc3, /* ret */ 60 0xcc, /* int 3 */ 61 }; 62 63 p = zalloc(2 * page_size); 64 if (!p) { 65 printf("malloc() failed. %m"); 66 return 1; 67 } 68 69 func = (void *)((unsigned long)(p + page_size - 1) & ~(page_size - 1)); 70 71 ret = mprotect(func, page_size, PROT_READ | PROT_WRITE | PROT_EXEC); 72 if (ret) { 73 printf("mprotect() failed. %m"); 74 goto out; 75 } 76 77 if (count < 100000) 78 count = 100000; 79 else if (count > 10000000) 80 count = 10000000; 81 while (count--) { 82 memcpy((void *)func, insn1, sizeof(insn1)); 83 if (func() != 1) { 84 pr_debug("ERROR insn1\n"); 85 ret = -1; 86 goto out; 87 } 88 memcpy((void *)func, insn2, sizeof(insn2)); 89 if (func() != 2) { 90 pr_debug("ERROR insn2\n"); 91 ret = -1; 92 goto out; 93 } 94 } 95 96 out: 97 free(p); 98 return ret; 99 } 100 101 /* Another dummy workload to generate IBS samples. */ 102 static void dummy_workload_2(char *perf) 103 { 104 char bench[] = " bench sched messaging -g 10 -l 5000 > /dev/null 2>&1"; 105 char taskset[] = "taskset -c 0 "; 106 int ret __maybe_unused; 107 struct strbuf sb; 108 char *cmd; 109 110 strbuf_init(&sb, 0); 111 strbuf_add(&sb, taskset, strlen(taskset)); 112 strbuf_add(&sb, perf, strlen(perf)); 113 strbuf_add(&sb, bench, strlen(bench)); 114 cmd = strbuf_detach(&sb, NULL); 115 ret = system(cmd); 116 free(cmd); 117 } 118 119 static int sched_affine(int cpu) 120 { 121 cpu_set_t set; 122 123 CPU_ZERO(&set); 124 CPU_SET(cpu, &set); 125 if (sched_setaffinity(getpid(), sizeof(set), &set) == -1) { 126 pr_debug("sched_setaffinity() failed. [%m]"); 127 return -1; 128 } 129 return 0; 130 } 131 132 static void 133 copy_sample_data(void *src, unsigned long offset, void *dest, size_t size) 134 { 135 size_t chunk1_size, chunk2_size; 136 137 if ((offset + size) < (size_t)PERF_MMAP_DATA_SIZE) { 138 memcpy(dest, src + offset, size); 139 } else { 140 chunk1_size = PERF_MMAP_DATA_SIZE - offset; 141 chunk2_size = size - chunk1_size; 142 143 memcpy(dest, src + offset, chunk1_size); 144 memcpy(dest + chunk1_size, src, chunk2_size); 145 } 146 } 147 148 static int rb_read(struct perf_event_mmap_page *rb, void *dest, size_t size) 149 { 150 void *base; 151 unsigned long data_tail, data_head; 152 153 /* Casting to (void *) is needed. */ 154 base = (void *)rb + page_size; 155 156 data_head = rb->data_head; 157 rmb(); 158 data_tail = rb->data_tail; 159 160 if ((data_head - data_tail) < size) 161 return -1; 162 163 data_tail &= PERF_MMAP_DATA_MASK; 164 copy_sample_data(base, data_tail, dest, size); 165 rb->data_tail += size; 166 return 0; 167 } 168 169 static void rb_skip(struct perf_event_mmap_page *rb, size_t size) 170 { 171 size_t data_head = rb->data_head; 172 173 rmb(); 174 175 if ((rb->data_tail + size) > data_head) 176 rb->data_tail = data_head; 177 else 178 rb->data_tail += size; 179 } 180 181 /* Sample period value taken from perf sample must match with expected value. */ 182 static int period_equal(unsigned long exp_period, unsigned long act_period) 183 { 184 return exp_period == act_period ? 0 : -1; 185 } 186 187 /* 188 * Sample period value taken from perf sample must be >= minimum sample period 189 * supported by IBS HW. 190 */ 191 static int period_higher(unsigned long min_period, unsigned long act_period) 192 { 193 return min_period <= act_period ? 0 : -1; 194 } 195 196 static int rb_drain_samples(struct perf_event_mmap_page *rb, 197 unsigned long exp_period, 198 int *nr_samples, 199 int (*callback)(unsigned long, unsigned long)) 200 { 201 struct perf_event_header hdr; 202 unsigned long period; 203 int ret = 0; 204 205 /* 206 * PERF_RECORD_SAMPLE: 207 * struct { 208 * struct perf_event_header hdr; 209 * { u64 period; } && PERF_SAMPLE_PERIOD 210 * }; 211 */ 212 while (1) { 213 if (rb_read(rb, &hdr, sizeof(hdr))) 214 return ret; 215 216 if (hdr.type == PERF_RECORD_SAMPLE) { 217 (*nr_samples)++; 218 period = 0; 219 if (rb_read(rb, &period, sizeof(period))) 220 pr_debug("rb_read(period) error. [%m]"); 221 ret |= callback(exp_period, period); 222 } else { 223 rb_skip(rb, hdr.size - sizeof(hdr)); 224 } 225 } 226 return ret; 227 } 228 229 static long perf_event_open(struct perf_event_attr *attr, pid_t pid, 230 int cpu, int group_fd, unsigned long flags) 231 { 232 return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags); 233 } 234 235 static void fetch_prepare_attr(struct perf_event_attr *attr, 236 unsigned long long config, int freq, 237 unsigned long sample_period) 238 { 239 memset(attr, 0, sizeof(struct perf_event_attr)); 240 241 attr->type = fetch_pmu->type; 242 attr->size = sizeof(struct perf_event_attr); 243 attr->config = config; 244 attr->disabled = 1; 245 attr->sample_type = PERF_SAMPLE_PERIOD; 246 attr->freq = freq; 247 attr->sample_period = sample_period; /* = ->sample_freq */ 248 } 249 250 static void op_prepare_attr(struct perf_event_attr *attr, 251 unsigned long config, int freq, 252 unsigned long sample_period) 253 { 254 memset(attr, 0, sizeof(struct perf_event_attr)); 255 256 attr->type = op_pmu->type; 257 attr->size = sizeof(struct perf_event_attr); 258 attr->config = config; 259 attr->disabled = 1; 260 attr->sample_type = PERF_SAMPLE_PERIOD; 261 attr->freq = freq; 262 attr->sample_period = sample_period; /* = ->sample_freq */ 263 } 264 265 struct ibs_configs { 266 /* Input */ 267 unsigned long config; 268 269 /* Expected output */ 270 unsigned long period; 271 int fd; 272 }; 273 274 /* 275 * Somehow first Fetch event with sample period = 0x10 causes 0 276 * samples. So start with large period and decrease it gradually. 277 */ 278 struct ibs_configs fetch_configs[] = { 279 { .config = 0xffff, .period = 0xffff0, .fd = FD_SUCCESS }, 280 { .config = 0x1000, .period = 0x10000, .fd = FD_SUCCESS }, 281 { .config = 0xff, .period = 0xff0, .fd = FD_SUCCESS }, 282 { .config = 0x1, .period = 0x10, .fd = FD_SUCCESS }, 283 { .config = 0x0, .period = -1, .fd = FD_ERROR }, 284 { .config = 0x10000, .period = -1, .fd = FD_ERROR }, 285 }; 286 287 struct ibs_configs op_configs[] = { 288 { .config = 0x0, .period = -1, .fd = FD_ERROR }, 289 { .config = 0x1, .period = -1, .fd = FD_ERROR }, 290 { .config = 0x8, .period = -1, .fd = FD_ERROR }, 291 { .config = 0x9, .period = 0x90, .fd = FD_SUCCESS }, 292 { .config = 0xf, .period = 0xf0, .fd = FD_SUCCESS }, 293 { .config = 0x1000, .period = 0x10000, .fd = FD_SUCCESS }, 294 { .config = 0xffff, .period = 0xffff0, .fd = FD_SUCCESS }, 295 { .config = 0x10000, .period = -1, .fd = FD_ERROR }, 296 { .config = 0x100000, .period = 0x100000, .fd = FD_SUCCESS }, 297 { .config = 0xf00000, .period = 0xf00000, .fd = FD_SUCCESS }, 298 { .config = 0xf0ffff, .period = 0xfffff0, .fd = FD_SUCCESS }, 299 { .config = 0x1f0ffff, .period = 0x1fffff0, .fd = FD_SUCCESS }, 300 { .config = 0x7f0ffff, .period = 0x7fffff0, .fd = FD_SUCCESS }, 301 { .config = 0x8f0ffff, .period = -1, .fd = FD_ERROR }, 302 { .config = 0x17f0ffff, .period = -1, .fd = FD_ERROR }, 303 }; 304 305 static int __ibs_config_test(int ibs_type, struct ibs_configs *config, int *nr_samples) 306 { 307 struct perf_event_attr attr; 308 int fd, i; 309 void *rb; 310 int ret = 0; 311 312 if (ibs_type == IBS_FETCH) 313 fetch_prepare_attr(&attr, config->config, 0, 0); 314 else 315 op_prepare_attr(&attr, config->config, 0, 0); 316 317 /* CPU0, All processes */ 318 fd = perf_event_open(&attr, -1, 0, -1, 0); 319 if (config->fd == FD_ERROR) { 320 if (fd != -1) { 321 close(fd); 322 return -1; 323 } 324 return 0; 325 } 326 if (fd <= -1) 327 return -1; 328 329 rb = mmap(NULL, PERF_MMAP_TOTAL_SIZE, PROT_READ | PROT_WRITE, 330 MAP_SHARED, fd, 0); 331 if (rb == MAP_FAILED) { 332 pr_debug("mmap() failed. [%m]\n"); 333 return -1; 334 } 335 336 ioctl(fd, PERF_EVENT_IOC_RESET, 0); 337 ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); 338 339 i = 5; 340 while (i--) { 341 dummy_workload_1(1000000); 342 343 ret = rb_drain_samples(rb, config->period, nr_samples, 344 period_equal); 345 if (ret) 346 break; 347 } 348 349 ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); 350 munmap(rb, PERF_MMAP_TOTAL_SIZE); 351 close(fd); 352 return ret; 353 } 354 355 static int ibs_config_test(void) 356 { 357 int nr_samples = 0; 358 unsigned long i; 359 int ret = 0; 360 int r; 361 362 pr_debug("\nIBS config tests:\n"); 363 pr_debug("-----------------\n"); 364 365 pr_debug("Fetch PMU tests:\n"); 366 for (i = 0; i < ARRAY_SIZE(fetch_configs); i++) { 367 nr_samples = 0; 368 r = __ibs_config_test(IBS_FETCH, &(fetch_configs[i]), &nr_samples); 369 370 if (fetch_configs[i].fd == FD_ERROR) { 371 pr_debug("0x%-16lx: %-4s\n", fetch_configs[i].config, 372 !r ? "Ok" : "Fail"); 373 } else { 374 /* 375 * Although nr_samples == 0 is reported as Fail here, 376 * the failure status is not cascaded up because, we 377 * can not decide whether test really failed or not 378 * without actual samples. 379 */ 380 pr_debug("0x%-16lx: %-4s (nr samples: %d)\n", fetch_configs[i].config, 381 (!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples); 382 } 383 384 ret |= r; 385 } 386 387 pr_debug("Op PMU tests:\n"); 388 for (i = 0; i < ARRAY_SIZE(op_configs); i++) { 389 nr_samples = 0; 390 r = __ibs_config_test(IBS_OP, &(op_configs[i]), &nr_samples); 391 392 if (op_configs[i].fd == FD_ERROR) { 393 pr_debug("0x%-16lx: %-4s\n", op_configs[i].config, 394 !r ? "Ok" : "Fail"); 395 } else { 396 /* 397 * Although nr_samples == 0 is reported as Fail here, 398 * the failure status is not cascaded up because, we 399 * can not decide whether test really failed or not 400 * without actual samples. 401 */ 402 pr_debug("0x%-16lx: %-4s (nr samples: %d)\n", op_configs[i].config, 403 (!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples); 404 } 405 406 ret |= r; 407 } 408 409 return ret; 410 } 411 412 struct ibs_period { 413 /* Input */ 414 int freq; 415 unsigned long sample_freq; 416 417 /* Output */ 418 int ret; 419 unsigned long period; 420 }; 421 422 struct ibs_period fetch_period[] = { 423 { .freq = 0, .sample_freq = 0, .ret = FD_ERROR, .period = -1 }, 424 { .freq = 0, .sample_freq = 1, .ret = FD_ERROR, .period = -1 }, 425 { .freq = 0, .sample_freq = 0xf, .ret = FD_ERROR, .period = -1 }, 426 { .freq = 0, .sample_freq = 0x10, .ret = FD_SUCCESS, .period = 0x10 }, 427 { .freq = 0, .sample_freq = 0x11, .ret = FD_SUCCESS, .period = 0x10 }, 428 { .freq = 0, .sample_freq = 0x8f, .ret = FD_SUCCESS, .period = 0x80 }, 429 { .freq = 0, .sample_freq = 0x90, .ret = FD_SUCCESS, .period = 0x90 }, 430 { .freq = 0, .sample_freq = 0x91, .ret = FD_SUCCESS, .period = 0x90 }, 431 { .freq = 0, .sample_freq = 0x4d2, .ret = FD_SUCCESS, .period = 0x4d0 }, 432 { .freq = 0, .sample_freq = 0x1007, .ret = FD_SUCCESS, .period = 0x1000 }, 433 { .freq = 0, .sample_freq = 0xfff0, .ret = FD_SUCCESS, .period = 0xfff0 }, 434 { .freq = 0, .sample_freq = 0xffff, .ret = FD_SUCCESS, .period = 0xfff0 }, 435 { .freq = 0, .sample_freq = 0x10010, .ret = FD_SUCCESS, .period = 0x10010 }, 436 { .freq = 0, .sample_freq = 0x7fffff, .ret = FD_SUCCESS, .period = 0x7ffff0 }, 437 { .freq = 0, .sample_freq = 0xfffffff, .ret = FD_SUCCESS, .period = 0xffffff0 }, 438 { .freq = 1, .sample_freq = 0, .ret = FD_ERROR, .period = -1 }, 439 { .freq = 1, .sample_freq = 1, .ret = FD_SUCCESS, .period = 0x10 }, 440 { .freq = 1, .sample_freq = 0xf, .ret = FD_SUCCESS, .period = 0x10 }, 441 { .freq = 1, .sample_freq = 0x10, .ret = FD_SUCCESS, .period = 0x10 }, 442 { .freq = 1, .sample_freq = 0x11, .ret = FD_SUCCESS, .period = 0x10 }, 443 { .freq = 1, .sample_freq = 0x8f, .ret = FD_SUCCESS, .period = 0x10 }, 444 { .freq = 1, .sample_freq = 0x90, .ret = FD_SUCCESS, .period = 0x10 }, 445 { .freq = 1, .sample_freq = 0x91, .ret = FD_SUCCESS, .period = 0x10 }, 446 { .freq = 1, .sample_freq = 0x4d2, .ret = FD_SUCCESS, .period = 0x10 }, 447 { .freq = 1, .sample_freq = 0x1007, .ret = FD_SUCCESS, .period = 0x10 }, 448 { .freq = 1, .sample_freq = 0xfff0, .ret = FD_SUCCESS, .period = 0x10 }, 449 { .freq = 1, .sample_freq = 0xffff, .ret = FD_SUCCESS, .period = 0x10 }, 450 { .freq = 1, .sample_freq = 0x10010, .ret = FD_SUCCESS, .period = 0x10 }, 451 /* ret=FD_ERROR because freq > default perf_event_max_sample_rate (100000) */ 452 { .freq = 1, .sample_freq = 0x7fffff, .ret = FD_ERROR, .period = -1 }, 453 }; 454 455 struct ibs_period op_period[] = { 456 { .freq = 0, .sample_freq = 0, .ret = FD_ERROR, .period = -1 }, 457 { .freq = 0, .sample_freq = 1, .ret = FD_ERROR, .period = -1 }, 458 { .freq = 0, .sample_freq = 0xf, .ret = FD_ERROR, .period = -1 }, 459 { .freq = 0, .sample_freq = 0x10, .ret = FD_ERROR, .period = -1 }, 460 { .freq = 0, .sample_freq = 0x11, .ret = FD_ERROR, .period = -1 }, 461 { .freq = 0, .sample_freq = 0x8f, .ret = FD_ERROR, .period = -1 }, 462 { .freq = 0, .sample_freq = 0x90, .ret = FD_SUCCESS, .period = 0x90 }, 463 { .freq = 0, .sample_freq = 0x91, .ret = FD_SUCCESS, .period = 0x90 }, 464 { .freq = 0, .sample_freq = 0x4d2, .ret = FD_SUCCESS, .period = 0x4d0 }, 465 { .freq = 0, .sample_freq = 0x1007, .ret = FD_SUCCESS, .period = 0x1000 }, 466 { .freq = 0, .sample_freq = 0xfff0, .ret = FD_SUCCESS, .period = 0xfff0 }, 467 { .freq = 0, .sample_freq = 0xffff, .ret = FD_SUCCESS, .period = 0xfff0 }, 468 { .freq = 0, .sample_freq = 0x10010, .ret = FD_SUCCESS, .period = 0x10010 }, 469 { .freq = 0, .sample_freq = 0x7fffff, .ret = FD_SUCCESS, .period = 0x7ffff0 }, 470 { .freq = 0, .sample_freq = 0xfffffff, .ret = FD_SUCCESS, .period = 0xffffff0 }, 471 { .freq = 1, .sample_freq = 0, .ret = FD_ERROR, .period = -1 }, 472 { .freq = 1, .sample_freq = 1, .ret = FD_SUCCESS, .period = 0x90 }, 473 { .freq = 1, .sample_freq = 0xf, .ret = FD_SUCCESS, .period = 0x90 }, 474 { .freq = 1, .sample_freq = 0x10, .ret = FD_SUCCESS, .period = 0x90 }, 475 { .freq = 1, .sample_freq = 0x11, .ret = FD_SUCCESS, .period = 0x90 }, 476 { .freq = 1, .sample_freq = 0x8f, .ret = FD_SUCCESS, .period = 0x90 }, 477 { .freq = 1, .sample_freq = 0x90, .ret = FD_SUCCESS, .period = 0x90 }, 478 { .freq = 1, .sample_freq = 0x91, .ret = FD_SUCCESS, .period = 0x90 }, 479 { .freq = 1, .sample_freq = 0x4d2, .ret = FD_SUCCESS, .period = 0x90 }, 480 { .freq = 1, .sample_freq = 0x1007, .ret = FD_SUCCESS, .period = 0x90 }, 481 { .freq = 1, .sample_freq = 0xfff0, .ret = FD_SUCCESS, .period = 0x90 }, 482 { .freq = 1, .sample_freq = 0xffff, .ret = FD_SUCCESS, .period = 0x90 }, 483 { .freq = 1, .sample_freq = 0x10010, .ret = FD_SUCCESS, .period = 0x90 }, 484 /* ret=FD_ERROR because freq > default perf_event_max_sample_rate (100000) */ 485 { .freq = 1, .sample_freq = 0x7fffff, .ret = FD_ERROR, .period = -1 }, 486 }; 487 488 static int __ibs_period_constraint_test(int ibs_type, struct ibs_period *period, 489 int *nr_samples) 490 { 491 struct perf_event_attr attr; 492 int ret = 0; 493 void *rb; 494 int fd; 495 496 if (period->freq && period->sample_freq > perf_event_max_sample_rate) 497 period->ret = FD_ERROR; 498 499 if (ibs_type == IBS_FETCH) 500 fetch_prepare_attr(&attr, 0, period->freq, period->sample_freq); 501 else 502 op_prepare_attr(&attr, 0, period->freq, period->sample_freq); 503 504 /* CPU0, All processes */ 505 fd = perf_event_open(&attr, -1, 0, -1, 0); 506 if (period->ret == FD_ERROR) { 507 if (fd != -1) { 508 close(fd); 509 return -1; 510 } 511 return 0; 512 } 513 if (fd <= -1) 514 return -1; 515 516 rb = mmap(NULL, PERF_MMAP_TOTAL_SIZE, PROT_READ | PROT_WRITE, 517 MAP_SHARED, fd, 0); 518 if (rb == MAP_FAILED) { 519 pr_debug("mmap() failed. [%m]\n"); 520 close(fd); 521 return -1; 522 } 523 524 ioctl(fd, PERF_EVENT_IOC_RESET, 0); 525 ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); 526 527 if (period->freq) { 528 dummy_workload_1(100000); 529 ret = rb_drain_samples(rb, period->period, nr_samples, 530 period_higher); 531 } else { 532 dummy_workload_1(period->sample_freq * 10); 533 ret = rb_drain_samples(rb, period->period, nr_samples, 534 period_equal); 535 } 536 537 ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); 538 munmap(rb, PERF_MMAP_TOTAL_SIZE); 539 close(fd); 540 return ret; 541 } 542 543 static int ibs_period_constraint_test(void) 544 { 545 unsigned long i; 546 int nr_samples; 547 int ret = 0; 548 int r; 549 550 pr_debug("\nIBS sample period constraint tests:\n"); 551 pr_debug("-----------------------------------\n"); 552 553 pr_debug("Fetch PMU test:\n"); 554 for (i = 0; i < ARRAY_SIZE(fetch_period); i++) { 555 nr_samples = 0; 556 r = __ibs_period_constraint_test(IBS_FETCH, &fetch_period[i], 557 &nr_samples); 558 559 if (fetch_period[i].ret == FD_ERROR) { 560 pr_debug("freq %d, sample_freq %9ld: %-4s\n", 561 fetch_period[i].freq, fetch_period[i].sample_freq, 562 !r ? "Ok" : "Fail"); 563 } else { 564 /* 565 * Although nr_samples == 0 is reported as Fail here, 566 * the failure status is not cascaded up because, we 567 * can not decide whether test really failed or not 568 * without actual samples. 569 */ 570 pr_debug("freq %d, sample_freq %9ld: %-4s (nr samples: %d)\n", 571 fetch_period[i].freq, fetch_period[i].sample_freq, 572 (!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples); 573 } 574 ret |= r; 575 } 576 577 pr_debug("Op PMU test:\n"); 578 for (i = 0; i < ARRAY_SIZE(op_period); i++) { 579 nr_samples = 0; 580 r = __ibs_period_constraint_test(IBS_OP, &op_period[i], 581 &nr_samples); 582 583 if (op_period[i].ret == FD_ERROR) { 584 pr_debug("freq %d, sample_freq %9ld: %-4s\n", 585 op_period[i].freq, op_period[i].sample_freq, 586 !r ? "Ok" : "Fail"); 587 } else { 588 /* 589 * Although nr_samples == 0 is reported as Fail here, 590 * the failure status is not cascaded up because, we 591 * can not decide whether test really failed or not 592 * without actual samples. 593 */ 594 pr_debug("freq %d, sample_freq %9ld: %-4s (nr samples: %d)\n", 595 op_period[i].freq, op_period[i].sample_freq, 596 (!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples); 597 } 598 ret |= r; 599 } 600 601 return ret; 602 } 603 604 struct ibs_ioctl { 605 /* Input */ 606 int freq; 607 unsigned long period; 608 609 /* Expected output */ 610 int ret; 611 }; 612 613 struct ibs_ioctl fetch_ioctl[] = { 614 { .freq = 0, .period = 0x0, .ret = FD_ERROR }, 615 { .freq = 0, .period = 0x1, .ret = FD_ERROR }, 616 { .freq = 0, .period = 0xf, .ret = FD_ERROR }, 617 { .freq = 0, .period = 0x10, .ret = FD_SUCCESS }, 618 { .freq = 0, .period = 0x11, .ret = FD_ERROR }, 619 { .freq = 0, .period = 0x1f, .ret = FD_ERROR }, 620 { .freq = 0, .period = 0x20, .ret = FD_SUCCESS }, 621 { .freq = 0, .period = 0x80, .ret = FD_SUCCESS }, 622 { .freq = 0, .period = 0x8f, .ret = FD_ERROR }, 623 { .freq = 0, .period = 0x90, .ret = FD_SUCCESS }, 624 { .freq = 0, .period = 0x91, .ret = FD_ERROR }, 625 { .freq = 0, .period = 0x100, .ret = FD_SUCCESS }, 626 { .freq = 0, .period = 0xfff0, .ret = FD_SUCCESS }, 627 { .freq = 0, .period = 0xffff, .ret = FD_ERROR }, 628 { .freq = 0, .period = 0x10000, .ret = FD_SUCCESS }, 629 { .freq = 0, .period = 0x1fff0, .ret = FD_SUCCESS }, 630 { .freq = 0, .period = 0x1fff5, .ret = FD_ERROR }, 631 { .freq = 1, .period = 0x0, .ret = FD_ERROR }, 632 { .freq = 1, .period = 0x1, .ret = FD_SUCCESS }, 633 { .freq = 1, .period = 0xf, .ret = FD_SUCCESS }, 634 { .freq = 1, .period = 0x10, .ret = FD_SUCCESS }, 635 { .freq = 1, .period = 0x11, .ret = FD_SUCCESS }, 636 { .freq = 1, .period = 0x1f, .ret = FD_SUCCESS }, 637 { .freq = 1, .period = 0x20, .ret = FD_SUCCESS }, 638 { .freq = 1, .period = 0x80, .ret = FD_SUCCESS }, 639 { .freq = 1, .period = 0x8f, .ret = FD_SUCCESS }, 640 { .freq = 1, .period = 0x90, .ret = FD_SUCCESS }, 641 { .freq = 1, .period = 0x91, .ret = FD_SUCCESS }, 642 { .freq = 1, .period = 0x100, .ret = FD_SUCCESS }, 643 }; 644 645 struct ibs_ioctl op_ioctl[] = { 646 { .freq = 0, .period = 0x0, .ret = FD_ERROR }, 647 { .freq = 0, .period = 0x1, .ret = FD_ERROR }, 648 { .freq = 0, .period = 0xf, .ret = FD_ERROR }, 649 { .freq = 0, .period = 0x10, .ret = FD_ERROR }, 650 { .freq = 0, .period = 0x11, .ret = FD_ERROR }, 651 { .freq = 0, .period = 0x1f, .ret = FD_ERROR }, 652 { .freq = 0, .period = 0x20, .ret = FD_ERROR }, 653 { .freq = 0, .period = 0x80, .ret = FD_ERROR }, 654 { .freq = 0, .period = 0x8f, .ret = FD_ERROR }, 655 { .freq = 0, .period = 0x90, .ret = FD_SUCCESS }, 656 { .freq = 0, .period = 0x91, .ret = FD_ERROR }, 657 { .freq = 0, .period = 0x100, .ret = FD_SUCCESS }, 658 { .freq = 0, .period = 0xfff0, .ret = FD_SUCCESS }, 659 { .freq = 0, .period = 0xffff, .ret = FD_ERROR }, 660 { .freq = 0, .period = 0x10000, .ret = FD_SUCCESS }, 661 { .freq = 0, .period = 0x1fff0, .ret = FD_SUCCESS }, 662 { .freq = 0, .period = 0x1fff5, .ret = FD_ERROR }, 663 { .freq = 1, .period = 0x0, .ret = FD_ERROR }, 664 { .freq = 1, .period = 0x1, .ret = FD_SUCCESS }, 665 { .freq = 1, .period = 0xf, .ret = FD_SUCCESS }, 666 { .freq = 1, .period = 0x10, .ret = FD_SUCCESS }, 667 { .freq = 1, .period = 0x11, .ret = FD_SUCCESS }, 668 { .freq = 1, .period = 0x1f, .ret = FD_SUCCESS }, 669 { .freq = 1, .period = 0x20, .ret = FD_SUCCESS }, 670 { .freq = 1, .period = 0x80, .ret = FD_SUCCESS }, 671 { .freq = 1, .period = 0x8f, .ret = FD_SUCCESS }, 672 { .freq = 1, .period = 0x90, .ret = FD_SUCCESS }, 673 { .freq = 1, .period = 0x91, .ret = FD_SUCCESS }, 674 { .freq = 1, .period = 0x100, .ret = FD_SUCCESS }, 675 }; 676 677 static int __ibs_ioctl_test(int ibs_type, struct ibs_ioctl *ibs_ioctl) 678 { 679 struct perf_event_attr attr; 680 int ret = 0; 681 int fd; 682 int r; 683 684 if (ibs_type == IBS_FETCH) 685 fetch_prepare_attr(&attr, 0, ibs_ioctl->freq, 1000); 686 else 687 op_prepare_attr(&attr, 0, ibs_ioctl->freq, 1000); 688 689 /* CPU0, All processes */ 690 fd = perf_event_open(&attr, -1, 0, -1, 0); 691 if (fd <= -1) { 692 pr_debug("event_open() Failed\n"); 693 return -1; 694 } 695 696 r = ioctl(fd, PERF_EVENT_IOC_PERIOD, &ibs_ioctl->period); 697 if ((ibs_ioctl->ret == FD_SUCCESS && r <= -1) || 698 (ibs_ioctl->ret == FD_ERROR && r >= 0)) { 699 ret = -1; 700 } 701 702 close(fd); 703 return ret; 704 } 705 706 static int ibs_ioctl_test(void) 707 { 708 unsigned long i; 709 int ret = 0; 710 int r; 711 712 pr_debug("\nIBS ioctl() tests:\n"); 713 pr_debug("------------------\n"); 714 715 pr_debug("Fetch PMU tests\n"); 716 for (i = 0; i < ARRAY_SIZE(fetch_ioctl); i++) { 717 r = __ibs_ioctl_test(IBS_FETCH, &fetch_ioctl[i]); 718 719 pr_debug("ioctl(%s = 0x%-7lx): %s\n", 720 fetch_ioctl[i].freq ? "freq " : "period", 721 fetch_ioctl[i].period, r ? "Fail" : "Ok"); 722 ret |= r; 723 } 724 725 pr_debug("Op PMU tests\n"); 726 for (i = 0; i < ARRAY_SIZE(op_ioctl); i++) { 727 r = __ibs_ioctl_test(IBS_OP, &op_ioctl[i]); 728 729 pr_debug("ioctl(%s = 0x%-7lx): %s\n", 730 op_ioctl[i].freq ? "freq " : "period", 731 op_ioctl[i].period, r ? "Fail" : "Ok"); 732 ret |= r; 733 } 734 735 return ret; 736 } 737 738 static int ibs_freq_neg_test(void) 739 { 740 struct perf_event_attr attr; 741 int fd; 742 743 pr_debug("\nIBS freq (negative) tests:\n"); 744 pr_debug("--------------------------\n"); 745 746 /* 747 * Assuming perf_event_max_sample_rate <= 100000, 748 * config: 0x300D40 ==> MaxCnt: 200000 749 */ 750 op_prepare_attr(&attr, 0x300D40, 1, 0); 751 752 /* CPU0, All processes */ 753 fd = perf_event_open(&attr, -1, 0, -1, 0); 754 if (fd != -1) { 755 pr_debug("freq 1, sample_freq 200000: Fail\n"); 756 close(fd); 757 return -1; 758 } 759 760 pr_debug("freq 1, sample_freq 200000: Ok\n"); 761 762 return 0; 763 } 764 765 struct ibs_l3missonly { 766 /* Input */ 767 int freq; 768 unsigned long sample_freq; 769 770 /* Expected output */ 771 int ret; 772 unsigned long min_period; 773 }; 774 775 struct ibs_l3missonly fetch_l3missonly = { 776 .freq = 1, 777 .sample_freq = 10000, 778 .ret = FD_SUCCESS, 779 .min_period = 0x10, 780 }; 781 782 struct ibs_l3missonly op_l3missonly = { 783 .freq = 1, 784 .sample_freq = 10000, 785 .ret = FD_SUCCESS, 786 .min_period = 0x90, 787 }; 788 789 static int __ibs_l3missonly_test(char *perf, int ibs_type, int *nr_samples, 790 struct ibs_l3missonly *l3missonly) 791 { 792 struct perf_event_attr attr; 793 int ret = 0; 794 void *rb; 795 int fd; 796 797 if (l3missonly->sample_freq > perf_event_max_sample_rate) 798 l3missonly->ret = FD_ERROR; 799 800 if (ibs_type == IBS_FETCH) { 801 fetch_prepare_attr(&attr, 0x800000000000000UL, l3missonly->freq, 802 l3missonly->sample_freq); 803 } else { 804 op_prepare_attr(&attr, 0x10000, l3missonly->freq, 805 l3missonly->sample_freq); 806 } 807 808 /* CPU0, All processes */ 809 fd = perf_event_open(&attr, -1, 0, -1, 0); 810 if (l3missonly->ret == FD_ERROR) { 811 if (fd != -1) { 812 close(fd); 813 return -1; 814 } 815 return 0; 816 } 817 if (fd == -1) { 818 pr_debug("perf_event_open() failed. [%m]\n"); 819 return -1; 820 } 821 822 rb = mmap(NULL, PERF_MMAP_TOTAL_SIZE, PROT_READ | PROT_WRITE, 823 MAP_SHARED, fd, 0); 824 if (rb == MAP_FAILED) { 825 pr_debug("mmap() failed. [%m]\n"); 826 close(fd); 827 return -1; 828 } 829 830 ioctl(fd, PERF_EVENT_IOC_RESET, 0); 831 ioctl(fd, PERF_EVENT_IOC_ENABLE, 0); 832 833 dummy_workload_2(perf); 834 835 ioctl(fd, PERF_EVENT_IOC_DISABLE, 0); 836 837 ret = rb_drain_samples(rb, l3missonly->min_period, nr_samples, period_higher); 838 839 munmap(rb, PERF_MMAP_TOTAL_SIZE); 840 close(fd); 841 return ret; 842 } 843 844 static int ibs_l3missonly_test(char *perf) 845 { 846 int nr_samples = 0; 847 int ret = 0; 848 int r = 0; 849 850 pr_debug("\nIBS L3MissOnly test: (takes a while)\n"); 851 pr_debug("--------------------\n"); 852 853 if (perf_pmu__has_format(fetch_pmu, "l3missonly")) { 854 nr_samples = 0; 855 r = __ibs_l3missonly_test(perf, IBS_FETCH, &nr_samples, &fetch_l3missonly); 856 if (fetch_l3missonly.ret == FD_ERROR) { 857 pr_debug("Fetch L3MissOnly: %-4s\n", !r ? "Ok" : "Fail"); 858 } else { 859 /* 860 * Although nr_samples == 0 is reported as Fail here, 861 * the failure status is not cascaded up because, we 862 * can not decide whether test really failed or not 863 * without actual samples. 864 */ 865 pr_debug("Fetch L3MissOnly: %-4s (nr_samples: %d)\n", 866 (!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples); 867 } 868 ret |= r; 869 } 870 871 if (perf_pmu__has_format(op_pmu, "l3missonly")) { 872 nr_samples = 0; 873 r = __ibs_l3missonly_test(perf, IBS_OP, &nr_samples, &op_l3missonly); 874 if (op_l3missonly.ret == FD_ERROR) { 875 pr_debug("Op L3MissOnly: %-4s\n", !r ? "Ok" : "Fail"); 876 } else { 877 /* 878 * Although nr_samples == 0 is reported as Fail here, 879 * the failure status is not cascaded up because, we 880 * can not decide whether test really failed or not 881 * without actual samples. 882 */ 883 pr_debug("Op L3MissOnly: %-4s (nr_samples: %d)\n", 884 (!r && nr_samples != 0) ? "Ok" : "Fail", nr_samples); 885 } 886 ret |= r; 887 } 888 889 return ret; 890 } 891 892 static unsigned int get_perf_event_max_sample_rate(void) 893 { 894 unsigned int max_sample_rate = 100000; 895 FILE *fp; 896 int ret; 897 898 fp = fopen("/proc/sys/kernel/perf_event_max_sample_rate", "r"); 899 if (!fp) { 900 pr_debug("Can't open perf_event_max_sample_rate. Assuming %d\n", 901 max_sample_rate); 902 goto out; 903 } 904 905 ret = fscanf(fp, "%d", &max_sample_rate); 906 if (ret == EOF) { 907 pr_debug("Can't read perf_event_max_sample_rate. Assuming 100000\n"); 908 max_sample_rate = 100000; 909 } 910 fclose(fp); 911 912 out: 913 return max_sample_rate; 914 } 915 916 /* 917 * Bunch of IBS sample period fixes that this test exercise went in v6.15. 918 * Skip the test on older kernels to distinguish between test failure due 919 * to a new bug vs known failure due to older kernel. 920 */ 921 static bool kernel_v6_15_or_newer(void) 922 { 923 struct utsname utsname; 924 char *endptr = NULL; 925 long major, minor; 926 927 if (uname(&utsname) < 0) { 928 pr_debug("uname() failed. [%m]"); 929 return false; 930 } 931 932 major = strtol(utsname.release, &endptr, 10); 933 endptr++; 934 minor = strtol(endptr, NULL, 10); 935 936 return major >= 6 && minor >= 15; 937 } 938 939 int test__amd_ibs_period(struct test_suite *test __maybe_unused, 940 int subtest __maybe_unused) 941 { 942 char perf[PATH_MAX] = {'\0'}; 943 int ret = TEST_OK; 944 945 page_size = sysconf(_SC_PAGESIZE); 946 947 /* 948 * Reading perf_event_max_sample_rate only once _might_ cause some 949 * of the test to fail if kernel changes it after reading it here. 950 */ 951 perf_event_max_sample_rate = get_perf_event_max_sample_rate(); 952 fetch_pmu = perf_pmus__find("ibs_fetch"); 953 op_pmu = perf_pmus__find("ibs_op"); 954 955 if (!x86__is_amd_cpu() || !fetch_pmu || !op_pmu) 956 return TEST_SKIP; 957 958 if (!kernel_v6_15_or_newer()) { 959 pr_debug("Need v6.15 or newer kernel. Skipping.\n"); 960 return TEST_SKIP; 961 } 962 963 perf_exe(perf, sizeof(perf)); 964 965 if (sched_affine(0)) 966 return TEST_FAIL; 967 968 /* 969 * Perf event can be opened in two modes: 970 * 1 Freq mode 971 * perf_event_attr->freq = 1, ->sample_freq = <frequency> 972 * 2 Sample period mode 973 * perf_event_attr->freq = 0, ->sample_period = <period> 974 * 975 * Instead of using above interface, IBS event in 'sample period mode' 976 * can also be opened by passing <period> value directly in a MaxCnt 977 * bitfields of perf_event_attr->config. Test this IBS specific special 978 * interface. 979 */ 980 if (ibs_config_test()) 981 ret = TEST_FAIL; 982 983 /* 984 * IBS Fetch and Op PMUs have HW constraints on minimum sample period. 985 * Also, sample period value must be in multiple of 0x10. Test that IBS 986 * driver honors HW constraints for various possible values in Freq as 987 * well as Sample Period mode IBS events. 988 */ 989 if (ibs_period_constraint_test()) 990 ret = TEST_FAIL; 991 992 /* 993 * Test ioctl() with various sample period values for IBS event. 994 */ 995 if (ibs_ioctl_test()) 996 ret = TEST_FAIL; 997 998 /* 999 * Test that opening of freq mode IBS event fails when the freq value 1000 * is passed through ->config, not explicitly in ->sample_freq. Also 1001 * use high freq value (beyond perf_event_max_sample_rate) to test IBS 1002 * driver do not bypass perf_event_max_sample_rate checks. 1003 */ 1004 if (ibs_freq_neg_test()) 1005 ret = TEST_FAIL; 1006 1007 /* 1008 * L3MissOnly is a post-processing filter, i.e. IBS HW checks for L3 1009 * Miss at the completion of the tagged uOp. The sample is discarded 1010 * if the tagged uOp did not cause L3Miss. Also, IBS HW internally 1011 * resets CurCnt to a small pseudo-random value and resumes counting. 1012 * A new uOp is tagged once CurCnt reaches to MaxCnt. But the process 1013 * repeats until the tagged uOp causes an L3 Miss. 1014 * 1015 * With the freq mode event, the next sample period is calculated by 1016 * generic kernel on every sample to achieve desired freq of samples. 1017 * 1018 * Since the number of times HW internally reset CurCnt and the pseudo- 1019 * random value of CurCnt for all those occurrences are not known to SW, 1020 * the sample period adjustment by kernel goes for a toes for freq mode 1021 * IBS events. Kernel will set very small period for the next sample if 1022 * the window between current sample and prev sample is too high due to 1023 * multiple samples being discarded internally by IBS HW. 1024 * 1025 * Test that IBS sample period constraints are honored when L3MissOnly 1026 * is ON. 1027 */ 1028 if (ibs_l3missonly_test(perf)) 1029 ret = TEST_FAIL; 1030 1031 return ret; 1032 } 1033