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