perf/core improvements and fixes
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJPHzYrAAoJENZQFvNTUqpAg9sP/RGkgADZZVQol3alLFG8Z0fI XNmPwvaGB9Gk+ZzqmF+MOEHZBvRlFdElORHRPh0VzI5r05lURqIgaUIaaErzf4FR sGtpG4kYRAJV8YGAUbeRCzBSl2LI8//xgLiQaMQztuqMGaDs/LRt7u2vnyZzGKLn uwuaR4iMUjQhYv5YMA/vxvnI8h18kWmiKndViwWGDP0C6pIs6OpQsWq5lkGuehjR 3xoixSa1yRMcc1QxPlCbh8pVS1aFoIhox8aX5dLCArU/YbDLy4pKax58cAtyoEsS HaPL2GkrFF8Aestswm3KOZ5V0JRmMLluswEU+eknZaW08wIr34ZPGRyps0abHyTm yKB2ESjN6Uu70OZot59ng1FRKLclHIlo5yipgrEpqnumYTbmWupQFfmcNvQusVph gIbzOLHvETW/TbW01GnTM39syr7kKZm3849teOYTC/jCzu+wT6MRw824nBLNEgte RggtcdsjvKX9Y4BN5IB3ZNjoRhDOyowLQDV6BcQcKNixuq2XHkIyu+336hEy0G8V hofvucRtuwLZA2GFO1pJd3n07YpWqz1m3jWcCY+Hd6ofkZtuvQ5bSykB4UpYu8EV YvpFEGsc5C319a8IB2C3xdVwYJde9r4uuT3LiEm54Vvi46ijnI/HrmqXaMmTQdG8 3caCdQZj/qg3xo1Kln1F =XIr1 -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull in the latest perf/core improvements and fixes. Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
commit
939ddcfa60
37 changed files with 597 additions and 47 deletions
|
@ -58,6 +58,10 @@ OPTIONS
|
||||||
--tid=::
|
--tid=::
|
||||||
Record events on existing thread ID.
|
Record events on existing thread ID.
|
||||||
|
|
||||||
|
-u::
|
||||||
|
--uid=::
|
||||||
|
Record events in threads owned by uid. Name or number.
|
||||||
|
|
||||||
-r::
|
-r::
|
||||||
--realtime=::
|
--realtime=::
|
||||||
Collect data with this RT SCHED_FIFO priority.
|
Collect data with this RT SCHED_FIFO priority.
|
||||||
|
|
|
@ -78,6 +78,10 @@ Default is to monitor all CPUS.
|
||||||
--tid=<tid>::
|
--tid=<tid>::
|
||||||
Profile events on existing thread ID.
|
Profile events on existing thread ID.
|
||||||
|
|
||||||
|
-u::
|
||||||
|
--uid=::
|
||||||
|
Record events in threads owned by uid. Name or number.
|
||||||
|
|
||||||
-r <priority>::
|
-r <priority>::
|
||||||
--realtime=<priority>::
|
--realtime=<priority>::
|
||||||
Collect data with this RT SCHED_FIFO priority.
|
Collect data with this RT SCHED_FIFO priority.
|
||||||
|
|
|
@ -61,7 +61,7 @@ ifeq ($(ARCH),x86_64)
|
||||||
ifeq (${IS_X86_64}, 1)
|
ifeq (${IS_X86_64}, 1)
|
||||||
RAW_ARCH := x86_64
|
RAW_ARCH := x86_64
|
||||||
ARCH_CFLAGS := -DARCH_X86_64
|
ARCH_CFLAGS := -DARCH_X86_64
|
||||||
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S
|
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ endif
|
||||||
|
|
||||||
CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
|
CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
|
||||||
EXTLIBS = -lpthread -lrt -lelf -lm
|
EXTLIBS = -lpthread -lrt -lelf -lm
|
||||||
ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
|
||||||
ALL_LDFLAGS = $(LDFLAGS)
|
ALL_LDFLAGS = $(LDFLAGS)
|
||||||
STRIP ?= strip
|
STRIP ?= strip
|
||||||
|
|
||||||
|
@ -168,10 +168,7 @@ endif
|
||||||
|
|
||||||
### --- END CONFIGURATION SECTION ---
|
### --- END CONFIGURATION SECTION ---
|
||||||
|
|
||||||
# Those must not be GNU-specific; they are shared with perl/ which may
|
BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
|
||||||
# be built by a different compiler. (Note that this is an artifact now
|
|
||||||
# but it still might be nice to keep that distinction.)
|
|
||||||
BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include
|
|
||||||
BASIC_LDFLAGS =
|
BASIC_LDFLAGS =
|
||||||
|
|
||||||
# Guard against environment variables
|
# Guard against environment variables
|
||||||
|
@ -362,8 +359,10 @@ BUILTIN_OBJS += $(OUTPUT)bench/sched-messaging.o
|
||||||
BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
|
BUILTIN_OBJS += $(OUTPUT)bench/sched-pipe.o
|
||||||
ifeq ($(RAW_ARCH),x86_64)
|
ifeq ($(RAW_ARCH),x86_64)
|
||||||
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
|
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy-x86-64-asm.o
|
||||||
|
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
|
||||||
endif
|
endif
|
||||||
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
|
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
|
||||||
|
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
|
||||||
|
|
||||||
BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
|
BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
|
||||||
BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
|
BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
|
extern int bench_sched_messaging(int argc, const char **argv, const char *prefix);
|
||||||
extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
|
extern int bench_sched_pipe(int argc, const char **argv, const char *prefix);
|
||||||
extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used);
|
extern int bench_mem_memcpy(int argc, const char **argv, const char *prefix __used);
|
||||||
|
extern int bench_mem_memset(int argc, const char **argv, const char *prefix);
|
||||||
|
|
||||||
#define BENCH_FORMAT_DEFAULT_STR "default"
|
#define BENCH_FORMAT_DEFAULT_STR "default"
|
||||||
#define BENCH_FORMAT_DEFAULT 0
|
#define BENCH_FORMAT_DEFAULT 0
|
||||||
|
|
|
@ -2,3 +2,11 @@
|
||||||
MEMCPY_FN(__memcpy,
|
MEMCPY_FN(__memcpy,
|
||||||
"x86-64-unrolled",
|
"x86-64-unrolled",
|
||||||
"unrolled memcpy() in arch/x86/lib/memcpy_64.S")
|
"unrolled memcpy() in arch/x86/lib/memcpy_64.S")
|
||||||
|
|
||||||
|
MEMCPY_FN(memcpy_c,
|
||||||
|
"x86-64-movsq",
|
||||||
|
"movsq-based memcpy() in arch/x86/lib/memcpy_64.S")
|
||||||
|
|
||||||
|
MEMCPY_FN(memcpy_c_e,
|
||||||
|
"x86-64-movsb",
|
||||||
|
"movsb-based memcpy() in arch/x86/lib/memcpy_64.S")
|
||||||
|
|
|
@ -1,2 +1,6 @@
|
||||||
|
#define memcpy MEMCPY /* don't hide glibc's memcpy() */
|
||||||
|
#define altinstr_replacement text
|
||||||
|
#define globl p2align 4; .globl
|
||||||
|
#define Lmemcpy_c globl memcpy_c; memcpy_c
|
||||||
|
#define Lmemcpy_c_e globl memcpy_c_e; memcpy_c_e
|
||||||
#include "../../../arch/x86/lib/memcpy_64.S"
|
#include "../../../arch/x86/lib/memcpy_64.S"
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
static const char *length_str = "1MB";
|
static const char *length_str = "1MB";
|
||||||
static const char *routine = "default";
|
static const char *routine = "default";
|
||||||
|
static int iterations = 1;
|
||||||
static bool use_clock;
|
static bool use_clock;
|
||||||
static int clock_fd;
|
static int clock_fd;
|
||||||
static bool only_prefault;
|
static bool only_prefault;
|
||||||
|
@ -35,6 +36,8 @@ static const struct option options[] = {
|
||||||
"available unit: B, MB, GB (upper and lower)"),
|
"available unit: B, MB, GB (upper and lower)"),
|
||||||
OPT_STRING('r', "routine", &routine, "default",
|
OPT_STRING('r', "routine", &routine, "default",
|
||||||
"Specify routine to copy"),
|
"Specify routine to copy"),
|
||||||
|
OPT_INTEGER('i', "iterations", &iterations,
|
||||||
|
"repeat memcpy() invocation this number of times"),
|
||||||
OPT_BOOLEAN('c', "clock", &use_clock,
|
OPT_BOOLEAN('c', "clock", &use_clock,
|
||||||
"Use CPU clock for measuring"),
|
"Use CPU clock for measuring"),
|
||||||
OPT_BOOLEAN('o', "only-prefault", &only_prefault,
|
OPT_BOOLEAN('o', "only-prefault", &only_prefault,
|
||||||
|
@ -121,6 +124,7 @@ static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault)
|
||||||
{
|
{
|
||||||
u64 clock_start = 0ULL, clock_end = 0ULL;
|
u64 clock_start = 0ULL, clock_end = 0ULL;
|
||||||
void *src = NULL, *dst = NULL;
|
void *src = NULL, *dst = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
alloc_mem(&src, &dst, len);
|
alloc_mem(&src, &dst, len);
|
||||||
|
|
||||||
|
@ -128,7 +132,8 @@ static u64 do_memcpy_clock(memcpy_t fn, size_t len, bool prefault)
|
||||||
fn(dst, src, len);
|
fn(dst, src, len);
|
||||||
|
|
||||||
clock_start = get_clock();
|
clock_start = get_clock();
|
||||||
fn(dst, src, len);
|
for (i = 0; i < iterations; ++i)
|
||||||
|
fn(dst, src, len);
|
||||||
clock_end = get_clock();
|
clock_end = get_clock();
|
||||||
|
|
||||||
free(src);
|
free(src);
|
||||||
|
@ -140,6 +145,7 @@ static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
|
||||||
{
|
{
|
||||||
struct timeval tv_start, tv_end, tv_diff;
|
struct timeval tv_start, tv_end, tv_diff;
|
||||||
void *src = NULL, *dst = NULL;
|
void *src = NULL, *dst = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
alloc_mem(&src, &dst, len);
|
alloc_mem(&src, &dst, len);
|
||||||
|
|
||||||
|
@ -147,7 +153,8 @@ static double do_memcpy_gettimeofday(memcpy_t fn, size_t len, bool prefault)
|
||||||
fn(dst, src, len);
|
fn(dst, src, len);
|
||||||
|
|
||||||
BUG_ON(gettimeofday(&tv_start, NULL));
|
BUG_ON(gettimeofday(&tv_start, NULL));
|
||||||
fn(dst, src, len);
|
for (i = 0; i < iterations; ++i)
|
||||||
|
fn(dst, src, len);
|
||||||
BUG_ON(gettimeofday(&tv_end, NULL));
|
BUG_ON(gettimeofday(&tv_end, NULL));
|
||||||
|
|
||||||
timersub(&tv_end, &tv_start, &tv_diff);
|
timersub(&tv_end, &tv_start, &tv_diff);
|
||||||
|
|
12
tools/perf/bench/mem-memset-arch.h
Normal file
12
tools/perf/bench/mem-memset-arch.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
#ifdef ARCH_X86_64
|
||||||
|
|
||||||
|
#define MEMSET_FN(fn, name, desc) \
|
||||||
|
extern void *fn(void *, int, size_t);
|
||||||
|
|
||||||
|
#include "mem-memset-x86-64-asm-def.h"
|
||||||
|
|
||||||
|
#undef MEMSET_FN
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
12
tools/perf/bench/mem-memset-x86-64-asm-def.h
Normal file
12
tools/perf/bench/mem-memset-x86-64-asm-def.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
MEMSET_FN(__memset,
|
||||||
|
"x86-64-unrolled",
|
||||||
|
"unrolled memset() in arch/x86/lib/memset_64.S")
|
||||||
|
|
||||||
|
MEMSET_FN(memset_c,
|
||||||
|
"x86-64-stosq",
|
||||||
|
"movsq-based memset() in arch/x86/lib/memset_64.S")
|
||||||
|
|
||||||
|
MEMSET_FN(memset_c_e,
|
||||||
|
"x86-64-stosb",
|
||||||
|
"movsb-based memset() in arch/x86/lib/memset_64.S")
|
6
tools/perf/bench/mem-memset-x86-64-asm.S
Normal file
6
tools/perf/bench/mem-memset-x86-64-asm.S
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#define memset MEMSET /* don't hide glibc's memset() */
|
||||||
|
#define altinstr_replacement text
|
||||||
|
#define globl p2align 4; .globl
|
||||||
|
#define Lmemset_c globl memset_c; memset_c
|
||||||
|
#define Lmemset_c_e globl memset_c_e; memset_c_e
|
||||||
|
#include "../../../arch/x86/lib/memset_64.S"
|
298
tools/perf/bench/mem-memset.c
Normal file
298
tools/perf/bench/mem-memset.c
Normal file
|
@ -0,0 +1,298 @@
|
||||||
|
/*
|
||||||
|
* mem-memset.c
|
||||||
|
*
|
||||||
|
* memset: Simple memory set in various ways
|
||||||
|
*
|
||||||
|
* Trivial clone of mem-memcpy.c.
|
||||||
|
*/
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "../perf.h"
|
||||||
|
#include "../util/util.h"
|
||||||
|
#include "../util/parse-options.h"
|
||||||
|
#include "../util/header.h"
|
||||||
|
#include "bench.h"
|
||||||
|
#include "mem-memset-arch.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define K 1024
|
||||||
|
|
||||||
|
static const char *length_str = "1MB";
|
||||||
|
static const char *routine = "default";
|
||||||
|
static int iterations = 1;
|
||||||
|
static bool use_clock;
|
||||||
|
static int clock_fd;
|
||||||
|
static bool only_prefault;
|
||||||
|
static bool no_prefault;
|
||||||
|
|
||||||
|
static const struct option options[] = {
|
||||||
|
OPT_STRING('l', "length", &length_str, "1MB",
|
||||||
|
"Specify length of memory to copy. "
|
||||||
|
"available unit: B, MB, GB (upper and lower)"),
|
||||||
|
OPT_STRING('r', "routine", &routine, "default",
|
||||||
|
"Specify routine to copy"),
|
||||||
|
OPT_INTEGER('i', "iterations", &iterations,
|
||||||
|
"repeat memset() invocation this number of times"),
|
||||||
|
OPT_BOOLEAN('c', "clock", &use_clock,
|
||||||
|
"Use CPU clock for measuring"),
|
||||||
|
OPT_BOOLEAN('o', "only-prefault", &only_prefault,
|
||||||
|
"Show only the result with page faults before memset()"),
|
||||||
|
OPT_BOOLEAN('n', "no-prefault", &no_prefault,
|
||||||
|
"Show only the result without page faults before memset()"),
|
||||||
|
OPT_END()
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void *(*memset_t)(void *, int, size_t);
|
||||||
|
|
||||||
|
struct routine {
|
||||||
|
const char *name;
|
||||||
|
const char *desc;
|
||||||
|
memset_t fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct routine routines[] = {
|
||||||
|
{ "default",
|
||||||
|
"Default memset() provided by glibc",
|
||||||
|
memset },
|
||||||
|
#ifdef ARCH_X86_64
|
||||||
|
|
||||||
|
#define MEMSET_FN(fn, name, desc) { name, desc, fn },
|
||||||
|
#include "mem-memset-x86-64-asm-def.h"
|
||||||
|
#undef MEMSET_FN
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{ NULL,
|
||||||
|
NULL,
|
||||||
|
NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const bench_mem_memset_usage[] = {
|
||||||
|
"perf bench mem memset <options>",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct perf_event_attr clock_attr = {
|
||||||
|
.type = PERF_TYPE_HARDWARE,
|
||||||
|
.config = PERF_COUNT_HW_CPU_CYCLES
|
||||||
|
};
|
||||||
|
|
||||||
|
static void init_clock(void)
|
||||||
|
{
|
||||||
|
clock_fd = sys_perf_event_open(&clock_attr, getpid(), -1, -1, 0);
|
||||||
|
|
||||||
|
if (clock_fd < 0 && errno == ENOSYS)
|
||||||
|
die("No CONFIG_PERF_EVENTS=y kernel support configured?\n");
|
||||||
|
else
|
||||||
|
BUG_ON(clock_fd < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 get_clock(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
u64 clk;
|
||||||
|
|
||||||
|
ret = read(clock_fd, &clk, sizeof(u64));
|
||||||
|
BUG_ON(ret != sizeof(u64));
|
||||||
|
|
||||||
|
return clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double timeval2double(struct timeval *ts)
|
||||||
|
{
|
||||||
|
return (double)ts->tv_sec +
|
||||||
|
(double)ts->tv_usec / (double)1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alloc_mem(void **dst, size_t length)
|
||||||
|
{
|
||||||
|
*dst = zalloc(length);
|
||||||
|
if (!dst)
|
||||||
|
die("memory allocation failed - maybe length is too large?\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static u64 do_memset_clock(memset_t fn, size_t len, bool prefault)
|
||||||
|
{
|
||||||
|
u64 clock_start = 0ULL, clock_end = 0ULL;
|
||||||
|
void *dst = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
alloc_mem(&dst, len);
|
||||||
|
|
||||||
|
if (prefault)
|
||||||
|
fn(dst, -1, len);
|
||||||
|
|
||||||
|
clock_start = get_clock();
|
||||||
|
for (i = 0; i < iterations; ++i)
|
||||||
|
fn(dst, i, len);
|
||||||
|
clock_end = get_clock();
|
||||||
|
|
||||||
|
free(dst);
|
||||||
|
return clock_end - clock_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
static double do_memset_gettimeofday(memset_t fn, size_t len, bool prefault)
|
||||||
|
{
|
||||||
|
struct timeval tv_start, tv_end, tv_diff;
|
||||||
|
void *dst = NULL;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
alloc_mem(&dst, len);
|
||||||
|
|
||||||
|
if (prefault)
|
||||||
|
fn(dst, -1, len);
|
||||||
|
|
||||||
|
BUG_ON(gettimeofday(&tv_start, NULL));
|
||||||
|
for (i = 0; i < iterations; ++i)
|
||||||
|
fn(dst, i, len);
|
||||||
|
BUG_ON(gettimeofday(&tv_end, NULL));
|
||||||
|
|
||||||
|
timersub(&tv_end, &tv_start, &tv_diff);
|
||||||
|
|
||||||
|
free(dst);
|
||||||
|
return (double)((double)len / timeval2double(&tv_diff));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define pf (no_prefault ? 0 : 1)
|
||||||
|
|
||||||
|
#define print_bps(x) do { \
|
||||||
|
if (x < K) \
|
||||||
|
printf(" %14lf B/Sec", x); \
|
||||||
|
else if (x < K * K) \
|
||||||
|
printf(" %14lfd KB/Sec", x / K); \
|
||||||
|
else if (x < K * K * K) \
|
||||||
|
printf(" %14lf MB/Sec", x / K / K); \
|
||||||
|
else \
|
||||||
|
printf(" %14lf GB/Sec", x / K / K / K); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
int bench_mem_memset(int argc, const char **argv,
|
||||||
|
const char *prefix __used)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
size_t len;
|
||||||
|
double result_bps[2];
|
||||||
|
u64 result_clock[2];
|
||||||
|
|
||||||
|
argc = parse_options(argc, argv, options,
|
||||||
|
bench_mem_memset_usage, 0);
|
||||||
|
|
||||||
|
if (use_clock)
|
||||||
|
init_clock();
|
||||||
|
|
||||||
|
len = (size_t)perf_atoll((char *)length_str);
|
||||||
|
|
||||||
|
result_clock[0] = result_clock[1] = 0ULL;
|
||||||
|
result_bps[0] = result_bps[1] = 0.0;
|
||||||
|
|
||||||
|
if ((s64)len <= 0) {
|
||||||
|
fprintf(stderr, "Invalid length:%s\n", length_str);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* same to without specifying either of prefault and no-prefault */
|
||||||
|
if (only_prefault && no_prefault)
|
||||||
|
only_prefault = no_prefault = false;
|
||||||
|
|
||||||
|
for (i = 0; routines[i].name; i++) {
|
||||||
|
if (!strcmp(routines[i].name, routine))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!routines[i].name) {
|
||||||
|
printf("Unknown routine:%s\n", routine);
|
||||||
|
printf("Available routines...\n");
|
||||||
|
for (i = 0; routines[i].name; i++) {
|
||||||
|
printf("\t%s ... %s\n",
|
||||||
|
routines[i].name, routines[i].desc);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bench_format == BENCH_FORMAT_DEFAULT)
|
||||||
|
printf("# Copying %s Bytes ...\n\n", length_str);
|
||||||
|
|
||||||
|
if (!only_prefault && !no_prefault) {
|
||||||
|
/* show both of results */
|
||||||
|
if (use_clock) {
|
||||||
|
result_clock[0] =
|
||||||
|
do_memset_clock(routines[i].fn, len, false);
|
||||||
|
result_clock[1] =
|
||||||
|
do_memset_clock(routines[i].fn, len, true);
|
||||||
|
} else {
|
||||||
|
result_bps[0] =
|
||||||
|
do_memset_gettimeofday(routines[i].fn,
|
||||||
|
len, false);
|
||||||
|
result_bps[1] =
|
||||||
|
do_memset_gettimeofday(routines[i].fn,
|
||||||
|
len, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (use_clock) {
|
||||||
|
result_clock[pf] =
|
||||||
|
do_memset_clock(routines[i].fn,
|
||||||
|
len, only_prefault);
|
||||||
|
} else {
|
||||||
|
result_bps[pf] =
|
||||||
|
do_memset_gettimeofday(routines[i].fn,
|
||||||
|
len, only_prefault);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bench_format) {
|
||||||
|
case BENCH_FORMAT_DEFAULT:
|
||||||
|
if (!only_prefault && !no_prefault) {
|
||||||
|
if (use_clock) {
|
||||||
|
printf(" %14lf Clock/Byte\n",
|
||||||
|
(double)result_clock[0]
|
||||||
|
/ (double)len);
|
||||||
|
printf(" %14lf Clock/Byte (with prefault)\n ",
|
||||||
|
(double)result_clock[1]
|
||||||
|
/ (double)len);
|
||||||
|
} else {
|
||||||
|
print_bps(result_bps[0]);
|
||||||
|
printf("\n");
|
||||||
|
print_bps(result_bps[1]);
|
||||||
|
printf(" (with prefault)\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (use_clock) {
|
||||||
|
printf(" %14lf Clock/Byte",
|
||||||
|
(double)result_clock[pf]
|
||||||
|
/ (double)len);
|
||||||
|
} else
|
||||||
|
print_bps(result_bps[pf]);
|
||||||
|
|
||||||
|
printf("%s\n", only_prefault ? " (with prefault)" : "");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BENCH_FORMAT_SIMPLE:
|
||||||
|
if (!only_prefault && !no_prefault) {
|
||||||
|
if (use_clock) {
|
||||||
|
printf("%lf %lf\n",
|
||||||
|
(double)result_clock[0] / (double)len,
|
||||||
|
(double)result_clock[1] / (double)len);
|
||||||
|
} else {
|
||||||
|
printf("%lf %lf\n",
|
||||||
|
result_bps[0], result_bps[1]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (use_clock) {
|
||||||
|
printf("%lf\n", (double)result_clock[pf]
|
||||||
|
/ (double)len);
|
||||||
|
} else
|
||||||
|
printf("%lf\n", result_bps[pf]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* reaching this means there's some disaster: */
|
||||||
|
die("unknown format: %d\n", bench_format);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -52,6 +52,9 @@ static struct bench_suite mem_suites[] = {
|
||||||
{ "memcpy",
|
{ "memcpy",
|
||||||
"Simple memory copy in various ways",
|
"Simple memory copy in various ways",
|
||||||
bench_mem_memcpy },
|
bench_mem_memcpy },
|
||||||
|
{ "memset",
|
||||||
|
"Simple memory set in various ways",
|
||||||
|
bench_mem_memset },
|
||||||
suite_all,
|
suite_all,
|
||||||
{ NULL,
|
{ NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -31,7 +30,6 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#undef _GNU_SOURCE
|
|
||||||
#include "perf.h"
|
#include "perf.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
#include "util/util.h"
|
#include "util/util.h"
|
||||||
|
|
|
@ -44,6 +44,7 @@ struct perf_record {
|
||||||
struct perf_evlist *evlist;
|
struct perf_evlist *evlist;
|
||||||
struct perf_session *session;
|
struct perf_session *session;
|
||||||
const char *progname;
|
const char *progname;
|
||||||
|
const char *uid_str;
|
||||||
int output;
|
int output;
|
||||||
unsigned int page_size;
|
unsigned int page_size;
|
||||||
int realtime_prio;
|
int realtime_prio;
|
||||||
|
@ -727,6 +728,7 @@ const struct option record_options[] = {
|
||||||
OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
|
OPT_CALLBACK('G', "cgroup", &record.evlist, "name",
|
||||||
"monitor event in cgroup name only",
|
"monitor event in cgroup name only",
|
||||||
parse_cgroups),
|
parse_cgroups),
|
||||||
|
OPT_STRING('u', "uid", &record.uid_str, "user", "user to profile"),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -748,7 +750,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
|
||||||
argc = parse_options(argc, argv, record_options, record_usage,
|
argc = parse_options(argc, argv, record_options, record_usage,
|
||||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||||
if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
|
if (!argc && rec->opts.target_pid == -1 && rec->opts.target_tid == -1 &&
|
||||||
!rec->opts.system_wide && !rec->opts.cpu_list)
|
!rec->opts.system_wide && !rec->opts.cpu_list && !rec->uid_str)
|
||||||
usage_with_options(record_usage, record_options);
|
usage_with_options(record_usage, record_options);
|
||||||
|
|
||||||
if (rec->force && rec->append_file) {
|
if (rec->force && rec->append_file) {
|
||||||
|
@ -788,11 +790,17 @@ int cmd_record(int argc, const char **argv, const char *prefix __used)
|
||||||
goto out_symbol_exit;
|
goto out_symbol_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rec->opts.uid = parse_target_uid(rec->uid_str, rec->opts.target_tid,
|
||||||
|
rec->opts.target_pid);
|
||||||
|
if (rec->uid_str != NULL && rec->opts.uid == UINT_MAX - 1)
|
||||||
|
goto out_free_fd;
|
||||||
|
|
||||||
if (rec->opts.target_pid != -1)
|
if (rec->opts.target_pid != -1)
|
||||||
rec->opts.target_tid = rec->opts.target_pid;
|
rec->opts.target_tid = rec->opts.target_pid;
|
||||||
|
|
||||||
if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
|
if (perf_evlist__create_maps(evsel_list, rec->opts.target_pid,
|
||||||
rec->opts.target_tid, rec->opts.cpu_list) < 0)
|
rec->opts.target_tid, rec->opts.uid,
|
||||||
|
rec->opts.cpu_list) < 0)
|
||||||
usage_with_options(record_usage, record_options);
|
usage_with_options(record_usage, record_options);
|
||||||
|
|
||||||
list_for_each_entry(pos, &evsel_list->entries, node) {
|
list_for_each_entry(pos, &evsel_list->entries, node) {
|
||||||
|
|
|
@ -1201,7 +1201,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
|
||||||
if (target_pid != -1)
|
if (target_pid != -1)
|
||||||
target_tid = target_pid;
|
target_tid = target_pid;
|
||||||
|
|
||||||
evsel_list->threads = thread_map__new(target_pid, target_tid);
|
evsel_list->threads = thread_map__new(target_pid, target_tid, UINT_MAX);
|
||||||
if (evsel_list->threads == NULL) {
|
if (evsel_list->threads == NULL) {
|
||||||
pr_err("Problems finding threads of monitor\n");
|
pr_err("Problems finding threads of monitor\n");
|
||||||
usage_with_options(stat_usage, options);
|
usage_with_options(stat_usage, options);
|
||||||
|
|
|
@ -276,7 +276,7 @@ static int test__open_syscall_event(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
threads = thread_map__new(-1, getpid());
|
threads = thread_map__new(-1, getpid(), UINT_MAX);
|
||||||
if (threads == NULL) {
|
if (threads == NULL) {
|
||||||
pr_debug("thread_map__new\n");
|
pr_debug("thread_map__new\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -342,7 +342,7 @@ static int test__open_syscall_event_on_all_cpus(void)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
threads = thread_map__new(-1, getpid());
|
threads = thread_map__new(-1, getpid(), UINT_MAX);
|
||||||
if (threads == NULL) {
|
if (threads == NULL) {
|
||||||
pr_debug("thread_map__new\n");
|
pr_debug("thread_map__new\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -490,7 +490,7 @@ static int test__basic_mmap(void)
|
||||||
expected_nr_events[i] = random() % 257;
|
expected_nr_events[i] = random() % 257;
|
||||||
}
|
}
|
||||||
|
|
||||||
threads = thread_map__new(-1, getpid());
|
threads = thread_map__new(-1, getpid(), UINT_MAX);
|
||||||
if (threads == NULL) {
|
if (threads == NULL) {
|
||||||
pr_debug("thread_map__new\n");
|
pr_debug("thread_map__new\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1054,7 +1054,7 @@ static int test__PERF_RECORD(void)
|
||||||
* we're monitoring, the one forked there.
|
* we're monitoring, the one forked there.
|
||||||
*/
|
*/
|
||||||
err = perf_evlist__create_maps(evlist, opts.target_pid,
|
err = perf_evlist__create_maps(evlist, opts.target_pid,
|
||||||
opts.target_tid, opts.cpu_list);
|
opts.target_tid, UINT_MAX, opts.cpu_list);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
pr_debug("Not enough memory to create thread/cpu maps\n");
|
pr_debug("Not enough memory to create thread/cpu maps\n");
|
||||||
goto out_delete_evlist;
|
goto out_delete_evlist;
|
||||||
|
|
|
@ -64,7 +64,6 @@
|
||||||
#include <linux/unistd.h>
|
#include <linux/unistd.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
|
||||||
void get_term_dimensions(struct winsize *ws)
|
void get_term_dimensions(struct winsize *ws)
|
||||||
{
|
{
|
||||||
char *s = getenv("LINES");
|
char *s = getenv("LINES");
|
||||||
|
@ -537,10 +536,20 @@ static void perf_top__sort_new_samples(void *arg)
|
||||||
|
|
||||||
static void *display_thread_tui(void *arg)
|
static void *display_thread_tui(void *arg)
|
||||||
{
|
{
|
||||||
|
struct perf_evsel *pos;
|
||||||
struct perf_top *top = arg;
|
struct perf_top *top = arg;
|
||||||
const char *help = "For a higher level overview, try: perf top --sort comm,dso";
|
const char *help = "For a higher level overview, try: perf top --sort comm,dso";
|
||||||
|
|
||||||
perf_top__sort_new_samples(top);
|
perf_top__sort_new_samples(top);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the uid_filter_str, in the future the TUI will allow
|
||||||
|
* Zooming in/out UIDs. For now juse use whatever the user passed
|
||||||
|
* via --uid.
|
||||||
|
*/
|
||||||
|
list_for_each_entry(pos, &top->evlist->entries, node)
|
||||||
|
pos->hists.uid_filter_str = top->uid_str;
|
||||||
|
|
||||||
perf_evlist__tui_browse_hists(top->evlist, help,
|
perf_evlist__tui_browse_hists(top->evlist, help,
|
||||||
perf_top__sort_new_samples,
|
perf_top__sort_new_samples,
|
||||||
top, top->delay_secs);
|
top, top->delay_secs);
|
||||||
|
@ -949,7 +958,7 @@ static int __cmd_top(struct perf_top *top)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_delete;
|
goto out_delete;
|
||||||
|
|
||||||
if (top->target_tid != -1)
|
if (top->target_tid != -1 || top->uid != UINT_MAX)
|
||||||
perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
|
perf_event__synthesize_thread_map(&top->tool, top->evlist->threads,
|
||||||
perf_event__process,
|
perf_event__process,
|
||||||
&top->session->host_machine);
|
&top->session->host_machine);
|
||||||
|
@ -1089,6 +1098,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
|
||||||
.delay_secs = 2,
|
.delay_secs = 2,
|
||||||
.target_pid = -1,
|
.target_pid = -1,
|
||||||
.target_tid = -1,
|
.target_tid = -1,
|
||||||
|
.uid = UINT_MAX,
|
||||||
.freq = 1000, /* 1 KHz */
|
.freq = 1000, /* 1 KHz */
|
||||||
.sample_id_all_avail = true,
|
.sample_id_all_avail = true,
|
||||||
.mmap_pages = 128,
|
.mmap_pages = 128,
|
||||||
|
@ -1162,6 +1172,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
|
||||||
"Display raw encoding of assembly instructions (default)"),
|
"Display raw encoding of assembly instructions (default)"),
|
||||||
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
|
OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style",
|
||||||
"Specify disassembler style (e.g. -M intel for intel syntax)"),
|
"Specify disassembler style (e.g. -M intel for intel syntax)"),
|
||||||
|
OPT_STRING('u', "uid", &top.uid_str, "user", "user to profile"),
|
||||||
OPT_END()
|
OPT_END()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1187,6 +1198,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
|
||||||
|
|
||||||
setup_browser(false);
|
setup_browser(false);
|
||||||
|
|
||||||
|
top.uid = parse_target_uid(top.uid_str, top.target_tid, top.target_pid);
|
||||||
|
if (top.uid_str != NULL && top.uid == UINT_MAX - 1)
|
||||||
|
goto out_delete_evlist;
|
||||||
|
|
||||||
/* CPU and PID are mutually exclusive */
|
/* CPU and PID are mutually exclusive */
|
||||||
if (top.target_tid > 0 && top.cpu_list) {
|
if (top.target_tid > 0 && top.cpu_list) {
|
||||||
printf("WARNING: PID switch overriding CPU\n");
|
printf("WARNING: PID switch overriding CPU\n");
|
||||||
|
@ -1198,7 +1213,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
|
||||||
top.target_tid = top.target_pid;
|
top.target_tid = top.target_pid;
|
||||||
|
|
||||||
if (perf_evlist__create_maps(top.evlist, top.target_pid,
|
if (perf_evlist__create_maps(top.evlist, top.target_pid,
|
||||||
top.target_tid, top.cpu_list) < 0)
|
top.target_tid, top.uid, top.cpu_list) < 0)
|
||||||
usage_with_options(top_usage, options);
|
usage_with_options(top_usage, options);
|
||||||
|
|
||||||
if (!top.evlist->nr_entries &&
|
if (!top.evlist->nr_entries &&
|
||||||
|
@ -1262,6 +1277,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __used)
|
||||||
|
|
||||||
status = __cmd_top(&top);
|
status = __cmd_top(&top);
|
||||||
|
|
||||||
|
out_delete_evlist:
|
||||||
perf_evlist__delete(top.evlist);
|
perf_evlist__delete(top.evlist);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
|
|
@ -188,6 +188,7 @@ void pthread__unblock_sigwinch(void);
|
||||||
struct perf_record_opts {
|
struct perf_record_opts {
|
||||||
pid_t target_pid;
|
pid_t target_pid;
|
||||||
pid_t target_tid;
|
pid_t target_tid;
|
||||||
|
uid_t uid;
|
||||||
bool call_graph;
|
bool call_graph;
|
||||||
bool group;
|
bool group;
|
||||||
bool inherit_stat;
|
bool inherit_stat;
|
||||||
|
|
|
@ -166,6 +166,17 @@ struct cpu_map *cpu_map__new(const char *cpu_list)
|
||||||
return cpus;
|
return cpus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
size_t printed = fprintf(fp, "%d cpu%s: ",
|
||||||
|
map->nr, map->nr > 1 ? "s" : "");
|
||||||
|
for (i = 0; i < map->nr; ++i)
|
||||||
|
printed += fprintf(fp, "%s%d", i ? ", " : "", map->map[i]);
|
||||||
|
|
||||||
|
return printed + fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
struct cpu_map *cpu_map__dummy_new(void)
|
struct cpu_map *cpu_map__dummy_new(void)
|
||||||
{
|
{
|
||||||
struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
|
struct cpu_map *cpus = malloc(sizeof(*cpus) + sizeof(int));
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#ifndef __PERF_CPUMAP_H
|
#ifndef __PERF_CPUMAP_H
|
||||||
#define __PERF_CPUMAP_H
|
#define __PERF_CPUMAP_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
struct cpu_map {
|
struct cpu_map {
|
||||||
int nr;
|
int nr;
|
||||||
int map[];
|
int map[];
|
||||||
|
@ -10,4 +12,6 @@ struct cpu_map *cpu_map__new(const char *cpu_list);
|
||||||
struct cpu_map *cpu_map__dummy_new(void);
|
struct cpu_map *cpu_map__dummy_new(void);
|
||||||
void cpu_map__delete(struct cpu_map *map);
|
void cpu_map__delete(struct cpu_map *map);
|
||||||
|
|
||||||
|
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
|
||||||
|
|
||||||
#endif /* __PERF_CPUMAP_H */
|
#endif /* __PERF_CPUMAP_H */
|
||||||
|
|
|
@ -594,14 +594,14 @@ int perf_evlist__mmap(struct perf_evlist *evlist, unsigned int pages,
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
|
int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
|
||||||
pid_t target_tid, const char *cpu_list)
|
pid_t target_tid, uid_t uid, const char *cpu_list)
|
||||||
{
|
{
|
||||||
evlist->threads = thread_map__new(target_pid, target_tid);
|
evlist->threads = thread_map__new(target_pid, target_tid, uid);
|
||||||
|
|
||||||
if (evlist->threads == NULL)
|
if (evlist->threads == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (cpu_list == NULL && target_tid != -1)
|
if (uid != UINT_MAX || (cpu_list == NULL && target_tid != -1))
|
||||||
evlist->cpus = cpu_map__dummy_new();
|
evlist->cpus = cpu_map__dummy_new();
|
||||||
else
|
else
|
||||||
evlist->cpus = cpu_map__new(cpu_list);
|
evlist->cpus = cpu_map__new(cpu_list);
|
||||||
|
|
|
@ -107,7 +107,7 @@ static inline void perf_evlist__set_maps(struct perf_evlist *evlist,
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
|
int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
|
||||||
pid_t target_tid, const char *cpu_list);
|
pid_t tid, uid_t uid, const char *cpu_list);
|
||||||
void perf_evlist__delete_maps(struct perf_evlist *evlist);
|
void perf_evlist__delete_maps(struct perf_evlist *evlist);
|
||||||
int perf_evlist__set_filters(struct perf_evlist *evlist);
|
int perf_evlist__set_filters(struct perf_evlist *evlist);
|
||||||
|
|
||||||
|
|
|
@ -2105,7 +2105,7 @@ int perf_event__synthesize_event_type(struct perf_tool *tool,
|
||||||
strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
|
strncpy(ev.event_type.event_type.name, name, MAX_EVENT_NAME - 1);
|
||||||
|
|
||||||
ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
|
ev.event_type.header.type = PERF_RECORD_HEADER_EVENT_TYPE;
|
||||||
size = strlen(name);
|
size = strlen(ev.event_type.event_type.name);
|
||||||
size = ALIGN(size, sizeof(u64));
|
size = ALIGN(size, sizeof(u64));
|
||||||
ev.event_type.header.size = sizeof(ev.event_type) -
|
ev.event_type.header.size = sizeof(ev.event_type) -
|
||||||
(sizeof(ev.event_type.event_type.name) - size);
|
(sizeof(ev.event_type.event_type.name) - size);
|
||||||
|
|
|
@ -55,6 +55,7 @@ struct hists {
|
||||||
u64 nr_entries;
|
u64 nr_entries;
|
||||||
const struct thread *thread_filter;
|
const struct thread *thread_filter;
|
||||||
const struct dso *dso_filter;
|
const struct dso *dso_filter;
|
||||||
|
const char *uid_filter_str;
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
struct events_stats stats;
|
struct events_stats stats;
|
||||||
u64 event_stream;
|
u64 event_stream;
|
||||||
|
|
|
@ -2,10 +2,12 @@
|
||||||
#ifndef PERF_DWARF2_H
|
#ifndef PERF_DWARF2_H
|
||||||
#define PERF_DWARF2_H
|
#define PERF_DWARF2_H
|
||||||
|
|
||||||
/* dwarf2.h ... dummy header file for including arch/x86/lib/memcpy_64.S */
|
/* dwarf2.h ... dummy header file for including arch/x86/lib/mem{cpy,set}_64.S */
|
||||||
|
|
||||||
#define CFI_STARTPROC
|
#define CFI_STARTPROC
|
||||||
#define CFI_ENDPROC
|
#define CFI_ENDPROC
|
||||||
|
#define CFI_REMEMBER_STATE
|
||||||
|
#define CFI_RESTORE_STATE
|
||||||
|
|
||||||
#endif /* PERF_DWARF2_H */
|
#endif /* PERF_DWARF2_H */
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -33,7 +32,6 @@
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
|
|
||||||
#undef _GNU_SOURCE
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
@ -1731,7 +1729,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":");
|
printf("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
|
||||||
for (i = 0; i < ntevs; i++) {
|
for (i = 0; i < ntevs; i++) {
|
||||||
tev = &tevs[i];
|
tev = &tevs[i];
|
||||||
if (pev->event)
|
if (pev->event)
|
||||||
|
@ -1786,7 +1784,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
|
||||||
|
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
/* Show how to use the event. */
|
/* Show how to use the event. */
|
||||||
printf("\nYou can now use it on all perf tools, such as:\n\n");
|
printf("\nYou can now use it in all perf tools, such as:\n\n");
|
||||||
printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
|
printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
|
||||||
tev->event);
|
tev->event);
|
||||||
}
|
}
|
||||||
|
@ -1961,7 +1959,7 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Remove event: %s\n", ent->s);
|
printf("Removed event: %s\n", ent->s);
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
error:
|
||||||
pr_warning("Failed to delete event: %s\n", strerror(-ret));
|
pr_warning("Failed to delete event: %s\n", strerror(-ret));
|
||||||
|
|
|
@ -425,14 +425,14 @@ struct pyrf_thread_map {
|
||||||
static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
|
static int pyrf_thread_map__init(struct pyrf_thread_map *pthreads,
|
||||||
PyObject *args, PyObject *kwargs)
|
PyObject *args, PyObject *kwargs)
|
||||||
{
|
{
|
||||||
static char *kwlist[] = { "pid", "tid", NULL };
|
static char *kwlist[] = { "pid", "tid", "uid", NULL };
|
||||||
int pid = -1, tid = -1;
|
int pid = -1, tid = -1, uid = UINT_MAX;
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ii",
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iii",
|
||||||
kwlist, &pid, &tid))
|
kwlist, &pid, &tid, &uid))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
pthreads->threads = thread_map__new(pid, tid);
|
pthreads->threads = thread_map__new(pid, tid, uid);
|
||||||
if (pthreads->threads == NULL)
|
if (pthreads->threads == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include "thread_map.h"
|
#include "thread_map.h"
|
||||||
|
|
||||||
/* Skip "." and ".." directories */
|
/* Skip "." and ".." directories */
|
||||||
|
@ -23,7 +28,7 @@ struct thread_map *thread_map__new_by_pid(pid_t pid)
|
||||||
sprintf(name, "/proc/%d/task", pid);
|
sprintf(name, "/proc/%d/task", pid);
|
||||||
items = scandir(name, &namelist, filter, NULL);
|
items = scandir(name, &namelist, filter, NULL);
|
||||||
if (items <= 0)
|
if (items <= 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
|
threads = malloc(sizeof(*threads) + sizeof(pid_t) * items);
|
||||||
if (threads != NULL) {
|
if (threads != NULL) {
|
||||||
|
@ -51,10 +56,99 @@ struct thread_map *thread_map__new_by_tid(pid_t tid)
|
||||||
return threads;
|
return threads;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct thread_map *thread_map__new(pid_t pid, pid_t tid)
|
struct thread_map *thread_map__new_by_uid(uid_t uid)
|
||||||
|
{
|
||||||
|
DIR *proc;
|
||||||
|
int max_threads = 32, items, i;
|
||||||
|
char path[256];
|
||||||
|
struct dirent dirent, *next, **namelist = NULL;
|
||||||
|
struct thread_map *threads = malloc(sizeof(*threads) +
|
||||||
|
max_threads * sizeof(pid_t));
|
||||||
|
if (threads == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
proc = opendir("/proc");
|
||||||
|
if (proc == NULL)
|
||||||
|
goto out_free_threads;
|
||||||
|
|
||||||
|
threads->nr = 0;
|
||||||
|
|
||||||
|
while (!readdir_r(proc, &dirent, &next) && next) {
|
||||||
|
char *end;
|
||||||
|
bool grow = false;
|
||||||
|
struct stat st;
|
||||||
|
pid_t pid = strtol(dirent.d_name, &end, 10);
|
||||||
|
|
||||||
|
if (*end) /* only interested in proper numerical dirents */
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "/proc/%s", dirent.d_name);
|
||||||
|
|
||||||
|
if (stat(path, &st) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (st.st_uid != uid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snprintf(path, sizeof(path), "/proc/%d/task", pid);
|
||||||
|
items = scandir(path, &namelist, filter, NULL);
|
||||||
|
if (items <= 0)
|
||||||
|
goto out_free_closedir;
|
||||||
|
|
||||||
|
while (threads->nr + items >= max_threads) {
|
||||||
|
max_threads *= 2;
|
||||||
|
grow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (grow) {
|
||||||
|
struct thread_map *tmp;
|
||||||
|
|
||||||
|
tmp = realloc(threads, (sizeof(*threads) +
|
||||||
|
max_threads * sizeof(pid_t)));
|
||||||
|
if (tmp == NULL)
|
||||||
|
goto out_free_namelist;
|
||||||
|
|
||||||
|
threads = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < items; i++)
|
||||||
|
threads->map[threads->nr + i] = atoi(namelist[i]->d_name);
|
||||||
|
|
||||||
|
for (i = 0; i < items; i++)
|
||||||
|
free(namelist[i]);
|
||||||
|
free(namelist);
|
||||||
|
|
||||||
|
threads->nr += items;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_closedir:
|
||||||
|
closedir(proc);
|
||||||
|
out:
|
||||||
|
return threads;
|
||||||
|
|
||||||
|
out_free_threads:
|
||||||
|
free(threads);
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
out_free_namelist:
|
||||||
|
for (i = 0; i < items; i++)
|
||||||
|
free(namelist[i]);
|
||||||
|
free(namelist);
|
||||||
|
|
||||||
|
out_free_closedir:
|
||||||
|
free(threads);
|
||||||
|
threads = NULL;
|
||||||
|
goto out_closedir;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid)
|
||||||
{
|
{
|
||||||
if (pid != -1)
|
if (pid != -1)
|
||||||
return thread_map__new_by_pid(pid);
|
return thread_map__new_by_pid(pid);
|
||||||
|
|
||||||
|
if (tid == -1 && uid != UINT_MAX)
|
||||||
|
return thread_map__new_by_uid(uid);
|
||||||
|
|
||||||
return thread_map__new_by_tid(tid);
|
return thread_map__new_by_tid(tid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,3 +156,14 @@ void thread_map__delete(struct thread_map *threads)
|
||||||
{
|
{
|
||||||
free(threads);
|
free(threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t thread_map__fprintf(struct thread_map *threads, FILE *fp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
size_t printed = fprintf(fp, "%d thread%s: ",
|
||||||
|
threads->nr, threads->nr > 1 ? "s" : "");
|
||||||
|
for (i = 0; i < threads->nr; ++i)
|
||||||
|
printed += fprintf(fp, "%s%d", i ? ", " : "", threads->map[i]);
|
||||||
|
|
||||||
|
return printed + fprintf(fp, "\n");
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define __PERF_THREAD_MAP_H
|
#define __PERF_THREAD_MAP_H
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
struct thread_map {
|
struct thread_map {
|
||||||
int nr;
|
int nr;
|
||||||
|
@ -10,6 +11,10 @@ struct thread_map {
|
||||||
|
|
||||||
struct thread_map *thread_map__new_by_pid(pid_t pid);
|
struct thread_map *thread_map__new_by_pid(pid_t pid);
|
||||||
struct thread_map *thread_map__new_by_tid(pid_t tid);
|
struct thread_map *thread_map__new_by_tid(pid_t tid);
|
||||||
struct thread_map *thread_map__new(pid_t pid, pid_t tid);
|
struct thread_map *thread_map__new_by_uid(uid_t uid);
|
||||||
|
struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
|
||||||
void thread_map__delete(struct thread_map *threads);
|
void thread_map__delete(struct thread_map *threads);
|
||||||
|
|
||||||
|
size_t thread_map__fprintf(struct thread_map *threads, FILE *fp);
|
||||||
|
|
||||||
#endif /* __PERF_THREAD_MAP_H */
|
#endif /* __PERF_THREAD_MAP_H */
|
||||||
|
|
|
@ -75,6 +75,9 @@ size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size)
|
||||||
else if (top->target_tid != -1)
|
else if (top->target_tid != -1)
|
||||||
ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d",
|
ret += SNPRINTF(bf + ret, size - ret, " (target_tid: %d",
|
||||||
top->target_tid);
|
top->target_tid);
|
||||||
|
else if (top->uid_str != NULL)
|
||||||
|
ret += SNPRINTF(bf + ret, size - ret, " (uid: %s",
|
||||||
|
top->uid_str);
|
||||||
else
|
else
|
||||||
ret += SNPRINTF(bf + ret, size - ret, " (all");
|
ret += SNPRINTF(bf + ret, size - ret, " (all");
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ struct perf_top {
|
||||||
int print_entries, count_filter, delay_secs;
|
int print_entries, count_filter, delay_secs;
|
||||||
int freq;
|
int freq;
|
||||||
pid_t target_pid, target_tid;
|
pid_t target_pid, target_tid;
|
||||||
|
uid_t uid;
|
||||||
bool hide_kernel_symbols, hide_user_symbols, zero;
|
bool hide_kernel_symbols, hide_user_symbols, zero;
|
||||||
bool system_wide;
|
bool system_wide;
|
||||||
bool use_tui, use_stdio;
|
bool use_tui, use_stdio;
|
||||||
|
@ -45,6 +46,7 @@ struct perf_top {
|
||||||
int realtime_prio;
|
int realtime_prio;
|
||||||
int sym_pcnt_filter;
|
int sym_pcnt_filter;
|
||||||
const char *sym_filter;
|
const char *sym_filter;
|
||||||
|
const char *uid_str;
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
|
size_t perf_top__header_snprintf(struct perf_top *top, char *bf, size_t size);
|
||||||
|
|
|
@ -21,14 +21,13 @@
|
||||||
* The parts for function graph printing was taken and modified from the
|
* The parts for function graph printing was taken and modified from the
|
||||||
* Linux Kernel that were written by Frederic Weisbecker.
|
* Linux Kernel that were written by Frederic Weisbecker.
|
||||||
*/
|
*/
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#undef _GNU_SOURCE
|
|
||||||
#include "../perf.h"
|
#include "../perf.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "trace-event.h"
|
#include "trace-event.h"
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#undef _GNU_SOURCE
|
|
||||||
#include "../libslang.h"
|
#include "../libslang.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -841,6 +839,9 @@ static int hists__browser_title(struct hists *self, char *bf, size_t size,
|
||||||
nr_events = convert_unit(nr_events, &unit);
|
nr_events = convert_unit(nr_events, &unit);
|
||||||
printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
|
printed = snprintf(bf, size, "Events: %lu%c %s", nr_events, unit, ev_name);
|
||||||
|
|
||||||
|
if (self->uid_filter_str)
|
||||||
|
printed += snprintf(bf + printed, size - printed,
|
||||||
|
", UID: %s", self->uid_filter_str);
|
||||||
if (thread)
|
if (thread)
|
||||||
printed += snprintf(bf + printed, size - printed,
|
printed += snprintf(bf + printed, size - printed,
|
||||||
", Thread: %s(%d)",
|
", Thread: %s(%d)",
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
* Copyright (C) Linus Torvalds, 2005
|
* Copyright (C) Linus Torvalds, 2005
|
||||||
*/
|
*/
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
static void report(const char *prefix, const char *err, va_list params)
|
static void report(const char *prefix, const char *err, va_list params)
|
||||||
{
|
{
|
||||||
|
@ -81,3 +82,41 @@ void warning(const char *warn, ...)
|
||||||
warn_routine(warn, params);
|
warn_routine(warn, params);
|
||||||
va_end(params);
|
va_end(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid)
|
||||||
|
{
|
||||||
|
struct passwd pwd, *result;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
if (str == NULL)
|
||||||
|
return UINT_MAX;
|
||||||
|
|
||||||
|
/* CPU and PID are mutually exclusive */
|
||||||
|
if (tid > 0 || pid > 0) {
|
||||||
|
ui__warning("PID/TID switch overriding UID\n");
|
||||||
|
sleep(1);
|
||||||
|
return UINT_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
|
||||||
|
|
||||||
|
if (result == NULL) {
|
||||||
|
char *endptr;
|
||||||
|
int uid = strtol(str, &endptr, 10);
|
||||||
|
|
||||||
|
if (*endptr != '\0') {
|
||||||
|
ui__error("Invalid user %s\n", str);
|
||||||
|
return UINT_MAX - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
|
||||||
|
|
||||||
|
if (result == NULL) {
|
||||||
|
ui__error("Problems obtaining information for user %s\n",
|
||||||
|
str);
|
||||||
|
return UINT_MAX - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result->pw_uid;
|
||||||
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
|
#define decimal_length(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
|
||||||
|
|
||||||
#define _ALL_SOURCE 1
|
#define _ALL_SOURCE 1
|
||||||
#define _GNU_SOURCE 1
|
|
||||||
#define _BSD_SOURCE 1
|
#define _BSD_SOURCE 1
|
||||||
#define HAS_BOOL
|
#define HAS_BOOL
|
||||||
|
|
||||||
|
@ -246,6 +245,8 @@ struct perf_event_attr;
|
||||||
|
|
||||||
void event_attr_init(struct perf_event_attr *attr);
|
void event_attr_init(struct perf_event_attr *attr);
|
||||||
|
|
||||||
|
uid_t parse_target_uid(const char *str, pid_t tid, pid_t pid);
|
||||||
|
|
||||||
#define _STR(x) #x
|
#define _STR(x) #x
|
||||||
#define STR(x) _STR(x)
|
#define STR(x) _STR(x)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue