mirror of
https://github.com/torvalds/linux.git
synced 2026-05-26 16:12:59 +02:00
perf/core improvements and fixes:
User visible:
- 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:
- '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: Arnaldo Carvalho de Melo <acme@redhat.com>
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAABAgAGBQJV9vT7AAoJENZQFvNTUqpAXLMP/jXZVHq09chEBIiIM8UxnlE0
fdreX3RUpqvmkiFdiv+EfcoEUQOZtV2r5Je7FjsdOT8s/2fjDcVfHpoDKgG1U5SS
8QjqKXYP6NE/kOEzVH76QiDec3PuISEe9WZg5BMAD48MjDmfYA8/mPEYPdVk7oh9
8UpGMo1w9+txEL8CXgE31eDc/BUvyB0Edbmx7jyLrfaZzJTJfuOTOICv5AZ75vrz
CnNHwH933jSUEP8gUgjDPlLWWQUtREJiscPUSp5jB7VWCTN391GsX6/OXmZEOabE
T8Q3M4KIYTO8Gn9P+IcEsBW/oLQ2wLG9fhUNnzJVouu/Nwp5IItES/kO1K+KXe6J
qyqq+5prys9PRD9o17zD20gGvUlVrv738bI11MwixzsWo7uJvYclGtHnxWmLI1xD
xZwRK4YclUe7oEXJxcZJEKJg2mqrzo2KyCcvq4ZOXRfgHHohMQhhIci8QJgLMemJ
6ovIQjBmeo/4tNxhQ6dV/ZnpdYTMp/CMUdRN8oRYmKAxqCjIlQfnJpjWiPaTI716
hmemT8bre95XrYNIyZj4rtKAaQcSsHIcCOd3p66o8scXBFCKJcfQli1erUyKq2jG
9325R/0uTu0EunjKrYCKkcm3xruKIJXkv065UYtMg3pG8Oandj+n2YOB0JttucqD
guwUT5vBlzwErn3yB8Mt
=bDjb
-----END PGP SIGNATURE-----
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: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
9059b284ca
|
|
@ -1,2 +1,3 @@
|
|||
libapi-y += fd/
|
||||
libapi-y += fs/
|
||||
libapi-y += cpu.o
|
||||
|
|
|
|||
18
tools/lib/api/cpu.c
Normal file
18
tools/lib/api/cpu.c
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#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);
|
||||
}
|
||||
6
tools/lib/api/cpu.h
Normal file
6
tools/lib/api/cpu.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef __API_CPU__
|
||||
#define __API_CPU__
|
||||
|
||||
int cpu__get_max_freq(unsigned long long *freq);
|
||||
|
||||
#endif /* __API_CPU__ */
|
||||
|
|
@ -1,5 +1,2 @@
|
|||
libapi-y += fs.o
|
||||
libapi-y += tracing_path.o
|
||||
libapi-y += debugfs.o
|
||||
libapi-y += findfs.o
|
||||
libapi-y += tracefs.o
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#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__ */
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#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__ */
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#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__ */
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
#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;
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
#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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
#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;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
#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
|
||||
|
|
|
|||
115
tools/perf/tests/topology.c
Normal file
115
tools/perf/tests/topology.c
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
#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)
|
||||
|
|
|
|||
86
tools/perf/util/env.c
Normal file
86
tools/perf/util/env.c
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
#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;
|
||||
}
|
||||
44
tools/perf/util/env.h
Normal file
44
tools/perf/util/env.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user