162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <stdarg.h> 362306a36Sopenharmony_ci#include <stdio.h> 462306a36Sopenharmony_ci#include <string.h> 562306a36Sopenharmony_ci#include <linux/perf_event.h> 662306a36Sopenharmony_ci#include <linux/kernel.h> 762306a36Sopenharmony_ci#include <perf/cpumap.h> 862306a36Sopenharmony_ci#include <perf/threadmap.h> 962306a36Sopenharmony_ci#include <perf/evsel.h> 1062306a36Sopenharmony_ci#include <internal/evsel.h> 1162306a36Sopenharmony_ci#include <internal/tests.h> 1262306a36Sopenharmony_ci#include "tests.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic int libperf_print(enum libperf_print_level level, 1562306a36Sopenharmony_ci const char *fmt, va_list ap) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci return vfprintf(stderr, fmt, ap); 1862306a36Sopenharmony_ci} 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int test_stat_cpu(void) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct perf_cpu_map *cpus; 2362306a36Sopenharmony_ci struct perf_evsel *evsel; 2462306a36Sopenharmony_ci struct perf_event_attr attr = { 2562306a36Sopenharmony_ci .type = PERF_TYPE_SOFTWARE, 2662306a36Sopenharmony_ci .config = PERF_COUNT_SW_CPU_CLOCK, 2762306a36Sopenharmony_ci }; 2862306a36Sopenharmony_ci int err, idx; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci cpus = perf_cpu_map__new(NULL); 3162306a36Sopenharmony_ci __T("failed to create cpus", cpus); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci evsel = perf_evsel__new(&attr); 3462306a36Sopenharmony_ci __T("failed to create evsel", evsel); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci err = perf_evsel__open(evsel, cpus, NULL); 3762306a36Sopenharmony_ci __T("failed to open evsel", err == 0); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci for (idx = 0; idx < perf_cpu_map__nr(cpus); idx++) { 4062306a36Sopenharmony_ci struct perf_counts_values counts = { .val = 0 }; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci perf_evsel__read(evsel, idx, 0, &counts); 4362306a36Sopenharmony_ci __T("failed to read value for evsel", counts.val != 0); 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci perf_evsel__close(evsel); 4762306a36Sopenharmony_ci perf_evsel__delete(evsel); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci perf_cpu_map__put(cpus); 5062306a36Sopenharmony_ci return 0; 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int test_stat_thread(void) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci struct perf_counts_values counts = { .val = 0 }; 5662306a36Sopenharmony_ci struct perf_thread_map *threads; 5762306a36Sopenharmony_ci struct perf_evsel *evsel; 5862306a36Sopenharmony_ci struct perf_event_attr attr = { 5962306a36Sopenharmony_ci .type = PERF_TYPE_SOFTWARE, 6062306a36Sopenharmony_ci .config = PERF_COUNT_SW_TASK_CLOCK, 6162306a36Sopenharmony_ci }; 6262306a36Sopenharmony_ci int err; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci threads = perf_thread_map__new_dummy(); 6562306a36Sopenharmony_ci __T("failed to create threads", threads); 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci perf_thread_map__set_pid(threads, 0, 0); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci evsel = perf_evsel__new(&attr); 7062306a36Sopenharmony_ci __T("failed to create evsel", evsel); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci err = perf_evsel__open(evsel, NULL, threads); 7362306a36Sopenharmony_ci __T("failed to open evsel", err == 0); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci perf_evsel__read(evsel, 0, 0, &counts); 7662306a36Sopenharmony_ci __T("failed to read value for evsel", counts.val != 0); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci perf_evsel__close(evsel); 7962306a36Sopenharmony_ci perf_evsel__delete(evsel); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci perf_thread_map__put(threads); 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic int test_stat_thread_enable(void) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct perf_counts_values counts = { .val = 0 }; 8862306a36Sopenharmony_ci struct perf_thread_map *threads; 8962306a36Sopenharmony_ci struct perf_evsel *evsel; 9062306a36Sopenharmony_ci struct perf_event_attr attr = { 9162306a36Sopenharmony_ci .type = PERF_TYPE_SOFTWARE, 9262306a36Sopenharmony_ci .config = PERF_COUNT_SW_TASK_CLOCK, 9362306a36Sopenharmony_ci .disabled = 1, 9462306a36Sopenharmony_ci }; 9562306a36Sopenharmony_ci int err; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci threads = perf_thread_map__new_dummy(); 9862306a36Sopenharmony_ci __T("failed to create threads", threads); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci perf_thread_map__set_pid(threads, 0, 0); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci evsel = perf_evsel__new(&attr); 10362306a36Sopenharmony_ci __T("failed to create evsel", evsel); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci err = perf_evsel__open(evsel, NULL, threads); 10662306a36Sopenharmony_ci __T("failed to open evsel", err == 0); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci perf_evsel__read(evsel, 0, 0, &counts); 10962306a36Sopenharmony_ci __T("failed to read value for evsel", counts.val == 0); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci err = perf_evsel__enable(evsel); 11262306a36Sopenharmony_ci __T("failed to enable evsel", err == 0); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci perf_evsel__read(evsel, 0, 0, &counts); 11562306a36Sopenharmony_ci __T("failed to read value for evsel", counts.val != 0); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci err = perf_evsel__disable(evsel); 11862306a36Sopenharmony_ci __T("failed to enable evsel", err == 0); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci perf_evsel__close(evsel); 12162306a36Sopenharmony_ci perf_evsel__delete(evsel); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci perf_thread_map__put(threads); 12462306a36Sopenharmony_ci return 0; 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int test_stat_user_read(int event) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct perf_counts_values counts = { .val = 0 }; 13062306a36Sopenharmony_ci struct perf_thread_map *threads; 13162306a36Sopenharmony_ci struct perf_evsel *evsel; 13262306a36Sopenharmony_ci struct perf_event_mmap_page *pc; 13362306a36Sopenharmony_ci struct perf_event_attr attr = { 13462306a36Sopenharmony_ci .type = PERF_TYPE_HARDWARE, 13562306a36Sopenharmony_ci .config = event, 13662306a36Sopenharmony_ci#ifdef __aarch64__ 13762306a36Sopenharmony_ci .config1 = 0x2, /* Request user access */ 13862306a36Sopenharmony_ci#endif 13962306a36Sopenharmony_ci }; 14062306a36Sopenharmony_ci int err, i; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci threads = perf_thread_map__new_dummy(); 14362306a36Sopenharmony_ci __T("failed to create threads", threads); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci perf_thread_map__set_pid(threads, 0, 0); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci evsel = perf_evsel__new(&attr); 14862306a36Sopenharmony_ci __T("failed to create evsel", evsel); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci err = perf_evsel__open(evsel, NULL, threads); 15162306a36Sopenharmony_ci __T("failed to open evsel", err == 0); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci err = perf_evsel__mmap(evsel, 0); 15462306a36Sopenharmony_ci __T("failed to mmap evsel", err == 0); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci pc = perf_evsel__mmap_base(evsel, 0, 0); 15762306a36Sopenharmony_ci __T("failed to get mmapped address", pc); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) 16062306a36Sopenharmony_ci __T("userspace counter access not supported", pc->cap_user_rdpmc); 16162306a36Sopenharmony_ci __T("userspace counter access not enabled", pc->index); 16262306a36Sopenharmony_ci __T("userspace counter width not set", pc->pmc_width >= 32); 16362306a36Sopenharmony_ci#endif 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci perf_evsel__read(evsel, 0, 0, &counts); 16662306a36Sopenharmony_ci __T("failed to read value for evsel", counts.val != 0); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci for (i = 0; i < 5; i++) { 16962306a36Sopenharmony_ci volatile int count = 0x10000 << i; 17062306a36Sopenharmony_ci __u64 start, end, last = 0; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci __T_VERBOSE("\tloop = %u, ", count); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci perf_evsel__read(evsel, 0, 0, &counts); 17562306a36Sopenharmony_ci start = counts.val; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci while (count--) ; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci perf_evsel__read(evsel, 0, 0, &counts); 18062306a36Sopenharmony_ci end = counts.val; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci __T("invalid counter data", (end - start) > last); 18362306a36Sopenharmony_ci last = end - start; 18462306a36Sopenharmony_ci __T_VERBOSE("count = %llu\n", end - start); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci perf_evsel__munmap(evsel); 18862306a36Sopenharmony_ci perf_evsel__close(evsel); 18962306a36Sopenharmony_ci perf_evsel__delete(evsel); 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci perf_thread_map__put(threads); 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int test_stat_read_format_single(struct perf_event_attr *attr, struct perf_thread_map *threads) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci struct perf_evsel *evsel; 19862306a36Sopenharmony_ci struct perf_counts_values counts; 19962306a36Sopenharmony_ci volatile int count = 0x100000; 20062306a36Sopenharmony_ci int err; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci evsel = perf_evsel__new(attr); 20362306a36Sopenharmony_ci __T("failed to create evsel", evsel); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci /* skip old kernels that don't support the format */ 20662306a36Sopenharmony_ci err = perf_evsel__open(evsel, NULL, threads); 20762306a36Sopenharmony_ci if (err < 0) 20862306a36Sopenharmony_ci return 0; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci while (count--) ; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci memset(&counts, -1, sizeof(counts)); 21362306a36Sopenharmony_ci perf_evsel__read(evsel, 0, 0, &counts); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci __T("failed to read value", counts.val); 21662306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 21762306a36Sopenharmony_ci __T("failed to read TOTAL_TIME_ENABLED", counts.ena); 21862306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 21962306a36Sopenharmony_ci __T("failed to read TOTAL_TIME_RUNNING", counts.run); 22062306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_ID) 22162306a36Sopenharmony_ci __T("failed to read ID", counts.id); 22262306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_LOST) 22362306a36Sopenharmony_ci __T("failed to read LOST", counts.lost == 0); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci perf_evsel__close(evsel); 22662306a36Sopenharmony_ci perf_evsel__delete(evsel); 22762306a36Sopenharmony_ci return 0; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int test_stat_read_format_group(struct perf_event_attr *attr, struct perf_thread_map *threads) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct perf_evsel *leader, *member; 23362306a36Sopenharmony_ci struct perf_counts_values counts; 23462306a36Sopenharmony_ci volatile int count = 0x100000; 23562306a36Sopenharmony_ci int err; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci attr->read_format |= PERF_FORMAT_GROUP; 23862306a36Sopenharmony_ci leader = perf_evsel__new(attr); 23962306a36Sopenharmony_ci __T("failed to create leader", leader); 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci attr->read_format &= ~PERF_FORMAT_GROUP; 24262306a36Sopenharmony_ci member = perf_evsel__new(attr); 24362306a36Sopenharmony_ci __T("failed to create member", member); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci member->leader = leader; 24662306a36Sopenharmony_ci leader->nr_members = 2; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* skip old kernels that don't support the format */ 24962306a36Sopenharmony_ci err = perf_evsel__open(leader, NULL, threads); 25062306a36Sopenharmony_ci if (err < 0) 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci err = perf_evsel__open(member, NULL, threads); 25362306a36Sopenharmony_ci if (err < 0) 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci while (count--) ; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci memset(&counts, -1, sizeof(counts)); 25962306a36Sopenharmony_ci perf_evsel__read(leader, 0, 0, &counts); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci __T("failed to read leader value", counts.val); 26262306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 26362306a36Sopenharmony_ci __T("failed to read leader TOTAL_TIME_ENABLED", counts.ena); 26462306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 26562306a36Sopenharmony_ci __T("failed to read leader TOTAL_TIME_RUNNING", counts.run); 26662306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_ID) 26762306a36Sopenharmony_ci __T("failed to read leader ID", counts.id); 26862306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_LOST) 26962306a36Sopenharmony_ci __T("failed to read leader LOST", counts.lost == 0); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci memset(&counts, -1, sizeof(counts)); 27262306a36Sopenharmony_ci perf_evsel__read(member, 0, 0, &counts); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci __T("failed to read member value", counts.val); 27562306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) 27662306a36Sopenharmony_ci __T("failed to read member TOTAL_TIME_ENABLED", counts.ena); 27762306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) 27862306a36Sopenharmony_ci __T("failed to read member TOTAL_TIME_RUNNING", counts.run); 27962306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_ID) 28062306a36Sopenharmony_ci __T("failed to read member ID", counts.id); 28162306a36Sopenharmony_ci if (attr->read_format & PERF_FORMAT_LOST) 28262306a36Sopenharmony_ci __T("failed to read member LOST", counts.lost == 0); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci perf_evsel__close(member); 28562306a36Sopenharmony_ci perf_evsel__close(leader); 28662306a36Sopenharmony_ci perf_evsel__delete(member); 28762306a36Sopenharmony_ci perf_evsel__delete(leader); 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic int test_stat_read_format(void) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct perf_thread_map *threads; 29462306a36Sopenharmony_ci struct perf_event_attr attr = { 29562306a36Sopenharmony_ci .type = PERF_TYPE_SOFTWARE, 29662306a36Sopenharmony_ci .config = PERF_COUNT_SW_TASK_CLOCK, 29762306a36Sopenharmony_ci }; 29862306a36Sopenharmony_ci int err, i; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci#define FMT(_fmt) PERF_FORMAT_ ## _fmt 30162306a36Sopenharmony_ci#define FMT_TIME (FMT(TOTAL_TIME_ENABLED) | FMT(TOTAL_TIME_RUNNING)) 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci uint64_t test_formats [] = { 30462306a36Sopenharmony_ci 0, 30562306a36Sopenharmony_ci FMT_TIME, 30662306a36Sopenharmony_ci FMT(ID), 30762306a36Sopenharmony_ci FMT(LOST), 30862306a36Sopenharmony_ci FMT_TIME | FMT(ID), 30962306a36Sopenharmony_ci FMT_TIME | FMT(LOST), 31062306a36Sopenharmony_ci FMT_TIME | FMT(ID) | FMT(LOST), 31162306a36Sopenharmony_ci FMT(ID) | FMT(LOST), 31262306a36Sopenharmony_ci }; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci#undef FMT 31562306a36Sopenharmony_ci#undef FMT_TIME 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci threads = perf_thread_map__new_dummy(); 31862306a36Sopenharmony_ci __T("failed to create threads", threads); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci perf_thread_map__set_pid(threads, 0, 0); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci for (i = 0; i < (int)ARRAY_SIZE(test_formats); i++) { 32362306a36Sopenharmony_ci attr.read_format = test_formats[i]; 32462306a36Sopenharmony_ci __T_VERBOSE("testing single read with read_format: %lx\n", 32562306a36Sopenharmony_ci (unsigned long)test_formats[i]); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci err = test_stat_read_format_single(&attr, threads); 32862306a36Sopenharmony_ci __T("failed to read single format", err == 0); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci perf_thread_map__put(threads); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci threads = perf_thread_map__new_array(2, NULL); 33462306a36Sopenharmony_ci __T("failed to create threads", threads); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci perf_thread_map__set_pid(threads, 0, 0); 33762306a36Sopenharmony_ci perf_thread_map__set_pid(threads, 1, 0); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci for (i = 0; i < (int)ARRAY_SIZE(test_formats); i++) { 34062306a36Sopenharmony_ci attr.read_format = test_formats[i]; 34162306a36Sopenharmony_ci __T_VERBOSE("testing group read with read_format: %lx\n", 34262306a36Sopenharmony_ci (unsigned long)test_formats[i]); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci err = test_stat_read_format_group(&attr, threads); 34562306a36Sopenharmony_ci __T("failed to read group format", err == 0); 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci perf_thread_map__put(threads); 34962306a36Sopenharmony_ci return 0; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ciint test_evsel(int argc, char **argv) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci __T_START; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci libperf_init(libperf_print); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci test_stat_cpu(); 35962306a36Sopenharmony_ci test_stat_thread(); 36062306a36Sopenharmony_ci test_stat_thread_enable(); 36162306a36Sopenharmony_ci test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS); 36262306a36Sopenharmony_ci test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES); 36362306a36Sopenharmony_ci test_stat_read_format(); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci __T_END; 36662306a36Sopenharmony_ci return tests_failed == 0 ? 0 : -1; 36762306a36Sopenharmony_ci} 368