brintos

brintos / linux-shallow public Read only

0
0
Text · 7.5 KiB · e867de8 Raw
292 lines · c
1// SPDX-License-Identifier: GPL-2.02#include "debug.h"3#include "evlist.h"4#include "evsel.h"5#include "evsel_config.h"6#include "parse-events.h"7#include <errno.h>8#include <limits.h>9#include <stdlib.h>10#include <api/fs/fs.h>11#include <subcmd/parse-options.h>12#include <perf/cpumap.h>13#include "cloexec.h"14#include "util/perf_api_probe.h"15#include "record.h"16#include "../perf-sys.h"17#include "topdown.h"18#include "map_symbol.h"19#include "mem-events.h"20 21/*22 * evsel__config_leader_sampling() uses special rules for leader sampling.23 * However, if the leader is an AUX area event, then assume the event to sample24 * is the next event.25 */26static struct evsel *evsel__read_sampler(struct evsel *evsel, struct evlist *evlist)27{28	struct evsel *leader = evsel__leader(evsel);29 30	if (evsel__is_aux_event(leader) || arch_topdown_sample_read(leader) ||31	    is_mem_loads_aux_event(leader)) {32		evlist__for_each_entry(evlist, evsel) {33			if (evsel__leader(evsel) == leader && evsel != evsel__leader(evsel))34				return evsel;35		}36	}37 38	return leader;39}40 41static u64 evsel__config_term_mask(struct evsel *evsel)42{43	struct evsel_config_term *term;44	struct list_head *config_terms = &evsel->config_terms;45	u64 term_types = 0;46 47	list_for_each_entry(term, config_terms, list) {48		term_types |= 1 << term->type;49	}50	return term_types;51}52 53static void evsel__config_leader_sampling(struct evsel *evsel, struct evlist *evlist)54{55	struct perf_event_attr *attr = &evsel->core.attr;56	struct evsel *leader = evsel__leader(evsel);57	struct evsel *read_sampler;58	u64 term_types, freq_mask;59 60	if (!leader->sample_read)61		return;62 63	read_sampler = evsel__read_sampler(evsel, evlist);64 65	if (evsel == read_sampler)66		return;67 68	term_types = evsel__config_term_mask(evsel);69	/*70	 * Disable sampling for all group members except those with explicit71	 * config terms or the leader. In the case of an AUX area event, the 2nd72	 * event in the group is the one that 'leads' the sampling.73	 */74	freq_mask = (1 << EVSEL__CONFIG_TERM_FREQ) | (1 << EVSEL__CONFIG_TERM_PERIOD);75	if ((term_types & freq_mask) == 0) {76		attr->freq           = 0;77		attr->sample_freq    = 0;78		attr->sample_period  = 0;79	}80	if ((term_types & (1 << EVSEL__CONFIG_TERM_OVERWRITE)) == 0)81		attr->write_backward = 0;82 83	/*84	 * We don't get a sample for slave events, we make them when delivering85	 * the group leader sample. Set the slave event to follow the master86	 * sample_type to ease up reporting.87	 * An AUX area event also has sample_type requirements, so also include88	 * the sample type bits from the leader's sample_type to cover that89	 * case.90	 */91	attr->sample_type = read_sampler->core.attr.sample_type |92			    leader->core.attr.sample_type;93}94 95void evlist__config(struct evlist *evlist, struct record_opts *opts, struct callchain_param *callchain)96{97	struct evsel *evsel;98	bool use_sample_identifier = false;99	bool use_comm_exec;100	bool sample_id = opts->sample_id;101 102	if (perf_cpu_map__cpu(evlist->core.user_requested_cpus, 0).cpu < 0)103		opts->no_inherit = true;104 105	use_comm_exec = perf_can_comm_exec();106 107	evlist__for_each_entry(evlist, evsel) {108		evsel__config(evsel, opts, callchain);109		if (evsel->tracking && use_comm_exec)110			evsel->core.attr.comm_exec = 1;111	}112 113	/* Configure leader sampling here now that the sample type is known */114	evlist__for_each_entry(evlist, evsel)115		evsel__config_leader_sampling(evsel, evlist);116 117	if (opts->full_auxtrace || opts->sample_identifier) {118		/*119		 * Need to be able to synthesize and parse selected events with120		 * arbitrary sample types, which requires always being able to121		 * match the id.122		 */123		use_sample_identifier = perf_can_sample_identifier();124		sample_id = true;125	} else if (evlist->core.nr_entries > 1) {126		struct evsel *first = evlist__first(evlist);127 128		evlist__for_each_entry(evlist, evsel) {129			if (evsel->core.attr.sample_type == first->core.attr.sample_type)130				continue;131			use_sample_identifier = perf_can_sample_identifier();132			break;133		}134		sample_id = true;135	}136 137	if (sample_id) {138		evlist__for_each_entry(evlist, evsel)139			evsel__set_sample_id(evsel, use_sample_identifier);140	}141 142	evlist__set_id_pos(evlist);143}144 145static int get_max_rate(unsigned int *rate)146{147	return sysctl__read_int("kernel/perf_event_max_sample_rate", (int *)rate);148}149 150static int record_opts__config_freq(struct record_opts *opts)151{152	bool user_freq = opts->user_freq != UINT_MAX;153	bool user_interval = opts->user_interval != ULLONG_MAX;154	unsigned int max_rate;155 156	if (user_interval && user_freq) {157		pr_err("cannot set frequency and period at the same time\n");158		return -1;159	}160 161	if (user_interval)162		opts->default_interval = opts->user_interval;163	if (user_freq)164		opts->freq = opts->user_freq;165 166	/*167	 * User specified count overrides default frequency.168	 */169	if (opts->default_interval)170		opts->freq = 0;171	else if (opts->freq) {172		opts->default_interval = opts->freq;173	} else {174		pr_err("frequency and count are zero, aborting\n");175		return -1;176	}177 178	if (get_max_rate(&max_rate))179		return 0;180 181	/*182	 * User specified frequency is over current maximum.183	 */184	if (user_freq && (max_rate < opts->freq)) {185		if (opts->strict_freq) {186			pr_err("error: Maximum frequency rate (%'u Hz) exceeded.\n"187			       "       Please use -F freq option with a lower value or consider\n"188			       "       tweaking /proc/sys/kernel/perf_event_max_sample_rate.\n",189			       max_rate);190			return -1;191		} else {192			pr_warning("warning: Maximum frequency rate (%'u Hz) exceeded, throttling from %'u Hz to %'u Hz.\n"193				   "         The limit can be raised via /proc/sys/kernel/perf_event_max_sample_rate.\n"194				   "         The kernel will lower it when perf's interrupts take too long.\n"195				   "         Use --strict-freq to disable this throttling, refusing to record.\n",196				   max_rate, opts->freq, max_rate);197 198			opts->freq = max_rate;199		}200	}201 202	/*203	 * Default frequency is over current maximum.204	 */205	if (max_rate < opts->freq) {206		pr_warning("Lowering default frequency rate from %u to %u.\n"207			   "Please consider tweaking "208			   "/proc/sys/kernel/perf_event_max_sample_rate.\n",209			   opts->freq, max_rate);210		opts->freq = max_rate;211	}212 213	return 0;214}215 216int record_opts__config(struct record_opts *opts)217{218	return record_opts__config_freq(opts);219}220 221bool evlist__can_select_event(struct evlist *evlist, const char *str)222{223	struct evlist *temp_evlist;224	struct evsel *evsel;225	int err, fd;226	struct perf_cpu cpu = { .cpu = 0 };227	bool ret = false;228	pid_t pid = -1;229 230	temp_evlist = evlist__new();231	if (!temp_evlist)232		return false;233 234	err = parse_event(temp_evlist, str);235	if (err)236		goto out_delete;237 238	evsel = evlist__last(temp_evlist);239 240	if (!evlist || perf_cpu_map__is_any_cpu_or_is_empty(evlist->core.user_requested_cpus)) {241		struct perf_cpu_map *cpus = perf_cpu_map__new_online_cpus();242 243		if (cpus)244			cpu =  perf_cpu_map__cpu(cpus, 0);245 246		perf_cpu_map__put(cpus);247	} else {248		cpu = perf_cpu_map__cpu(evlist->core.user_requested_cpus, 0);249	}250 251	while (1) {252		fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1,253					 perf_event_open_cloexec_flag());254		if (fd < 0) {255			if (pid == -1 && errno == EACCES) {256				pid = 0;257				continue;258			}259			goto out_delete;260		}261		break;262	}263	close(fd);264	ret = true;265 266out_delete:267	evlist__delete(temp_evlist);268	return ret;269}270 271int record__parse_freq(const struct option *opt, const char *str, int unset __maybe_unused)272{273	unsigned int freq;274	struct record_opts *opts = opt->value;275 276	if (!str)277		return -EINVAL;278 279	if (strcasecmp(str, "max") == 0) {280		if (get_max_rate(&freq)) {281			pr_err("couldn't read /proc/sys/kernel/perf_event_max_sample_rate\n");282			return -1;283		}284		pr_info("info: Using a maximum frequency rate of %'d Hz\n", freq);285	} else {286		freq = atoi(str);287	}288 289	opts->user_freq = freq;290	return 0;291}292