0001
0002 #include <errno.h>
0003 #include <inttypes.h>
0004 #include <linux/string.h>
0005
0006 #include <pthread.h>
0007
0008 #include <sched.h>
0009 #include <perf/mmap.h>
0010 #include "evlist.h"
0011 #include "evsel.h"
0012 #include "debug.h"
0013 #include "record.h"
0014 #include "tests.h"
0015 #include "util/mmap.h"
0016
0017 static int sched__get_first_possible_cpu(pid_t pid, cpu_set_t *maskp)
0018 {
0019 int i, cpu = -1, nrcpus = 1024;
0020 realloc:
0021 CPU_ZERO(maskp);
0022
0023 if (sched_getaffinity(pid, sizeof(*maskp), maskp) == -1) {
0024 if (errno == EINVAL && nrcpus < (1024 << 8)) {
0025 nrcpus = nrcpus << 2;
0026 goto realloc;
0027 }
0028 perror("sched_getaffinity");
0029 return -1;
0030 }
0031
0032 for (i = 0; i < nrcpus; i++) {
0033 if (CPU_ISSET(i, maskp)) {
0034 if (cpu == -1)
0035 cpu = i;
0036 else
0037 CPU_CLR(i, maskp);
0038 }
0039 }
0040
0041 return cpu;
0042 }
0043
0044 static int test__PERF_RECORD(struct test_suite *test __maybe_unused, int subtest __maybe_unused)
0045 {
0046 struct record_opts opts = {
0047 .target = {
0048 .uid = UINT_MAX,
0049 .uses_mmap = true,
0050 },
0051 .no_buffering = true,
0052 .mmap_pages = 256,
0053 };
0054 cpu_set_t cpu_mask;
0055 size_t cpu_mask_size = sizeof(cpu_mask);
0056 struct evlist *evlist = evlist__new_dummy();
0057 struct evsel *evsel;
0058 struct perf_sample sample;
0059 const char *cmd = "sleep";
0060 const char *argv[] = { cmd, "1", NULL, };
0061 char *bname, *mmap_filename;
0062 u64 prev_time = 0;
0063 bool found_cmd_mmap = false,
0064 found_coreutils_mmap = false,
0065 found_libc_mmap = false,
0066 found_vdso_mmap = false,
0067 found_ld_mmap = false;
0068 int err = -1, errs = 0, i, wakeups = 0;
0069 u32 cpu;
0070 int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
0071 char sbuf[STRERR_BUFSIZE];
0072
0073 if (evlist == NULL)
0074 evlist = evlist__new_default();
0075
0076 if (evlist == NULL) {
0077 pr_debug("Not enough memory to create evlist\n");
0078 goto out;
0079 }
0080
0081
0082
0083
0084
0085
0086
0087 err = evlist__create_maps(evlist, &opts.target);
0088 if (err < 0) {
0089 pr_debug("Not enough memory to create thread/cpu maps\n");
0090 goto out_delete_evlist;
0091 }
0092
0093
0094
0095
0096
0097
0098
0099 err = evlist__prepare_workload(evlist, &opts.target, argv, false, NULL);
0100 if (err < 0) {
0101 pr_debug("Couldn't run the workload!\n");
0102 goto out_delete_evlist;
0103 }
0104
0105
0106
0107
0108 evsel = evlist__first(evlist);
0109 evsel__set_sample_bit(evsel, CPU);
0110 evsel__set_sample_bit(evsel, TID);
0111 evsel__set_sample_bit(evsel, TIME);
0112 evlist__config(evlist, &opts, NULL);
0113
0114 err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask);
0115 if (err < 0) {
0116 pr_debug("sched__get_first_possible_cpu: %s\n",
0117 str_error_r(errno, sbuf, sizeof(sbuf)));
0118 goto out_delete_evlist;
0119 }
0120
0121 cpu = err;
0122
0123
0124
0125
0126 if (sched_setaffinity(evlist->workload.pid, cpu_mask_size, &cpu_mask) < 0) {
0127 pr_debug("sched_setaffinity: %s\n",
0128 str_error_r(errno, sbuf, sizeof(sbuf)));
0129 goto out_delete_evlist;
0130 }
0131
0132
0133
0134
0135
0136 err = evlist__open(evlist);
0137 if (err < 0) {
0138 pr_debug("perf_evlist__open: %s\n",
0139 str_error_r(errno, sbuf, sizeof(sbuf)));
0140 goto out_delete_evlist;
0141 }
0142
0143
0144
0145
0146
0147
0148 err = evlist__mmap(evlist, opts.mmap_pages);
0149 if (err < 0) {
0150 pr_debug("evlist__mmap: %s\n",
0151 str_error_r(errno, sbuf, sizeof(sbuf)));
0152 goto out_delete_evlist;
0153 }
0154
0155
0156
0157
0158
0159 evlist__enable(evlist);
0160
0161
0162
0163
0164 evlist__start_workload(evlist);
0165
0166 while (1) {
0167 int before = total_events;
0168
0169 for (i = 0; i < evlist->core.nr_mmaps; i++) {
0170 union perf_event *event;
0171 struct mmap *md;
0172
0173 md = &evlist->mmap[i];
0174 if (perf_mmap__read_init(&md->core) < 0)
0175 continue;
0176
0177 while ((event = perf_mmap__read_event(&md->core)) != NULL) {
0178 const u32 type = event->header.type;
0179 const char *name = perf_event__name(type);
0180
0181 ++total_events;
0182 if (type < PERF_RECORD_MAX)
0183 nr_events[type]++;
0184
0185 err = evlist__parse_sample(evlist, event, &sample);
0186 if (err < 0) {
0187 if (verbose > 0)
0188 perf_event__fprintf(event, NULL, stderr);
0189 pr_debug("Couldn't parse sample\n");
0190 goto out_delete_evlist;
0191 }
0192
0193 if (verbose > 0) {
0194 pr_info("%" PRIu64" %d ", sample.time, sample.cpu);
0195 perf_event__fprintf(event, NULL, stderr);
0196 }
0197
0198 if (prev_time > sample.time) {
0199 pr_debug("%s going backwards in time, prev=%" PRIu64 ", curr=%" PRIu64 "\n",
0200 name, prev_time, sample.time);
0201 ++errs;
0202 }
0203
0204 prev_time = sample.time;
0205
0206 if (sample.cpu != cpu) {
0207 pr_debug("%s with unexpected cpu, expected %d, got %d\n",
0208 name, cpu, sample.cpu);
0209 ++errs;
0210 }
0211
0212 if ((pid_t)sample.pid != evlist->workload.pid) {
0213 pr_debug("%s with unexpected pid, expected %d, got %d\n",
0214 name, evlist->workload.pid, sample.pid);
0215 ++errs;
0216 }
0217
0218 if ((pid_t)sample.tid != evlist->workload.pid) {
0219 pr_debug("%s with unexpected tid, expected %d, got %d\n",
0220 name, evlist->workload.pid, sample.tid);
0221 ++errs;
0222 }
0223
0224 if ((type == PERF_RECORD_COMM ||
0225 type == PERF_RECORD_MMAP ||
0226 type == PERF_RECORD_MMAP2 ||
0227 type == PERF_RECORD_FORK ||
0228 type == PERF_RECORD_EXIT) &&
0229 (pid_t)event->comm.pid != evlist->workload.pid) {
0230 pr_debug("%s with unexpected pid/tid\n", name);
0231 ++errs;
0232 }
0233
0234 if ((type == PERF_RECORD_COMM ||
0235 type == PERF_RECORD_MMAP ||
0236 type == PERF_RECORD_MMAP2) &&
0237 event->comm.pid != event->comm.tid) {
0238 pr_debug("%s with different pid/tid!\n", name);
0239 ++errs;
0240 }
0241
0242 switch (type) {
0243 case PERF_RECORD_COMM:
0244 if (strcmp(event->comm.comm, cmd)) {
0245 pr_debug("%s with unexpected comm!\n", name);
0246 ++errs;
0247 }
0248 break;
0249 case PERF_RECORD_EXIT:
0250 goto found_exit;
0251 case PERF_RECORD_MMAP:
0252 mmap_filename = event->mmap.filename;
0253 goto check_bname;
0254 case PERF_RECORD_MMAP2:
0255 mmap_filename = event->mmap2.filename;
0256 check_bname:
0257 bname = strrchr(mmap_filename, '/');
0258 if (bname != NULL) {
0259 if (!found_cmd_mmap)
0260 found_cmd_mmap = !strcmp(bname + 1, cmd);
0261 if (!found_coreutils_mmap)
0262 found_coreutils_mmap = !strcmp(bname + 1, "coreutils");
0263 if (!found_libc_mmap)
0264 found_libc_mmap = !strncmp(bname + 1, "libc", 4);
0265 if (!found_ld_mmap)
0266 found_ld_mmap = !strncmp(bname + 1, "ld", 2);
0267 } else if (!found_vdso_mmap)
0268 found_vdso_mmap = !strcmp(mmap_filename, "[vdso]");
0269 break;
0270
0271 case PERF_RECORD_SAMPLE:
0272
0273 break;
0274 default:
0275 pr_debug("Unexpected perf_event->header.type %d!\n",
0276 type);
0277 ++errs;
0278 }
0279
0280 perf_mmap__consume(&md->core);
0281 }
0282 perf_mmap__read_done(&md->core);
0283 }
0284
0285
0286
0287
0288
0289
0290 if (total_events == before && false)
0291 evlist__poll(evlist, -1);
0292
0293 sleep(1);
0294 if (++wakeups > 5) {
0295 pr_debug("No PERF_RECORD_EXIT event!\n");
0296 break;
0297 }
0298 }
0299
0300 found_exit:
0301 if (nr_events[PERF_RECORD_COMM] > 1 + !!found_coreutils_mmap) {
0302 pr_debug("Excessive number of PERF_RECORD_COMM events!\n");
0303 ++errs;
0304 }
0305
0306 if (nr_events[PERF_RECORD_COMM] == 0) {
0307 pr_debug("Missing PERF_RECORD_COMM for %s!\n", cmd);
0308 ++errs;
0309 }
0310
0311 if (!found_cmd_mmap && !found_coreutils_mmap) {
0312 pr_debug("PERF_RECORD_MMAP for %s missing!\n", cmd);
0313 ++errs;
0314 }
0315
0316 if (!found_libc_mmap) {
0317 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "libc");
0318 ++errs;
0319 }
0320
0321 if (!found_ld_mmap) {
0322 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "ld");
0323 ++errs;
0324 }
0325
0326 if (!found_vdso_mmap) {
0327 pr_debug("PERF_RECORD_MMAP for %s missing!\n", "[vdso]");
0328 ++errs;
0329 }
0330 out_delete_evlist:
0331 evlist__delete(evlist);
0332 out:
0333 if (err == -EACCES)
0334 return TEST_SKIP;
0335 if (err < 0 || errs != 0)
0336 return TEST_FAIL;
0337 return TEST_OK;
0338 }
0339
0340 static struct test_case tests__PERF_RECORD[] = {
0341 TEST_CASE_REASON("PERF_RECORD_* events & perf_sample fields",
0342 PERF_RECORD,
0343 "permissions"),
0344 { .name = NULL, }
0345 };
0346
0347 struct test_suite suite__PERF_RECORD = {
0348 .desc = "PERF_RECORD_* events & perf_sample fields",
0349 .test_cases = tests__PERF_RECORD,
0350 };