1 #include "tests/tests.h" 2 #include "perf.h" 3 #include "cloexec.h" 4 #include "debug.h" 5 #include "evlist.h" 6 #include "evsel.h" 7 #include "arch-tests.h" 8 9 #include <signal.h> 10 #include <sys/mman.h> 11 #include <sys/wait.h> 12 #include <errno.h> 13 #include <string.h> 14 15 static pid_t spawn(void) 16 { 17 pid_t pid; 18 19 pid = fork(); 20 if (pid) 21 return pid; 22 23 while(1) 24 sleep(5); 25 return 0; 26 } 27 28 /* 29 * Create an event group that contains both a sampled hardware 30 * (cpu-cycles) and software (intel_cqm/llc_occupancy/) event. We then 31 * wait for the hardware perf counter to overflow and generate a PMI, 32 * which triggers an event read for both of the events in the group. 33 * 34 * Since reading Intel CQM event counters requires sending SMP IPIs, the 35 * CQM pmu needs to handle the above situation gracefully, and return 36 * the last read counter value to avoid triggering a WARN_ON_ONCE() in 37 * smp_call_function_many() caused by sending IPIs from NMI context. 38 */ 39 int test__intel_cqm_count_nmi_context(int subtest __maybe_unused) 40 { 41 struct perf_evlist *evlist = NULL; 42 struct perf_evsel *evsel = NULL; 43 struct perf_event_attr pe; 44 int i, fd[2], flag, ret; 45 size_t mmap_len; 46 void *event; 47 pid_t pid; 48 int err = TEST_FAIL; 49 50 flag = perf_event_open_cloexec_flag(); 51 52 evlist = perf_evlist__new(); 53 if (!evlist) { 54 pr_debug("perf_evlist__new failed\n"); 55 return TEST_FAIL; 56 } 57 58 ret = parse_events(evlist, "intel_cqm/llc_occupancy/", NULL); 59 if (ret) { 60 pr_debug("parse_events failed, is \"intel_cqm/llc_occupancy/\" available?\n"); 61 err = TEST_SKIP; 62 goto out; 63 } 64 65 evsel = perf_evlist__first(evlist); 66 if (!evsel) { 67 pr_debug("perf_evlist__first failed\n"); 68 goto out; 69 } 70 71 memset(&pe, 0, sizeof(pe)); 72 pe.size = sizeof(pe); 73 74 pe.type = PERF_TYPE_HARDWARE; 75 pe.config = PERF_COUNT_HW_CPU_CYCLES; 76 pe.read_format = PERF_FORMAT_GROUP; 77 78 pe.sample_period = 128; 79 pe.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_READ; 80 81 pid = spawn(); 82 83 fd[0] = sys_perf_event_open(&pe, pid, -1, -1, flag); 84 if (fd[0] < 0) { 85 pr_debug("failed to open event\n"); 86 goto out; 87 } 88 89 memset(&pe, 0, sizeof(pe)); 90 pe.size = sizeof(pe); 91 92 pe.type = evsel->attr.type; 93 pe.config = evsel->attr.config; 94 95 fd[1] = sys_perf_event_open(&pe, pid, -1, fd[0], flag); 96 if (fd[1] < 0) { 97 pr_debug("failed to open event\n"); 98 goto out; 99 } 100 101 /* 102 * Pick a power-of-two number of pages + 1 for the meta-data 103 * page (struct perf_event_mmap_page). See tools/perf/design.txt. 104 */ 105 mmap_len = page_size * 65; 106 107 event = mmap(NULL, mmap_len, PROT_READ, MAP_SHARED, fd[0], 0); 108 if (event == (void *)(-1)) { 109 pr_debug("failed to mmap %d\n", errno); 110 goto out; 111 } 112 113 sleep(1); 114 115 err = TEST_OK; 116 117 munmap(event, mmap_len); 118 119 for (i = 0; i < 2; i++) 120 close(fd[i]); 121 122 kill(pid, SIGKILL); 123 wait(NULL); 124 out: 125 perf_evlist__delete(evlist); 126 return err; 127 } 128