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 += fd/
libapi-y += fs/ 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 += fs.o
libapi-y += tracing_path.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 <ctype.h>
#include <errno.h> #include <errno.h>
#include <limits.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -11,7 +12,6 @@ ...@@ -11,7 +12,6 @@
#include <unistd.h> #include <unistd.h>
#include <sys/mount.h> #include <sys/mount.h>
#include "debugfs.h"
#include "fs.h" #include "fs.h"
#define _STR(x) #x #define _STR(x) #x
...@@ -282,6 +282,50 @@ int filename__read_int(const char *filename, int *value) ...@@ -282,6 +282,50 @@ int filename__read_int(const char *filename, int *value)
return err; 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) int sysctl__read_int(const char *sysctl, int *value)
{ {
char path[PATH_MAX]; char path[PATH_MAX];
......
...@@ -25,5 +25,9 @@ FS(tracefs) ...@@ -25,5 +25,9 @@ FS(tracefs)
int filename__read_int(const char *filename, int *value); 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 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__ */ #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 @@ ...@@ -7,8 +7,7 @@
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include "debugfs.h" #include "fs.h"
#include "tracefs.h"
#include "tracing_path.h" #include "tracing_path.h"
...@@ -29,7 +28,7 @@ static const char *tracing_path_tracefs_mount(void) ...@@ -29,7 +28,7 @@ static const char *tracing_path_tracefs_mount(void)
{ {
const char *mnt; const char *mnt;
mnt = tracefs_mount(NULL); mnt = tracefs__mount();
if (!mnt) if (!mnt)
return NULL; return NULL;
...@@ -42,7 +41,7 @@ static const char *tracing_path_debugfs_mount(void) ...@@ -42,7 +41,7 @@ static const char *tracing_path_debugfs_mount(void)
{ {
const char *mnt; const char *mnt;
mnt = debugfs_mount(NULL); mnt = debugfs__mount();
if (!mnt) if (!mnt)
return NULL; return NULL;
...@@ -90,33 +89,39 @@ static int strerror_open(int err, char *buf, size_t size, const char *filename) ...@@ -90,33 +89,39 @@ static int strerror_open(int err, char *buf, size_t size, const char *filename)
switch (err) { switch (err) {
case ENOENT: 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, snprintf(buf, size,
"Error:\tFile %s/%s not found.\n" "Error:\tFile %s/%s not found.\n"
"Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n", "Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n",
debugfs_mountpoint, filename); tracing_events_path, filename);
break; break;
} }
snprintf(buf, size, "%s", snprintf(buf, size, "%s",
"Error:\tUnable to find debugfs\n" "Error:\tUnable to find debugfs/tracefs\n"
"Hint:\tWas your kernel compiled with debugfs support?\n" "Hint:\tWas your kernel compiled with debugfs/tracefs support?\n"
"Hint:\tIs the debugfs filesystem mounted?\n" "Hint:\tIs the debugfs/tracefs filesystem mounted?\n"
"Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'"); "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
break; break;
case EACCES: { case EACCES: {
const char *mountpoint = debugfs_mountpoint; const char *mountpoint = debugfs__mountpoint();
if (!access(debugfs_mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) { if (!access(mountpoint, R_OK) && strncmp(filename, "tracing/", 8) == 0) {
const char *tracefs_mntpoint = tracefs_find_mountpoint(); const char *tracefs_mntpoint = tracefs__mountpoint();
if (tracefs_mntpoint) if (tracefs_mntpoint)
mountpoint = tracefs_mntpoint; mountpoint = tracefs__mountpoint();
} }
snprintf(buf, size, snprintf(buf, size,
"Error:\tNo permissions to read %s/%s\n" "Error:\tNo permissions to read %s/%s\n"
"Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n", "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
debugfs_mountpoint, filename, mountpoint); tracing_events_path, filename, mountpoint);
} }
break; break;
default: default:
...@@ -131,7 +136,7 @@ int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char * ...@@ -131,7 +136,7 @@ int tracing_path__strerror_open_tp(int err, char *buf, size_t size, const char *
{ {
char path[PATH_MAX]; 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); return strerror_open(err, buf, size, path);
} }
...@@ -68,7 +68,7 @@ OPTIONS ...@@ -68,7 +68,7 @@ OPTIONS
--sort=:: --sort=::
Sort histogram entries by given key(s) - multiple keys can be specified Sort histogram entries by given key(s) - multiple keys can be specified
in CSV format. Following sort keys are available: 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: Each key has following meaning:
...@@ -79,6 +79,7 @@ OPTIONS ...@@ -79,6 +79,7 @@ OPTIONS
- parent: name of function matched to the parent regex filter. Unmatched - parent: name of function matched to the parent regex filter. Unmatched
entries are displayed as "[other]". entries are displayed as "[other]".
- cpu: cpu number the task ran at the time of sample - 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 - srcline: filename and line number executed at the time of sample. The
DWARF debugging info must be provided. DWARF debugging info must be provided.
- srcfile: file name of the source file of the same. Requires dwarf - srcfile: file name of the source file of the same. Requires dwarf
...@@ -349,6 +350,9 @@ include::itrace.txt[] ...@@ -349,6 +350,9 @@ include::itrace.txt[]
This option extends the perf report to show reference callgraphs, This option extends the perf report to show reference callgraphs,
which collected by reference event, in no callgraph event. 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[] include::callchain-overhead-calculation.txt[]
SEE ALSO SEE ALSO
......
...@@ -459,7 +459,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html ...@@ -459,7 +459,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
$(DOC_TARGETS): $(DOC_TARGETS):
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all) $(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 TAG_FILES= ../../include/uapi/linux/perf_event.h
TAGS: TAGS:
......
...@@ -128,9 +128,8 @@ static const char *normalize_arch(char *arch) ...@@ -128,9 +128,8 @@ static const char *normalize_arch(char *arch)
return arch; return arch;
} }
static int perf_session_env__lookup_binutils_path(struct perf_env *env, static int perf_env__lookup_binutils_path(struct perf_env *env,
const char *name, const char *name, const char **path)
const char **path)
{ {
int idx; int idx;
const char *arch, *cross_env; const char *arch, *cross_env;
...@@ -206,7 +205,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_env *env, ...@@ -206,7 +205,7 @@ static int perf_session_env__lookup_binutils_path(struct perf_env *env,
return -1; 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 * 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) ...@@ -215,6 +214,5 @@ int perf_session_env__lookup_objdump(struct perf_env *env)
if (env->arch == NULL) if (env->arch == NULL)
return 0; return 0;
return perf_session_env__lookup_binutils_path(env, "objdump", return perf_env__lookup_binutils_path(env, "objdump", &objdump_path);
&objdump_path);
} }
#ifndef ARCH_PERF_COMMON_H #ifndef ARCH_PERF_COMMON_H
#define ARCH_PERF_COMMON_H #define ARCH_PERF_COMMON_H
#include "../util/session.h" #include "../util/env.h"
extern const char *objdump_path; 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 */ #endif /* ARCH_PERF_COMMON_H */
...@@ -211,7 +211,7 @@ static int __cmd_annotate(struct perf_annotate *ann) ...@@ -211,7 +211,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
} }
if (!objdump_path) { if (!objdump_path) {
ret = perf_session_env__lookup_objdump(&session->header.env); ret = perf_env__lookup_objdump(&session->header.env);
if (ret) if (ret)
goto out; goto out;
} }
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "util/parse-options.h" #include "util/parse-options.h"
#include "util/trace-event.h" #include "util/trace-event.h"
#include "util/debug.h" #include "util/debug.h"
#include <api/fs/debugfs.h>
#include "util/tool.h" #include "util/tool.h"
#include "util/stat.h" #include "util/stat.h"
#include "util/top.h" #include "util/top.h"
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include "util/strfilter.h" #include "util/strfilter.h"
#include "util/symbol.h" #include "util/symbol.h"
#include "util/debug.h" #include "util/debug.h"
#include <api/fs/debugfs.h>
#include "util/parse-options.h" #include "util/parse-options.h"
#include "util/probe-finder.h" #include "util/probe-finder.h"
#include "util/probe-event.h" #include "util/probe-event.h"
......
...@@ -62,6 +62,7 @@ struct report { ...@@ -62,6 +62,7 @@ struct report {
float min_percent; float min_percent;
u64 nr_entries; u64 nr_entries;
u64 queue_size; u64 queue_size;
int socket_filter;
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
}; };
...@@ -286,6 +287,7 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report ...@@ -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); struct perf_evsel *evsel = hists_to_evsel(hists);
char buf[512]; char buf[512];
size_t size = sizeof(buf); size_t size = sizeof(buf);
int socked_id = hists->socket_filter;
if (symbol_conf.filter_relative) { if (symbol_conf.filter_relative) {
nr_samples = hists->stats.nr_non_filtered_samples; 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 ...@@ -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); ret += fprintf(fp, "\n# Sort order : %s", sort_order ? : default_mem_sort_order);
} else } else
ret += fprintf(fp, "\n# Event count (approx.): %" PRIu64, nr_events); 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"); return ret + fprintf(fp, "\n#\n");
} }
...@@ -450,6 +456,8 @@ static void report__collapse_hists(struct report *rep) ...@@ -450,6 +456,8 @@ static void report__collapse_hists(struct report *rep)
if (pos->idx == 0) if (pos->idx == 0)
hists->symbol_filter_str = rep->symbol_filter_str; hists->symbol_filter_str = rep->symbol_filter_str;
hists->socket_filter = rep->socket_filter;
hists__collapse_resort(hists, &prog); hists__collapse_resort(hists, &prog);
/* Non-group events are considered as leader */ /* Non-group events are considered as leader */
...@@ -635,6 +643,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -635,6 +643,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
}, },
.max_stack = PERF_MAX_STACK_DEPTH, .max_stack = PERF_MAX_STACK_DEPTH,
.pretty_printing_style = "normal", .pretty_printing_style = "normal",
.socket_filter = -1,
}; };
const struct option options[] = { const struct option options[] = {
OPT_STRING('i', "input", &input_name, "file", OPT_STRING('i', "input", &input_name, "file",
...@@ -747,6 +756,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -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"), "Show full source file name path for source lines"),
OPT_BOOLEAN(0, "show-ref-call-graph", &symbol_conf.show_ref_callgraph, OPT_BOOLEAN(0, "show-ref-call-graph", &symbol_conf.show_ref_callgraph,
"Show callgraph from reference event"), "Show callgraph from reference event"),
OPT_INTEGER(0, "socket-filter", &report.socket_filter,
"only show processor socket that match with this filter"),
OPT_END() OPT_END()
}; };
struct perf_data_file file = { struct perf_data_file file = {
......
...@@ -952,7 +952,7 @@ static int __cmd_top(struct perf_top *top) ...@@ -952,7 +952,7 @@ static int __cmd_top(struct perf_top *top)
machines__set_symbol_filter(&top->session->machines, symbol_filter); machines__set_symbol_filter(&top->session->machines, symbol_filter);
if (!objdump_path) { if (!objdump_path) {
ret = perf_session_env__lookup_objdump(&top->session->header.env); ret = perf_env__lookup_objdump(&top->session->header.env);
if (ret) if (ret)
goto out_delete; goto out_delete;
} }
...@@ -963,6 +963,13 @@ static int __cmd_top(struct perf_top *top) ...@@ -963,6 +963,13 @@ static int __cmd_top(struct perf_top *top)
machine__synthesize_threads(&top->session->machines.host, &opts->target, machine__synthesize_threads(&top->session->machines.host, &opts->target,
top->evlist->threads, false, opts->proc_map_timeout); 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); ret = perf_top__start_counters(top);
if (ret) if (ret)
goto out_delete; goto out_delete;
...@@ -1020,6 +1027,14 @@ static int __cmd_top(struct perf_top *top) ...@@ -1020,6 +1027,14 @@ static int __cmd_top(struct perf_top *top)
top->session = NULL; top->session = NULL;
return ret; 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 static int
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
*/ */
#include "builtin.h" #include "builtin.h"
#include "util/env.h"
#include "util/exec_cmd.h" #include "util/exec_cmd.h"
#include "util/cache.h" #include "util/cache.h"
#include "util/quote.h" #include "util/quote.h"
...@@ -369,6 +370,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) ...@@ -369,6 +370,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
status = p->fn(argc, argv, prefix); status = p->fn(argc, argv, prefix);
exit_browser(status); exit_browser(status);
perf_env__exit(&perf_env);
if (status) if (status)
return status & 0xff; return status & 0xff;
......
...@@ -33,6 +33,7 @@ perf-y += parse-no-sample-id-all.o ...@@ -33,6 +33,7 @@ perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o perf-y += kmod-path.o
perf-y += thread-map.o perf-y += thread-map.o
perf-y += llvm.o perf-y += llvm.o
perf-y += topology.o
perf-$(CONFIG_X86) += perf-time-to-tsc.o perf-$(CONFIG_X86) += perf-time-to-tsc.o
ifdef CONFIG_AUXTRACE ifdef CONFIG_AUXTRACE
......
...@@ -186,12 +186,16 @@ static struct test { ...@@ -186,12 +186,16 @@ static struct test {
}, },
#endif #endif
#endif #endif
{
.desc = "Test topology in session",
.func = test_session_topology,
},
{ {
.func = NULL, .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; int i;
...@@ -208,7 +212,7 @@ static bool perf_test__matches(int curr, int argc, const char *argv[]) ...@@ -208,7 +212,7 @@ static bool perf_test__matches(int curr, int argc, const char *argv[])
continue; continue;
} }
if (strstr(tests[curr].desc, argv[i])) if (strstr(test->desc, argv[i]))
return true; return true;
} }
...@@ -245,27 +249,28 @@ static int run_test(struct test *test) ...@@ -245,27 +249,28 @@ static int run_test(struct test *test)
return err; 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) static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
{ {
struct test *t;
int i = 0; int i = 0;
int width = 0; int width = 0;
while (tests[i].func) { for_each_test(t) {
int len = strlen(tests[i].desc); int len = strlen(t->desc);
if (width < len) if (width < len)
width = len; width = len;
++i;
} }
i = 0; for_each_test(t) {
while (tests[i].func) {
int curr = i++, err; int curr = i++, err;
if (!perf_test__matches(curr, argc, argv)) if (!perf_test__matches(t, curr, argc, argv))
continue; continue;
pr_info("%2d: %-*s:", i, width, tests[curr].desc); pr_info("%2d: %-*s:", i, width, t->desc);
if (intlist__find(skiplist, i)) { if (intlist__find(skiplist, i)) {
color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip (user override)\n"); 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) ...@@ -273,8 +278,8 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
} }
pr_debug("\n--- start ---\n"); pr_debug("\n--- start ---\n");
err = run_test(&tests[curr]); err = run_test(t);
pr_debug("---- end ----\n%s:", tests[curr].desc); pr_debug("---- end ----\n%s:", t->desc);
switch (err) { switch (err) {
case TEST_OK: case TEST_OK:
...@@ -295,15 +300,14 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist) ...@@ -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) static int perf_test__list(int argc, const char **argv)
{ {
struct test *t;
int i = 0; int i = 0;
while (tests[i].func) { for_each_test(t) {
int curr = i++; if (argc > 1 && !strstr(t->desc, argv[1]))
if (argc > 1 && !strstr(tests[curr].desc, argv[1]))
continue; continue;
pr_info("%2d: %s\n", i, tests[curr].desc); pr_info("%2d: %s\n", ++i, t->desc);
} }
return 0; return 0;
......
...@@ -33,20 +33,20 @@ static unsigned int hex(char c) ...@@ -33,20 +33,20 @@ static unsigned int hex(char c)
return c - 'A' + 10; return c - 'A' + 10;
} }
static void read_objdump_line(const char *line, size_t line_len, void **buf, static size_t read_objdump_line(const char *line, size_t line_len, void *buf,
size_t *len) size_t len)
{ {
const char *p; const char *p;
size_t i; size_t i, j = 0;
/* Skip to a colon */ /* Skip to a colon */
p = strchr(line, ':'); p = strchr(line, ':');
if (!p) if (!p)
return; return 0;
i = p + 1 - line; i = p + 1 - line;
/* Read bytes */ /* Read bytes */
while (*len) { while (j < len) {
char c1, c2; char c1, c2;
/* Skip spaces */ /* Skip spaces */
...@@ -65,20 +65,26 @@ static void read_objdump_line(const char *line, size_t line_len, void **buf, ...@@ -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])) if (i < line_len && line[i] && !isspace(line[i]))
break; break;
/* Store byte */ /* Store byte */
*(unsigned char *)*buf = (hex(c1) << 4) | hex(c2); *(unsigned char *)buf = (hex(c1) << 4) | hex(c2);
*buf += 1; buf += 1;
*len -= 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; char *line = NULL;
size_t line_len; size_t line_len, off_last = 0;
ssize_t ret; ssize_t ret;
int err = 0; 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); ret = getline(&line, &line_len, f);
if (feof(f)) if (feof(f))
break; break;
...@@ -87,9 +93,33 @@ static int read_objdump_output(FILE *f, void **buf, size_t *len) ...@@ -87,9 +93,33 @@ static int read_objdump_output(FILE *f, void **buf, size_t *len)
err = -1; err = -1;
break; 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); free(line);
return err; return err;
...@@ -103,7 +133,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf, ...@@ -103,7 +133,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
FILE *f; FILE *f;
int ret; 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, ret = snprintf(cmd, sizeof(cmd), fmt, "objdump", addr, addr + len,
filename); filename);
if (ret <= 0 || (size_t)ret >= sizeof(cmd)) if (ret <= 0 || (size_t)ret >= sizeof(cmd))
...@@ -120,7 +150,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf, ...@@ -120,7 +150,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
return -1; return -1;
} }
ret = read_objdump_output(f, &buf, &len); ret = read_objdump_output(f, buf, &len, addr);
if (len) { if (len) {
pr_debug("objdump read too few bytes\n"); pr_debug("objdump read too few bytes\n");
if (!ret) if (!ret)
...@@ -132,6 +162,18 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf, ...@@ -132,6 +162,18 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
return ret; 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, static int read_object_code(u64 addr, size_t len, u8 cpumode,
struct thread *thread, struct state *state) struct thread *thread, struct state *state)
{ {
...@@ -234,6 +276,10 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode, ...@@ -234,6 +276,10 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
/* The results should be identical */ /* The results should be identical */
if (memcmp(buf1, buf2, len)) { if (memcmp(buf1, buf2, len)) {
pr_debug("Bytes read differ from those read by objdump\n"); 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; return -1;
} }
pr_debug("Bytes read match those read by objdump\n"); pr_debug("Bytes read match those read by objdump\n");
......
...@@ -16,30 +16,31 @@ struct sample { ...@@ -16,30 +16,31 @@ struct sample {
struct thread *thread; struct thread *thread;
struct map *map; struct map *map;
struct symbol *sym; struct symbol *sym;
int socket;
}; };
/* For the numbers, see hists_common.c */ /* For the numbers, see hists_common.c */
static struct sample fake_samples[] = { static struct sample fake_samples[] = {
/* perf [kernel] schedule() */ /* 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() */ /* 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() */ /* 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() */ /* 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() */ /* 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() */ /* 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() */ /* 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() */ /* 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() */ /* 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() */ /* 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, static int add_hist_entries(struct perf_evlist *evlist,
...@@ -83,6 +84,7 @@ static int add_hist_entries(struct perf_evlist *evlist, ...@@ -83,6 +84,7 @@ static int add_hist_entries(struct perf_evlist *evlist,
&sample) < 0) &sample) < 0)
goto out; goto out;
al.socket = fake_samples[i].socket;
if (hist_entry_iter__add(&iter, &al, if (hist_entry_iter__add(&iter, &al,
PERF_MAX_STACK_DEPTH, NULL) < 0) { PERF_MAX_STACK_DEPTH, NULL) < 0) {
addr_location__put(&al); addr_location__put(&al);
...@@ -253,6 +255,39 @@ int test__hists_filter(void) ...@@ -253,6 +255,39 @@ int test__hists_filter(void)
TEST_ASSERT_VAL("Unmatched total period for symbol filter", TEST_ASSERT_VAL("Unmatched total period for symbol filter",
hists->stats.total_non_filtered_period == 300); 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. */ /* now applying all filters at once. */
hists->thread_filter = fake_samples[1].thread; hists->thread_filter = fake_samples[1].thread;
hists->dso_filter = fake_samples[1].map->dso; hists->dso_filter = fake_samples[1].map->dso;
......
#include <api/fs/fs.h>
#include "evsel.h" #include "evsel.h"
#include "tests.h" #include "tests.h"
#include "thread_map.h" #include "thread_map.h"
...@@ -14,6 +15,7 @@ int test__openat_syscall_event_on_all_cpus(void) ...@@ -14,6 +15,7 @@ int test__openat_syscall_event_on_all_cpus(void)
cpu_set_t cpu_set; cpu_set_t cpu_set;
struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
char sbuf[STRERR_BUFSIZE]; char sbuf[STRERR_BUFSIZE];
char errbuf[BUFSIZ];
if (threads == NULL) { if (threads == NULL) {
pr_debug("thread_map__new\n"); pr_debug("thread_map__new\n");
...@@ -30,12 +32,8 @@ int test__openat_syscall_event_on_all_cpus(void) ...@@ -30,12 +32,8 @@ int test__openat_syscall_event_on_all_cpus(void)
evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); evsel = perf_evsel__newtp("syscalls", "sys_enter_openat");
if (evsel == NULL) { if (evsel == NULL) {
if (tracefs_configured()) tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat");
pr_debug("is tracefs mounted on /sys/kernel/tracing?\n"); pr_err("%s\n", errbuf);
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");
goto out_thread_map_delete; goto out_thread_map_delete;
} }
......
#include <api/fs/tracing_path.h>
#include "thread_map.h" #include "thread_map.h"
#include "evsel.h" #include "evsel.h"
#include "debug.h" #include "debug.h"
...@@ -10,6 +11,7 @@ int test__openat_syscall_event(void) ...@@ -10,6 +11,7 @@ int test__openat_syscall_event(void)
unsigned int nr_openat_calls = 111, i; unsigned int nr_openat_calls = 111, i;
struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX); struct thread_map *threads = thread_map__new(-1, getpid(), UINT_MAX);
char sbuf[STRERR_BUFSIZE]; char sbuf[STRERR_BUFSIZE];
char errbuf[BUFSIZ];
if (threads == NULL) { if (threads == NULL) {
pr_debug("thread_map__new\n"); pr_debug("thread_map__new\n");
...@@ -18,12 +20,8 @@ int test__openat_syscall_event(void) ...@@ -18,12 +20,8 @@ int test__openat_syscall_event(void)
evsel = perf_evsel__newtp("syscalls", "sys_enter_openat"); evsel = perf_evsel__newtp("syscalls", "sys_enter_openat");
if (evsel == NULL) { if (evsel == NULL) {
if (tracefs_configured()) tracing_path__strerror_open_tp(errno, errbuf, sizeof(errbuf), "syscalls", "sys_enter_openat");
pr_debug("is tracefs mounted on /sys/kernel/tracing?\n"); pr_err("%s\n", errbuf);
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");
goto out_thread_map_delete; goto out_thread_map_delete;
} }
......
...@@ -3,11 +3,10 @@ ...@@ -3,11 +3,10 @@
#include "evsel.h" #include "evsel.h"
#include "evlist.h" #include "evlist.h"
#include <api/fs/fs.h> #include <api/fs/fs.h>
#include <api/fs/tracefs.h>
#include <api/fs/debugfs.h>
#include "tests.h" #include "tests.h"
#include "debug.h" #include "debug.h"
#include <linux/hw_breakpoint.h> #include <linux/hw_breakpoint.h>
#include <api/fs/fs.h>
#define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \ #define PERF_TP_SAMPLE_TYPE (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | \
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD) PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)
...@@ -1262,23 +1261,11 @@ test__checkevent_breakpoint_len_rw_modifier(struct perf_evlist *evlist) ...@@ -1262,23 +1261,11 @@ test__checkevent_breakpoint_len_rw_modifier(struct perf_evlist *evlist)
static int count_tracepoints(void) static int count_tracepoints(void)
{ {
char events_path[PATH_MAX];
struct dirent *events_ent; struct dirent *events_ent;
const char *mountpoint;
DIR *events_dir; DIR *events_dir;
int cnt = 0; int cnt = 0;
mountpoint = tracefs_find_mountpoint(); events_dir = opendir(tracing_events_path);
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);
TEST_ASSERT_VAL("Can't open events dir", events_dir); TEST_ASSERT_VAL("Can't open events dir", events_dir);
...@@ -1295,7 +1282,7 @@ static int count_tracepoints(void) ...@@ -1295,7 +1282,7 @@ static int count_tracepoints(void)
continue; continue;
scnprintf(sys_path, PATH_MAX, "%s/%s", 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); sys_dir = opendir(sys_path);
TEST_ASSERT_VAL("Can't open sys dir", sys_dir); TEST_ASSERT_VAL("Can't open sys dir", sys_dir);
......
...@@ -64,6 +64,7 @@ int test__kmod_path__parse(void); ...@@ -64,6 +64,7 @@ int test__kmod_path__parse(void);
int test__thread_map(void); int test__thread_map(void);
int test__llvm(void); int test__llvm(void);
int test__insn_x86(void); int test__insn_x86(void);
int test_session_topology(void);
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT #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, ...@@ -1261,6 +1261,7 @@ static int hists__browser_title(struct hists *hists,
int printed; int printed;
const struct dso *dso = hists->dso_filter; const struct dso *dso = hists->dso_filter;
const struct thread *thread = hists->thread_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]; unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE];
u64 nr_events = hists->stats.total_period; u64 nr_events = hists->stats.total_period;
struct perf_evsel *evsel = hists_to_evsel(hists); struct perf_evsel *evsel = hists_to_evsel(hists);
...@@ -1314,6 +1315,9 @@ static int hists__browser_title(struct hists *hists, ...@@ -1314,6 +1315,9 @@ static int hists__browser_title(struct hists *hists,
if (dso) if (dso)
printed += scnprintf(bf + printed, size - printed, printed += scnprintf(bf + printed, size - printed,
", DSO: %s", dso->short_name); ", 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)) { if (!is_report_browser(hbt)) {
struct perf_top *top = hbt->arg; struct perf_top *top = hbt->arg;
...@@ -1425,6 +1429,7 @@ struct popup_action { ...@@ -1425,6 +1429,7 @@ struct popup_action {
struct thread *thread; struct thread *thread;
struct dso *dso; struct dso *dso;
struct map_symbol ms; struct map_symbol ms;
int socket;
int (*fn)(struct hist_browser *browser, struct popup_action *act); int (*fn)(struct hist_browser *browser, struct popup_action *act);
}; };
...@@ -1437,7 +1442,7 @@ do_annotate(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; struct hist_entry *he;
int err; int err;
if (!objdump_path && perf_session_env__lookup_objdump(browser->env)) if (!objdump_path && perf_env__lookup_objdump(browser->env))
return 0; return 0;
notes = symbol__annotation(act->ms.sym); notes = symbol__annotation(act->ms.sym);
...@@ -1672,6 +1677,41 @@ add_exit_opt(struct hist_browser *browser __maybe_unused, ...@@ -1672,6 +1677,41 @@ add_exit_opt(struct hist_browser *browser __maybe_unused,
return 1; 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) static void hist_browser__update_nr_entries(struct hist_browser *hb)
{ {
u64 nr_entries = 0; u64 nr_entries = 0;
...@@ -1725,6 +1765,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1725,6 +1765,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
"E Expand all callchains\n" \ "E Expand all callchains\n" \
"F Toggle percentage of filtered entries\n" \ "F Toggle percentage of filtered entries\n" \
"H Display column headers\n" \ "H Display column headers\n" \
"S Zoom into current Processor Socket\n" \
/* help messages are sorted by lexical order of the hotkey */ /* help messages are sorted by lexical order of the hotkey */
const char report_help[] = HIST_BROWSER_HELP_COMMON 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, ...@@ -1755,7 +1796,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
hist_browser__update_nr_entries(browser); hist_browser__update_nr_entries(browser);
} }
browser->pstack = pstack__new(2); browser->pstack = pstack__new(3);
if (browser->pstack == NULL) if (browser->pstack == NULL)
goto out; goto out;
...@@ -1774,6 +1815,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1774,6 +1815,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
struct thread *thread = NULL; struct thread *thread = NULL;
struct dso *dso = NULL; struct dso *dso = NULL;
int choice = 0; int choice = 0;
int socked_id = -1;
nr_options = 0; nr_options = 0;
...@@ -1782,6 +1824,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1782,6 +1824,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (browser->he_selection != NULL) { if (browser->he_selection != NULL) {
thread = hist_browser__selected_thread(browser); thread = hist_browser__selected_thread(browser);
dso = browser->selection->map ? browser->selection->map->dso : NULL; dso = browser->selection->map ? browser->selection->map->dso : NULL;
socked_id = browser->he_selection->socket;
} }
switch (key) { switch (key) {
case K_TAB: case K_TAB:
...@@ -1824,6 +1867,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1824,6 +1867,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
actions->thread = thread; actions->thread = thread;
do_zoom_thread(browser, actions); do_zoom_thread(browser, actions);
continue; continue;
case 'S':
actions->socket = socked_id;
do_zoom_socket(browser, actions);
continue;
case '/': case '/':
if (ui_browser__input_window("Symbol to show", if (ui_browser__input_window("Symbol to show",
"Please enter the name of symbol you want to see", "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, ...@@ -1899,9 +1946,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
* Ditto for thread below. * Ditto for thread below.
*/ */
do_zoom_dso(browser, actions); do_zoom_dso(browser, actions);
} } else if (top == &browser->hists->thread_filter) {
if (top == &browser->hists->thread_filter)
do_zoom_thread(browser, actions); do_zoom_thread(browser, actions);
} else if (top == &browser->hists->socket_filter) {
do_zoom_socket(browser, actions);
}
continue; continue;
} }
case 'q': case 'q':
...@@ -1969,7 +2018,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -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], nr_options += add_map_opt(browser, &actions[nr_options],
&options[nr_options], &options[nr_options],
browser->selection->map); browser->selection->map);
nr_options += add_socket_opt(browser, &actions[nr_options],
&options[nr_options],
socked_id);
/* perf script support */ /* perf script support */
if (browser->he_selection) { if (browser->he_selection) {
nr_options += add_script_opt(browser, nr_options += add_script_opt(browser,
......
...@@ -5,6 +5,7 @@ libperf-y += build-id.o ...@@ -5,6 +5,7 @@ libperf-y += build-id.o
libperf-y += config.o libperf-y += config.o
libperf-y += ctype.o libperf-y += ctype.o
libperf-y += db-export.o libperf-y += db-export.o
libperf-y += env.o
libperf-y += environment.o libperf-y += environment.o
libperf-y += event.o libperf-y += event.o
libperf-y += evlist.o libperf-y += evlist.o
......
...@@ -225,28 +225,20 @@ void cpu_map__put(struct cpu_map *map) ...@@ -225,28 +225,20 @@ void cpu_map__put(struct cpu_map *map)
cpu_map__delete(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]; char path[PATH_MAX];
int socket_id, ret;
mnt = sysfs__mountpoint();
if (!mnt)
return -1;
snprintf(path, PATH_MAX, snprintf(path, PATH_MAX,
"%s/devices/system/cpu/cpu%d/topology/physical_package_id", "devices/system/cpu/cpu%d/topology/%s", cpu, name);
mnt, cpu);
fp = fopen(path, "r"); return sysfs__read_int(path, value);
if (!fp) }
return -1;
ret = fscanf(fp, "%d", &socket_id);
fclose(fp);
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) 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, ...@@ -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) int cpu_map__get_core_id(int cpu)
{ {
FILE *fp; int value, ret = cpu__get_topology_int(cpu, "core_id", &value);
const char *mnt; return ret ?: value;
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 cpu_map__get_core(struct cpu_map *map, int idx) 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, ...@@ -1021,6 +1021,14 @@ int perf_event__preprocess_sample(const union perf_event *event,
al->sym = NULL; al->sym = NULL;
al->cpu = sample->cpu; 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) { if (al->map) {
struct dso *dso = al->map->dso; struct dso *dso = al->map->dso;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#include <byteswap.h> #include <byteswap.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <api/fs/debugfs.h> #include <api/fs/tracing_path.h>
#include <traceevent/event-parse.h> #include <traceevent/event-parse.h>
#include <linux/hw_breakpoint.h> #include <linux/hw_breakpoint.h>
#include <linux/perf_event.h> #include <linux/perf_event.h>
......
...@@ -129,7 +129,6 @@ union u64_swap { ...@@ -129,7 +129,6 @@ union u64_swap {
struct cpu_map; struct cpu_map;
struct target; struct target;
struct thread_map; struct thread_map;
struct perf_evlist;
struct record_opts; struct record_opts;
static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel) static inline struct cpu_map *perf_evsel__cpus(struct perf_evsel *evsel)
......
...@@ -24,9 +24,6 @@ ...@@ -24,9 +24,6 @@
#include "build-id.h" #include "build-id.h"
#include "data.h" #include "data.h"
static u32 header_argc;
static const char **header_argv;
/* /*
* magic2 = "PERFILE2" * magic2 = "PERFILE2"
* must be a numerical value to let the endianness * must be a numerical value to let the endianness
...@@ -138,37 +135,6 @@ static char *do_read_string(int fd, struct perf_header *ph) ...@@ -138,37 +135,6 @@ static char *do_read_string(int fd, struct perf_header *ph)
return NULL; 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, static int write_tracing_data(int fd, struct perf_header *h __maybe_unused,
struct perf_evlist *evlist) struct perf_evlist *evlist)
{ {
...@@ -405,8 +371,8 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, ...@@ -405,8 +371,8 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
{ {
char buf[MAXPATHLEN]; char buf[MAXPATHLEN];
char proc[32]; char proc[32];
u32 i, n; u32 n;
int ret; int i, ret;
/* /*
* actual atual path to perf binary * actual atual path to perf binary
...@@ -420,7 +386,7 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, ...@@ -420,7 +386,7 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
buf[ret] = '\0'; buf[ret] = '\0';
/* account for binary path */ /* account for binary path */
n = header_argc + 1; n = perf_env.nr_cmdline + 1;
ret = do_write(fd, &n, sizeof(n)); ret = do_write(fd, &n, sizeof(n));
if (ret < 0) if (ret < 0)
...@@ -430,8 +396,8 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused, ...@@ -430,8 +396,8 @@ static int write_cmdline(int fd, struct perf_header *h __maybe_unused,
if (ret < 0) if (ret < 0)
return ret; return ret;
for (i = 0 ; i < header_argc; i++) { for (i = 0 ; i < perf_env.nr_cmdline; i++) {
ret = do_write_string(fd, header_argv[i]); ret = do_write_string(fd, perf_env.cmdline_argv[i]);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
...@@ -449,8 +415,6 @@ struct cpu_topo { ...@@ -449,8 +415,6 @@ struct cpu_topo {
u32 thread_sib; u32 thread_sib;
char **core_siblings; char **core_siblings;
char **thread_siblings; char **thread_siblings;
int *core_id;
int *phy_pkg_id;
}; };
static int build_cpu_topo(struct cpu_topo *tp, int cpu) 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) ...@@ -513,9 +477,6 @@ static int build_cpu_topo(struct cpu_topo *tp, int cpu)
} }
ret = 0; ret = 0;
done: done:
tp->core_id[cpu] = cpu_map__get_core_id(cpu);
tp->phy_pkg_id[cpu] = cpu_map__get_socket_id(cpu);
if(fp) if(fp)
fclose(fp); fclose(fp);
free(buf); free(buf);
...@@ -543,7 +504,7 @@ static struct cpu_topo *build_cpu_topology(void) ...@@ -543,7 +504,7 @@ static struct cpu_topo *build_cpu_topology(void)
struct cpu_topo *tp; struct cpu_topo *tp;
void *addr; void *addr;
u32 nr, i; u32 nr, i;
size_t sz, sz_id; size_t sz;
long ncpus; long ncpus;
int ret = -1; int ret = -1;
...@@ -554,9 +515,8 @@ static struct cpu_topo *build_cpu_topology(void) ...@@ -554,9 +515,8 @@ static struct cpu_topo *build_cpu_topology(void)
nr = (u32)(ncpus & UINT_MAX); nr = (u32)(ncpus & UINT_MAX);
sz = nr * sizeof(char *); 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) if (!addr)
return NULL; return NULL;
...@@ -566,10 +526,6 @@ static struct cpu_topo *build_cpu_topology(void) ...@@ -566,10 +526,6 @@ static struct cpu_topo *build_cpu_topology(void)
tp->core_siblings = addr; tp->core_siblings = addr;
addr += sz; addr += sz;
tp->thread_siblings = addr; tp->thread_siblings = addr;
addr += sz;
tp->core_id = addr;
addr += sz_id;
tp->phy_pkg_id = addr;
for (i = 0; i < nr; i++) { for (i = 0; i < nr; i++) {
ret = build_cpu_topo(tp, i); ret = build_cpu_topo(tp, i);
...@@ -588,7 +544,7 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused, ...@@ -588,7 +544,7 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused,
{ {
struct cpu_topo *tp; struct cpu_topo *tp;
u32 i; u32 i;
int ret; int ret, j;
tp = build_cpu_topology(); tp = build_cpu_topology();
if (!tp) if (!tp)
...@@ -613,11 +569,17 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused, ...@@ -613,11 +569,17 @@ static int write_cpu_topology(int fd, struct perf_header *h __maybe_unused,
break; break;
} }
for (i = 0; i < tp->cpu_nr; i++) { ret = perf_env__read_cpu_topology_map(&perf_env);
ret = do_write(fd, &tp->core_id[i], sizeof(int)); 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) if (ret < 0)
return ret; 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) if (ret < 0)
return ret; return ret;
} }
...@@ -1821,6 +1783,9 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused ...@@ -1821,6 +1783,9 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused
/* include a NULL character at the end */ /* include a NULL character at the end */
strbuf_add(&sb, "", 1); strbuf_add(&sb, "", 1);
if (!strcmp(name, "msr"))
ph->env.msr_pmu_type = type;
free(name); free(name);
pmu_num--; pmu_num--;
} }
...@@ -2599,6 +2564,7 @@ int perf_session__read_header(struct perf_session *session) ...@@ -2599,6 +2564,7 @@ int perf_session__read_header(struct perf_session *session)
return -ENOMEM; return -ENOMEM;
session->evlist->env = &header->env; session->evlist->env = &header->env;
session->machines.host.env = &header->env;
if (perf_data_file__is_pipe(file)) if (perf_data_file__is_pipe(file))
return perf_header__read_pipe(session); return perf_header__read_pipe(session);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/types.h> #include <linux/types.h>
#include "event.h" #include "event.h"
#include "env.h"
enum { enum {
HEADER_RESERVED = 0, /* always cleared */ HEADER_RESERVED = 0, /* always cleared */
...@@ -66,37 +66,6 @@ struct perf_header; ...@@ -66,37 +66,6 @@ struct perf_header;
int perf_file_header__read(struct perf_file_header *header, int perf_file_header__read(struct perf_file_header *header,
struct perf_header *ph, int fd); 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 { struct perf_header {
enum perf_header_version version; enum perf_header_version version;
bool needs_swap; bool needs_swap;
......
...@@ -15,6 +15,8 @@ static bool hists__filter_entry_by_thread(struct hists *hists, ...@@ -15,6 +15,8 @@ static bool hists__filter_entry_by_thread(struct hists *hists,
struct hist_entry *he); struct hist_entry *he);
static bool hists__filter_entry_by_symbol(struct hists *hists, static bool hists__filter_entry_by_symbol(struct hists *hists,
struct hist_entry *he); 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) 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) ...@@ -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__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_LOCKED, 6);
hists__new_col_len(hists, HISTC_MEM_TLB, 22); hists__new_col_len(hists, HISTC_MEM_TLB, 22);
hists__new_col_len(hists, HISTC_MEM_SNOOP, 12); hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
...@@ -452,6 +456,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists, ...@@ -452,6 +456,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
.map = al->map, .map = al->map,
.sym = al->sym, .sym = al->sym,
}, },
.socket = al->socket,
.cpu = al->cpu, .cpu = al->cpu,
.cpumode = al->cpumode, .cpumode = al->cpumode,
.ip = al->addr, .ip = al->addr,
...@@ -1024,6 +1029,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he) ...@@ -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_dso(hists, he);
hists__filter_entry_by_thread(hists, he); hists__filter_entry_by_thread(hists, he);
hists__filter_entry_by_symbol(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) void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
...@@ -1292,6 +1298,37 @@ void hists__filter_by_symbol(struct hists *hists) ...@@ -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) void events_stats__inc(struct events_stats *stats, u32 type)
{ {
++stats->nr_events[0]; ++stats->nr_events[0];
...@@ -1517,6 +1554,7 @@ static int hists_evsel__init(struct perf_evsel *evsel) ...@@ -1517,6 +1554,7 @@ static int hists_evsel__init(struct perf_evsel *evsel)
hists->entries_collapsed = RB_ROOT; hists->entries_collapsed = RB_ROOT;
hists->entries = RB_ROOT; hists->entries = RB_ROOT;
pthread_mutex_init(&hists->lock, NULL); pthread_mutex_init(&hists->lock, NULL);
hists->socket_filter = -1;
return 0; return 0;
} }
......
...@@ -20,6 +20,7 @@ enum hist_filter { ...@@ -20,6 +20,7 @@ enum hist_filter {
HIST_FILTER__SYMBOL, HIST_FILTER__SYMBOL,
HIST_FILTER__GUEST, HIST_FILTER__GUEST,
HIST_FILTER__HOST, HIST_FILTER__HOST,
HIST_FILTER__SOCKET,
}; };
enum hist_column { enum hist_column {
...@@ -29,6 +30,7 @@ enum hist_column { ...@@ -29,6 +30,7 @@ enum hist_column {
HISTC_COMM, HISTC_COMM,
HISTC_PARENT, HISTC_PARENT,
HISTC_CPU, HISTC_CPU,
HISTC_SOCKET,
HISTC_SRCLINE, HISTC_SRCLINE,
HISTC_SRCFILE, HISTC_SRCFILE,
HISTC_MISPREDICT, HISTC_MISPREDICT,
...@@ -70,6 +72,7 @@ struct hists { ...@@ -70,6 +72,7 @@ struct hists {
struct events_stats stats; struct events_stats stats;
u64 event_stream; u64 event_stream;
u16 col_len[HISTC_NR_COLS]; u16 col_len[HISTC_NR_COLS];
int socket_filter;
}; };
struct hist_entry_iter; struct hist_entry_iter;
...@@ -144,11 +147,12 @@ size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp); ...@@ -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_dso(struct hists *hists);
void hists__filter_by_thread(struct hists *hists); void hists__filter_by_thread(struct hists *hists);
void hists__filter_by_symbol(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) static inline bool hists__has_filter(struct hists *hists)
{ {
return hists->thread_filter || hists->dso_filter || 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); 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) ...@@ -35,6 +35,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
machine->last_match = NULL; machine->last_match = NULL;
machine->vdso_info = NULL; machine->vdso_info = NULL;
machine->env = NULL;
machine->pid = pid; machine->pid = pid;
......
...@@ -34,6 +34,7 @@ struct machine { ...@@ -34,6 +34,7 @@ struct machine {
struct list_head dead_threads; struct list_head dead_threads;
struct thread *last_match; struct thread *last_match;
struct vdso_info *vdso_info; struct vdso_info *vdso_info;
struct perf_env *env;
struct dsos dsos; struct dsos dsos;
struct map_groups kmaps; struct map_groups kmaps;
struct map *vmlinux_maps[MAP__NR_TYPES]; struct map *vmlinux_maps[MAP__NR_TYPES];
......
...@@ -496,7 +496,7 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o ...@@ -496,7 +496,7 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
{ {
struct parse_opt_ctx_t ctx; 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 */ /* build usage string if it's not provided */
if (subcommands && !usagestr[0]) { if (subcommands && !usagestr[0]) {
......
...@@ -40,8 +40,7 @@ ...@@ -40,8 +40,7 @@
#include "color.h" #include "color.h"
#include "symbol.h" #include "symbol.h"
#include "thread.h" #include "thread.h"
#include <api/fs/debugfs.h> #include <api/fs/fs.h>
#include <api/fs/tracefs.h>
#include "trace-event.h" /* For __maybe_unused */ #include "trace-event.h" /* For __maybe_unused */
#include "probe-event.h" #include "probe-event.h"
#include "probe-finder.h" #include "probe-finder.h"
...@@ -2054,7 +2053,7 @@ static void kprobe_blacklist__delete(struct list_head *blacklist) ...@@ -2054,7 +2053,7 @@ static void kprobe_blacklist__delete(struct list_head *blacklist)
static int kprobe_blacklist__load(struct list_head *blacklist) static int kprobe_blacklist__load(struct list_head *blacklist)
{ {
struct kprobe_blacklist_node *node; struct kprobe_blacklist_node *node;
const char *__debugfs = debugfs_find_mountpoint(); const char *__debugfs = debugfs__mountpoint();
char buf[PATH_MAX], *p; char buf[PATH_MAX], *p;
FILE *fp; FILE *fp;
int ret; int ret;
......
...@@ -22,8 +22,7 @@ ...@@ -22,8 +22,7 @@
#include "color.h" #include "color.h"
#include "symbol.h" #include "symbol.h"
#include "thread.h" #include "thread.h"
#include <api/fs/debugfs.h> #include <api/fs/tracing_path.h>
#include <api/fs/tracefs.h>
#include "probe-event.h" #include "probe-event.h"
#include "probe-file.h" #include "probe-file.h"
#include "session.h" #include "session.h"
...@@ -73,21 +72,11 @@ static void print_both_open_warning(int kerr, int uerr) ...@@ -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) static int open_probe_events(const char *trace_file, bool readwrite)
{ {
char buf[PATH_MAX]; char buf[PATH_MAX];
const char *__debugfs;
const char *tracing_dir = ""; const char *tracing_dir = "";
int ret; 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", ret = e_snprintf(buf, PATH_MAX, "%s/%s%s",
__debugfs, tracing_dir, trace_file); tracing_path, tracing_dir, trace_file);
if (ret >= 0) { if (ret >= 0) {
pr_debug("Opening %s write=%d\n", buf, readwrite); pr_debug("Opening %s write=%d\n", buf, readwrite);
if (readwrite && !probe_event_dry_run) if (readwrite && !probe_event_dry_run)
......
...@@ -138,6 +138,8 @@ struct perf_session *perf_session__new(struct perf_data_file *file, ...@@ -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_id_hdr_size(session);
perf_session__set_comm_exec(session); perf_session__set_comm_exec(session);
} }
} else {
session->machines.host.env = &perf_env;
} }
if (!file || perf_data_file__is_write(file)) { if (!file || perf_data_file__is_write(file)) {
...@@ -170,31 +172,13 @@ static void perf_session__delete_threads(struct perf_session *session) ...@@ -170,31 +172,13 @@ static void perf_session__delete_threads(struct perf_session *session)
machine__delete_threads(&session->machines.host); 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) void perf_session__delete(struct perf_session *session)
{ {
auxtrace__free(session); auxtrace__free(session);
auxtrace_index__free(&session->auxtrace_index); auxtrace_index__free(&session->auxtrace_index);
perf_session__destroy_kernel_maps(session); perf_session__destroy_kernel_maps(session);
perf_session__delete_threads(session); perf_session__delete_threads(session);
perf_session_env__exit(&session->header.env); perf_env__exit(&session->header.env);
machines__exit(&session->machines); machines__exit(&session->machines);
if (session->file) if (session->file)
perf_data_file__close(session->file); perf_data_file__close(session->file);
......
...@@ -21,6 +21,7 @@ int sort__need_collapse = 0; ...@@ -21,6 +21,7 @@ int sort__need_collapse = 0;
int sort__has_parent = 0; int sort__has_parent = 0;
int sort__has_sym = 0; int sort__has_sym = 0;
int sort__has_dso = 0; int sort__has_dso = 0;
int sort__has_socket = 0;
enum sort_mode sort__mode = SORT_MODE__NORMAL; enum sort_mode sort__mode = SORT_MODE__NORMAL;
...@@ -421,6 +422,27 @@ struct sort_entry sort_cpu = { ...@@ -421,6 +422,27 @@ struct sort_entry sort_cpu = {
.se_width_idx = HISTC_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 */ /* sort keys for branch stacks */
static int64_t static int64_t
...@@ -1248,6 +1270,7 @@ static struct sort_dimension common_sort_dimensions[] = { ...@@ -1248,6 +1270,7 @@ static struct sort_dimension common_sort_dimensions[] = {
DIM(SORT_SYM, "symbol", sort_sym), DIM(SORT_SYM, "symbol", sort_sym),
DIM(SORT_PARENT, "parent", sort_parent), DIM(SORT_PARENT, "parent", sort_parent),
DIM(SORT_CPU, "cpu", sort_cpu), DIM(SORT_CPU, "cpu", sort_cpu),
DIM(SORT_SOCKET, "socket", sort_socket),
DIM(SORT_SRCLINE, "srcline", sort_srcline), DIM(SORT_SRCLINE, "srcline", sort_srcline),
DIM(SORT_SRCFILE, "srcfile", sort_srcfile), DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
...@@ -1550,6 +1573,8 @@ int sort_dimension__add(const char *tok) ...@@ -1550,6 +1573,8 @@ int sort_dimension__add(const char *tok)
} else if (sd->entry == &sort_dso) { } else if (sd->entry == &sort_dso) {
sort__has_dso = 1; sort__has_dso = 1;
} else if (sd->entry == &sort_socket) {
sort__has_socket = 1;
} }
return __sort_dimension__add(sd); return __sort_dimension__add(sd);
......
...@@ -34,6 +34,7 @@ extern int have_ignore_callees; ...@@ -34,6 +34,7 @@ extern int have_ignore_callees;
extern int sort__need_collapse; extern int sort__need_collapse;
extern int sort__has_parent; extern int sort__has_parent;
extern int sort__has_sym; extern int sort__has_sym;
extern int sort__has_socket;
extern enum sort_mode sort__mode; extern enum sort_mode sort__mode;
extern struct sort_entry sort_comm; extern struct sort_entry sort_comm;
extern struct sort_entry sort_dso; extern struct sort_entry sort_dso;
...@@ -90,6 +91,7 @@ struct hist_entry { ...@@ -90,6 +91,7 @@ struct hist_entry {
struct comm *comm; struct comm *comm;
u64 ip; u64 ip;
u64 transaction; u64 transaction;
s32 socket;
s32 cpu; s32 cpu;
u8 cpumode; u8 cpumode;
...@@ -172,6 +174,7 @@ enum sort_type { ...@@ -172,6 +174,7 @@ enum sort_type {
SORT_SYM, SORT_SYM,
SORT_PARENT, SORT_PARENT,
SORT_CPU, SORT_CPU,
SORT_SOCKET,
SORT_SRCLINE, SORT_SRCLINE,
SORT_SRCFILE, SORT_SRCFILE,
SORT_LOCAL_WEIGHT, SORT_LOCAL_WEIGHT,
......
...@@ -191,6 +191,7 @@ struct addr_location { ...@@ -191,6 +191,7 @@ struct addr_location {
u8 filtered; u8 filtered;
u8 cpumode; u8 cpumode;
s32 cpu; s32 cpu;
s32 socket;
}; };
struct symsrc { struct symsrc {
......
...@@ -74,8 +74,7 @@ ...@@ -74,8 +74,7 @@
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/types.h> #include <linux/types.h>
#include <sys/ttydefaults.h> #include <sys/ttydefaults.h>
#include <api/fs/debugfs.h> #include <api/fs/tracing_path.h>
#include <api/fs/tracefs.h>
#include <termios.h> #include <termios.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <termios.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