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