perf/core improvement and fixes:
User visible: - Add new compaction-times python script (Tony Jones) - Make the --[no-]-demangle/--[no-]-demangle-kernel command line options available in 'perf script' too (Mark Drayton) - Allow for negative numbers in libtraceevent's print format, fixing up misformatting in some tracepoints (Steven Rostedt) Infrastructure: - perf_env/perf_evlist changes to allow accessing the data structure with the environment where some perf data was collected in functions not necessarily related to perf.data file processing (Kan Liang) - Cleanups for the tracepoint definition location paths routines (Jiri Olsa) - Introduce sysfs/filename__sprintf_build_id, removing code duplication (Masami Hiramatsu) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJV4KISAAoJENZQFvNTUqpA4LsQALYpGTDLft7c7sQhRLMyGVAg vrd7xbJ/Plp7+A5XDSzEtqurKCTSCRxKQ/Wr9LQyD4Ja7lEKy6oWo/tIqTZSFoQt Xojx/NI2uvdKgX6TCx4JVPx2cXyzwn0r+GGFbFLYl+E1QMTeUI6xQICBGq7+cgfM WceXWkrydxC4rvJUKVYh/y9O98DVSWQ032vHDwPdmaWYl8sjFOG8c3TJQx3Jzrsa Vs0ZpDx01rqMtRMOPBY++9H3az4yv5J+hpLdkzrRD7BJHDyq6rkZTovlOwXdYvcs fspYm1dPxl0RhIZyqsFCj8njtGvjjRLPkE1EGYrr0SAcAFISC3xp9wHhS97I9XfV rLOed/xksEg81Koac7JanqXmxwpaY9fZPLqqLdrKhHSLbM3dOypee8IDNTpbGdoX CySojk7q/7aoRG5GRDz0UhpFSYj8+r15EulZSTG5TDUV36ZGurGI6H7DPjg0peu0 TpY4AL/si/C1vRxc0H97mdy6dQHgJh5DQdiwwNJftjnV7Oi5ZVwQjR/LOTqYK5TR 1+FxzOkHqF//cXUAxCt5801OAQKt+WMmunGrGk30vMses7kuWVKnCOD+z1PVLPfA vwI/BYNbBOoqkZvA8pz5duXbxRVpn0yk6hxff1Pdwk5e1LNG8U1SIrZ2WnzGN8N3 mRwr20IOLv28qrk5oHTD =9AFe -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvement and fixes from Arnaldo Carvalho de Melo: User visible changes: - Add new compaction-times python script. (Tony Jones) - Make the --[no-]-demangle/--[no-]-demangle-kernel command line options available in 'perf script' too. (Mark Drayton) - Allow for negative numbers in libtraceevent's print format, fixing up misformatting in some tracepoints. (Steven Rostedt) Infrastructure changes: - perf_env/perf_evlist changes to allow accessing the data structure with the environment where some perf data was collected in functions not necessarily related to perf.data file processing. (Kan Liang) - Cleanups for the tracepoint definition location paths routines. (Jiri Olsa) - Introduce sysfs/filename__sprintf_build_id, removing code duplication. (Masami Hiramatsu) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
bac2e4a96d
@ -4828,6 +4828,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
|
||||
case 'z':
|
||||
case 'Z':
|
||||
case '0' ... '9':
|
||||
case '-':
|
||||
goto cont_process;
|
||||
case 'p':
|
||||
if (pevent->long_size == 4)
|
||||
|
@ -226,6 +226,13 @@ OPTIONS
|
||||
Display context switch events i.e. events of type PERF_RECORD_SWITCH or
|
||||
PERF_RECORD_SWITCH_CPU_WIDE.
|
||||
|
||||
--demangle::
|
||||
Demangle symbol names to human readable form. It's enabled by default,
|
||||
disable with --no-demangle.
|
||||
|
||||
--demangle-kernel::
|
||||
Demangle kernel symbol names to human readable form (for C++ kernels).
|
||||
|
||||
--header
|
||||
Show perf.data header.
|
||||
|
||||
|
@ -128,7 +128,7 @@ static const char *normalize_arch(char *arch)
|
||||
return arch;
|
||||
}
|
||||
|
||||
static int perf_session_env__lookup_binutils_path(struct perf_session_env *env,
|
||||
static int perf_session_env__lookup_binutils_path(struct perf_env *env,
|
||||
const char *name,
|
||||
const char **path)
|
||||
{
|
||||
@ -206,7 +206,7 @@ out_error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int perf_session_env__lookup_objdump(struct perf_session_env *env)
|
||||
int perf_session_env__lookup_objdump(struct perf_env *env)
|
||||
{
|
||||
/*
|
||||
* For live mode, env->arch will be NULL and we can use
|
||||
|
@ -5,6 +5,6 @@
|
||||
|
||||
extern const char *objdump_path;
|
||||
|
||||
int perf_session_env__lookup_objdump(struct perf_session_env *env);
|
||||
int perf_session_env__lookup_objdump(struct perf_env *env);
|
||||
|
||||
#endif /* ARCH_PERF_COMMON_H */
|
||||
|
@ -25,8 +25,6 @@
|
||||
static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
|
||||
{
|
||||
char root_dir[PATH_MAX];
|
||||
char notes[PATH_MAX];
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
char *p;
|
||||
|
||||
strlcpy(root_dir, proc_dir, sizeof(root_dir));
|
||||
@ -35,15 +33,7 @@ static int build_id_cache__kcore_buildid(const char *proc_dir, char *sbuildid)
|
||||
if (!p)
|
||||
return -1;
|
||||
*p = '\0';
|
||||
|
||||
scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
|
||||
|
||||
if (sysfs__read_build_id(notes, build_id, sizeof(build_id)))
|
||||
return -1;
|
||||
|
||||
build_id__sprintf(build_id, sizeof(build_id), sbuildid);
|
||||
|
||||
return 0;
|
||||
return sysfs__sprintf_build_id(root_dir, sbuildid);
|
||||
}
|
||||
|
||||
static int build_id_cache__kcore_dir(char *dir, size_t sz)
|
||||
@ -138,7 +128,7 @@ static int build_id_cache__add_kcore(const char *filename, bool force)
|
||||
return -1;
|
||||
*p = '\0';
|
||||
|
||||
if (build_id_cache__kcore_buildid(from_dir, sbuildid))
|
||||
if (build_id_cache__kcore_buildid(from_dir, sbuildid) < 0)
|
||||
return -1;
|
||||
|
||||
scnprintf(to_dir, sizeof(to_dir), "%s/[kernel.kcore]/%s",
|
||||
|
@ -19,29 +19,25 @@
|
||||
|
||||
static int sysfs__fprintf_build_id(FILE *fp)
|
||||
{
|
||||
u8 kallsyms_build_id[BUILD_ID_SIZE];
|
||||
char sbuild_id[SBUILD_ID_SIZE];
|
||||
int ret;
|
||||
|
||||
if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
|
||||
sizeof(kallsyms_build_id)) != 0)
|
||||
return -1;
|
||||
ret = sysfs__sprintf_build_id("/", sbuild_id);
|
||||
if (ret != sizeof(sbuild_id))
|
||||
return ret < 0 ? ret : -EINVAL;
|
||||
|
||||
build_id__sprintf(kallsyms_build_id, sizeof(kallsyms_build_id),
|
||||
sbuild_id);
|
||||
fprintf(fp, "%s\n", sbuild_id);
|
||||
return 0;
|
||||
return fprintf(fp, "%s\n", sbuild_id);
|
||||
}
|
||||
|
||||
static int filename__fprintf_build_id(const char *name, FILE *fp)
|
||||
{
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
char sbuild_id[SBUILD_ID_SIZE];
|
||||
int ret;
|
||||
|
||||
if (filename__read_build_id(name, build_id,
|
||||
sizeof(build_id)) != sizeof(build_id))
|
||||
return 0;
|
||||
ret = filename__sprintf_build_id(name, sbuild_id);
|
||||
if (ret != sizeof(sbuild_id))
|
||||
return ret < 0 ? ret : -EINVAL;
|
||||
|
||||
build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
|
||||
return fprintf(fp, "%s\n", sbuild_id);
|
||||
}
|
||||
|
||||
@ -63,7 +59,7 @@ static int perf_session__list_build_ids(bool force, bool with_hits)
|
||||
/*
|
||||
* See if this is an ELF file first:
|
||||
*/
|
||||
if (filename__fprintf_build_id(input_name, stdout))
|
||||
if (filename__fprintf_build_id(input_name, stdout) > 0)
|
||||
goto out;
|
||||
|
||||
session = perf_session__new(&file, false, &build_id__mark_dso_hit_ops);
|
||||
|
@ -1671,6 +1671,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||
itrace_parse_synth_opts),
|
||||
OPT_BOOLEAN(0, "full-source-path", &srcline_full_filename,
|
||||
"Show full source file name path for source lines"),
|
||||
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
|
||||
"Enable symbol demangling"),
|
||||
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
|
||||
"Enable kernel symbol demangling"),
|
||||
|
||||
OPT_END()
|
||||
};
|
||||
const char * const script_subcommands[] = { "record", "report", NULL };
|
||||
|
@ -1,3 +1,21 @@
|
||||
/*
|
||||
* builtin-trace.c
|
||||
*
|
||||
* Builtin 'trace' command:
|
||||
*
|
||||
* Display a continuously updated trace of any workload, CPU, specific PID,
|
||||
* system wide, etc. Default format is loosely strace like, but any other
|
||||
* event may be specified using --event.
|
||||
*
|
||||
* Copyright (C) 2012, 2013, 2014, 2015 Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
|
||||
*
|
||||
* Initially based on the 'trace' prototype by Thomas Gleixner:
|
||||
*
|
||||
* http://lwn.net/Articles/415728/ ("Announcing a new utility: 'trace'")
|
||||
*
|
||||
* Released under the GPL v2. (and only v2, not any later version)
|
||||
*/
|
||||
|
||||
#include <traceevent/event-parse.h>
|
||||
#include "builtin.h"
|
||||
#include "util/color.h"
|
||||
@ -27,6 +45,7 @@
|
||||
|
||||
#ifndef MADV_HWPOISON
|
||||
# define MADV_HWPOISON 100
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef MADV_MERGEABLE
|
||||
|
@ -231,7 +231,7 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
|
||||
(*argc)--;
|
||||
} else if (!prefixcmp(cmd, CMD_DEBUGFS_DIR)) {
|
||||
perf_debugfs_set_path(cmd + strlen(CMD_DEBUGFS_DIR));
|
||||
fprintf(stderr, "dir: %s\n", debugfs_mountpoint);
|
||||
fprintf(stderr, "dir: %s\n", tracing_path);
|
||||
if (envchanged)
|
||||
*envchanged = 1;
|
||||
} else if (!strcmp(cmd, "--list-cmds")) {
|
||||
|
2
tools/perf/scripts/python/bin/compaction-times-record
Normal file
2
tools/perf/scripts/python/bin/compaction-times-record
Normal file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
perf record -e compaction:mm_compaction_begin -e compaction:mm_compaction_end -e compaction:mm_compaction_migratepages -e compaction:mm_compaction_isolate_migratepages -e compaction:mm_compaction_isolate_freepages $@
|
4
tools/perf/scripts/python/bin/compaction-times-report
Normal file
4
tools/perf/scripts/python/bin/compaction-times-report
Normal file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
#description: display time taken by mm compaction
|
||||
#args: [-h] [-u] [-p|-pv] [-t | [-m] [-fs] [-ms]] [pid|pid-range|comm-regex]
|
||||
perf script -s "$PERF_EXEC_PATH"/scripts/python/compaction-times.py $@
|
311
tools/perf/scripts/python/compaction-times.py
Normal file
311
tools/perf/scripts/python/compaction-times.py
Normal file
@ -0,0 +1,311 @@
|
||||
# report time spent in compaction
|
||||
# Licensed under the terms of the GNU GPL License version 2
|
||||
|
||||
# testing:
|
||||
# 'echo 1 > /proc/sys/vm/compact_memory' to force compaction of all zones
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
import signal
|
||||
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
|
||||
|
||||
usage = "usage: perf script report compaction-times.py -- [-h] [-u] [-p|-pv] [-t | [-m] [-fs] [-ms]] [pid|pid-range|comm-regex]\n"
|
||||
|
||||
class popt:
|
||||
DISP_DFL = 0
|
||||
DISP_PROC = 1
|
||||
DISP_PROC_VERBOSE=2
|
||||
|
||||
class topt:
|
||||
DISP_TIME = 0
|
||||
DISP_MIG = 1
|
||||
DISP_ISOLFREE = 2
|
||||
DISP_ISOLMIG = 4
|
||||
DISP_ALL = 7
|
||||
|
||||
class comm_filter:
|
||||
def __init__(self, re):
|
||||
self.re = re
|
||||
|
||||
def filter(self, pid, comm):
|
||||
m = self.re.search(comm)
|
||||
return m == None or m.group() == ""
|
||||
|
||||
class pid_filter:
|
||||
def __init__(self, low, high):
|
||||
self.low = (0 if low == "" else int(low))
|
||||
self.high = (0 if high == "" else int(high))
|
||||
|
||||
def filter(self, pid, comm):
|
||||
return not (pid >= self.low and (self.high == 0 or pid <= self.high))
|
||||
|
||||
def set_type(t):
|
||||
global opt_disp
|
||||
opt_disp = (t if opt_disp == topt.DISP_ALL else opt_disp|t)
|
||||
|
||||
def ns(sec, nsec):
|
||||
return (sec * 1000000000) + nsec
|
||||
|
||||
def time(ns):
|
||||
return "%dns" % ns if opt_ns else "%dus" % (round(ns, -3) / 1000)
|
||||
|
||||
class pair:
|
||||
def __init__(self, aval, bval, alabel = None, blabel = None):
|
||||
self.alabel = alabel
|
||||
self.blabel = blabel
|
||||
self.aval = aval
|
||||
self.bval = bval
|
||||
|
||||
def __add__(self, rhs):
|
||||
self.aval += rhs.aval
|
||||
self.bval += rhs.bval
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
return "%s=%d %s=%d" % (self.alabel, self.aval, self.blabel, self.bval)
|
||||
|
||||
class cnode:
|
||||
def __init__(self, ns):
|
||||
self.ns = ns
|
||||
self.migrated = pair(0, 0, "moved", "failed")
|
||||
self.fscan = pair(0,0, "scanned", "isolated")
|
||||
self.mscan = pair(0,0, "scanned", "isolated")
|
||||
|
||||
def __add__(self, rhs):
|
||||
self.ns += rhs.ns
|
||||
self.migrated += rhs.migrated
|
||||
self.fscan += rhs.fscan
|
||||
self.mscan += rhs.mscan
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
prev = 0
|
||||
s = "%s " % time(self.ns)
|
||||
if (opt_disp & topt.DISP_MIG):
|
||||
s += "migration: %s" % self.migrated
|
||||
prev = 1
|
||||
if (opt_disp & topt.DISP_ISOLFREE):
|
||||
s += "%sfree_scanner: %s" % (" " if prev else "", self.fscan)
|
||||
prev = 1
|
||||
if (opt_disp & topt.DISP_ISOLMIG):
|
||||
s += "%smigration_scanner: %s" % (" " if prev else "", self.mscan)
|
||||
return s
|
||||
|
||||
def complete(self, secs, nsecs):
|
||||
self.ns = ns(secs, nsecs) - self.ns
|
||||
|
||||
def increment(self, migrated, fscan, mscan):
|
||||
if (migrated != None):
|
||||
self.migrated += migrated
|
||||
if (fscan != None):
|
||||
self.fscan += fscan
|
||||
if (mscan != None):
|
||||
self.mscan += mscan
|
||||
|
||||
|
||||
class chead:
|
||||
heads = {}
|
||||
val = cnode(0);
|
||||
fobj = None
|
||||
|
||||
@classmethod
|
||||
def add_filter(cls, filter):
|
||||
cls.fobj = filter
|
||||
|
||||
@classmethod
|
||||
def create_pending(cls, pid, comm, start_secs, start_nsecs):
|
||||
filtered = 0
|
||||
try:
|
||||
head = cls.heads[pid]
|
||||
filtered = head.is_filtered()
|
||||
except KeyError:
|
||||
if cls.fobj != None:
|
||||
filtered = cls.fobj.filter(pid, comm)
|
||||
head = cls.heads[pid] = chead(comm, pid, filtered)
|
||||
|
||||
if not filtered:
|
||||
head.mark_pending(start_secs, start_nsecs)
|
||||
|
||||
@classmethod
|
||||
def increment_pending(cls, pid, migrated, fscan, mscan):
|
||||
head = cls.heads[pid]
|
||||
if not head.is_filtered():
|
||||
if head.is_pending():
|
||||
head.do_increment(migrated, fscan, mscan)
|
||||
else:
|
||||
sys.stderr.write("missing start compaction event for pid %d\n" % pid)
|
||||
|
||||
@classmethod
|
||||
def complete_pending(cls, pid, secs, nsecs):
|
||||
head = cls.heads[pid]
|
||||
if not head.is_filtered():
|
||||
if head.is_pending():
|
||||
head.make_complete(secs, nsecs)
|
||||
else:
|
||||
sys.stderr.write("missing start compaction event for pid %d\n" % pid)
|
||||
|
||||
@classmethod
|
||||
def gen(cls):
|
||||
if opt_proc != popt.DISP_DFL:
|
||||
for i in cls.heads:
|
||||
yield cls.heads[i]
|
||||
|
||||
@classmethod
|
||||
def str(cls):
|
||||
return cls.val
|
||||
|
||||
def __init__(self, comm, pid, filtered):
|
||||
self.comm = comm
|
||||
self.pid = pid
|
||||
self.val = cnode(0)
|
||||
self.pending = None
|
||||
self.filtered = filtered
|
||||
self.list = []
|
||||
|
||||
def __add__(self, rhs):
|
||||
self.ns += rhs.ns
|
||||
self.val += rhs.val
|
||||
return self
|
||||
|
||||
def mark_pending(self, secs, nsecs):
|
||||
self.pending = cnode(ns(secs, nsecs))
|
||||
|
||||
def do_increment(self, migrated, fscan, mscan):
|
||||
self.pending.increment(migrated, fscan, mscan)
|
||||
|
||||
def make_complete(self, secs, nsecs):
|
||||
self.pending.complete(secs, nsecs)
|
||||
chead.val += self.pending
|
||||
|
||||
if opt_proc != popt.DISP_DFL:
|
||||
self.val += self.pending
|
||||
|
||||
if opt_proc == popt.DISP_PROC_VERBOSE:
|
||||
self.list.append(self.pending)
|
||||
self.pending = None
|
||||
|
||||
def enumerate(self):
|
||||
if opt_proc == popt.DISP_PROC_VERBOSE and not self.is_filtered():
|
||||
for i, pelem in enumerate(self.list):
|
||||
sys.stdout.write("%d[%s].%d: %s\n" % (self.pid, self.comm, i+1, pelem))
|
||||
|
||||
def is_pending(self):
|
||||
return self.pending != None
|
||||
|
||||
def is_filtered(self):
|
||||
return self.filtered
|
||||
|
||||
def display(self):
|
||||
if not self.is_filtered():
|
||||
sys.stdout.write("%d[%s]: %s\n" % (self.pid, self.comm, self.val))
|
||||
|
||||
|
||||
def trace_end():
|
||||
sys.stdout.write("total: %s\n" % chead.str())
|
||||
for i in chead.gen():
|
||||
i.display(),
|
||||
i.enumerate()
|
||||
|
||||
def compaction__mm_compaction_migratepages(event_name, context, common_cpu,
|
||||
common_secs, common_nsecs, common_pid, common_comm,
|
||||
common_callchain, nr_migrated, nr_failed):
|
||||
|
||||
chead.increment_pending(common_pid,
|
||||
pair(nr_migrated, nr_failed), None, None)
|
||||
|
||||
def compaction__mm_compaction_isolate_freepages(event_name, context, common_cpu,
|
||||
common_secs, common_nsecs, common_pid, common_comm,
|
||||
common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken):
|
||||
|
||||
chead.increment_pending(common_pid,
|
||||
None, pair(nr_scanned, nr_taken), None)
|
||||
|
||||
def compaction__mm_compaction_isolate_migratepages(event_name, context, common_cpu,
|
||||
common_secs, common_nsecs, common_pid, common_comm,
|
||||
common_callchain, start_pfn, end_pfn, nr_scanned, nr_taken):
|
||||
|
||||
chead.increment_pending(common_pid,
|
||||
None, None, pair(nr_scanned, nr_taken))
|
||||
|
||||
def compaction__mm_compaction_end(event_name, context, common_cpu,
|
||||
common_secs, common_nsecs, common_pid, common_comm,
|
||||
common_callchain, zone_start, migrate_start, free_start, zone_end,
|
||||
sync, status):
|
||||
|
||||
chead.complete_pending(common_pid, common_secs, common_nsecs)
|
||||
|
||||
def compaction__mm_compaction_begin(event_name, context, common_cpu,
|
||||
common_secs, common_nsecs, common_pid, common_comm,
|
||||
common_callchain, zone_start, migrate_start, free_start, zone_end,
|
||||
sync):
|
||||
|
||||
chead.create_pending(common_pid, common_comm, common_secs, common_nsecs)
|
||||
|
||||
def pr_help():
|
||||
global usage
|
||||
|
||||
sys.stdout.write(usage)
|
||||
sys.stdout.write("\n")
|
||||
sys.stdout.write("-h display this help\n")
|
||||
sys.stdout.write("-p display by process\n")
|
||||
sys.stdout.write("-pv display by process (verbose)\n")
|
||||
sys.stdout.write("-t display stall times only\n")
|
||||
sys.stdout.write("-m display stats for migration\n")
|
||||
sys.stdout.write("-fs display stats for free scanner\n")
|
||||
sys.stdout.write("-ms display stats for migration scanner\n")
|
||||
sys.stdout.write("-u display results in microseconds (default nanoseconds)\n")
|
||||
|
||||
|
||||
comm_re = None
|
||||
pid_re = None
|
||||
pid_regex = "^(\d*)-(\d*)$|^(\d*)$"
|
||||
|
||||
opt_proc = popt.DISP_DFL
|
||||
opt_disp = topt.DISP_ALL
|
||||
|
||||
opt_ns = True
|
||||
|
||||
argc = len(sys.argv) - 1
|
||||
if argc >= 1:
|
||||
pid_re = re.compile(pid_regex)
|
||||
|
||||
for i, opt in enumerate(sys.argv[1:]):
|
||||
if opt[0] == "-":
|
||||
if opt == "-h":
|
||||
pr_help()
|
||||
exit(0);
|
||||
elif opt == "-p":
|
||||
opt_proc = popt.DISP_PROC
|
||||
elif opt == "-pv":
|
||||
opt_proc = popt.DISP_PROC_VERBOSE
|
||||
elif opt == '-u':
|
||||
opt_ns = False
|
||||
elif opt == "-t":
|
||||
set_type(topt.DISP_TIME)
|
||||
elif opt == "-m":
|
||||
set_type(topt.DISP_MIG)
|
||||
elif opt == "-fs":
|
||||
set_type(topt.DISP_ISOLFREE)
|
||||
elif opt == "-ms":
|
||||
set_type(topt.DISP_ISOLMIG)
|
||||
else:
|
||||
sys.exit(usage)
|
||||
|
||||
elif i == argc - 1:
|
||||
m = pid_re.search(opt)
|
||||
if m != None and m.group() != "":
|
||||
if m.group(3) != None:
|
||||
f = pid_filter(m.group(3), m.group(3))
|
||||
else:
|
||||
f = pid_filter(m.group(1), m.group(2))
|
||||
else:
|
||||
try:
|
||||
comm_re=re.compile(opt)
|
||||
except:
|
||||
sys.stderr.write("invalid regex '%s'" % opt)
|
||||
sys.exit(usage)
|
||||
f = comm_filter(comm_re)
|
||||
|
||||
chead.add_filter(f)
|
@ -61,8 +61,8 @@ int ui_browser__help_window(struct ui_browser *browser, const char *text);
|
||||
bool ui_browser__dialog_yesno(struct ui_browser *browser, const char *text);
|
||||
int ui_browser__input_window(const char *title, const char *text, char *input,
|
||||
const char *exit_msg, int delay_sec);
|
||||
struct perf_session_env;
|
||||
int tui__header_window(struct perf_session_env *env);
|
||||
struct perf_env;
|
||||
int tui__header_window(struct perf_env *env);
|
||||
|
||||
void ui_browser__argv_seek(struct ui_browser *browser, off_t offset, int whence);
|
||||
unsigned int ui_browser__argv_refresh(struct ui_browser *browser);
|
||||
|
@ -91,7 +91,7 @@ static int ui__list_menu(int argc, char * const argv[])
|
||||
return list_menu__run(&menu);
|
||||
}
|
||||
|
||||
int tui__header_window(struct perf_session_env *env)
|
||||
int tui__header_window(struct perf_env *env)
|
||||
{
|
||||
int i, argc = 0;
|
||||
char **argv;
|
||||
|
@ -26,7 +26,7 @@ struct hist_browser {
|
||||
struct map_symbol *selection;
|
||||
struct hist_browser_timer *hbt;
|
||||
struct pstack *pstack;
|
||||
struct perf_session_env *env;
|
||||
struct perf_env *env;
|
||||
int print_seq;
|
||||
bool show_dso;
|
||||
bool show_headers;
|
||||
@ -1214,7 +1214,7 @@ static int hist_browser__dump(struct hist_browser *browser)
|
||||
|
||||
static struct hist_browser *hist_browser__new(struct hists *hists,
|
||||
struct hist_browser_timer *hbt,
|
||||
struct perf_session_env *env)
|
||||
struct perf_env *env)
|
||||
{
|
||||
struct hist_browser *browser = zalloc(sizeof(*browser));
|
||||
|
||||
@ -1695,7 +1695,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
|
||||
bool left_exits,
|
||||
struct hist_browser_timer *hbt,
|
||||
float min_pcnt,
|
||||
struct perf_session_env *env)
|
||||
struct perf_env *env)
|
||||
{
|
||||
struct hists *hists = evsel__hists(evsel);
|
||||
struct hist_browser *browser = hist_browser__new(hists, hbt, env);
|
||||
@ -2016,7 +2016,7 @@ struct perf_evsel_menu {
|
||||
struct perf_evsel *selection;
|
||||
bool lost_events, lost_events_warned;
|
||||
float min_pcnt;
|
||||
struct perf_session_env *env;
|
||||
struct perf_env *env;
|
||||
};
|
||||
|
||||
static void perf_evsel_menu__write(struct ui_browser *browser,
|
||||
@ -2169,7 +2169,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
|
||||
int nr_entries, const char *help,
|
||||
struct hist_browser_timer *hbt,
|
||||
float min_pcnt,
|
||||
struct perf_session_env *env)
|
||||
struct perf_env *env)
|
||||
{
|
||||
struct perf_evsel *pos;
|
||||
struct perf_evsel_menu menu = {
|
||||
@ -2202,7 +2202,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist,
|
||||
int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
|
||||
struct hist_browser_timer *hbt,
|
||||
float min_pcnt,
|
||||
struct perf_session_env *env)
|
||||
struct perf_env *env)
|
||||
{
|
||||
int nr_entries = evlist->nr_entries;
|
||||
|
||||
|
@ -93,6 +93,38 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
|
||||
return raw - build_id;
|
||||
}
|
||||
|
||||
int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
|
||||
{
|
||||
char notes[PATH_MAX];
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
int ret;
|
||||
|
||||
if (!root_dir)
|
||||
root_dir = "";
|
||||
|
||||
scnprintf(notes, sizeof(notes), "%s/sys/kernel/notes", root_dir);
|
||||
|
||||
ret = sysfs__read_build_id(notes, build_id, sizeof(build_id));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
|
||||
}
|
||||
|
||||
int filename__sprintf_build_id(const char *pathname, char *sbuild_id)
|
||||
{
|
||||
u8 build_id[BUILD_ID_SIZE];
|
||||
int ret;
|
||||
|
||||
ret = filename__read_build_id(pathname, build_id, sizeof(build_id));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
else if (ret != sizeof(build_id))
|
||||
return -EINVAL;
|
||||
|
||||
return build_id__sprintf(build_id, sizeof(build_id), sbuild_id);
|
||||
}
|
||||
|
||||
/* asnprintf consolidates asprintf and snprintf */
|
||||
static int asnprintf(char **strp, size_t size, const char *fmt, ...)
|
||||
{
|
||||
|
@ -12,6 +12,9 @@ extern struct perf_tool build_id__mark_dso_hit_ops;
|
||||
struct dso;
|
||||
|
||||
int build_id__sprintf(const u8 *build_id, int len, char *bf);
|
||||
int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id);
|
||||
int filename__sprintf_build_id(const char *pathname, char *sbuild_id);
|
||||
|
||||
char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
|
||||
|
||||
int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
|
||||
|
@ -98,6 +98,7 @@ static void perf_evlist__purge(struct perf_evlist *evlist)
|
||||
|
||||
evlist__for_each_safe(evlist, n, pos) {
|
||||
list_del_init(&pos->node);
|
||||
pos->evlist = NULL;
|
||||
perf_evsel__delete(pos);
|
||||
}
|
||||
|
||||
@ -125,6 +126,7 @@ void perf_evlist__delete(struct perf_evlist *evlist)
|
||||
|
||||
void perf_evlist__add(struct perf_evlist *evlist, struct perf_evsel *entry)
|
||||
{
|
||||
entry->evlist = evlist;
|
||||
list_add_tail(&entry->node, &evlist->entries);
|
||||
entry->idx = evlist->nr_entries;
|
||||
entry->tracking = !entry->idx;
|
||||
|
@ -56,6 +56,7 @@ struct perf_evlist {
|
||||
struct cpu_map *cpus;
|
||||
struct perf_evsel *selected;
|
||||
struct events_stats stats;
|
||||
struct perf_env *env;
|
||||
};
|
||||
|
||||
struct perf_evsel_str_handler {
|
||||
|
@ -206,6 +206,7 @@ void perf_evsel__init(struct perf_evsel *evsel,
|
||||
evsel->leader = evsel;
|
||||
evsel->unit = "";
|
||||
evsel->scale = 1.0;
|
||||
evsel->evlist = NULL;
|
||||
INIT_LIST_HEAD(&evsel->node);
|
||||
INIT_LIST_HEAD(&evsel->config_terms);
|
||||
perf_evsel__object.init(evsel);
|
||||
@ -1026,6 +1027,7 @@ void perf_evsel__close_fd(struct perf_evsel *evsel, int ncpus, int nthreads)
|
||||
void perf_evsel__exit(struct perf_evsel *evsel)
|
||||
{
|
||||
assert(list_empty(&evsel->node));
|
||||
assert(evsel->evlist == NULL);
|
||||
perf_evsel__free_fd(evsel);
|
||||
perf_evsel__free_id(evsel);
|
||||
perf_evsel__free_config_terms(evsel);
|
||||
|
@ -60,6 +60,9 @@ struct perf_evsel_config_term {
|
||||
|
||||
/** struct perf_evsel - event selector
|
||||
*
|
||||
* @evlist - evlist this evsel is in, if it is in one.
|
||||
* @node - To insert it into evlist->entries or in other list_heads, say in
|
||||
* the event parsing routines.
|
||||
* @name - Can be set to retain the original event name passed by the user,
|
||||
* so that when showing results in tools such as 'perf stat', we
|
||||
* show the name used, not some alias.
|
||||
@ -73,6 +76,7 @@ struct perf_evsel_config_term {
|
||||
*/
|
||||
struct perf_evsel {
|
||||
struct list_head node;
|
||||
struct perf_evlist *evlist;
|
||||
struct perf_event_attr attr;
|
||||
char *filter;
|
||||
struct xyarray *fd;
|
||||
|
@ -2514,6 +2514,7 @@ int perf_session__read_header(struct perf_session *session)
|
||||
if (session->evlist == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
session->evlist->env = &header->env;
|
||||
if (perf_data_file__is_pipe(file))
|
||||
return perf_header__read_pipe(session);
|
||||
|
||||
|
@ -66,7 +66,7 @@ struct perf_header;
|
||||
int perf_file_header__read(struct perf_file_header *header,
|
||||
struct perf_header *ph, int fd);
|
||||
|
||||
struct perf_session_env {
|
||||
struct perf_env {
|
||||
char *hostname;
|
||||
char *os_release;
|
||||
char *version;
|
||||
@ -98,7 +98,7 @@ struct perf_header {
|
||||
u64 data_size;
|
||||
u64 feat_offset;
|
||||
DECLARE_BITMAP(adds_features, HEADER_FEAT_BITS);
|
||||
struct perf_session_env env;
|
||||
struct perf_env env;
|
||||
};
|
||||
|
||||
struct perf_evlist;
|
||||
|
@ -313,7 +313,7 @@ int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel,
|
||||
int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help,
|
||||
struct hist_browser_timer *hbt,
|
||||
float min_pcnt,
|
||||
struct perf_session_env *env);
|
||||
struct perf_env *env);
|
||||
int script_browse(const char *script_opt);
|
||||
#else
|
||||
static inline
|
||||
@ -321,7 +321,7 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused,
|
||||
const char *help __maybe_unused,
|
||||
struct hist_browser_timer *hbt __maybe_unused,
|
||||
float min_pcnt __maybe_unused,
|
||||
struct perf_session_env *env __maybe_unused)
|
||||
struct perf_env *env __maybe_unused)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ static void perf_session__delete_threads(struct perf_session *session)
|
||||
machine__delete_threads(&session->machines.host);
|
||||
}
|
||||
|
||||
static void perf_session_env__exit(struct perf_session_env *env)
|
||||
static void perf_session_env__exit(struct perf_env *env)
|
||||
{
|
||||
zfree(&env->hostname);
|
||||
zfree(&env->os_release);
|
||||
|
@ -1853,7 +1853,7 @@ static void vmlinux_path__exit(void)
|
||||
zfree(&vmlinux_path);
|
||||
}
|
||||
|
||||
static int vmlinux_path__init(struct perf_session_env *env)
|
||||
static int vmlinux_path__init(struct perf_env *env)
|
||||
{
|
||||
struct utsname uts;
|
||||
char bf[PATH_MAX];
|
||||
@ -1964,7 +1964,7 @@ static bool symbol__read_kptr_restrict(void)
|
||||
return value;
|
||||
}
|
||||
|
||||
int symbol__init(struct perf_session_env *env)
|
||||
int symbol__init(struct perf_env *env)
|
||||
{
|
||||
const char *symfs;
|
||||
|
||||
|
@ -252,8 +252,8 @@ int modules__parse(const char *filename, void *arg,
|
||||
int filename__read_debuglink(const char *filename, char *debuglink,
|
||||
size_t size);
|
||||
|
||||
struct perf_session_env;
|
||||
int symbol__init(struct perf_session_env *env);
|
||||
struct perf_env;
|
||||
int symbol__init(struct perf_env *env);
|
||||
void symbol__exit(void);
|
||||
void symbol__elf_init(void);
|
||||
struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name);
|
||||
|
@ -34,6 +34,7 @@ bool test_attr__enabled;
|
||||
bool perf_host = true;
|
||||
bool perf_guest = false;
|
||||
|
||||
char tracing_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing";
|
||||
char tracing_events_path[PATH_MAX + 1] = "/sys/kernel/debug/tracing/events";
|
||||
|
||||
void event_attr_init(struct perf_event_attr *attr)
|
||||
@ -391,6 +392,8 @@ void set_term_quiet_input(struct termios *old)
|
||||
|
||||
static void set_tracing_events_path(const char *tracing, const char *mountpoint)
|
||||
{
|
||||
snprintf(tracing_path, sizeof(tracing_path), "%s/%s",
|
||||
mountpoint, tracing);
|
||||
snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s%s",
|
||||
mountpoint, tracing, "events");
|
||||
}
|
||||
@ -436,66 +439,14 @@ const char *perf_debugfs_mount(const char *mountpoint)
|
||||
|
||||
void perf_debugfs_set_path(const char *mntpt)
|
||||
{
|
||||
snprintf(debugfs_mountpoint, strlen(debugfs_mountpoint), "%s", mntpt);
|
||||
set_tracing_events_path("tracing/", mntpt);
|
||||
}
|
||||
|
||||
static const char *find_tracefs(void)
|
||||
{
|
||||
const char *path = __perf_tracefs_mount(NULL);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
static const char *find_debugfs(void)
|
||||
{
|
||||
const char *path = __perf_debugfs_mount(NULL);
|
||||
|
||||
if (!path)
|
||||
fprintf(stderr, "Your kernel does not support the debugfs filesystem");
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finds the path to the debugfs/tracing
|
||||
* Allocates the string and stores it.
|
||||
*/
|
||||
const char *find_tracing_dir(void)
|
||||
{
|
||||
const char *tracing_dir = "";
|
||||
static char *tracing;
|
||||
static int tracing_found;
|
||||
const char *debugfs;
|
||||
|
||||
if (tracing_found)
|
||||
return tracing;
|
||||
|
||||
debugfs = find_tracefs();
|
||||
if (!debugfs) {
|
||||
tracing_dir = "/tracing";
|
||||
debugfs = find_debugfs();
|
||||
if (!debugfs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (asprintf(&tracing, "%s%s", debugfs, tracing_dir) < 0)
|
||||
return NULL;
|
||||
|
||||
tracing_found = 1;
|
||||
return tracing;
|
||||
}
|
||||
|
||||
char *get_tracing_file(const char *name)
|
||||
{
|
||||
const char *tracing;
|
||||
char *file;
|
||||
|
||||
tracing = find_tracing_dir();
|
||||
if (!tracing)
|
||||
return NULL;
|
||||
|
||||
if (asprintf(&file, "%s/%s", tracing, name) < 0)
|
||||
if (asprintf(&file, "%s/%s", tracing_path, name) < 0)
|
||||
return NULL;
|
||||
|
||||
return file;
|
||||
|
@ -83,10 +83,10 @@
|
||||
extern const char *graph_line;
|
||||
extern const char *graph_dotted_line;
|
||||
extern char buildid_dir[];
|
||||
extern char tracing_path[];
|
||||
extern char tracing_events_path[];
|
||||
extern void perf_debugfs_set_path(const char *mountpoint);
|
||||
const char *perf_debugfs_mount(const char *mountpoint);
|
||||
const char *find_tracing_dir(void);
|
||||
char *get_tracing_file(const char *name);
|
||||
void put_tracing_file(char *file);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user