xref: /linux/tools/perf/util/tool_pmu.c (revision 60675d4ca1ef0857e44eba5849b74a3a998d0c0f)
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