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

Commit ce1e22b0 authored by Jiri Olsa's avatar Jiri Olsa Committed by Arnaldo Carvalho de Melo
Browse files

perf mem: Add -e record option



Adding -e option for perf mem record command, to be able to specify
memory event directly.

Get list of available events:

  $ perf mem record -e list
  ldlat-loads
  ldlat-stores

Monitor ldlat-loads:
  $ perf mem record -e ldlat-loads true

Committer notes:

Further testing:

  # perf mem record -e ldlat-loads true
  [ perf record: Woken up 1 times to write data ]
  [ perf record: Captured and wrote 0.020 MB perf.data (10 samples) ]
  # perf evlist
  cpu/mem-loads,ldlat=30/P
  #

Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1455525293-8671-6-git-send-email-jolsa@kernel.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent acbe613e
Loading
Loading
Loading
Loading
+59 −4
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#include "util/session.h"
#include "util/data.h"
#include "util/mem-events.h"
#include "util/debug.h"

#define MEM_OPERATION_LOAD	0x1
#define MEM_OPERATION_STORE	0x2
@@ -22,11 +23,55 @@ struct perf_mem {
	DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
};

static int parse_record_events(const struct option *opt,
			       const char *str, int unset __maybe_unused)
{
	struct perf_mem *mem = *(struct perf_mem **)opt->value;
	int j;

	if (strcmp(str, "list")) {
		if (!perf_mem_events__parse(str)) {
			mem->operation = 0;
			return 0;
		}
		exit(-1);
	}

	for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
		struct perf_mem_event *e = &perf_mem_events[j];

		fprintf(stderr, "%-20s%s",
			e->tag, verbose ? "" : "\n");
		if (verbose)
			fprintf(stderr, " [%s]\n", e->name);
	}
	exit(0);
}

static const char * const __usage[] = {
	"perf mem record [<options>] [<command>]",
	"perf mem record [<options>] -- <command> [<options>]",
	NULL
};

static const char * const *record_mem_usage = __usage;

static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
{
	int rec_argc, i = 0, j;
	const char **rec_argv;
	int ret;
	struct option options[] = {
	OPT_CALLBACK('e', "event", &mem, "event",
		     "event selector. use 'perf mem record -e list' to list available events",
		     parse_record_events),
	OPT_INCR('v', "verbose", &verbose,
		 "be more verbose (show counter open errors, etc)"),
	OPT_END()
	};

	argc = parse_options(argc, argv, options, record_mem_usage,
			     PARSE_OPT_STOP_AT_NON_OPTION);

	rec_argc = argc + 7; /* max number of arguments */
	rec_argv = calloc(rec_argc + 1, sizeof(char *));
@@ -35,10 +80,11 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)

	rec_argv[i++] = "record";

	if (mem->operation & MEM_OPERATION_LOAD) {
	if (mem->operation & MEM_OPERATION_LOAD)
		perf_mem_events[PERF_MEM_EVENTS__LOAD].record = true;

	if (perf_mem_events[PERF_MEM_EVENTS__LOAD].record)
		rec_argv[i++] = "-W";
	}

	rec_argv[i++] = "-d";

@@ -50,9 +96,19 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem)
		rec_argv[i++] = perf_mem_events[j].name;
	};

	for (j = 1; j < argc; j++, i++)
	for (j = 0; j < argc; j++, i++)
		rec_argv[i] = argv[j];

	if (verbose > 0) {
		pr_debug("calling: record ");

		while (rec_argv[j]) {
			pr_debug("%s ", rec_argv[j]);
			j++;
		}
		pr_debug("\n");
	}

	ret = cmd_record(i, rec_argv, NULL);
	free(rec_argv);
	return ret;
@@ -299,7 +355,6 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
		NULL
	};


	argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands,
					mem_usage, PARSE_OPT_STOP_AT_NON_OPTION);

+44 −3
Original line number Diff line number Diff line
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "mem-events.h"
#include "debug.h"

#define E(n) { .name = n }
#define E(t, n) { .tag = t, .name = n }

struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX] = {
	E("cpu/mem-loads,ldlat=30/P"),
	E("cpu/mem-stores/P"),
	E("ldlat-loads",	"cpu/mem-loads,ldlat=30/P"),
	E("ldlat-stores",	"cpu/mem-stores/P"),
};

#undef E

int perf_mem_events__parse(const char *str)
{
	char *tok, *saveptr = NULL;
	bool found = false;
	char *buf;
	int j;

	/* We need buffer that we know we can write to. */
	buf = malloc(strlen(str) + 1);
	if (!buf)
		return -ENOMEM;

	strcpy(buf, str);

	tok = strtok_r((char *)buf, ",", &saveptr);

	while (tok) {
		for (j = 0; j < PERF_MEM_EVENTS__MAX; j++) {
			struct perf_mem_event *e = &perf_mem_events[j];

			if (strstr(e->tag, tok))
				e->record = found = true;
		}

		tok = strtok_r(NULL, ",", &saveptr);
	}

	free(buf);

	if (found)
		return 0;

	pr_err("failed: event '%s' not found, use '-e list' to get list of available events\n", str);
	return -1;
}
+3 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@

struct perf_mem_event {
	bool		record;
	const char	*tag;
	const char	*name;
};

@@ -16,4 +17,6 @@ enum {

extern struct perf_mem_event perf_mem_events[PERF_MEM_EVENTS__MAX];

int perf_mem_events__parse(const char *str);

#endif /* __PERF_MEM_EVENTS_H */