1240505b2SIan Rogers // SPDX-License-Identifier: GPL-2.0-only 2240505b2SIan Rogers #include "cgroup.h" 3240505b2SIan Rogers #include "counts.h" 406905723SIan Rogers #include "cputopo.h" 5240505b2SIan Rogers #include "evsel.h" 6240505b2SIan Rogers #include "pmu.h" 7240505b2SIan Rogers #include "print-events.h" 806905723SIan Rogers #include "smt.h" 9240505b2SIan Rogers #include "time-utils.h" 10240505b2SIan Rogers #include "tool_pmu.h" 1106905723SIan Rogers #include "tsc.h" 1206905723SIan Rogers #include <api/fs/fs.h> 1306905723SIan Rogers #include <api/io.h> 14240505b2SIan Rogers #include <internal/threadmap.h> 15240505b2SIan Rogers #include <perf/threadmap.h> 16240505b2SIan Rogers #include <fcntl.h> 17240505b2SIan Rogers #include <strings.h> 18240505b2SIan Rogers 190709a82cSIan Rogers static const char *const tool_pmu__event_names[TOOL_PMU__EVENT_MAX] = { 20240505b2SIan Rogers NULL, 21240505b2SIan Rogers "duration_time", 22240505b2SIan Rogers "user_time", 23240505b2SIan Rogers "system_time", 2406905723SIan Rogers "has_pmem", 2506905723SIan Rogers "num_cores", 2606905723SIan Rogers "num_cpus", 2706905723SIan Rogers "num_cpus_online", 2806905723SIan Rogers "num_dies", 2906905723SIan Rogers "num_packages", 3006905723SIan Rogers "slots", 3106905723SIan Rogers "smt_on", 3206905723SIan Rogers "system_tsc_freq", 33240505b2SIan Rogers }; 34240505b2SIan Rogers 35609aa266SIan Rogers bool tool_pmu__skip_event(const char *name __maybe_unused) 36609aa266SIan Rogers { 37609aa266SIan Rogers #if !defined(__aarch64__) 38609aa266SIan Rogers /* The slots event should only appear on arm64. */ 39609aa266SIan Rogers if (strcasecmp(name, "slots") == 0) 40609aa266SIan Rogers return true; 41609aa266SIan Rogers #endif 42609aa266SIan Rogers #if !defined(__i386__) && !defined(__x86_64__) 43609aa266SIan Rogers /* The system_tsc_freq event should only appear on x86. */ 44609aa266SIan Rogers if (strcasecmp(name, "system_tsc_freq") == 0) 45609aa266SIan Rogers return true; 46609aa266SIan Rogers #endif 47609aa266SIan Rogers return false; 48609aa266SIan Rogers } 49609aa266SIan Rogers 50609aa266SIan Rogers int tool_pmu__num_skip_events(void) 51609aa266SIan Rogers { 52609aa266SIan Rogers int num = 0; 53609aa266SIan Rogers 54609aa266SIan Rogers #if !defined(__aarch64__) 55609aa266SIan Rogers num++; 56609aa266SIan Rogers #endif 57609aa266SIan Rogers #if !defined(__i386__) && !defined(__x86_64__) 58609aa266SIan Rogers num++; 59609aa266SIan Rogers #endif 60609aa266SIan Rogers return num; 61609aa266SIan Rogers } 62240505b2SIan Rogers 63b8f1a1b0SIan Rogers const char *tool_pmu__event_to_str(enum tool_pmu_event ev) 64240505b2SIan Rogers { 650709a82cSIan Rogers if (ev > TOOL_PMU__EVENT_NONE && ev < TOOL_PMU__EVENT_MAX) 66240505b2SIan Rogers return tool_pmu__event_names[ev]; 67240505b2SIan Rogers 68240505b2SIan Rogers return NULL; 69240505b2SIan Rogers } 70240505b2SIan Rogers 71b8f1a1b0SIan Rogers enum tool_pmu_event tool_pmu__str_to_event(const char *str) 72240505b2SIan Rogers { 73240505b2SIan Rogers int i; 74240505b2SIan Rogers 75609aa266SIan Rogers if (tool_pmu__skip_event(str)) 7606905723SIan Rogers return TOOL_PMU__EVENT_NONE; 77609aa266SIan Rogers 78609aa266SIan Rogers tool_pmu__for_each_event(i) { 79609aa266SIan Rogers if (!strcasecmp(str, tool_pmu__event_names[i])) 80240505b2SIan Rogers return i; 81240505b2SIan Rogers } 820709a82cSIan Rogers return TOOL_PMU__EVENT_NONE; 83240505b2SIan Rogers } 84240505b2SIan Rogers 85240505b2SIan Rogers bool perf_pmu__is_tool(const struct perf_pmu *pmu) 86240505b2SIan Rogers { 87240505b2SIan Rogers return pmu && pmu->type == PERF_PMU_TYPE_TOOL; 88240505b2SIan Rogers } 89240505b2SIan Rogers 90240505b2SIan Rogers bool evsel__is_tool(const struct evsel *evsel) 91240505b2SIan Rogers { 92240505b2SIan Rogers return perf_pmu__is_tool(evsel->pmu); 93240505b2SIan Rogers } 94240505b2SIan Rogers 950709a82cSIan Rogers enum tool_pmu_event evsel__tool_event(const struct evsel *evsel) 96240505b2SIan Rogers { 97240505b2SIan Rogers if (!evsel__is_tool(evsel)) 980709a82cSIan Rogers return TOOL_PMU__EVENT_NONE; 99240505b2SIan Rogers 1000709a82cSIan Rogers return (enum tool_pmu_event)evsel->core.attr.config; 101240505b2SIan Rogers } 102240505b2SIan Rogers 103240505b2SIan Rogers const char *evsel__tool_pmu_event_name(const struct evsel *evsel) 104240505b2SIan Rogers { 105b8f1a1b0SIan Rogers return tool_pmu__event_to_str(evsel->core.attr.config); 106240505b2SIan Rogers } 107240505b2SIan Rogers 108240505b2SIan Rogers static bool read_until_char(struct io *io, char e) 109240505b2SIan Rogers { 110240505b2SIan Rogers int c; 111240505b2SIan Rogers 112240505b2SIan Rogers do { 113240505b2SIan Rogers c = io__get_char(io); 114240505b2SIan Rogers if (c == -1) 115240505b2SIan Rogers return false; 116240505b2SIan Rogers } while (c != e); 117240505b2SIan Rogers return true; 118240505b2SIan Rogers } 119240505b2SIan Rogers 120240505b2SIan Rogers static int read_stat_field(int fd, struct perf_cpu cpu, int field, __u64 *val) 121240505b2SIan Rogers { 122240505b2SIan Rogers char buf[256]; 123240505b2SIan Rogers struct io io; 124240505b2SIan Rogers int i; 125240505b2SIan Rogers 126240505b2SIan Rogers io__init(&io, fd, buf, sizeof(buf)); 127240505b2SIan Rogers 128240505b2SIan Rogers /* Skip lines to relevant CPU. */ 129240505b2SIan Rogers for (i = -1; i < cpu.cpu; i++) { 130240505b2SIan Rogers if (!read_until_char(&io, '\n')) 131240505b2SIan Rogers return -EINVAL; 132240505b2SIan Rogers } 133240505b2SIan Rogers /* Skip to "cpu". */ 134240505b2SIan Rogers if (io__get_char(&io) != 'c') return -EINVAL; 135240505b2SIan Rogers if (io__get_char(&io) != 'p') return -EINVAL; 136240505b2SIan Rogers if (io__get_char(&io) != 'u') return -EINVAL; 137240505b2SIan Rogers 138240505b2SIan Rogers /* Skip N of cpuN. */ 139240505b2SIan Rogers if (!read_until_char(&io, ' ')) 140240505b2SIan Rogers return -EINVAL; 141240505b2SIan Rogers 142240505b2SIan Rogers i = 1; 143240505b2SIan Rogers while (true) { 144240505b2SIan Rogers if (io__get_dec(&io, val) != ' ') 145240505b2SIan Rogers break; 146240505b2SIan Rogers if (field == i) 147240505b2SIan Rogers return 0; 148240505b2SIan Rogers i++; 149240505b2SIan Rogers } 150240505b2SIan Rogers return -EINVAL; 151240505b2SIan Rogers } 152240505b2SIan Rogers 153240505b2SIan Rogers static int read_pid_stat_field(int fd, int field, __u64 *val) 154240505b2SIan Rogers { 155240505b2SIan Rogers char buf[256]; 156240505b2SIan Rogers struct io io; 157240505b2SIan Rogers int c, i; 158240505b2SIan Rogers 159240505b2SIan Rogers io__init(&io, fd, buf, sizeof(buf)); 160240505b2SIan Rogers if (io__get_dec(&io, val) != ' ') 161240505b2SIan Rogers return -EINVAL; 162240505b2SIan Rogers if (field == 1) 163240505b2SIan Rogers return 0; 164240505b2SIan Rogers 165240505b2SIan Rogers /* Skip comm. */ 166240505b2SIan Rogers if (io__get_char(&io) != '(' || !read_until_char(&io, ')')) 167240505b2SIan Rogers return -EINVAL; 168240505b2SIan Rogers if (field == 2) 169240505b2SIan Rogers return -EINVAL; /* String can't be returned. */ 170240505b2SIan Rogers 171240505b2SIan Rogers /* Skip state */ 172240505b2SIan Rogers if (io__get_char(&io) != ' ' || io__get_char(&io) == -1) 173240505b2SIan Rogers return -EINVAL; 174240505b2SIan Rogers if (field == 3) 175240505b2SIan Rogers return -EINVAL; /* String can't be returned. */ 176240505b2SIan Rogers 177240505b2SIan Rogers /* Loop over numeric fields*/ 178240505b2SIan Rogers if (io__get_char(&io) != ' ') 179240505b2SIan Rogers return -EINVAL; 180240505b2SIan Rogers 181240505b2SIan Rogers i = 4; 182240505b2SIan Rogers while (true) { 183240505b2SIan Rogers c = io__get_dec(&io, val); 184240505b2SIan Rogers if (c == -1) 185240505b2SIan Rogers return -EINVAL; 186240505b2SIan Rogers if (c == -2) { 187240505b2SIan Rogers /* Assume a -ve was read */ 188240505b2SIan Rogers c = io__get_dec(&io, val); 189240505b2SIan Rogers *val *= -1; 190240505b2SIan Rogers } 191240505b2SIan Rogers if (c != ' ') 192240505b2SIan Rogers return -EINVAL; 193240505b2SIan Rogers if (field == i) 194240505b2SIan Rogers return 0; 195240505b2SIan Rogers i++; 196240505b2SIan Rogers } 197240505b2SIan Rogers return -EINVAL; 198240505b2SIan Rogers } 199240505b2SIan Rogers 200240505b2SIan Rogers int evsel__tool_pmu_prepare_open(struct evsel *evsel, 201240505b2SIan Rogers struct perf_cpu_map *cpus, 202240505b2SIan Rogers int nthreads) 203240505b2SIan Rogers { 2040709a82cSIan Rogers if ((evsel__tool_event(evsel) == TOOL_PMU__EVENT_SYSTEM_TIME || 2050709a82cSIan Rogers evsel__tool_event(evsel) == TOOL_PMU__EVENT_USER_TIME) && 206240505b2SIan Rogers !evsel->start_times) { 207240505b2SIan Rogers evsel->start_times = xyarray__new(perf_cpu_map__nr(cpus), 208240505b2SIan Rogers nthreads, 209240505b2SIan Rogers sizeof(__u64)); 210240505b2SIan Rogers if (!evsel->start_times) 211240505b2SIan Rogers return -ENOMEM; 212240505b2SIan Rogers } 213240505b2SIan Rogers return 0; 214240505b2SIan Rogers } 215240505b2SIan Rogers 216240505b2SIan Rogers #define FD(e, x, y) (*(int *)xyarray__entry(e->core.fd, x, y)) 217240505b2SIan Rogers 218240505b2SIan Rogers int evsel__tool_pmu_open(struct evsel *evsel, 219240505b2SIan Rogers struct perf_thread_map *threads, 220240505b2SIan Rogers int start_cpu_map_idx, int end_cpu_map_idx) 221240505b2SIan Rogers { 2220709a82cSIan Rogers enum tool_pmu_event ev = evsel__tool_event(evsel); 223240505b2SIan Rogers int pid = -1, idx = 0, thread = 0, nthreads, err = 0, old_errno; 224240505b2SIan Rogers 22506905723SIan Rogers if (ev == TOOL_PMU__EVENT_NUM_CPUS) 22606905723SIan Rogers return 0; 22706905723SIan Rogers 2280709a82cSIan Rogers if (ev == TOOL_PMU__EVENT_DURATION_TIME) { 229240505b2SIan Rogers if (evsel->core.attr.sample_period) /* no sampling */ 230240505b2SIan Rogers return -EINVAL; 231240505b2SIan Rogers evsel->start_time = rdclock(); 232240505b2SIan Rogers return 0; 233240505b2SIan Rogers } 234240505b2SIan Rogers 235240505b2SIan Rogers if (evsel->cgrp) 236240505b2SIan Rogers pid = evsel->cgrp->fd; 237240505b2SIan Rogers 238240505b2SIan Rogers nthreads = perf_thread_map__nr(threads); 239240505b2SIan Rogers for (idx = start_cpu_map_idx; idx < end_cpu_map_idx; idx++) { 240240505b2SIan Rogers for (thread = 0; thread < nthreads; thread++) { 241240505b2SIan Rogers if (thread >= nthreads) 242240505b2SIan Rogers break; 243240505b2SIan Rogers 244240505b2SIan Rogers if (!evsel->cgrp && !evsel->core.system_wide) 245240505b2SIan Rogers pid = perf_thread_map__pid(threads, thread); 246240505b2SIan Rogers 2470709a82cSIan Rogers if (ev == TOOL_PMU__EVENT_USER_TIME || ev == TOOL_PMU__EVENT_SYSTEM_TIME) { 2480709a82cSIan Rogers bool system = ev == TOOL_PMU__EVENT_SYSTEM_TIME; 249240505b2SIan Rogers __u64 *start_time = NULL; 250240505b2SIan Rogers int fd; 251240505b2SIan Rogers 252240505b2SIan Rogers if (evsel->core.attr.sample_period) { 253240505b2SIan Rogers /* no sampling */ 254240505b2SIan Rogers err = -EINVAL; 255240505b2SIan Rogers goto out_close; 256240505b2SIan Rogers } 257240505b2SIan Rogers if (pid > -1) { 258240505b2SIan Rogers char buf[64]; 259240505b2SIan Rogers 260240505b2SIan Rogers snprintf(buf, sizeof(buf), "/proc/%d/stat", pid); 261240505b2SIan Rogers fd = open(buf, O_RDONLY); 262240505b2SIan Rogers evsel->pid_stat = true; 263240505b2SIan Rogers } else { 264240505b2SIan Rogers fd = open("/proc/stat", O_RDONLY); 265240505b2SIan Rogers } 266240505b2SIan Rogers FD(evsel, idx, thread) = fd; 267240505b2SIan Rogers if (fd < 0) { 268240505b2SIan Rogers err = -errno; 269240505b2SIan Rogers goto out_close; 270240505b2SIan Rogers } 271240505b2SIan Rogers start_time = xyarray__entry(evsel->start_times, idx, thread); 272240505b2SIan Rogers if (pid > -1) { 273240505b2SIan Rogers err = read_pid_stat_field(fd, system ? 15 : 14, 274240505b2SIan Rogers start_time); 275240505b2SIan Rogers } else { 276240505b2SIan Rogers struct perf_cpu cpu; 277240505b2SIan Rogers 278240505b2SIan Rogers cpu = perf_cpu_map__cpu(evsel->core.cpus, idx); 279240505b2SIan Rogers err = read_stat_field(fd, cpu, system ? 3 : 1, 280240505b2SIan Rogers start_time); 281240505b2SIan Rogers } 282240505b2SIan Rogers if (err) 283240505b2SIan Rogers goto out_close; 284240505b2SIan Rogers } 285240505b2SIan Rogers 286240505b2SIan Rogers } 287240505b2SIan Rogers } 288240505b2SIan Rogers return 0; 289240505b2SIan Rogers out_close: 290240505b2SIan Rogers if (err) 291240505b2SIan Rogers threads->err_thread = thread; 292240505b2SIan Rogers 293240505b2SIan Rogers old_errno = errno; 294240505b2SIan Rogers do { 295240505b2SIan Rogers while (--thread >= 0) { 296240505b2SIan Rogers if (FD(evsel, idx, thread) >= 0) 297240505b2SIan Rogers close(FD(evsel, idx, thread)); 298240505b2SIan Rogers FD(evsel, idx, thread) = -1; 299240505b2SIan Rogers } 300240505b2SIan Rogers thread = nthreads; 301240505b2SIan Rogers } while (--idx >= 0); 302240505b2SIan Rogers errno = old_errno; 303240505b2SIan Rogers return err; 304240505b2SIan Rogers } 305240505b2SIan Rogers 30606905723SIan Rogers #if !defined(__i386__) && !defined(__x86_64__) 30706905723SIan Rogers u64 arch_get_tsc_freq(void) 30806905723SIan Rogers { 30906905723SIan Rogers return 0; 31006905723SIan Rogers } 31106905723SIan Rogers #endif 31206905723SIan Rogers 31306905723SIan Rogers #if !defined(__aarch64__) 31406905723SIan Rogers u64 tool_pmu__cpu_slots_per_cycle(void) 31506905723SIan Rogers { 31606905723SIan Rogers return 0; 31706905723SIan Rogers } 31806905723SIan Rogers #endif 31906905723SIan Rogers 32006905723SIan Rogers static bool has_pmem(void) 32106905723SIan Rogers { 32206905723SIan Rogers static bool has_pmem, cached; 32306905723SIan Rogers const char *sysfs = sysfs__mountpoint(); 32406905723SIan Rogers char path[PATH_MAX]; 32506905723SIan Rogers 32606905723SIan Rogers if (!cached) { 32706905723SIan Rogers snprintf(path, sizeof(path), "%s/firmware/acpi/tables/NFIT", sysfs); 32806905723SIan Rogers has_pmem = access(path, F_OK) == 0; 32906905723SIan Rogers cached = true; 33006905723SIan Rogers } 33106905723SIan Rogers return has_pmem; 33206905723SIan Rogers } 33306905723SIan Rogers 33406905723SIan Rogers bool tool_pmu__read_event(enum tool_pmu_event ev, u64 *result) 33506905723SIan Rogers { 33606905723SIan Rogers const struct cpu_topology *topology; 33706905723SIan Rogers 33806905723SIan Rogers switch (ev) { 33906905723SIan Rogers case TOOL_PMU__EVENT_HAS_PMEM: 34006905723SIan Rogers *result = has_pmem() ? 1 : 0; 34106905723SIan Rogers return true; 34206905723SIan Rogers 34306905723SIan Rogers case TOOL_PMU__EVENT_NUM_CORES: 34406905723SIan Rogers topology = online_topology(); 34506905723SIan Rogers *result = topology->core_cpus_lists; 34606905723SIan Rogers return true; 34706905723SIan Rogers 34806905723SIan Rogers case TOOL_PMU__EVENT_NUM_CPUS: 34906905723SIan Rogers *result = cpu__max_present_cpu().cpu; 35006905723SIan Rogers return true; 35106905723SIan Rogers 35206905723SIan Rogers case TOOL_PMU__EVENT_NUM_CPUS_ONLINE: { 35306905723SIan Rogers struct perf_cpu_map *online = cpu_map__online(); 35406905723SIan Rogers 35506905723SIan Rogers if (online) { 35606905723SIan Rogers *result = perf_cpu_map__nr(online); 35706905723SIan Rogers return true; 35806905723SIan Rogers } 35906905723SIan Rogers return false; 36006905723SIan Rogers } 36106905723SIan Rogers case TOOL_PMU__EVENT_NUM_DIES: 36206905723SIan Rogers topology = online_topology(); 36306905723SIan Rogers *result = topology->die_cpus_lists; 36406905723SIan Rogers return true; 36506905723SIan Rogers 36606905723SIan Rogers case TOOL_PMU__EVENT_NUM_PACKAGES: 36706905723SIan Rogers topology = online_topology(); 36806905723SIan Rogers *result = topology->package_cpus_lists; 36906905723SIan Rogers return true; 37006905723SIan Rogers 37106905723SIan Rogers case TOOL_PMU__EVENT_SLOTS: 37206905723SIan Rogers *result = tool_pmu__cpu_slots_per_cycle(); 37306905723SIan Rogers return *result ? true : false; 37406905723SIan Rogers 37506905723SIan Rogers case TOOL_PMU__EVENT_SMT_ON: 37606905723SIan Rogers *result = smt_on() ? 1 : 0; 37706905723SIan Rogers return true; 37806905723SIan Rogers 37906905723SIan Rogers case TOOL_PMU__EVENT_SYSTEM_TSC_FREQ: 38006905723SIan Rogers *result = arch_get_tsc_freq(); 38106905723SIan Rogers return true; 38206905723SIan Rogers 38306905723SIan Rogers case TOOL_PMU__EVENT_NONE: 38406905723SIan Rogers case TOOL_PMU__EVENT_DURATION_TIME: 38506905723SIan Rogers case TOOL_PMU__EVENT_USER_TIME: 38606905723SIan Rogers case TOOL_PMU__EVENT_SYSTEM_TIME: 38706905723SIan Rogers case TOOL_PMU__EVENT_MAX: 38806905723SIan Rogers default: 38906905723SIan Rogers return false; 39006905723SIan Rogers } 39106905723SIan Rogers } 39206905723SIan Rogers 393b8f1a1b0SIan Rogers int evsel__tool_pmu_read(struct evsel *evsel, int cpu_map_idx, int thread) 394240505b2SIan Rogers { 395240505b2SIan Rogers __u64 *start_time, cur_time, delta_start; 396*1a3d6a97SNamhyung Kim u64 val; 397240505b2SIan Rogers int fd, err = 0; 39806905723SIan Rogers struct perf_counts_values *count, *old_count = NULL; 399240505b2SIan Rogers bool adjust = false; 40006905723SIan Rogers enum tool_pmu_event ev = evsel__tool_event(evsel); 401240505b2SIan Rogers 402240505b2SIan Rogers count = perf_counts(evsel->counts, cpu_map_idx, thread); 403240505b2SIan Rogers 40406905723SIan Rogers switch (ev) { 40506905723SIan Rogers case TOOL_PMU__EVENT_HAS_PMEM: 40606905723SIan Rogers case TOOL_PMU__EVENT_NUM_CORES: 40706905723SIan Rogers case TOOL_PMU__EVENT_NUM_CPUS: 40806905723SIan Rogers case TOOL_PMU__EVENT_NUM_CPUS_ONLINE: 40906905723SIan Rogers case TOOL_PMU__EVENT_NUM_DIES: 41006905723SIan Rogers case TOOL_PMU__EVENT_NUM_PACKAGES: 41106905723SIan Rogers case TOOL_PMU__EVENT_SLOTS: 41206905723SIan Rogers case TOOL_PMU__EVENT_SMT_ON: 41306905723SIan Rogers case TOOL_PMU__EVENT_SYSTEM_TSC_FREQ: 41406905723SIan Rogers if (evsel->prev_raw_counts) 41506905723SIan Rogers old_count = perf_counts(evsel->prev_raw_counts, cpu_map_idx, thread); 41606905723SIan Rogers val = 0; 41706905723SIan Rogers if (cpu_map_idx == 0 && thread == 0) { 41806905723SIan Rogers if (!tool_pmu__read_event(ev, &val)) { 41906905723SIan Rogers count->lost++; 42006905723SIan Rogers val = 0; 42106905723SIan Rogers } 42206905723SIan Rogers } 42306905723SIan Rogers if (old_count) { 42406905723SIan Rogers count->val = old_count->val + val; 42506905723SIan Rogers count->run = old_count->run + 1; 42606905723SIan Rogers count->ena = old_count->ena + 1; 42706905723SIan Rogers } else { 42806905723SIan Rogers count->val = val; 42906905723SIan Rogers count->run++; 43006905723SIan Rogers count->ena++; 43106905723SIan Rogers } 43206905723SIan Rogers return 0; 4330709a82cSIan Rogers case TOOL_PMU__EVENT_DURATION_TIME: 434240505b2SIan Rogers /* 435240505b2SIan Rogers * Pretend duration_time is only on the first CPU and thread, or 436240505b2SIan Rogers * else aggregation will scale duration_time by the number of 437240505b2SIan Rogers * CPUs/threads. 438240505b2SIan Rogers */ 439240505b2SIan Rogers start_time = &evsel->start_time; 440240505b2SIan Rogers if (cpu_map_idx == 0 && thread == 0) 441240505b2SIan Rogers cur_time = rdclock(); 442240505b2SIan Rogers else 443240505b2SIan Rogers cur_time = *start_time; 444240505b2SIan Rogers break; 4450709a82cSIan Rogers case TOOL_PMU__EVENT_USER_TIME: 4460709a82cSIan Rogers case TOOL_PMU__EVENT_SYSTEM_TIME: { 4470709a82cSIan Rogers bool system = evsel__tool_event(evsel) == TOOL_PMU__EVENT_SYSTEM_TIME; 448240505b2SIan Rogers 449240505b2SIan Rogers start_time = xyarray__entry(evsel->start_times, cpu_map_idx, thread); 450240505b2SIan Rogers fd = FD(evsel, cpu_map_idx, thread); 451240505b2SIan Rogers lseek(fd, SEEK_SET, 0); 452240505b2SIan Rogers if (evsel->pid_stat) { 453240505b2SIan Rogers /* The event exists solely on 1 CPU. */ 454240505b2SIan Rogers if (cpu_map_idx == 0) 455240505b2SIan Rogers err = read_pid_stat_field(fd, system ? 15 : 14, &cur_time); 456240505b2SIan Rogers else 457240505b2SIan Rogers cur_time = 0; 458240505b2SIan Rogers } else { 459240505b2SIan Rogers /* The event is for all threads. */ 460240505b2SIan Rogers if (thread == 0) { 461240505b2SIan Rogers struct perf_cpu cpu = perf_cpu_map__cpu(evsel->core.cpus, 462240505b2SIan Rogers cpu_map_idx); 463240505b2SIan Rogers 464240505b2SIan Rogers err = read_stat_field(fd, cpu, system ? 3 : 1, &cur_time); 465240505b2SIan Rogers } else { 466240505b2SIan Rogers cur_time = 0; 467240505b2SIan Rogers } 468240505b2SIan Rogers } 469240505b2SIan Rogers adjust = true; 470240505b2SIan Rogers break; 471240505b2SIan Rogers } 4720709a82cSIan Rogers case TOOL_PMU__EVENT_NONE: 4730709a82cSIan Rogers case TOOL_PMU__EVENT_MAX: 474240505b2SIan Rogers default: 475240505b2SIan Rogers err = -EINVAL; 476240505b2SIan Rogers } 477240505b2SIan Rogers if (err) 478240505b2SIan Rogers return err; 479240505b2SIan Rogers 480240505b2SIan Rogers delta_start = cur_time - *start_time; 481240505b2SIan Rogers if (adjust) { 482240505b2SIan Rogers __u64 ticks_per_sec = sysconf(_SC_CLK_TCK); 483240505b2SIan Rogers 484240505b2SIan Rogers delta_start *= 1000000000 / ticks_per_sec; 485240505b2SIan Rogers } 486240505b2SIan Rogers count->val = delta_start; 487240505b2SIan Rogers count->ena = count->run = delta_start; 488240505b2SIan Rogers count->lost = 0; 489240505b2SIan Rogers return 0; 490240505b2SIan Rogers } 491240505b2SIan Rogers 492240505b2SIan Rogers struct perf_pmu *perf_pmus__tool_pmu(void) 493240505b2SIan Rogers { 494240505b2SIan Rogers static struct perf_pmu tool = { 495240505b2SIan Rogers .name = "tool", 496240505b2SIan Rogers .type = PERF_PMU_TYPE_TOOL, 497240505b2SIan Rogers .aliases = LIST_HEAD_INIT(tool.aliases), 498240505b2SIan Rogers .caps = LIST_HEAD_INIT(tool.caps), 499240505b2SIan Rogers .format = LIST_HEAD_INIT(tool.format), 500240505b2SIan Rogers }; 501609aa266SIan Rogers if (!tool.events_table) 502609aa266SIan Rogers tool.events_table = find_core_events_table("common", "common"); 503240505b2SIan Rogers 504240505b2SIan Rogers return &tool; 505240505b2SIan Rogers } 506