Skip to content

Commit

Permalink
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux…
Browse files Browse the repository at this point in the history
…/kernel/git/acme/linux into perf/core

Pull perf/core improvements and fixes from Arnaldo:

User visible:

  * Add several futex 'perf bench' microbenchmarks (Davidlohr Bueso)

  * Speed up thread map generation (Don Zickus)

  * Fix synthesizing mmaps for threads (Don Zickus)

  * Fix invalid output on event group stdio report  (Namhyung Kim)

  * Introduce 'perf kvm --list-cmds' command line option for use by
    scripts (Ramkumar Ramachandra)

Documentation:

  * Clarify load-latency information in the 'perf mem' docs (Andi Kleen)

  * Clarify x86 register naming in 'perf probe' docs (Andi Kleen)

Refactorings:

  * hists browser refactorings to reuse code accross UIs (Namhyung Kim)

Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
  • Loading branch information
Ingo Molnar committed Mar 18, 2014
2 parents 81827ed + d75e609 commit 0afd2d5
Show file tree
Hide file tree
Showing 27 changed files with 1,094 additions and 301 deletions.
4 changes: 4 additions & 0 deletions tools/perf/Documentation/perf-mem.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ from it, into perf.data. Perf record options are accepted and are passed through
"perf mem -t <TYPE> report" displays the result. It invokes perf report with the
right set of options to display a memory access profile.

Note that on Intel systems the memory latency reported is the use-latency,
not the pure load (or store latency). Use latency includes any pipeline
queueing delays in addition to the memory subsystem latency.

OPTIONS
-------
<command>...::
Expand Down
2 changes: 2 additions & 0 deletions tools/perf/Documentation/perf-probe.txt
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ Each probe argument follows below syntax.
'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type.

On x86 systems %REG is always the short form of the register: for example %AX. %RAX or %EAX is not valid.

LINE SYNTAX
-----------
Line range is described by following syntax.
Expand Down
3 changes: 3 additions & 0 deletions tools/perf/Makefile.perf
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,9 @@ BUILTIN_OBJS += $(OUTPUT)bench/mem-memset-x86-64-asm.o
endif
BUILTIN_OBJS += $(OUTPUT)bench/mem-memcpy.o
BUILTIN_OBJS += $(OUTPUT)bench/mem-memset.o
BUILTIN_OBJS += $(OUTPUT)bench/futex-hash.o
BUILTIN_OBJS += $(OUTPUT)bench/futex-wake.o
BUILTIN_OBJS += $(OUTPUT)bench/futex-requeue.o

BUILTIN_OBJS += $(OUTPUT)builtin-diff.o
BUILTIN_OBJS += $(OUTPUT)builtin-evlist.o
Expand Down
3 changes: 3 additions & 0 deletions tools/perf/bench/bench.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ 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 __maybe_unused);
extern int bench_mem_memset(int argc, const char **argv, const char *prefix);
extern int bench_futex_hash(int argc, const char **argv, const char *prefix);
extern int bench_futex_wake(int argc, const char **argv, const char *prefix);
extern int bench_futex_requeue(int argc, const char **argv, const char *prefix);

#define BENCH_FORMAT_DEFAULT_STR "default"
#define BENCH_FORMAT_DEFAULT 0
Expand Down
212 changes: 212 additions & 0 deletions tools/perf/bench/futex-hash.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/*
* Copyright (C) 2013 Davidlohr Bueso <davidlohr@hp.com>
*
* futex-hash: Stress the hell out of the Linux kernel futex uaddr hashing.
*
* This program is particularly useful for measuring the kernel's futex hash
* table/function implementation. In order for it to make sense, use with as
* many threads and futexes as possible.
*/

#include "../perf.h"
#include "../util/util.h"
#include "../util/stat.h"
#include "../util/parse-options.h"
#include "../util/header.h"
#include "bench.h"
#include "futex.h"

#include <err.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>

static unsigned int nthreads = 0;
static unsigned int nsecs = 10;
/* amount of futexes per thread */
static unsigned int nfutexes = 1024;
static bool fshared = false, done = false, silent = false;

struct timeval start, end, runtime;
static pthread_mutex_t thread_lock;
static unsigned int threads_starting;
static struct stats throughput_stats;
static pthread_cond_t thread_parent, thread_worker;

struct worker {
int tid;
u_int32_t *futex;
pthread_t thread;
unsigned long ops;
};

static const struct option options[] = {
OPT_UINTEGER('t', "threads", &nthreads, "Specify amount of threads"),
OPT_UINTEGER('r', "runtime", &nsecs, "Specify runtime (in seconds)"),
OPT_UINTEGER('f', "futexes", &nfutexes, "Specify amount of futexes per threads"),
OPT_BOOLEAN( 's', "silent", &silent, "Silent mode: do not display data/details"),
OPT_BOOLEAN( 'S', "shared", &fshared, "Use shared futexes instead of private ones"),
OPT_END()
};

static const char * const bench_futex_hash_usage[] = {
"perf bench futex hash <options>",
NULL
};

static void *workerfn(void *arg)
{
int ret;
unsigned int i;
struct worker *w = (struct worker *) arg;

pthread_mutex_lock(&thread_lock);
threads_starting--;
if (!threads_starting)
pthread_cond_signal(&thread_parent);
pthread_cond_wait(&thread_worker, &thread_lock);
pthread_mutex_unlock(&thread_lock);

do {
for (i = 0; i < nfutexes; i++, w->ops++) {
/*
* We want the futex calls to fail in order to stress
* the hashing of uaddr and not measure other steps,
* such as internal waitqueue handling, thus enlarging
* the critical region protected by hb->lock.
*/
ret = futex_wait(&w->futex[i], 1234, NULL,
fshared ? 0 : FUTEX_PRIVATE_FLAG);
if (!silent &&
(!ret || errno != EAGAIN || errno != EWOULDBLOCK))
warn("Non-expected futex return call");
}
} while (!done);

return NULL;
}

static void toggle_done(int sig __maybe_unused,
siginfo_t *info __maybe_unused,
void *uc __maybe_unused)
{
/* inform all threads that we're done for the day */
done = true;
gettimeofday(&end, NULL);
timersub(&end, &start, &runtime);
}

static void print_summary(void)
{
unsigned long avg = avg_stats(&throughput_stats);
double stddev = stddev_stats(&throughput_stats);

printf("%sAveraged %ld operations/sec (+- %.2f%%), total secs = %d\n",
!silent ? "\n" : "", avg, rel_stddev_stats(stddev, avg),
(int) runtime.tv_sec);
}

int bench_futex_hash(int argc, const char **argv,
const char *prefix __maybe_unused)
{
int ret = 0;
cpu_set_t cpu;
struct sigaction act;
unsigned int i, ncpus;
pthread_attr_t thread_attr;
struct worker *worker = NULL;

argc = parse_options(argc, argv, options, bench_futex_hash_usage, 0);
if (argc) {
usage_with_options(bench_futex_hash_usage, options);
exit(EXIT_FAILURE);
}

ncpus = sysconf(_SC_NPROCESSORS_ONLN);

sigfillset(&act.sa_mask);
act.sa_sigaction = toggle_done;
sigaction(SIGINT, &act, NULL);

if (!nthreads) /* default to the number of CPUs */
nthreads = ncpus;

worker = calloc(nthreads, sizeof(*worker));
if (!worker)
goto errmem;

printf("Run summary [PID %d]: %d threads, each operating on %d [%s] futexes for %d secs.\n\n",
getpid(), nthreads, nfutexes, fshared ? "shared":"private", nsecs);

init_stats(&throughput_stats);
pthread_mutex_init(&thread_lock, NULL);
pthread_cond_init(&thread_parent, NULL);
pthread_cond_init(&thread_worker, NULL);

threads_starting = nthreads;
pthread_attr_init(&thread_attr);
gettimeofday(&start, NULL);
for (i = 0; i < nthreads; i++) {
worker[i].tid = i;
worker[i].futex = calloc(nfutexes, sizeof(*worker[i].futex));
if (!worker[i].futex)
goto errmem;

CPU_ZERO(&cpu);
CPU_SET(i % ncpus, &cpu);

ret = pthread_attr_setaffinity_np(&thread_attr, sizeof(cpu_set_t), &cpu);
if (ret)
err(EXIT_FAILURE, "pthread_attr_setaffinity_np");

ret = pthread_create(&worker[i].thread, &thread_attr, workerfn,
(void *)(struct worker *) &worker[i]);
if (ret)
err(EXIT_FAILURE, "pthread_create");

}
pthread_attr_destroy(&thread_attr);

pthread_mutex_lock(&thread_lock);
while (threads_starting)
pthread_cond_wait(&thread_parent, &thread_lock);
pthread_cond_broadcast(&thread_worker);
pthread_mutex_unlock(&thread_lock);

sleep(nsecs);
toggle_done(0, NULL, NULL);

for (i = 0; i < nthreads; i++) {
ret = pthread_join(worker[i].thread, NULL);
if (ret)
err(EXIT_FAILURE, "pthread_join");
}

/* cleanup & report results */
pthread_cond_destroy(&thread_parent);
pthread_cond_destroy(&thread_worker);
pthread_mutex_destroy(&thread_lock);

for (i = 0; i < nthreads; i++) {
unsigned long t = worker[i].ops/runtime.tv_sec;
update_stats(&throughput_stats, t);
if (!silent) {
if (nfutexes == 1)
printf("[thread %2d] futex: %p [ %ld ops/sec ]\n",
worker[i].tid, &worker[i].futex[0], t);
else
printf("[thread %2d] futexes: %p ... %p [ %ld ops/sec ]\n",
worker[i].tid, &worker[i].futex[0],
&worker[i].futex[nfutexes-1], t);
}

free(worker[i].futex);
}

print_summary();

free(worker);
return ret;
errmem:
err(EXIT_FAILURE, "calloc");
}
Loading

0 comments on commit 0afd2d5

Please sign in to comment.