Commit 9059b284 authored by Ingo Molnar's avatar Ingo Molnar

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

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

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

User visible changes:

  - Add 'socket' sort entry, to sort by the processor socket in
    'perf top' and 'perf report'. (Kan Liang)

  - Introduce --socket-filter to 'perf report', for filtering by processor
    socket. (Kan Liang)

  - Add new "Zoom into Processor Socket" operation in the perf hists browser,
    used in 'perf top' and 'perf report'. (Kan Liang)

  - Fix the 'CPU' hist browser column width calculation. (Arnaldo Carvalho de Melo)

Infrastructure changes:

  - 'perf test' fixes for the object code reading entry. (Jan Stancek)

  - Add processor socket and cpu topology 'perf test' entries. (Kan Liang)

  - Introduce more sysfs__read_TYPE() helpers. (Arnaldo Carvalho de Melo)

  - Group cpu information reading functions in tools/lib/api/cpu.[ch],
    starting with cpu__get_max_freq() from a patchkit by Kan Liang.
    (Arnaldo Carvalho de Melo)

  - Retrieve the MSR PMU type from a perf.data file header and store it
    in struct perf_env. (Kan Liang)

  - Add tools/include into CTAGS file list. (Jiri Olsa)

  - Add iterator function for perf tests. (Matt Fleming)

  - Switch to tracing_patch interface. (Jiri Olsa)
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 8f3e5684 92d424ae
libapi-y += fd/
libapi-y += fs/
libapi-y += cpu.o
#include <stdio.h>
#include "cpu.h"
#include "fs/fs.h"
int cpu__get_max_freq(unsigned long long *freq)
{
char entry[PATH_MAX];
int cpu;
if (sysfs__read_int("devices/system/cpu/online", &cpu) < 0)
return -1;
snprintf(entry, sizeof(entry),
"devices/system/cpu/cpu%d/cpufreq/cpuinfo_max_freq", cpu);
return sysfs__read_ull(entry, freq);
}
#ifndef __API_CPU__
#define __API_CPU__
int cpu__get_max_freq(unsigned long long *freq);
#endif /* __API_CPU__ */
libapi-y += fs.o
libapi-y += tracing_path.o
libapi-y += debugfs.o
libapi-y += findfs.o
libapi-y += tracefs.o
#define _GNU_SOURCE
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/vfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <linux/kernel.h>
#include "debugfs.h"
#include "tracefs.h"
#ifndef DEBUGFS_DEFAULT_PATH
#define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
#endif
char debugfs_mountpoint[PATH_MAX + 1] = DEBUGFS_DEFAULT_PATH;
static const char * const debugfs_known_mountpoints[] = {
DEBUGFS_DEFAULT_PATH,
"/debug",
0,
};
static bool debugfs_found;
bool debugfs_configured(void)
{
return debugfs_find_mountpoint() != NULL;
}
/* find the path to the mounted debugfs */
const char *debugfs_find_mountpoint(void)
{
const char *ret;
if (debugfs_found)
return (const char *)debugfs_mountpoint;
ret = find_mountpoint("debugfs", (long) DEBUGFS_MAGIC,
debugfs_mountpoint, PATH_MAX + 1,
debugfs_known_mountpoints);
if (ret)
debugfs_found = true;
return ret;
}
/* mount the debugfs somewhere if it's not mounted */
char *debugfs_mount(const char *mountpoint)
{
/* see if it's already mounted */
if (debugfs_find_mountpoint())
goto out;
/* if not mounted and no argument */
if (mountpoint == NULL) {
/* see if environment variable set */
mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
/* if no environment variable, use default */
if (mountpoint == NULL)
mountpoint = DEBUGFS_DEFAULT_PATH;
}
if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
return NULL;
/* save the mountpoint */
debugfs_found = true;
strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
out:
return debugfs_mountpoint;
}
#ifndef __API_DEBUGFS_H__
#define __API_DEBUGFS_H__
#include "findfs.h"
#ifndef DEBUGFS_MAGIC
#define DEBUGFS_MAGIC 0x64626720
#endif
#ifndef PERF_DEBUGFS_ENVIRONMENT
#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
#endif
bool debugfs_configured(void);
const char *debugfs_find_mountpoint(void);
char *debugfs_mount(const char *mountpoint);
extern char debugfs_mountpoint[];
int debugfs__strerror_open(int err, char *buf, size_t size, const char *filename);
int debugfs__strerror_open_tp(int err, char *buf, size_t size, const char *sys, const char *name);
#endif /* __API_DEBUGFS_H__ */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/vfs.h>
#include "findfs.h"
/* verify that a mountpoint is actually the type we want */
int valid_mountpoint(const char *mount, long magic)
{
struct statfs st_fs;
if (statfs(mount, &st_fs) < 0)
return -ENOENT;
else if ((long)st_fs.f_type != magic)
return -ENOENT;
return 0;
}
/* find the path to a mounted file system */
const char *find_mountpoint(const char *fstype, long magic,
char *mountpoint, int len,
const char * const *known_mountpoints)
{
const char * const *ptr;
char format[128];
char type[100];
FILE *fp;
if (known_mountpoints) {
ptr = known_mountpoints;
while (*ptr) {
if (valid_mountpoint(*ptr, magic) == 0) {
strncpy(mountpoint, *ptr, len - 1);
mountpoint[len-1] = 0;
return mountpoint;
}
ptr++;
}
}
/* give up and parse /proc/mounts */
fp = fopen("/proc/mounts", "r");
if (fp == NULL)
return NULL;
snprintf(format, 128, "%%*s %%%ds %%99s %%*s %%*d %%*d\n", len);
while (fscanf(fp, format, mountpoint, type) == 2) {
if (strcmp(type, fstype) == 0)
break;
}
fclose(fp);
if (strcmp(type, fstype) != 0)
return NULL;
return mountpoint;
}
#ifndef __API_FINDFS_H__
#define __API_FINDFS_H__
#include <stdbool.h>
#define _STR(x) #x
#define STR(x) _STR(x)
/*
* On most systems <limits.h> would have given us this, but not on some systems
* (e.g. GNU/Hurd).
*/
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
const char *find_mountpoint(const char *fstype, long magic,
char *mountpoint, int len,
const char * const *known_mountpoints);
int valid_mountpoint(const char *mount, long magic);
#endif /* __API_FINDFS_H__ */
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
......@@ -11,7 +12,6 @@
#include <unistd.h>
#include <sys/mount.h>
#include "debugfs.h"
#include "fs.h"
#define _STR(x) #x
......@@ -282,6 +282,50 @@ int filename__read_int(const char *filename, int *value)
return err;
}
int filename__read_ull(const char *filename, unsigned long long *value)
{
char line[64];
int fd = open(filename, O_RDONLY), err = -1;
if (fd < 0)
return -1;
if (read(fd, line, sizeof(line)) > 0) {
*value = strtoull(line, NULL, 10);
if (*value != ULLONG_MAX)
err = 0;
}
close(fd);
return err;
}
int sysfs__read_ull(const char *entry, unsigned long long *value)
{
char path[PATH_MAX];
const char *sysfs = sysfs__mountpoint();
if (!sysfs)
return -1;
snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
return filename__read_ull(path, value);
}
int sysfs__read_int(const char *entry, int *value)
{
char path[PATH_MAX];
const char *sysfs = sysfs__mountpoint();
if (!sysfs)
return -1;
snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
return filename__read_int(path, value);
}
int sysctl__read_int(const char *sysctl, int *value)
{
char path[PATH_MAX];
......
......@@ -25,5 +25,9 @@ FS(tracefs)
int filename__read_int(const char *filename, int *value);
int filename__read_ull(const char *filename, unsigned long long *value);
int sysctl__read_int(const char *sysctl, int *value);
int sysfs__read_int(const char *entry, int *value);
int sysfs__read_ull(const char *entry, unsigned long long *value);
#endif /* __API_FS__ */
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
#include <sys/vfs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <linux/kernel.h>
#include "tracefs.h"
#ifndef TRACEFS_DEFAULT_PATH
#define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
#endif
char tracefs_mountpoint[PATH_MAX + 1] = TRACEFS_DEFAULT_PATH;
static const char * const tracefs_known_mountpoints[] = {
TRACEFS_DEFAULT_PATH,
"/sys/kernel/debug/tracing",
"/tracing",
"/trace",
0,
};
static bool tracefs_found;
bool tracefs_configured(void)
{
return tracefs_find_mountpoint() != NULL;
}
/* find the path to the mounted tracefs */
const char *tracefs_find_mountpoint(void)
{
const char *ret;
if (tracefs_found)
return (const char *)tracefs_mountpoint;
ret = find_mountpoint("tracefs", (long) TRACEFS_MAGIC,
tracefs_mountpoint, PATH_MAX + 1,
tracefs_known_mountpoints);
if (ret)
tracefs_found = true;
return ret;
}
/* mount the tracefs somewhere if it's not mounted */
char *tracefs_mount(const char *mountpoint)
{
/* see if it's already mounted */
if (tracefs_find_mountpoint())
goto out;
/* if not mounted and no argument */
if (mountpoint == NULL) {
/* see if environment variable set */
mountpoint = getenv(PERF_TRACEFS_ENVIRONMENT);
/* if no environment variable, use default */
if (mountpoint == NULL)
mountpoint = TRACEFS_DEFAULT_PATH;
}
if (mount(NULL, mountpoint, "tracefs", 0, NULL) < 0)
return NULL;
/* save the mountpoint */
tracefs_found = true;
strncpy(tracefs_mountpoint, mountpoint, sizeof(tracefs_mountpoint));
out:
return tracefs_mountpoint;
}
#ifndef __API_TRACEFS_H__
#define __API_TRACEFS_H__
#include "findfs.h"
#ifndef TRACEFS_MAGIC
#define TRACEFS_MAGIC 0x74726163
#endif
#ifndef PERF_TRACEFS_ENVIRONMENT
#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
#endif
bool tracefs_configured(void);
const char *tracefs_find_mountpoint(void);
int tracefs_valid_mountpoint(const char *debugfs);
char *tracefs_mount(const char *mountpoint);
extern char tracefs_mountpoint[];
#endif /* __API_DEBUGFS_H__ */
......@@ -7,8 +7,7 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "debugfs.h"
#include "tracefs.h"
#include "fs.h"
#include "tracing_path.h"
......@@ -29,7 +28,7 @@ static const char *tracing_path_tracefs_mount(void)
{
const char *mnt;
mnt = tracefs_mount(NULL);
mnt = tracefs__mount();
if (!mnt)
return NULL;
......@@ -42,7 +41,7 @@ static const char *tracing_path_debugfs_mount(void)
{
const char *mnt;
mnt = debugfs_mount(NULL);
mnt = debugfs__mount();
if (!mnt)
return NULL;
......@@ -90,33 +89,39 @@ static int strerror_open(int err, char *buf, size_t size, const char *filename)
switch (err) {
case ENOENT:
if (debugfs_configured()) {
/*
* We will get here if we can't find the tracepoint, but one of
* debugfs or tracefs is configured, which means you probably
* want some tracepoint which wasn't compiled in your kernel.
* - jirka
*/
if (debugfs__configured() || tracefs__configured()) {
snprintf(buf, size,
"Error:\tFile %s/%s not found.\n"
"Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n",
debugfs_mountpoint, filename);
tracing_events_path, filename);
break;
}
snprintf(buf, size, "%s",
"Error:\tUnable to find debugfs\n"
"Hint:\tWas your kernel compiled with debugfs support?\n"
"Hint:\tIs the debugfs filesystem mounted?\n"
"Error:\tUnable to find debugfs/tracefs\n"
"Hint:\tWas your kernel compiled with debugfs/tracefs support?\n"
"Hint:\tIs the debugfs/tracefs filesystem mounted?\n"
"Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
break;
case EACCES: {
const char *mountpoint = debugfs_mountpoint;
const char *mountpoint = debugfs__mountpoint();
if (!access(debugfs_mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) {
const char *tracefs_mntpoint = tracefs_find_mountpoint();
if (!access(mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) {
const char *tracefs_mntpoint = tracefs__mountpoint();
if (tracefs_mntpoint)
mountpoint = tracefs_mntpoint;
mountpoint = tracefs__mountpoint();
}
snprintf(buf, size,
"Error:\tNo permissions to read %s/%s\n"
"Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
debugfs_mountpoint, filename, mountpoint);
tracing_events_path, filename, mountpoint);
}
break;
default:
......@@ -131,7 +136,7 @@ int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *
{
char path[PATH_MAX];
snprintf(path, PATH_MAX, "tracing/events/%s/%s", sys, name ?: "*");
snprintf(path, PATH_MAX, "%s/%s", sys, name ?: "*");
return strerror_open(err, buf, size, path);
}
......@@ -68,7 +68,7 @@ OPTIONS
--sort=::
Sort histogram entries by given key(s) - multiple keys can be specified
in CSV format. Following sort keys are available:
pid, comm, dso, symbol, parent, cpu, srcline, weight, local_weight.
pid, comm, dso, symbol, parent, cpu, socket, srcline, weight, local_weight.
Each key has following meaning:
......@@ -79,6 +79,7 @@ OPTIONS
- parent: name of function matched to the parent regex filter. Unmatched
entries are displayed as "[other]".
- cpu: cpu number the task ran at the time of sample
- socket: processor socket number the task ran at the time of sample
- srcline: filename and line number executed at the time of sample. The
DWARF debugging info must be provided.
- srcfile: file name of the source file of the same. Requires dwarf
......@@ -349,6 +350,9 @@ include::itrace.txt[]
This option extends the perf report to show reference callgraphs,
which collected by reference event, in no callgraph event.
--socket-filter::
Only report the samples on the processor socket that match with this filter
include::callchain-overhead-calculation.txt[]
SEE ALSO
......
......@@ -459,7 +459,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
$(DOC_TARGETS):
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol
TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include
TAG_FILES= ../../include/uapi/linux/perf_event.h
TAGS:
......
......@@ -128,9 +128,8 @@ static const char *normalize_arch(char *arch)
return arch;
}
static int perf_session_env__lookup_binutils_path(struct perf_env *env,
const char *name,
const char **path)
static int perf_env__lookup_binutils_path(struct perf_env *env,
const char *name, const char **path)
{
int idx;
const char *arch, *cross_env;
......@@ -206,7 +205,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_env *env,
return -1;
}
int perf_session_env__lookup_objdump(struct perf_env *env)
int perf_env__lookup_objdump(struct perf_env *env)
{
/*
* For live mode, env->arch will be NULL and we can use
......@@ -215,6 +214,5 @@ int perf_session_env__lookup_objdump(struct perf_env *env)
if (env->arch == NULL)
return 0;
return perf_session_env__lookup_binutils_path(env, "objdump",
&objdump_path);
return perf_env__lookup_binutils_path(env, "objdump", &objdump_path);
}
#ifndef ARCH_PERF_COMMON_H
#define ARCH_PERF_COMMON_H
#include "../util/session.h"
#include "../util/env.h"
extern const char *objdump_path;
int perf_session_env__lookup_objdump(struct perf_env *env);
int perf_env__lookup_objdump(struct perf_env *env);
#endif /* ARCH_PERF_COMMON_H */
......@@ -211,7 +211,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
}
if (!objdump_path) {
ret = perf_session_env__lookup_objdump(&session->header.env);
ret = perf_env__lookup_objdump(&session->header.env);
if (ret)
goto out;
}
......
......@@ -13,7 +13,6 @@
#include "util/parse-options.h"
#include "util/trace-event.h"
#include "util/debug.h"
#include <api/fs/debugfs.h>
#include "util/tool.h"
#include "util/stat.h"
#include "util/top.h"
......
......@@ -37,7 +37,6 @@
#include "util/strfilter.h"
#include "util/symbol.h"
#include "util/debug.h"
#include <api/fs/debugfs.h>
#include "util/parse-options.h"
#include "util/probe-finder.h"
#include "util/probe-event.h"
......
......@@ -62,6 +62,7 @@ struct report {
float min_percent;
u64 nr_entries;
u64 queue_size;
int socket_filter;
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
};
......@@ -286,6 +287,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
struct perf_evsel *evsel = hists_to_evsel(hists);
char buf[512];
size_t size = sizeof(buf);
int socked_id = hists->socket_filter;
if (symbol_conf.filter_relative) {
nr_samples = hists->stats.nr_non_filtered_samples;
......@@ -326,6 +328,10 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
ret += fprintf(fp, "\n# Sort order : %s", sort_order ? : default_mem_sort_order);
} else
ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events);
if (socked_id > -1)
ret += fprintf(fp, "\n# Processor Socket: %d", socked_id);
return ret + fprintf(fp, "\n#\n");
}
......@@ -450,6 +456,8 @@ static void report__collapse_hists(struct report *rep)
if (pos->idx == 0)
hists->symbol_filter_str = rep->symbol_filter_str;
hists->socket_filter = rep->socket_filter;
hists__collapse_resort(hists, &prog);
/* Non-group events are considered as leader */
......@@ -635,6 +643,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
},
.max_stack = PERF_MAX_STACK_DEPTH,
.pretty_printing_style = "normal",
.socket_filter = -1,
};
const struct option options[] = {
OPT_STRING('i', "input", &input_name, "file",
......@@ -747,6 +756,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"Show full source file name path for source lines"),
OPT_BOOLEAN(0, "show-ref-call-graph", &symbol_conf.show_ref_callgraph,
"Show callgraph from reference event"),
OPT_INTEGER(0, "socket-filter", &report.socket_filter,
"only show processor socket that match with this filter"),
OPT_END()
};
struct perf_data_file file = {
......
......@@ -952,7 +952,7 @@ static int __cmd_top(struct perf_top *top)
machines__set_symbol_filter(&top->session->machines, symbol_filter);
if (!objdump_path) {
ret = perf_session_env__lookup_objdump(&top->session->header.env);
ret = perf_env__lookup_objdump(&top->session->header.env);
if (ret)
goto out_delete;
}
......@@ -963,6 +963,13 @@ static int __cmd_top(struct perf_top *top)
machine__synthesize_threads(&top->session->machines.host, &opts->target,
top->evlist->threads, false, opts->proc_map_timeout);
if (sort__has_socket) {
ret = perf_env__read_cpu_topology_map(&perf_env);
if (ret < 0)
goto out_err_cpu_topo;
}
ret = perf_top__start_counters(top);
if (ret)
goto out_delete;
......@@ -1020,6 +1027,14 @@ static int __cmd_top(struct perf_top *top)
top->session = NULL;
return ret;
out_err_cpu_topo: {
char errbuf[BUFSIZ];
const char *err = strerror_r(-ret, errbuf, sizeof(errbuf));
ui__error("Could not read the CPU topology map: %s\n", err);
goto out_delete;
}
}
static int
......
......@@ -8,6 +8,7 @@
*/
#include "builtin.h"
#include "util/env.h"
#include "util/exec_cmd.h"
#include "util/cache.h"
#include "util/quote.h"
......@@ -369,6 +370,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
status = p->fn(argc, argv, prefix);
exit_browser(status);
perf_env__exit(&perf_env);
if (status)
return status & 0xff;
......
......@@ -33,6 +33,7 @@ perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o
perf-y += thread-map.o
perf-y += llvm.o
perf-y += topology.o
perf-$(CONFIG_X86) += perf-time-to-tsc.o
ifdef CONFIG_AUXTRACE
......
......@@ -186,12 +186,16 @@ static struct test {
},
#endif
#endif
{
.desc = "Test topology in session",
.func = test_session_topology,
},
{
.func = NULL,
},
};
static bool perf_test__matches(int curr, int argc, const char *argv[])
static bool perf_test__matches(struct test *test, int curr, int argc, const char *argv[])
{
int i;
......@@ -208,7 +212,7 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
continue;
}
if (strstr(tests[curr].desc, argv[i]))
if (strstr(test->desc, argv[i]))
return true;
}
......@@ -245,27 +249,28 @@ static int run_test(struct test *test)
return err;
}
#define for_each_test(t) for (t = &tests[0]; t->func; t++)
static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
{
struct test *t;
int i = 0;
int width = 0;
while (tests[i].func) {
int len = strlen(tests[i].desc);
for_each_test(t) {
int len = strlen(t->desc);
if (width < len)
width = len;
++i;
}
i = 0;
while (tests[i].func) {
for_each_test(t) {
int curr = i++, err;
if (!perf_test__matches(curr, argc, argv))
if (!perf_test__matches(t, curr, argc, argv))
continue;
pr_info("%2d: %-*s:", i, width, tests[curr].desc);
pr_info("%2d: %-*s:", i, width, t->desc);
if (intlist__find(skiplist, i)) {
color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n");
......@@ -273,8 +278,8 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
}
pr_debug("\n--- start ---\n");
err = run_test(&tests[curr]);
pr_debug("---- end ----\n%s:", tests[curr].desc);
err = run_test(t);
pr_debug("---- end ----\n%s:", t->desc);
switch (err) {
case TEST_OK:
......@@ -295,15 +300,14 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
static int perf_test__list(int argc, const char **argv)
{
struct test *t;
int i = 0;
while (tests[i].func) {
int curr = i++;
if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
for_each_test(t) {
if (argc > 1 && !strstr(t->desc, argv[1]))
continue;
pr_info("%2d: %s\n", i, tests[curr].desc);
pr_info("%2d: %s\n", ++i, t->desc);
}
return 0;
......
......@@ -33,20 +33,20 @@ static unsigned int hex(char c)
return c - 'A' + 10;
}
static void read_objdump_line(const char *line, size_t line_len, void **buf,
size_t *len)
static size_t read_objdump_line(const char *line, size_t line_len, void *buf,
size_t len)
{
const char *p;
size_t i;
size_t i, j = 0;
/* Skip to a colon */
p = strchr(line, ':');
if (!p)
return;
return 0;
i = p + 1 - line;
/* Read bytes */
while (*len) {
while (j < len) {
char c1, c2;
/* Skip spaces */
......@@ -65,20 +65,26 @@ static void read_objdump_line(const char *line, size_t line_len, void **buf,
if (i < line_len && line[i] && !isspace(line[i]))
break;
/* Store byte */
*(unsigned char *)*buf = (hex(c1) << 4) | hex(c2);
*buf += 1;
*len -= 1;
*(unsigned char *)buf = (hex(c1) << 4) | hex(c2);
buf += 1;
j++;
}
/* return number of successfully read bytes */
return j;
}
static int read_objdump_output(FILE *f, void **buf, size_t *len)
static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr)
{
char *line = NULL;
size_t line_len;
size_t line_len, off_last = 0;
ssize_t ret;
int err = 0;
u64 addr, last_addr = start_addr;
while (off_last < *len) {
size_t off, read_bytes, written_bytes;
unsigned char tmp[BUFSZ];
while (1) {
ret = getline(&line, &line_len, f);
if (feof(f))
break;
......@@ -87,9 +93,33 @@ static int read_objdump_output(FILE *f, void **buf, size_t *len)
err = -1;
break;
}
read_objdump_line(line, ret, buf, len);
/* read objdump data into temporary buffer */
read_bytes = read_objdump_line(line, ret, tmp, sizeof(tmp));
if (!read_bytes)
continue;
if (sscanf(line, "%"PRIx64, &addr) != 1)
continue;
if (addr < last_addr) {
pr_debug("addr going backwards, read beyond section?\n");
break;
}
last_addr = addr;
/* copy it from temporary buffer to 'buf' according
* to address on current objdump line */
off = addr - start_addr;
if (off >= *len)
break;
written_bytes = MIN(read_bytes, *len - off);
memcpy(buf + off, tmp, written_bytes);
off_last = off + written_bytes;
}
/* len returns number of bytes that could not be read */
*len -= off_last;
free(line);
return err;
......@@ -103,7 +133,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
FILE *f;
int ret;
fmt = "%s -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len,
filename);
if (ret <= 0 || (size_t)ret >= sizeof(cmd))
......@@ -120,7 +150,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
return -1;
}
ret = read_objdump_output(f, &buf, &len);
ret = read_objdump_output(f, buf, &len, addr);
if (len) {
pr_debug("objdump read too few bytes\n");
if (!ret)
......@@ -132,6 +162,18 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
return ret;
}
static void dump_buf(unsigned char *buf, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
pr_debug("0x%02x ", buf[i]);
if (i % 16 == 15)
pr_debug("\n");
}
pr_debug("\n");
}
static int read_object_code(u64 addr, size_t len, u8 cpumode,
struct thread *thread, struct state *state)
{
......@@ -234,6 +276,10 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
/* The results should be identical */
if (memcmp(buf1, buf2, len)) {
pr_debug("Bytes read differ from those read by objdump\n");
pr_debug("buf1 (dso):\n");
dump_buf(buf1, len);
pr_debug("buf2 (objdump):\n");
dump_buf(buf2, len);
return -1;
}
pr_debug("Bytes read match those read by objdump\n");
......
......@@ -16,30 +16,31 @@ struct sample {
struct thread *thread;
struct map *map;
struct symbol *sym;
int socket;
};
/* For the numbers, see hists_common.c */
static struct sample fake_samples[] = {
/* perf [kernel] schedule() */
{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, .socket = 0 },
/* perf [perf] main() */
{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, .socket = 0 },
/* perf [libc] malloc() */
{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
{ .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, .socket = 0 },
/* perf [perf] main() */
{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, }, /* will be merged */
{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, .socket = 0 }, /* will be merged */
/* perf [perf] cmd_record() */
{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, },
{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_CMD_RECORD, .socket = 1 },
/* perf [kernel] page_fault() */
{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
{ .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 1 },
/* bash [bash] main() */
{ .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
{ .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, .socket = 2 },
/* bash [bash] xmalloc() */
{ .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
{ .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, .socket = 2 },
/* bash [libc] malloc() */
{ .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, },
{ .pid = FAKE_PID_BASH, .ip = FAKE_IP_LIBC_MALLOC, .socket = 3 },
/* bash [kernel] page_fault() */
{ .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
{ .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, .socket = 3 },
};
static int add_hist_entries(struct perf_evlist *evlist,
......@@ -83,6 +84,7 @@ static int add_hist_entries(struct perf_evlist *evlist,
&sample) < 0)
goto out;
al.socket = fake_samples[i].socket;
if (hist_entry_iter__add(&iter, &al,
PERF_MAX_STACK_DEPTH, NULL) < 0) {
addr_location__put(&al);
......@@ -253,6 +255,39 @@ int test__hists_filter(void)
TEST_ASSERT_VAL("Unmatched total period for symbol filter",
hists->stats.total_non_filtered_period == 300);
/* remove symbol filter first */
hists->symbol_filter_str = NULL;
hists__filter_by_symbol(hists);
/* now applying socket filters */
hists->socket_filter = 2;
hists__filter_by_socket(hists);
if (verbose > 2) {
pr_info("Histogram for socket filters\n");
print_hists_out(hists);
}
/* normal stats should be invariant */
TEST_ASSERT_VAL("Invalid nr samples",
hists->stats.nr_events[PERF_RECORD_SAMPLE] == 10);
TEST_ASSERT_VAL("Invalid nr hist entries",
hists->nr_entries == 9);
TEST_ASSERT_VAL("Invalid total period",
hists->stats.total_period == 1000);
/* but filter stats are changed */
TEST_ASSERT_VAL("Unmatched nr samples for socket filter",
hists->stats.nr_non_filtered_samples == 2);
TEST_ASSERT_VAL("Unmatched nr hist entries for socket filter",
hists->nr_non_filtered_entries == 2);
TEST_ASSERT_VAL("Unmatched total period for socket filter",
hists->stats.total_non_filtered_period == 200);
/* remove socket filter first */
hists->socket_filter = -1;
hists__filter_by_socket(hists);
/* now applying all filters at once. */
hists->thread_filter = fake_samples[1].thread;
hists->dso_filter = fake_samples[1].map->dso;
......
#include <api/fs/fs.h>
#include "evsel.h"
#include "tests.h"
#include "thread_map.h"
......@@ -14,6 +15,7 @@ int test__openat_syscall_event_on_all_cpus(void)
cpu_set_t cpu_set;
struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
char sbuf[STRERR_BUFSIZE];
char errbuf[BUFSIZ];
if (threads == NULL) {
pr_debug("thread_map__new\n");
......@@ -30,12 +32,8 @@ int test__openat_syscall_event_on_all_cpus(void)
evsel = perf_evsel__newtp("syscalls", "sys_enter_openat");
if (evsel == NULL) {
if (tracefs_configured())
pr_debug("is tracefs mounted on /sys/kernel/tracing?\n");
else if (debugfs_configured())
pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
else
pr_debug("Neither tracefs or debugfs is enabled in this kernel\n");
tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat");
pr_err("%s\n", errbuf);
goto out_thread_map_delete;
}
......
#include <api/fs/tracing_path.h>
#include "thread_map.h"
#include "evsel.h"
#include "debug.h"
......@@ -10,6 +11,7 @@ int test__openat_syscall_event(void)
unsigned int nr_openat_calls = 111, i;
struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
char sbuf[STRERR_BUFSIZE];
char errbuf[BUFSIZ];
if (threads == NULL) {
pr_debug("thread_map__new\n");
......@@ -18,12 +20,8 @@ int test__openat_syscall_event(void)
evsel = perf_evsel__newtp("syscalls", "sys_enter_openat");
if (evsel == NULL) {
if (tracefs_configured())
pr_debug("is tracefs mounted on /sys/kernel/tracing?\n");
else if (debugfs_configured())
pr_debug("is debugfs mounted on /sys/kernel/debug?\n");
else
pr_debug("Neither tracefs or debugfs is enabled in this kernel\n");
tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat");
pr_err("%s\n", errbuf);
goto out_thread_map_delete;
}
......
......@@ -3,11 +3,10 @@
#include "evsel.h"
#include "evlist.h"
#include <api/fs/fs.h>
#include <api/fs/tracefs.h>
#include <api/fs/debugfs.h>
#include "tests.h"
#include "debug.h"
#include <linux/hw_breakpoint.h>
#include <api/fs/fs.h>
#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
......@@ -1262,23 +1261,11 @@ test__checkevent_breakpoint_len_rw_modifier(struct perf_evlist *evlist)
static int count_tracepoints(void)
{
char events_path[PATH_MAX];
struct dirent *events_ent;
const char *mountpoint;
DIR *events_dir;
int cnt = 0;
mountpoint = tracefs_find_mountpoint();
if (mountpoint) {
scnprintf(events_path, PATH_MAX, "%s/events",
mountpoint);
} else {
mountpoint = debugfs_find_mountpoint();
scnprintf(events_path, PATH_MAX, "%s/tracing/events",
mountpoint);
}
events_dir = opendir(events_path);
events_dir = opendir(tracing_events_path);
TEST_ASSERT_VAL("Can't open events dir", events_dir);
......@@ -1295,7 +1282,7 @@ static int count_tracepoints(void)
continue;
scnprintf(sys_path, PATH_MAX, "%s/%s",
events_path, events_ent->d_name);
tracing_events_path, events_ent->d_name);
sys_dir = opendir(sys_path);
TEST_ASSERT_VAL("Can't open sys dir", sys_dir);
......
......@@ -64,6 +64,7 @@ int test__kmod_path__parse(void);
int test__thread_map(void);
int test__llvm(void);
int test__insn_x86(void);
int test_session_topology(void);
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT
......
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "tests.h"
#include "util.h"
#include "session.h"
#include "evlist.h"
#include "debug.h"
#define TEMPL "/tmp/perf-test-XXXXXX"
#define DATA_SIZE 10
static int get_temp(char *path)
{
int fd;
strcpy(path, TEMPL);
fd = mkstemp(path);
if (fd < 0) {
perror("mkstemp failed");
return -1;
}
close(fd);
return 0;
}
static int session_write_header(char *path)
{
struct perf_session *session;
struct perf_data_file file = {
.path = path,
.mode = PERF_DATA_MODE_WRITE,
};
session = perf_session__new(&file, false, NULL);
TEST_ASSERT_VAL("can't get session", session);
session->evlist = perf_evlist__new_default();
TEST_ASSERT_VAL("can't get evlist", session->evlist);
perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
perf_header__set_feat(&session->header, HEADER_NRCPUS);
session->header.data_size += DATA_SIZE;
TEST_ASSERT_VAL("failed to write header",
!perf_session__write_header(session, session->evlist, file.fd, true));
perf_session__delete(session);
return 0;
}
static int check_cpu_topology(char *path, struct cpu_map *map)
{
struct perf_session *session;
struct perf_data_file file = {
.path = path,
.mode = PERF_DATA_MODE_READ,
};
int i;
session = perf_session__new(&file, false, NULL);
TEST_ASSERT_VAL("can't get session", session);
for (i = 0; i < session->header.env.nr_cpus_online; i++) {
pr_debug("CPU %d, core %d, socket %d\n", i,
session->header.env.cpu[i].core_id,
session->header.env.cpu[i].socket_id);
}
for (i = 0; i < map->nr; i++) {
TEST_ASSERT_VAL("Core ID doesn't match",
(session->header.env.cpu[map->map[i]].core_id == (cpu_map__get_core(map, i) & 0xffff)));
TEST_ASSERT_VAL("Socket ID doesn't match",
(session->header.env.cpu[map->map[i]].socket_id == cpu_map__get_socket(map, i)));
}
perf_session__delete(session);
return 0;
}
int test_session_topology(void)
{
char path[PATH_MAX];
struct cpu_map *map;
int ret = -1;
TEST_ASSERT_VAL("can't get templ file", !get_temp(path));
pr_debug("templ file: %s\n", path);
if (session_write_header(path))
goto free_path;
map = cpu_map__new(NULL);
if (map == NULL) {
pr_debug("failed to get system cpumap\n");
goto free_path;
}
if (check_cpu_topology(path, map))
goto free_map;
ret = 0;
free_map:
cpu_map__put(map);
free_path:
unlink(path);
return ret;
}
......@@ -1261,6 +1261,7 @@ static int hists__browser_title(struct hists *hists,
int printed;
const struct dso *dso = hists->dso_filter;
const struct thread *thread = hists->thread_filter;
int socket_id = hists->socket_filter;
unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
u64 nr_events = hists->stats.total_period;
struct perf_evsel *evsel = hists_to_evsel(hists);
......@@ -1314,6 +1315,9 @@ static int hists__browser_title(struct hists *hists,
if (dso)
printed += scnprintf(bf + printed, size - printed,
", DSO: %s", dso->short_name);
if (socket_id > -1)
printed += scnprintf(bf + printed, size - printed,
", Processor Socket: %d", socket_id);
if (!is_report_browser(hbt)) {
struct perf_top *top = hbt->arg;
......@@ -1425,6 +1429,7 @@ struct popup_action {
struct thread *thread;
struct dso *dso;
struct map_symbol ms;
int socket;
int (*fn)(struct hist_browser *browser, struct popup_action *act);
};
......@@ -1437,7 +1442,7 @@ do_annotate(struct hist_browser *browser, struct popup_action *act)
struct hist_entry *he;
int err;
if (!objdump_path && perf_session_env__lookup_objdump(browser->env))
if (!objdump_path && perf_env__lookup_objdump(browser->env))
return 0;
notes = symbol__annotation(act->ms.sym);
......@@ -1672,6 +1677,41 @@ add_exit_opt(struct hist_browser *browser __maybe_unused,
return 1;
}
static int
do_zoom_socket(struct hist_browser *browser, struct popup_action *act)
{
if (browser->hists->socket_filter > -1) {
pstack__remove(browser->pstack, &browser->hists->socket_filter);
browser->hists->socket_filter = -1;
perf_hpp__set_elide(HISTC_SOCKET, false);
} else {
browser->hists->socket_filter = act->socket;
perf_hpp__set_elide(HISTC_SOCKET, true);
pstack__push(browser->pstack, &browser->hists->socket_filter);
}
hists__filter_by_socket(browser->hists);
hist_browser__reset(browser);
return 0;
}
static int
add_socket_opt(struct hist_browser *browser, struct popup_action *act,
char **optstr, int socket_id)
{
if (socket_id < 0)
return 0;
if (asprintf(optstr, "Zoom %s Processor Socket %d",
(browser->hists->socket_filter > -1) ? "out of" : "into",
socket_id) < 0)
return 0;
act->socket = socket_id;
act->fn = do_zoom_socket;
return 1;
}
static void hist_browser__update_nr_entries(struct hist_browser *hb)
{
u64 nr_entries = 0;
......@@ -1725,6 +1765,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
"E Expand all callchains\n" \
"F Toggle percentage of filtered entries\n" \
"H Display column headers\n" \
"S Zoom into current Processor Socket\n" \
/* help messages are sorted by lexical order of the hotkey */
const char report_help[] = HIST_BROWSER_HELP_COMMON
......@@ -1755,7 +1796,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
hist_browser__update_nr_entries(browser);
}
browser->pstack = pstack__new(2);
browser->pstack = pstack__new(3);
if (browser->pstack == NULL)
goto out;
......@@ -1774,6 +1815,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
struct thread *thread = NULL;
struct dso *dso = NULL;
int choice = 0;
int socked_id = -1;
nr_options = 0;
......@@ -1782,6 +1824,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (browser->he_selection != NULL) {
thread = hist_browser__selected_thread(browser);
dso = browser->selection->map ? browser->selection->map->dso : NULL;
socked_id = browser->he_selection->socket;
}
switch (key) {
case K_TAB:
......@@ -1824,6 +1867,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
actions->thread = thread;
do_zoom_thread(browser, actions);
continue;
case 'S':
actions->socket = socked_id;
do_zoom_socket(browser, actions);
continue;
case '/':
if (ui_browser__input_window("Symbol to show",
"Please enter the name of symbol you want to see",
......@@ -1899,9 +1946,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
* Ditto for thread below.
*/
do_zoom_dso(browser, actions);
}
if (top == &browser->hists->thread_filter)
} else if (top == &browser->hists->thread_filter) {
do_zoom_thread(browser, actions);
} else if (top == &browser->hists->socket_filter) {
do_zoom_socket(browser, actions);
}
continue;
}
case 'q':
......@@ -1969,7 +2018,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
nr_options += add_map_opt(browser, &actions[nr_options],
&options[nr_options],
browser->selection->map);
nr_options += add_socket_opt(browser, &actions[nr_options],
&options[nr_options],
socked_id);
/* perf script support */
if (browser->he_selection) {
nr_options += add_script_opt(browser,
......
......@@ -5,6 +5,7 @@ libperf-y += build-id.o
libperf-y += config.o
libperf-y += ctype.o
libperf-y += db-export.o
libperf-y += env.o
libperf-y += environment.o
libperf-y += event.o
libperf-y += evlist.o
......
......@@ -225,28 +225,20 @@ void cpu_map__put(struct cpu_map *map)
cpu_map__delete(map);
}
int cpu_map__get_socket_id(int cpu)
static int cpu__get_topology_int(int cpu, const char *name, int *value)
{
FILE *fp;
const char *mnt;
char path[PATH_MAX];
int socket_id, ret;
mnt = sysfs__mountpoint();
if (!mnt)
return -1;
snprintf(path, PATH_MAX,
"%s/devices/system/cpu/cpu%d/topology/physical_package_id",
mnt, cpu);
"devices/system/cpu/cpu%d/topology/%s", cpu, name);
fp = fopen(path, "r");
if (!fp)
return -1;
ret = fscanf(fp, "%d", &socket_id);
fclose(fp);
return sysfs__read_int(path, value);
}
return ret == 1 ? socket_id : -1;
int cpu_map__get_socket_id(int cpu)
{
int value, ret = cpu__get_topology_int(cpu, "physical_package_id", &value);
return ret ?: value;
}
int cpu_map__get_socket(struct cpu_map *map, int idx)
......@@ -299,26 +291,8 @@ static int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res,
int cpu_map__get_core_id(int cpu)
{
FILE *fp;
const char *mnt;
char path[PATH_MAX];
int core_id, ret;
mnt = sysfs__mountpoint();
if (!mnt)
return -1;
snprintf(path, PATH_MAX,
"%s/devices/system/cpu/cpu%d/topology/core_id",
mnt, cpu);
fp = fopen(path, "r");
if (!fp)
return -1;
ret = fscanf(fp, "%d", &core_id);
fclose(fp);
return ret == 1 ? core_id : -1;
int value, ret = cpu__get_topology_int(cpu, "core_id", &value);
return ret ?: value;
}
int cpu_map__get_core(struct cpu_map *map, int idx)
......
#include "cpumap.h"
#include "env.h"
#include "util.h"
struct perf_env perf_env;
void perf_env__exit(struct perf_env *env)
{
zfree(&env->hostname);
zfree(&env->os_release);
zfree(&env->version);
zfree(&env->arch);
zfree(&env->cpu_desc);
zfree(&env->cpuid);
zfree(&env->cmdline);
zfree(&env->cmdline_argv);
zfree(&env->sibling_cores);
zfree(&env->sibling_threads);
zfree(&env->numa_nodes);
zfree(&env->pmu_mappings);
zfree(&env->cpu);
}
int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
{
int i;
/*
* If env->cmdline_argv has already been set, do not override it. This allows
* a command to set the cmdline, parse args and then call another
* builtin function that implements a command -- e.g, cmd_kvm calling
* cmd_record.
*/
if (env->cmdline_argv != NULL)
return 0;
/* do not include NULL termination */
env->cmdline_argv = calloc(argc, sizeof(char *));
if (env->cmdline_argv == NULL)
goto out_enomem;
/*
* Must copy argv contents because it gets moved around during option
* parsing:
*/
for (i = 0; i < argc ; i++) {
env->cmdline_argv[i] = argv[i];
if (env->cmdline_argv[i] == NULL)
goto out_free;
}
env->nr_cmdline = argc;
return 0;
out_free:
zfree(&env->cmdline_argv);
out_enomem:
return -ENOMEM;
}
int perf_env__read_cpu_topology_map(struct perf_env *env)
{
int cpu, nr_cpus;
if (env->cpu != NULL)
return 0;
if (env->nr_cpus_avail == 0)
env->nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF);
nr_cpus = env->nr_cpus_avail;
if (nr_cpus == -1)
return -EINVAL;
env->cpu = calloc(nr_cpus, sizeof(env->cpu[0]));
if (env->cpu == NULL)
return -ENOMEM;
for (cpu = 0; cpu < nr_cpus; ++cpu) {
env->cpu[cpu].core_id = cpu_map__get_core_id(cpu);
env->cpu[cpu].socket_id = cpu_map__get_socket_id(cpu);
}
env->nr_cpus_avail = nr_cpus;
return 0;
}
#ifndef __PERF_ENV_H
#define __PERF_ENV_H
struct cpu_topology_map {
int socket_id;
int core_id;
};
struct perf_env {
char *hostname;
char *os_release;
char *version;
char *arch;
int nr_cpus_online;
int nr_cpus_avail;
char *cpu_desc;
char *cpuid;
unsigned long long total_mem;
unsigned int msr_pmu_type;
int nr_cmdline;
int nr_sibling_cores;
int nr_sibling_threads;
int nr_numa_nodes;
int nr_pmu_mappings;
int nr_groups;
char *cmdline;
const char **cmdline_argv;
char *sibling_cores;
char *sibling_threads;
char *numa_nodes;
char *pmu_mappings;
struct cpu_topology_map *cpu;
};
extern struct perf_env perf_env;
void perf_env__exit(struct perf_env *env);
int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[]);
int perf_env__read_cpu_topology_map(struct perf_env *env);
#endif /* __PERF_ENV_H */
......@@ -1021,6 +1021,14 @@ int perf_event__preprocess_sample(const union perf_event *event,
al->sym = NULL;
al->cpu = sample->cpu;
al->socket = -1;
if (al->cpu >= 0) {
struct perf_env *env = machine->env;
if (env && env->cpu)
al->socket = env->cpu[al->cpu].socket_id;
}
if (al->map) {
struct dso *dso = al->map->dso;
......
......@@ -9,7 +9,7 @@
#include <byteswap.h>
#include <linux/bitops.h>
#include <api/fs/debugfs.h>
#include <api/fs/tracing_path.h>
#include <traceevent/event-parse.h>
#include <linux/hw_breakpoint.h>
#include <linux/perf_event.h>
......
......@@ -129,7 +129,6 @@ union u64_swap {
struct cpu_map;
struct target;
struct thread_map;
struct perf_evlist;
struct record_opts;
static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
......
......@@ -24,9 +24,6 @@
#include "build-id.h"
#include "data.h"
static u32 header_argc;
static const char **header_argv;
/*
* magic2 = "PERFILE2"
* must be a numerical value to let the endianness
......@@ -138,37 +135,6 @@ static char *do_read_string(int fd, struct perf_header *ph)
return NULL;
}
int
perf_header__set_cmdline(int argc, const char **argv)
{
int i;
/*
* If header_argv has already been set, do not override it.
* This allows a command to set the cmdline, parse args and
* then call another builtin function that implements a
* command -- e.g, cmd_kvm calling cmd_record.
*/
if (header_argv)
return 0;
header_argc = (u32)argc;
/* do not include NULL termination */
header_argv = calloc(argc, sizeof(char *));
if (!header_argv)
return -ENOMEM;
/*
* must copy argv contents because it gets moved
* around during option parsing
*/
for (i = 0; i < argc ; i++)
header_argv[i] = argv[i];
return 0;
}
static int write_tracing_data(int fd, struct perf_header *h __maybe_unused,
struct perf_evlist *evlist)
{
......@@ -405,8 +371,8 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
{
char buf[MAXPATHLEN];
char proc[32];
u32 i, n;
int ret;
u32 n;
int i, ret;
/*
* actual atual path to perf binary
......@@ -420,7 +386,7 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
buf[ret] = '\0';
/* account for binary path */
n = header_argc + 1;
n = perf_env.nr_cmdline + 1;
ret = do_write(fd, &n, sizeof(n));
if (ret < 0)
......@@ -430,8 +396,8 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
if (ret < 0)
return ret;
for (i = 0 ; i < header_argc; i++) {
ret = do_write_string(fd, header_argv[i]);
for (i = 0 ; i < perf_env.nr_cmdline; i++) {
ret = do_write_string(fd, perf_env.cmdline_argv[i]);
if (ret < 0)
return ret;
}
......@@ -449,8 +415,6 @@ struct cpu_topo {
u32 thread_sib;
char **core_siblings;
char **thread_siblings;
int *core_id;
int *phy_pkg_id;
};
static int build_cpu_topo(struct cpu_topo *tp, int cpu)
......@@ -513,9 +477,6 @@ static int build_cpu_topo(struct cpu_topo *tp, int cpu)
}
ret = 0;
done:
tp->core_id[cpu] = cpu_map__get_core_id(cpu);
tp->phy_pkg_id[cpu] = cpu_map__get_socket_id(cpu);
if(fp)
fclose(fp);
free(buf);
......@@ -543,7 +504,7 @@ static struct cpu_topo *build_cpu_topology(void)
struct cpu_topo *tp;
void *addr;
u32 nr, i;
size_t sz, sz_id;
size_t sz;
long ncpus;
int ret = -1;
......@@ -554,9 +515,8 @@ static struct cpu_topo *build_cpu_topology(void)
nr = (u32)(ncpus & UINT_MAX);
sz = nr * sizeof(char *);
sz_id = nr * sizeof(int);
addr = calloc(1, sizeof(*tp) + 2 * sz + 2 * sz_id);
addr = calloc(1, sizeof(*tp) + 2 * sz);
if (!addr)
return NULL;
......@@ -566,10 +526,6 @@ static struct cpu_topo *build_cpu_topology(void)
tp->core_siblings = addr;
addr += sz;
tp->thread_siblings = addr;
addr += sz;
tp->core_id = addr;
addr += sz_id;
tp->phy_pkg_id = addr;
for (i = 0; i < nr; i++) {
ret = build_cpu_topo(tp, i);
......@@ -588,7 +544,7 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused,
{
struct cpu_topo *tp;
u32 i;
int ret;
int ret, j;
tp = build_cpu_topology();
if (!tp)
......@@ -613,11 +569,17 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused,
break;
}
for (i = 0; i < tp->cpu_nr; i++) {
ret = do_write(fd, &tp->core_id[i], sizeof(int));
ret = perf_env__read_cpu_topology_map(&perf_env);
if (ret < 0)
goto done;
for (j = 0; j < perf_env.nr_cpus_avail; j++) {
ret = do_write(fd, &perf_env.cpu[j].core_id,
sizeof(perf_env.cpu[j].core_id));
if (ret < 0)
return ret;
ret = do_write(fd, &tp->phy_pkg_id[i], sizeof(int));
ret = do_write(fd, &perf_env.cpu[j].socket_id,
sizeof(perf_env.cpu[j].socket_id));
if (ret < 0)
return ret;
}
......@@ -1821,6 +1783,9 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
/* include a NULL character at the end */
strbuf_add(&sb, "", 1);
if (!strcmp(name, "msr"))
ph->env.msr_pmu_type = type;
free(name);
pmu_num--;
}
......@@ -2599,6 +2564,7 @@ int perf_session__read_header(struct perf_session *session)
return -ENOMEM;
session->evlist->env = &header->env;
session->machines.host.env = &header->env;
if (perf_data_file__is_pipe(file))
return perf_header__read_pipe(session);
......
......@@ -7,7 +7,7 @@
#include <linux/bitmap.h>
#include <linux/types.h>
#include "event.h"
#include "env.h"
enum {
HEADER_RESERVED = 0, /* always cleared */
......@@ -66,37 +66,6 @@ struct perf_header;
int perf_file_header__read(struct perf_file_header *header,
struct perf_header *ph, int fd);
struct cpu_topology_map {
int socket_id;
int core_id;
};
struct perf_env {
char *hostname;
char *os_release;
char *version;
char *arch;
int nr_cpus_online;
int nr_cpus_avail;
char *cpu_desc;
char *cpuid;
unsigned long long total_mem;
int nr_cmdline;
int nr_sibling_cores;
int nr_sibling_threads;
int nr_numa_nodes;
int nr_pmu_mappings;
int nr_groups;
char *cmdline;
const char **cmdline_argv;
char *sibling_cores;
char *sibling_threads;
char *numa_nodes;
char *pmu_mappings;
struct cpu_topology_map *cpu;
};
struct perf_header {
enum perf_header_version version;
bool needs_swap;
......
......@@ -15,6 +15,8 @@ static bool hists__filter_entry_by_thread(struct hists *hists,
struct hist_entry *he);
static bool hists__filter_entry_by_symbol(struct hists *hists,
struct hist_entry *he);
static bool hists__filter_entry_by_socket(struct hists *hists,
struct hist_entry *he);
u16 hists__col_len(struct hists *hists, enum hist_column col)
{
......@@ -144,6 +146,8 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
}
hists__new_col_len(hists, HISTC_CPU, 3);
hists__new_col_len(hists, HISTC_SOCKET, 6);
hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
hists__new_col_len(hists, HISTC_MEM_TLB, 22);
hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
......@@ -452,6 +456,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
.map = al->map,
.sym = al->sym,
},
.socket = al->socket,
.cpu = al->cpu,
.cpumode = al->cpumode,
.ip = al->addr,
......@@ -1024,6 +1029,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
hists__filter_entry_by_dso(hists, he);
hists__filter_entry_by_thread(hists, he);
hists__filter_entry_by_symbol(hists, he);
hists__filter_entry_by_socket(hists, he);
}
void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
......@@ -1292,6 +1298,37 @@ void hists__filter_by_symbol(struct hists *hists)
}
}
static bool hists__filter_entry_by_socket(struct hists *hists,
struct hist_entry *he)
{
if ((hists->socket_filter > -1) &&
(he->socket != hists->socket_filter)) {
he->filtered |= (1 << HIST_FILTER__SOCKET);
return true;
}
return false;
}
void hists__filter_by_socket(struct hists *hists)
{
struct rb_node *nd;
hists->stats.nr_non_filtered_samples = 0;
hists__reset_filter_stats(hists);
hists__reset_col_len(hists);
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
if (hists__filter_entry_by_socket(hists, h))
continue;
hists__remove_entry_filter(hists, h, HIST_FILTER__SOCKET);
}
}
void events_stats__inc(struct events_stats *stats, u32 type)
{
++stats->nr_events[0];
......@@ -1517,6 +1554,7 @@ static int hists_evsel__init(struct perf_evsel *evsel)
hists->entries_collapsed = RB_ROOT;
hists->entries = RB_ROOT;
pthread_mutex_init(&hists->lock, NULL);
hists->socket_filter = -1;
return 0;
}
......
......@@ -20,6 +20,7 @@ enum hist_filter {
HIST_FILTER__SYMBOL,
HIST_FILTER__GUEST,
HIST_FILTER__HOST,
HIST_FILTER__SOCKET,
};
enum hist_column {
......@@ -29,6 +30,7 @@ enum hist_column {
HISTC_COMM,
HISTC_PARENT,
HISTC_CPU,
HISTC_SOCKET,
HISTC_SRCLINE,
HISTC_SRCFILE,
HISTC_MISPREDICT,
......@@ -70,6 +72,7 @@ struct hists {
struct events_stats stats;
u64 event_stream;
u16 col_len[HISTC_NR_COLS];
int socket_filter;
};
struct hist_entry_iter;
......@@ -144,11 +147,12 @@ size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp);
void hists__filter_by_dso(struct hists *hists);
void hists__filter_by_thread(struct hists *hists);
void hists__filter_by_symbol(struct hists *hists);
void hists__filter_by_socket(struct hists *hists);
static inline bool hists__has_filter(struct hists *hists)
{
return hists->thread_filter || hists->dso_filter ||
hists->symbol_filter_str;
hists->symbol_filter_str || (hists->socket_filter > -1);
}
u16 hists__col_len(struct hists *hists, enum hist_column col);
......
......@@ -35,6 +35,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
machine->last_match = NULL;
machine->vdso_info = NULL;
machine->env = NULL;
machine->pid = pid;
......
......@@ -34,6 +34,7 @@ struct machine {
struct list_head dead_threads;
struct thread *last_match;
struct vdso_info *vdso_info;
struct perf_env *env;
struct dsos dsos;
struct map_groups kmaps;
struct map *vmlinux_maps[MAP__NR_TYPES];
......
......@@ -496,7 +496,7 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
{
struct parse_opt_ctx_t ctx;
perf_header__set_cmdline(argc, argv);
perf_env__set_cmdline(&perf_env, argc, argv);
/* build usage string if it's not provided */
if (subcommands && !usagestr[0]) {
......
......@@ -40,8 +40,7 @@
#include "color.h"
#include "symbol.h"
#include "thread.h"
#include <api/fs/debugfs.h>
#include <api/fs/tracefs.h>
#include <api/fs/fs.h>
#include "trace-event.h" /* For __maybe_unused */
#include "probe-event.h"
#include "probe-finder.h"
......@@ -2054,7 +2053,7 @@ static void kprobe_blacklist__delete(struct list_head *blacklist)
static int kprobe_blacklist__load(struct list_head *blacklist)
{
struct kprobe_blacklist_node *node;
const char *__debugfs = debugfs_find_mountpoint();
const char *__debugfs = debugfs__mountpoint();
char buf[PATH_MAX], *p;
FILE *fp;
int ret;
......
......@@ -22,8 +22,7 @@
#include "color.h"
#include "symbol.h"
#include "thread.h"
#include <api/fs/debugfs.h>
#include <api/fs/tracefs.h>
#include <api/fs/tracing_path.h>
#include "probe-event.h"
#include "probe-file.h"
#include "session.h"
......@@ -73,21 +72,11 @@ static void print_both_open_warning(int kerr, int uerr)
static int open_probe_events(const char *trace_file, bool readwrite)
{
char buf[PATH_MAX];
const char *__debugfs;
const char *tracing_dir = "";
int ret;
__debugfs = tracefs_find_mountpoint();
if (__debugfs == NULL) {
tracing_dir = "tracing/";
__debugfs = debugfs_find_mountpoint();
if (__debugfs == NULL)
return -ENOTSUP;
}
ret = e_snprintf(buf, PATH_MAX, "%s/%s%s",
__debugfs, tracing_dir, trace_file);
tracing_path, tracing_dir, trace_file);
if (ret >= 0) {
pr_debug("Opening %s write=%d\n", buf, readwrite);
if (readwrite && !probe_event_dry_run)
......
......@@ -138,6 +138,8 @@ struct perf_session *perf_session__new(struct perf_data_file *file,
perf_session__set_id_hdr_size(session);
perf_session__set_comm_exec(session);
}
} else {
session->machines.host.env = &perf_env;
}
if (!file || perf_data_file__is_write(file)) {
......@@ -170,31 +172,13 @@ static void perf_session__delete_threads(struct perf_session *session)
machine__delete_threads(&session->machines.host);
}
static void perf_session_env__exit(struct perf_env *env)
{
zfree(&env->hostname);
zfree(&env->os_release);
zfree(&env->version);
zfree(&env->arch);
zfree(&env->cpu_desc);
zfree(&env->cpuid);
zfree(&env->cmdline);
zfree(&env->cmdline_argv);
zfree(&env->sibling_cores);
zfree(&env->sibling_threads);
zfree(&env->numa_nodes);
zfree(&env->pmu_mappings);
zfree(&env->cpu);
}
void perf_session__delete(struct perf_session *session)
{
auxtrace__free(session);
auxtrace_index__free(&session->auxtrace_index);
perf_session__destroy_kernel_maps(session);
perf_session__delete_threads(session);
perf_session_env__exit(&session->header.env);
perf_env__exit(&session->header.env);
machines__exit(&session->machines);
if (session->file)
perf_data_file__close(session->file);
......
......@@ -21,6 +21,7 @@ int sort__need_collapse = 0;
int sort__has_parent = 0;
int sort__has_sym = 0;
int sort__has_dso = 0;
int sort__has_socket = 0;
enum sort_mode sort__mode = SORT_MODE__NORMAL;
......@@ -421,6 +422,27 @@ struct sort_entry sort_cpu = {
.se_width_idx = HISTC_CPU,
};
/* --sort socket */
static int64_t
sort__socket_cmp(struct hist_entry *left, struct hist_entry *right)
{
return right->socket - left->socket;
}
static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
}
struct sort_entry sort_socket = {
.se_header = "Socket",
.se_cmp = sort__socket_cmp,
.se_snprintf = hist_entry__socket_snprintf,
.se_width_idx = HISTC_SOCKET,
};
/* sort keys for branch stacks */
static int64_t
......@@ -1248,6 +1270,7 @@ static struct sort_dimension common_sort_dimensions[] = {
DIM(SORT_SYM, "symbol", sort_sym),
DIM(SORT_PARENT, "parent", sort_parent),
DIM(SORT_CPU, "cpu", sort_cpu),
DIM(SORT_SOCKET, "socket", sort_socket),
DIM(SORT_SRCLINE, "srcline", sort_srcline),
DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
......@@ -1550,6 +1573,8 @@ int sort_dimension__add(const char *tok)
} else if (sd->entry == &sort_dso) {
sort__has_dso = 1;
} else if (sd->entry == &sort_socket) {
sort__has_socket = 1;
}
return __sort_dimension__add(sd);
......
......@@ -34,6 +34,7 @@ extern int have_ignore_callees;
extern int sort__need_collapse;
extern int sort__has_parent;
extern int sort__has_sym;
extern int sort__has_socket;
extern enum sort_mode sort__mode;
extern struct sort_entry sort_comm;
extern struct sort_entry sort_dso;
......@@ -90,6 +91,7 @@ struct hist_entry {
struct comm *comm;
u64 ip;
u64 transaction;
s32 socket;
s32 cpu;
u8 cpumode;
......@@ -172,6 +174,7 @@ enum sort_type {
SORT_SYM,
SORT_PARENT,
SORT_CPU,
SORT_SOCKET,
SORT_SRCLINE,
SORT_SRCFILE,
SORT_LOCAL_WEIGHT,
......
......@@ -191,6 +191,7 @@ struct addr_location {
u8 filtered;
u8 cpumode;
s32 cpu;
s32 socket;
};
struct symsrc {
......
......@@ -74,8 +74,7 @@
#include <linux/magic.h>
#include <linux/types.h>
#include <sys/ttydefaults.h>
#include <api/fs/debugfs.h>
#include <api/fs/tracefs.h>
#include <api/fs/tracing_path.h>
#include <termios.h>
#include <linux/bitops.h>
#include <termios.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment