Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include "tests/tests.h"
0003 #include "cloexec.h"
0004 #include "debug.h"
0005 #include "evlist.h"
0006 #include "evsel.h"
0007 #include "arch-tests.h"
0008 #include <internal/lib.h> // page_size
0009 
0010 #include <signal.h>
0011 #include <sys/mman.h>
0012 #include <sys/wait.h>
0013 #include <errno.h>
0014 #include <string.h>
0015 
0016 static pid_t spawn(void)
0017 {
0018     pid_t pid;
0019 
0020     pid = fork();
0021     if (pid)
0022         return pid;
0023 
0024     while(1)
0025         sleep(5);
0026     return 0;
0027 }
0028 
0029 /*
0030  * Create an event group that contains both a sampled hardware
0031  * (cpu-cycles) and software (intel_cqm/llc_occupancy/) event. We then
0032  * wait for the hardware perf counter to overflow and generate a PMI,
0033  * which triggers an event read for both of the events in the group.
0034  *
0035  * Since reading Intel CQM event counters requires sending SMP IPIs, the
0036  * CQM pmu needs to handle the above situation gracefully, and return
0037  * the last read counter value to avoid triggering a WARN_ON_ONCE() in
0038  * smp_call_function_many() caused by sending IPIs from NMI context.
0039  */
0040 int test__intel_cqm_count_nmi_context(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
0041 {
0042     struct evlist *evlist = NULL;
0043     struct evsel *evsel = NULL;
0044     struct perf_event_attr pe;
0045     int i, fd[2], flag, ret;
0046     size_t mmap_len;
0047     void *event;
0048     pid_t pid;
0049     int err = TEST_FAIL;
0050 
0051     flag = perf_event_open_cloexec_flag();
0052 
0053     evlist = evlist__new();
0054     if (!evlist) {
0055         pr_debug("evlist__new failed\n");
0056         return TEST_FAIL;
0057     }
0058 
0059     ret = parse_event(evlist, "intel_cqm/llc_occupancy/");
0060     if (ret) {
0061         pr_debug("parse_events failed, is \"intel_cqm/llc_occupancy/\" available?\n");
0062         err = TEST_SKIP;
0063         goto out;
0064     }
0065 
0066     evsel = evlist__first(evlist);
0067     if (!evsel) {
0068         pr_debug("evlist__first failed\n");
0069         goto out;
0070     }
0071 
0072     memset(&pe, 0, sizeof(pe));
0073     pe.size = sizeof(pe);
0074 
0075     pe.type = PERF_TYPE_HARDWARE;
0076     pe.config = PERF_COUNT_HW_CPU_CYCLES;
0077     pe.read_format = PERF_FORMAT_GROUP;
0078 
0079     pe.sample_period = 128;
0080     pe.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_READ;
0081 
0082     pid = spawn();
0083 
0084     fd[0] = sys_perf_event_open(&pe, pid, -1, -1, flag);
0085     if (fd[0] < 0) {
0086         pr_debug("failed to open event\n");
0087         goto out;
0088     }
0089 
0090     memset(&pe, 0, sizeof(pe));
0091     pe.size = sizeof(pe);
0092 
0093     pe.type = evsel->attr.type;
0094     pe.config = evsel->attr.config;
0095 
0096     fd[1] = sys_perf_event_open(&pe, pid, -1, fd[0], flag);
0097     if (fd[1] < 0) {
0098         pr_debug("failed to open event\n");
0099         goto out;
0100     }
0101 
0102     /*
0103      * Pick a power-of-two number of pages + 1 for the meta-data
0104      * page (struct perf_event_mmap_page). See tools/perf/design.txt.
0105      */
0106     mmap_len = page_size * 65;
0107 
0108     event = mmap(NULL, mmap_len, PROT_READ, MAP_SHARED, fd[0], 0);
0109     if (event == (void *)(-1)) {
0110         pr_debug("failed to mmap %d\n", errno);
0111         goto out;
0112     }
0113 
0114     sleep(1);
0115 
0116     err = TEST_OK;
0117 
0118     munmap(event, mmap_len);
0119 
0120     for (i = 0; i < 2; i++)
0121         close(fd[i]);
0122 
0123     kill(pid, SIGKILL);
0124     wait(NULL);
0125 out:
0126     evlist__delete(evlist);
0127     return err;
0128 }