Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2d6dac2f authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux

 into perf/urgent

Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:

User visible changes:

  - Validate syscall list passed via -e argument to 'perf trace'. (Arnaldo Carvalho de Melo)

  - Introduce 'perf stat --per-thread'. (Jiri Olsa)

  - Check access permission for --kallsyms and --vmlinux. (Li Zhang)

Infrastructure changes:

  - Move stuff out of 'perf stat' and into the lib for further use. (Jiri Olsa)

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 6eedf416 36c8bb56
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -144,6 +144,10 @@ is a useful mode to detect imbalance between physical cores. To enable this mod
use --per-core in addition to -a. (system-wide).  The output includes the
use --per-core in addition to -a. (system-wide).  The output includes the
core number and the number of online logical processors on that physical processor.
core number and the number of online logical processors on that physical processor.


--per-thread::
Aggregate counts per monitored threads, when monitoring threads (-t option)
or processes (-p option).

-D msecs::
-D msecs::
--delay msecs::
--delay msecs::
After starting the program, wait msecs before measuring. This is useful to
After starting the program, wait msecs before measuring. This is useful to
+11 −0
Original line number Original line Diff line number Diff line
@@ -742,6 +742,17 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)


	argc = parse_options(argc, argv, options, report_usage, 0);
	argc = parse_options(argc, argv, options, report_usage, 0);


	if (symbol_conf.vmlinux_name &&
	    access(symbol_conf.vmlinux_name, R_OK)) {
		pr_err("Invalid file: %s\n", symbol_conf.vmlinux_name);
		return -EINVAL;
	}
	if (symbol_conf.kallsyms_name &&
	    access(symbol_conf.kallsyms_name, R_OK)) {
		pr_err("Invalid file: %s\n", symbol_conf.kallsyms_name);
		return -EINVAL;
	}

	if (report.use_stdio)
	if (report.use_stdio)
		use_browser = 0;
		use_browser = 0;
	else if (report.use_tui)
	else if (report.use_tui)
+207 −195
Original line number Original line Diff line number Diff line
@@ -67,10 +67,7 @@
#define CNTR_NOT_SUPPORTED	"<not supported>"
#define CNTR_NOT_SUPPORTED	"<not supported>"
#define CNTR_NOT_COUNTED	"<not counted>"
#define CNTR_NOT_COUNTED	"<not counted>"


static void print_stat(int argc, const char **argv);
static void print_counters(struct timespec *ts, int argc, const char **argv);
static void print_counter_aggr(struct perf_evsel *counter, char *prefix);
static void print_counter(struct perf_evsel *counter, char *prefix);
static void print_aggr(char *prefix);


/* Default events used for perf stat -T */
/* Default events used for perf stat -T */
static const char *transaction_attrs = {
static const char *transaction_attrs = {
@@ -141,86 +138,9 @@ static inline void diff_timespec(struct timespec *r, struct timespec *a,
	}
	}
}
}


static void perf_evsel__reset_stat_priv(struct perf_evsel *evsel)
static void perf_stat__reset_stats(void)
{
{
	int i;
	perf_evlist__reset_stats(evsel_list);
	struct perf_stat *ps = evsel->priv;

	for (i = 0; i < 3; i++)
		init_stats(&ps->res_stats[i]);

	perf_stat_evsel_id_init(evsel);
}

static int perf_evsel__alloc_stat_priv(struct perf_evsel *evsel)
{
	evsel->priv = zalloc(sizeof(struct perf_stat));
	if (evsel->priv == NULL)
		return -ENOMEM;
	perf_evsel__reset_stat_priv(evsel);
	return 0;
}

static void perf_evsel__free_stat_priv(struct perf_evsel *evsel)
{
	zfree(&evsel->priv);
}

static int perf_evsel__alloc_prev_raw_counts(struct perf_evsel *evsel)
{
	struct perf_counts *counts;

	counts = perf_counts__new(perf_evsel__nr_cpus(evsel));
	if (counts)
		evsel->prev_raw_counts = counts;

	return counts ? 0 : -ENOMEM;
}

static void perf_evsel__free_prev_raw_counts(struct perf_evsel *evsel)
{
	perf_counts__delete(evsel->prev_raw_counts);
	evsel->prev_raw_counts = NULL;
}

static void perf_evlist__free_stats(struct perf_evlist *evlist)
{
	struct perf_evsel *evsel;

	evlist__for_each(evlist, evsel) {
		perf_evsel__free_stat_priv(evsel);
		perf_evsel__free_counts(evsel);
		perf_evsel__free_prev_raw_counts(evsel);
	}
}

static int perf_evlist__alloc_stats(struct perf_evlist *evlist, bool alloc_raw)
{
	struct perf_evsel *evsel;

	evlist__for_each(evlist, evsel) {
		if (perf_evsel__alloc_stat_priv(evsel) < 0 ||
		    perf_evsel__alloc_counts(evsel, perf_evsel__nr_cpus(evsel)) < 0 ||
		    (alloc_raw && perf_evsel__alloc_prev_raw_counts(evsel) < 0))
			goto out_free;
	}

	return 0;

out_free:
	perf_evlist__free_stats(evlist);
	return -1;
}

static void perf_stat__reset_stats(struct perf_evlist *evlist)
{
	struct perf_evsel *evsel;

	evlist__for_each(evlist, evsel) {
		perf_evsel__reset_stat_priv(evsel);
		perf_evsel__reset_counts(evsel, perf_evsel__nr_cpus(evsel));
	}

	perf_stat__reset_shadow_stats();
	perf_stat__reset_shadow_stats();
}
}


@@ -294,7 +214,8 @@ static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)
	return 0;
	return 0;
}
}


static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused,
static int
process_counter_values(struct perf_evsel *evsel, int cpu, int thread,
		       struct perf_counts_values *count)
		       struct perf_counts_values *count)
{
{
	struct perf_counts_values *aggr = &evsel->counts->aggr;
	struct perf_counts_values *aggr = &evsel->counts->aggr;
@@ -310,13 +231,13 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused,
		count = &zero;
		count = &zero;


	switch (aggr_mode) {
	switch (aggr_mode) {
	case AGGR_THREAD:
	case AGGR_CORE:
	case AGGR_CORE:
	case AGGR_SOCKET:
	case AGGR_SOCKET:
	case AGGR_NONE:
	case AGGR_NONE:
		if (!evsel->snapshot)
		if (!evsel->snapshot)
			perf_evsel__compute_deltas(evsel, cpu, count);
			perf_evsel__compute_deltas(evsel, cpu, thread, count);
		perf_counts_values__scale(count, scale, NULL);
		perf_counts_values__scale(count, scale, NULL);
		evsel->counts->cpu[cpu] = *count;
		if (aggr_mode == AGGR_NONE)
		if (aggr_mode == AGGR_NONE)
			perf_stat__update_shadow_stats(evsel, count->values, cpu);
			perf_stat__update_shadow_stats(evsel, count->values, cpu);
		break;
		break;
@@ -333,26 +254,48 @@ static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused,
	return 0;
	return 0;
}
}


static int read_counter(struct perf_evsel *counter);
static int process_counter_maps(struct perf_evsel *counter)
{
	int nthreads = thread_map__nr(counter->threads);
	int ncpus = perf_evsel__nr_cpus(counter);
	int cpu, thread;


/*
	if (counter->system_wide)
 * Read out the results of a single counter:
		nthreads = 1;
 * aggregate counts across CPUs in system-wide mode

 */
	for (thread = 0; thread < nthreads; thread++) {
static int read_counter_aggr(struct perf_evsel *counter)
		for (cpu = 0; cpu < ncpus; cpu++) {
			if (process_counter_values(counter, cpu, thread,
						   perf_counts(counter->counts, cpu, thread)))
				return -1;
		}
	}

	return 0;
}

static int process_counter(struct perf_evsel *counter)
{
{
	struct perf_counts_values *aggr = &counter->counts->aggr;
	struct perf_counts_values *aggr = &counter->counts->aggr;
	struct perf_stat *ps = counter->priv;
	struct perf_stat *ps = counter->priv;
	u64 *count = counter->counts->aggr.values;
	u64 *count = counter->counts->aggr.values;
	int i;
	int i, ret;


	aggr->val = aggr->ena = aggr->run = 0;
	aggr->val = aggr->ena = aggr->run = 0;
	init_stats(ps->res_stats);


	if (read_counter(counter))
	if (counter->per_pkg)
		return -1;
		zero_per_pkg(counter);

	ret = process_counter_maps(counter);
	if (ret)
		return ret;

	if (aggr_mode != AGGR_GLOBAL)
		return 0;


	if (!counter->snapshot)
	if (!counter->snapshot)
		perf_evsel__compute_deltas(counter, -1, aggr);
		perf_evsel__compute_deltas(counter, -1, -1, aggr);
	perf_counts_values__scale(aggr, scale, &counter->counts->scaled);
	perf_counts_values__scale(aggr, scale, &counter->counts->scaled);


	for (i = 0; i < 3; i++)
	for (i = 0; i < 3; i++)
@@ -387,12 +330,12 @@ static int read_counter(struct perf_evsel *counter)
	if (counter->system_wide)
	if (counter->system_wide)
		nthreads = 1;
		nthreads = 1;


	if (counter->per_pkg)
		zero_per_pkg(counter);

	for (thread = 0; thread < nthreads; thread++) {
	for (thread = 0; thread < nthreads; thread++) {
		for (cpu = 0; cpu < ncpus; cpu++) {
		for (cpu = 0; cpu < ncpus; cpu++) {
			if (perf_evsel__read_cb(counter, cpu, thread, read_cb))
			struct perf_counts_values *count;

			count = perf_counts(counter->counts, cpu, thread);
			if (perf_evsel__read(counter, cpu, thread, count))
				return -1;
				return -1;
		}
		}
	}
	}
@@ -400,68 +343,34 @@ static int read_counter(struct perf_evsel *counter)
	return 0;
	return 0;
}
}


static void print_interval(void)
static void read_counters(bool close)
{
{
	static int num_print_interval;
	struct perf_evsel *counter;
	struct perf_evsel *counter;
	struct perf_stat *ps;
	struct timespec ts, rs;
	char prefix[64];


	if (aggr_mode == AGGR_GLOBAL) {
		evlist__for_each(evsel_list, counter) {
			ps = counter->priv;
			memset(ps->res_stats, 0, sizeof(ps->res_stats));
			read_counter_aggr(counter);
		}
	} else	{
	evlist__for_each(evsel_list, counter) {
	evlist__for_each(evsel_list, counter) {
			ps = counter->priv;
		if (read_counter(counter))
			memset(ps->res_stats, 0, sizeof(ps->res_stats));
			pr_warning("failed to read counter %s\n", counter->name);
			read_counter(counter);
		}
	}


	clock_gettime(CLOCK_MONOTONIC, &ts);
		if (process_counter(counter))
	diff_timespec(&rs, &ts, &ref_time);
			pr_warning("failed to process counter %s\n", counter->name);
	sprintf(prefix, "%6lu.%09lu%s", rs.tv_sec, rs.tv_nsec, csv_sep);


	if (num_print_interval == 0 && !csv_output) {
		if (close) {
		switch (aggr_mode) {
			perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
		case AGGR_SOCKET:
					     thread_map__nr(evsel_list->threads));
			fprintf(output, "#           time socket cpus             counts %*s events\n", unit_width, "unit");
		}
			break;
		case AGGR_CORE:
			fprintf(output, "#           time core         cpus             counts %*s events\n", unit_width, "unit");
			break;
		case AGGR_NONE:
			fprintf(output, "#           time CPU                counts %*s events\n", unit_width, "unit");
			break;
		case AGGR_GLOBAL:
		default:
			fprintf(output, "#           time             counts %*s events\n", unit_width, "unit");
	}
	}
}
}


	if (++num_print_interval == 25)
static void process_interval(void)
		num_print_interval = 0;
{
	struct timespec ts, rs;


	switch (aggr_mode) {
	read_counters(false);
	case AGGR_CORE:
	case AGGR_SOCKET:
		print_aggr(prefix);
		break;
	case AGGR_NONE:
		evlist__for_each(evsel_list, counter)
			print_counter(counter, prefix);
		break;
	case AGGR_GLOBAL:
	default:
		evlist__for_each(evsel_list, counter)
			print_counter_aggr(counter, prefix);
	}


	fflush(output);
	clock_gettime(CLOCK_MONOTONIC, &ts);
	diff_timespec(&rs, &ts, &ref_time);

	print_counters(&rs, 0, NULL);
}
}


static void handle_initial_delay(void)
static void handle_initial_delay(void)
@@ -576,7 +485,7 @@ static int __run_perf_stat(int argc, const char **argv)
		if (interval) {
		if (interval) {
			while (!waitpid(child_pid, &status, WNOHANG)) {
			while (!waitpid(child_pid, &status, WNOHANG)) {
				nanosleep(&ts, NULL);
				nanosleep(&ts, NULL);
				print_interval();
				process_interval();
			}
			}
		}
		}
		wait(&status);
		wait(&status);
@@ -594,7 +503,7 @@ static int __run_perf_stat(int argc, const char **argv)
		while (!done) {
		while (!done) {
			nanosleep(&ts, NULL);
			nanosleep(&ts, NULL);
			if (interval)
			if (interval)
				print_interval();
				process_interval();
		}
		}
	}
	}


@@ -602,18 +511,7 @@ static int __run_perf_stat(int argc, const char **argv)


	update_stats(&walltime_nsecs_stats, t1 - t0);
	update_stats(&walltime_nsecs_stats, t1 - t0);


	if (aggr_mode == AGGR_GLOBAL) {
	read_counters(true);
		evlist__for_each(evsel_list, counter) {
			read_counter_aggr(counter);
			perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter),
					     thread_map__nr(evsel_list->threads));
		}
	} else {
		evlist__for_each(evsel_list, counter) {
			read_counter(counter);
			perf_evsel__close_fd(counter, perf_evsel__nr_cpus(counter), 1);
		}
	}


	return WEXITSTATUS(status);
	return WEXITSTATUS(status);
}
}
@@ -705,6 +603,14 @@ static void aggr_printout(struct perf_evsel *evsel, int id, int nr)
			csv_output ? 0 : -4,
			csv_output ? 0 : -4,
			perf_evsel__cpus(evsel)->map[id], csv_sep);
			perf_evsel__cpus(evsel)->map[id], csv_sep);
		break;
		break;
	case AGGR_THREAD:
		fprintf(output, "%*s-%*d%s",
			csv_output ? 0 : 16,
			thread_map__comm(evsel->threads, id),
			csv_output ? 0 : -8,
			thread_map__pid(evsel->threads, id),
			csv_sep);
		break;
	case AGGR_GLOBAL:
	case AGGR_GLOBAL:
	default:
	default:
		break;
		break;
@@ -805,9 +711,9 @@ static void print_aggr(char *prefix)
				s2 = aggr_get_id(evsel_list->cpus, cpu2);
				s2 = aggr_get_id(evsel_list->cpus, cpu2);
				if (s2 != id)
				if (s2 != id)
					continue;
					continue;
				val += counter->counts->cpu[cpu].val;
				val += perf_counts(counter->counts, cpu, 0)->val;
				ena += counter->counts->cpu[cpu].ena;
				ena += perf_counts(counter->counts, cpu, 0)->ena;
				run += counter->counts->cpu[cpu].run;
				run += perf_counts(counter->counts, cpu, 0)->run;
				nr++;
				nr++;
			}
			}
			if (prefix)
			if (prefix)
@@ -853,6 +759,40 @@ static void print_aggr(char *prefix)
	}
	}
}
}


static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
{
	int nthreads = thread_map__nr(counter->threads);
	int ncpus = cpu_map__nr(counter->cpus);
	int cpu, thread;
	double uval;

	for (thread = 0; thread < nthreads; thread++) {
		u64 ena = 0, run = 0, val = 0;

		for (cpu = 0; cpu < ncpus; cpu++) {
			val += perf_counts(counter->counts, cpu, thread)->val;
			ena += perf_counts(counter->counts, cpu, thread)->ena;
			run += perf_counts(counter->counts, cpu, thread)->run;
		}

		if (prefix)
			fprintf(output, "%s", prefix);

		uval = val * counter->scale;

		if (nsec_counter(counter))
			nsec_printout(thread, 0, counter, uval);
		else
			abs_printout(thread, 0, counter, uval);

		if (!csv_output)
			print_noise(counter, 1.0);

		print_running(run, ena);
		fputc('\n', output);
	}
}

/*
/*
 * Print out the results of a single counter:
 * Print out the results of a single counter:
 * aggregated counts in system-wide mode
 * aggregated counts in system-wide mode
@@ -915,9 +855,9 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
	int cpu;
	int cpu;


	for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
	for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
		val = counter->counts->cpu[cpu].val;
		val = perf_counts(counter->counts, cpu, 0)->val;
		ena = counter->counts->cpu[cpu].ena;
		ena = perf_counts(counter->counts, cpu, 0)->ena;
		run = counter->counts->cpu[cpu].run;
		run = perf_counts(counter->counts, cpu, 0)->run;


		if (prefix)
		if (prefix)
			fprintf(output, "%s", prefix);
			fprintf(output, "%s", prefix);
@@ -962,9 +902,38 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
	}
	}
}
}


static void print_stat(int argc, const char **argv)
static void print_interval(char *prefix, struct timespec *ts)
{
	static int num_print_interval;

	sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep);

	if (num_print_interval == 0 && !csv_output) {
		switch (aggr_mode) {
		case AGGR_SOCKET:
			fprintf(output, "#           time socket cpus             counts %*s events\n", unit_width, "unit");
			break;
		case AGGR_CORE:
			fprintf(output, "#           time core         cpus             counts %*s events\n", unit_width, "unit");
			break;
		case AGGR_NONE:
			fprintf(output, "#           time CPU                counts %*s events\n", unit_width, "unit");
			break;
		case AGGR_THREAD:
			fprintf(output, "#           time             comm-pid                  counts %*s events\n", unit_width, "unit");
			break;
		case AGGR_GLOBAL:
		default:
			fprintf(output, "#           time             counts %*s events\n", unit_width, "unit");
		}
	}

	if (++num_print_interval == 25)
		num_print_interval = 0;
}

static void print_header(int argc, const char **argv)
{
{
	struct perf_evsel *counter;
	int i;
	int i;


	fflush(stdout);
	fflush(stdout);
@@ -990,36 +959,57 @@ static void print_stat(int argc, const char **argv)
			fprintf(output, " (%d runs)", run_count);
			fprintf(output, " (%d runs)", run_count);
		fprintf(output, ":\n\n");
		fprintf(output, ":\n\n");
	}
	}
}

static void print_footer(void)
{
	if (!null_run)
		fprintf(output, "\n");
	fprintf(output, " %17.9f seconds time elapsed",
			avg_stats(&walltime_nsecs_stats)/1e9);
	if (run_count > 1) {
		fprintf(output, "                                        ");
		print_noise_pct(stddev_stats(&walltime_nsecs_stats),
				avg_stats(&walltime_nsecs_stats));
	}
	fprintf(output, "\n\n");
}

static void print_counters(struct timespec *ts, int argc, const char **argv)
{
	struct perf_evsel *counter;
	char buf[64], *prefix = NULL;

	if (interval)
		print_interval(prefix = buf, ts);
	else
		print_header(argc, argv);


	switch (aggr_mode) {
	switch (aggr_mode) {
	case AGGR_CORE:
	case AGGR_CORE:
	case AGGR_SOCKET:
	case AGGR_SOCKET:
		print_aggr(NULL);
		print_aggr(prefix);
		break;
	case AGGR_THREAD:
		evlist__for_each(evsel_list, counter)
			print_aggr_thread(counter, prefix);
		break;
		break;
	case AGGR_GLOBAL:
	case AGGR_GLOBAL:
		evlist__for_each(evsel_list, counter)
		evlist__for_each(evsel_list, counter)
			print_counter_aggr(counter, NULL);
			print_counter_aggr(counter, prefix);
		break;
		break;
	case AGGR_NONE:
	case AGGR_NONE:
		evlist__for_each(evsel_list, counter)
		evlist__for_each(evsel_list, counter)
			print_counter(counter, NULL);
			print_counter(counter, prefix);
		break;
		break;
	default:
	default:
		break;
		break;
	}
	}


	if (!csv_output) {
	if (!interval && !csv_output)
		if (!null_run)
		print_footer();
			fprintf(output, "\n");

		fprintf(output, " %17.9f seconds time elapsed",
	fflush(output);
				avg_stats(&walltime_nsecs_stats)/1e9);
		if (run_count > 1) {
			fprintf(output, "                                        ");
			print_noise_pct(stddev_stats(&walltime_nsecs_stats),
					avg_stats(&walltime_nsecs_stats));
		}
		fprintf(output, "\n\n");
	}
}
}


static volatile int signr = -1;
static volatile int signr = -1;
@@ -1091,6 +1081,7 @@ static int perf_stat_init_aggr_mode(void)
		break;
		break;
	case AGGR_NONE:
	case AGGR_NONE:
	case AGGR_GLOBAL:
	case AGGR_GLOBAL:
	case AGGR_THREAD:
	default:
	default:
		break;
		break;
	}
	}
@@ -1315,6 +1306,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
		     "aggregate counts per processor socket", AGGR_SOCKET),
		     "aggregate counts per processor socket", AGGR_SOCKET),
	OPT_SET_UINT(0, "per-core", &aggr_mode,
	OPT_SET_UINT(0, "per-core", &aggr_mode,
		     "aggregate counts per physical processor core", AGGR_CORE),
		     "aggregate counts per physical processor core", AGGR_CORE),
	OPT_SET_UINT(0, "per-thread", &aggr_mode,
		     "aggregate counts per thread", AGGR_THREAD),
	OPT_UINTEGER('D', "delay", &initial_delay,
	OPT_UINTEGER('D', "delay", &initial_delay,
		     "ms to wait before starting measurement after program start"),
		     "ms to wait before starting measurement after program start"),
	OPT_END()
	OPT_END()
@@ -1406,8 +1399,19 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
		run_count = 1;
		run_count = 1;
	}
	}


	/* no_aggr, cgroup are for system-wide only */
	if ((aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
	if ((aggr_mode != AGGR_GLOBAL || nr_cgroups) &&
		fprintf(stderr, "The --per-thread option is only available "
			"when monitoring via -p -t options.\n");
		parse_options_usage(NULL, options, "p", 1);
		parse_options_usage(NULL, options, "t", 1);
		goto out;
	}

	/*
	 * no_aggr, cgroup are for system-wide only
	 * --per-thread is aggregated per thread, we dont mix it with cpu mode
	 */
	if (((aggr_mode != AGGR_GLOBAL && aggr_mode != AGGR_THREAD) || nr_cgroups) &&
	    !target__has_cpu(&target)) {
	    !target__has_cpu(&target)) {
		fprintf(stderr, "both cgroup and no-aggregation "
		fprintf(stderr, "both cgroup and no-aggregation "
			"modes only available in system-wide mode\n");
			"modes only available in system-wide mode\n");
@@ -1435,6 +1439,14 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
		}
		}
		goto out;
		goto out;
	}
	}

	/*
	 * Initialize thread_map with comm names,
	 * so we could print it out on output.
	 */
	if (aggr_mode == AGGR_THREAD)
		thread_map__read_comms(evsel_list->threads);

	if (interval && interval < 100) {
	if (interval && interval < 100) {
		pr_err("print interval must be >= 100ms\n");
		pr_err("print interval must be >= 100ms\n");
		parse_options_usage(stat_usage, options, "I", 1);
		parse_options_usage(stat_usage, options, "I", 1);
@@ -1468,13 +1480,13 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)


		status = run_perf_stat(argc, argv);
		status = run_perf_stat(argc, argv);
		if (forever && status != -1) {
		if (forever && status != -1) {
			print_stat(argc, argv);
			print_counters(NULL, argc, argv);
			perf_stat__reset_stats(evsel_list);
			perf_stat__reset_stats();
		}
		}
	}
	}


	if (!forever && status != -1 && !interval)
	if (!forever && status != -1 && !interval)
		print_stat(argc, argv);
		print_counters(NULL, argc, argv);


	perf_evlist__free_stats(evsel_list);
	perf_evlist__free_stats(evsel_list);
out:
out:
+32 −0
Original line number Original line Diff line number Diff line
@@ -1617,6 +1617,34 @@ static int trace__read_syscall_info(struct trace *trace, int id)
	return syscall__set_arg_fmts(sc);
	return syscall__set_arg_fmts(sc);
}
}


static int trace__validate_ev_qualifier(struct trace *trace)
{
	int err = 0;
	struct str_node *pos;

	strlist__for_each(pos, trace->ev_qualifier) {
		const char *sc = pos->s;

		if (audit_name_to_syscall(sc, trace->audit.machine) < 0) {
			if (err == 0) {
				fputs("Error:\tInvalid syscall ", trace->output);
				err = -EINVAL;
			} else {
				fputs(", ", trace->output);
			}

			fputs(sc, trace->output);
		}
	}

	if (err < 0) {
		fputs("\nHint:\ttry 'perf list syscalls:sys_enter_*'"
		      "\nHint:\tand: 'man syscalls'\n", trace->output);
	}

	return err;
}

/*
/*
 * args is to be interpreted as a series of longs but we need to handle
 * args is to be interpreted as a series of longs but we need to handle
 * 8-byte unaligned accesses. args points to raw_data within the event
 * 8-byte unaligned accesses. args points to raw_data within the event
@@ -2862,6 +2890,10 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused)
			err = -ENOMEM;
			err = -ENOMEM;
			goto out_close;
			goto out_close;
		}
		}

		err = trace__validate_ev_qualifier(&trace);
		if (err)
			goto out_close;
	}
	}


	err = target__validate(&trace.opts.target);
	err = target__validate(&trace.opts.target);
+1 −0
Original line number Original line Diff line number Diff line
@@ -31,6 +31,7 @@ perf-y += code-reading.o
perf-y += sample-parsing.o
perf-y += sample-parsing.o
perf-y += parse-no-sample-id-all.o
perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o
perf-y += kmod-path.o
perf-y += thread-map.o


perf-$(CONFIG_X86) += perf-time-to-tsc.o
perf-$(CONFIG_X86) += perf-time-to-tsc.o


Loading