Merge branch 'linus' into perf/core

Conflicts:
	tools/perf/Makefile
	tools/perf/builtin-test.c
	tools/perf/perf.h
	tools/perf/tests/parse-events.c
	tools/perf/util/evsel.h

Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
Ingo Molnar 2012-12-08 15:25:06 +01:00
commit f0b9abfb04
1115 changed files with 13320 additions and 8061 deletions

View file

@ -169,7 +169,35 @@ endif
### --- END CONFIGURATION SECTION ---
BASIC_CFLAGS = -Iutil/include -Iarch/$(ARCH)/include -I$(OUTPUT)util -Iutil -I. -I$(TRACE_EVENT_DIR) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
srctree := $(patsubst %/,%,$(dir $(srctree)))
#$(info Determined 'srctree' to be $(srctree))
endif
ifneq ($(objtree),)
#$(info Determined 'objtree' to be $(objtree))
endif
ifneq ($(OUTPUT),)
#$(info Determined 'OUTPUT' to be $(OUTPUT))
endif
BASIC_CFLAGS = \
-Iutil/include \
-Iarch/$(ARCH)/include \
$(if $(objtree),-I$(objtree)/arch/$(ARCH)/include/generated/uapi) \
-I$(srctree)/arch/$(ARCH)/include/uapi \
-I$(srctree)/arch/$(ARCH)/include \
$(if $(objtree),-I$(objtree)/include/generated/uapi) \
-I$(srctree)/include/uapi \
-I$(srctree)/include \
-I$(OUTPUT)util \
-Iutil \
-I. \
-I$(TRACE_EVENT_DIR) \
-D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
BASIC_LDFLAGS =
ifeq ($(call try-cc,$(SOURCE_BIONIC),$(CFLAGS),bionic),y)

View file

@ -3,7 +3,7 @@
#include <stdlib.h>
#include "../../util/types.h"
#include "../../../../../arch/x86/include/asm/perf_regs.h"
#include <asm/perf_regs.h>
#ifndef ARCH_X86_64
#define PERF_REGS_MASK ((1ULL << PERF_REG_X86_32_MAX) - 1)

View file

@ -22,9 +22,10 @@
#include <pthread.h>
#include <math.h>
#include "../../arch/x86/include/asm/svm.h"
#include "../../arch/x86/include/asm/vmx.h"
#include "../../arch/x86/include/asm/kvm.h"
#if defined(__i386__) || defined(__x86_64__)
#include <asm/svm.h>
#include <asm/vmx.h>
#include <asm/kvm.h>
struct event_key {
#define INVALID_KEY (~0ULL)
@ -58,7 +59,7 @@ struct kvm_event_key {
};
struct perf_kvm;
struct perf_kvm_stat;
struct kvm_events_ops {
bool (*is_begin_event)(struct perf_evsel *evsel,
@ -66,7 +67,7 @@ struct kvm_events_ops {
struct event_key *key);
bool (*is_end_event)(struct perf_evsel *evsel,
struct perf_sample *sample, struct event_key *key);
void (*decode_key)(struct perf_kvm *kvm, struct event_key *key,
void (*decode_key)(struct perf_kvm_stat *kvm, struct event_key *key,
char decode[20]);
const char *name;
};
@ -79,7 +80,7 @@ struct exit_reasons_table {
#define EVENTS_BITS 12
#define EVENTS_CACHE_SIZE (1UL << EVENTS_BITS)
struct perf_kvm {
struct perf_kvm_stat {
struct perf_tool tool;
struct perf_session *session;
@ -146,7 +147,7 @@ static struct exit_reasons_table svm_exit_reasons[] = {
SVM_EXIT_REASONS
};
static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code)
static const char *get_exit_reason(struct perf_kvm_stat *kvm, u64 exit_code)
{
int i = kvm->exit_reasons_size;
struct exit_reasons_table *tbl = kvm->exit_reasons;
@ -162,7 +163,7 @@ static const char *get_exit_reason(struct perf_kvm *kvm, u64 exit_code)
return "UNKNOWN";
}
static void exit_event_decode_key(struct perf_kvm *kvm,
static void exit_event_decode_key(struct perf_kvm_stat *kvm,
struct event_key *key,
char decode[20])
{
@ -228,7 +229,7 @@ static bool mmio_event_end(struct perf_evsel *evsel, struct perf_sample *sample,
return false;
}
static void mmio_event_decode_key(struct perf_kvm *kvm __maybe_unused,
static void mmio_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
struct event_key *key,
char decode[20])
{
@ -271,7 +272,7 @@ static bool ioport_event_end(struct perf_evsel *evsel,
return kvm_entry_event(evsel);
}
static void ioport_event_decode_key(struct perf_kvm *kvm __maybe_unused,
static void ioport_event_decode_key(struct perf_kvm_stat *kvm __maybe_unused,
struct event_key *key,
char decode[20])
{
@ -286,7 +287,7 @@ static struct kvm_events_ops ioport_events = {
.name = "IO Port Access"
};
static bool register_kvm_events_ops(struct perf_kvm *kvm)
static bool register_kvm_events_ops(struct perf_kvm_stat *kvm)
{
bool ret = true;
@ -311,7 +312,7 @@ struct vcpu_event_record {
};
static void init_kvm_event_record(struct perf_kvm *kvm)
static void init_kvm_event_record(struct perf_kvm_stat *kvm)
{
unsigned int i;
@ -360,7 +361,7 @@ static struct kvm_event *kvm_alloc_init_event(struct event_key *key)
return event;
}
static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm,
static struct kvm_event *find_create_kvm_event(struct perf_kvm_stat *kvm,
struct event_key *key)
{
struct kvm_event *event;
@ -382,7 +383,7 @@ static struct kvm_event *find_create_kvm_event(struct perf_kvm *kvm,
return event;
}
static bool handle_begin_event(struct perf_kvm *kvm,
static bool handle_begin_event(struct perf_kvm_stat *kvm,
struct vcpu_event_record *vcpu_record,
struct event_key *key, u64 timestamp)
{
@ -429,7 +430,7 @@ static bool update_kvm_event(struct kvm_event *event, int vcpu_id,
return true;
}
static bool handle_end_event(struct perf_kvm *kvm,
static bool handle_end_event(struct perf_kvm_stat *kvm,
struct vcpu_event_record *vcpu_record,
struct event_key *key,
u64 timestamp)
@ -496,7 +497,7 @@ struct vcpu_event_record *per_vcpu_record(struct thread *thread,
return thread->priv;
}
static bool handle_kvm_event(struct perf_kvm *kvm,
static bool handle_kvm_event(struct perf_kvm_stat *kvm,
struct thread *thread,
struct perf_evsel *evsel,
struct perf_sample *sample)
@ -556,7 +557,7 @@ static struct kvm_event_key keys[] = {
{ NULL, NULL }
};
static bool select_key(struct perf_kvm *kvm)
static bool select_key(struct perf_kvm_stat *kvm)
{
int i;
@ -592,7 +593,8 @@ static void insert_to_result(struct rb_root *result, struct kvm_event *event,
rb_insert_color(&event->rb, result);
}
static void update_total_count(struct perf_kvm *kvm, struct kvm_event *event)
static void
update_total_count(struct perf_kvm_stat *kvm, struct kvm_event *event)
{
int vcpu = kvm->trace_vcpu;
@ -605,7 +607,7 @@ static bool event_is_valid(struct kvm_event *event, int vcpu)
return !!get_event_count(event, vcpu);
}
static void sort_result(struct perf_kvm *kvm)
static void sort_result(struct perf_kvm_stat *kvm)
{
unsigned int i;
int vcpu = kvm->trace_vcpu;
@ -644,7 +646,7 @@ static void print_vcpu_info(int vcpu)
pr_info("VCPU %d:\n\n", vcpu);
}
static void print_result(struct perf_kvm *kvm)
static void print_result(struct perf_kvm_stat *kvm)
{
char decode[20];
struct kvm_event *event;
@ -687,7 +689,8 @@ static int process_sample_event(struct perf_tool *tool,
struct machine *machine)
{
struct thread *thread = machine__findnew_thread(machine, sample->tid);
struct perf_kvm *kvm = container_of(tool, struct perf_kvm, tool);
struct perf_kvm_stat *kvm = container_of(tool, struct perf_kvm_stat,
tool);
if (thread == NULL) {
pr_debug("problem processing %d event, skipping it.\n",
@ -718,7 +721,7 @@ static int get_cpu_isa(struct perf_session *session)
return isa;
}
static int read_events(struct perf_kvm *kvm)
static int read_events(struct perf_kvm_stat *kvm)
{
int ret;
@ -767,7 +770,7 @@ static bool verify_vcpu(int vcpu)
return true;
}
static int kvm_events_report_vcpu(struct perf_kvm *kvm)
static int kvm_events_report_vcpu(struct perf_kvm_stat *kvm)
{
int ret = -EINVAL;
int vcpu = kvm->trace_vcpu;
@ -815,7 +818,8 @@ static const char * const record_args[] = {
_p; \
})
static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv)
static int
kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
{
unsigned int rec_argc, i, j;
const char **rec_argv;
@ -838,7 +842,8 @@ static int kvm_events_record(struct perf_kvm *kvm, int argc, const char **argv)
return cmd_record(i, rec_argv, NULL);
}
static int kvm_events_report(struct perf_kvm *kvm, int argc, const char **argv)
static int
kvm_events_report(struct perf_kvm_stat *kvm, int argc, const char **argv)
{
const struct option kvm_events_report_options[] = {
OPT_STRING(0, "event", &kvm->report_event, "report event",
@ -881,24 +886,37 @@ static void print_kvm_stat_usage(void)
printf("\nOtherwise, it is the alias of 'perf stat':\n");
}
static int kvm_cmd_stat(struct perf_kvm *kvm, int argc, const char **argv)
static int kvm_cmd_stat(const char *file_name, int argc, const char **argv)
{
struct perf_kvm_stat kvm = {
.file_name = file_name,
.trace_vcpu = -1,
.report_event = "vmexit",
.sort_key = "sample",
.exit_reasons = svm_exit_reasons,
.exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
.exit_reasons_isa = "SVM",
};
if (argc == 1) {
print_kvm_stat_usage();
goto perf_stat;
}
if (!strncmp(argv[1], "rec", 3))
return kvm_events_record(kvm, argc - 1, argv + 1);
return kvm_events_record(&kvm, argc - 1, argv + 1);
if (!strncmp(argv[1], "rep", 3))
return kvm_events_report(kvm, argc - 1 , argv + 1);
return kvm_events_report(&kvm, argc - 1 , argv + 1);
perf_stat:
return cmd_stat(argc, argv, NULL);
}
#endif
static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
static int __cmd_record(const char *file_name, int argc, const char **argv)
{
int rec_argc, i = 0, j;
const char **rec_argv;
@ -907,7 +925,7 @@ static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
rec_argv = calloc(rec_argc + 1, sizeof(char *));
rec_argv[i++] = strdup("record");
rec_argv[i++] = strdup("-o");
rec_argv[i++] = strdup(kvm->file_name);
rec_argv[i++] = strdup(file_name);
for (j = 1; j < argc; j++, i++)
rec_argv[i] = argv[j];
@ -916,7 +934,7 @@ static int __cmd_record(struct perf_kvm *kvm, int argc, const char **argv)
return cmd_record(i, rec_argv, NULL);
}
static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
static int __cmd_report(const char *file_name, int argc, const char **argv)
{
int rec_argc, i = 0, j;
const char **rec_argv;
@ -925,7 +943,7 @@ static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
rec_argv = calloc(rec_argc + 1, sizeof(char *));
rec_argv[i++] = strdup("report");
rec_argv[i++] = strdup("-i");
rec_argv[i++] = strdup(kvm->file_name);
rec_argv[i++] = strdup(file_name);
for (j = 1; j < argc; j++, i++)
rec_argv[i] = argv[j];
@ -934,7 +952,8 @@ static int __cmd_report(struct perf_kvm *kvm, int argc, const char **argv)
return cmd_report(i, rec_argv, NULL);
}
static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
static int
__cmd_buildid_list(const char *file_name, int argc, const char **argv)
{
int rec_argc, i = 0, j;
const char **rec_argv;
@ -943,7 +962,7 @@ static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
rec_argv = calloc(rec_argc + 1, sizeof(char *));
rec_argv[i++] = strdup("buildid-list");
rec_argv[i++] = strdup("-i");
rec_argv[i++] = strdup(kvm->file_name);
rec_argv[i++] = strdup(file_name);
for (j = 1; j < argc; j++, i++)
rec_argv[i] = argv[j];
@ -954,20 +973,12 @@ static int __cmd_buildid_list(struct perf_kvm *kvm, int argc, const char **argv)
int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
{
struct perf_kvm kvm = {
.trace_vcpu = -1,
.report_event = "vmexit",
.sort_key = "sample",
.exit_reasons = svm_exit_reasons,
.exit_reasons_size = ARRAY_SIZE(svm_exit_reasons),
.exit_reasons_isa = "SVM",
};
const char *file_name;
const struct option kvm_options[] = {
OPT_STRING('i', "input", &kvm.file_name, "file",
OPT_STRING('i', "input", &file_name, "file",
"Input file name"),
OPT_STRING('o', "output", &kvm.file_name, "file",
OPT_STRING('o', "output", &file_name, "file",
"Output file name"),
OPT_BOOLEAN(0, "guest", &perf_guest,
"Collect guest os data"),
@ -1002,32 +1013,34 @@ int cmd_kvm(int argc, const char **argv, const char *prefix __maybe_unused)
if (!perf_host)
perf_guest = 1;
if (!kvm.file_name) {
if (!file_name) {
if (perf_host && !perf_guest)
kvm.file_name = strdup("perf.data.host");
file_name = strdup("perf.data.host");
else if (!perf_host && perf_guest)
kvm.file_name = strdup("perf.data.guest");
file_name = strdup("perf.data.guest");
else
kvm.file_name = strdup("perf.data.kvm");
file_name = strdup("perf.data.kvm");
if (!kvm.file_name) {
if (!file_name) {
pr_err("Failed to allocate memory for filename\n");
return -ENOMEM;
}
}
if (!strncmp(argv[0], "rec", 3))
return __cmd_record(&kvm, argc, argv);
return __cmd_record(file_name, argc, argv);
else if (!strncmp(argv[0], "rep", 3))
return __cmd_report(&kvm, argc, argv);
return __cmd_report(file_name, argc, argv);
else if (!strncmp(argv[0], "diff", 4))
return cmd_diff(argc, argv, NULL);
else if (!strncmp(argv[0], "top", 3))
return cmd_top(argc, argv, NULL);
else if (!strncmp(argv[0], "buildid-list", 12))
return __cmd_buildid_list(&kvm, argc, argv);
return __cmd_buildid_list(file_name, argc, argv);
#if defined(__i386__) || defined(__x86_64__)
else if (!strncmp(argv[0], "stat", 4))
return kvm_cmd_stat(&kvm, argc, argv);
return kvm_cmd_stat(file_name, argc, argv);
#endif
else
usage_with_options(kvm_usage, kvm_options);

View file

@ -5,8 +5,9 @@ struct winsize;
void get_term_dimensions(struct winsize *ws);
#include <asm/unistd.h>
#if defined(__i386__)
#include "../../arch/x86/include/asm/unistd.h"
#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
#define CPUINFO_PROC "model name"
@ -16,7 +17,6 @@ void get_term_dimensions(struct winsize *ws);
#endif
#if defined(__x86_64__)
#include "../../arch/x86/include/asm/unistd.h"
#define rmb() asm volatile("lfence" ::: "memory")
#define cpu_relax() asm volatile("rep; nop" ::: "memory");
#define CPUINFO_PROC "model name"
@ -33,13 +33,11 @@ void get_term_dimensions(struct winsize *ws);
#endif
#ifdef __s390__
#include "../../arch/s390/include/asm/unistd.h"
#define rmb() asm volatile("bcr 15,0" ::: "memory")
#define cpu_relax() asm volatile("" ::: "memory");
#endif
#ifdef __sh__
#include "../../arch/sh/include/asm/unistd.h"
#if defined(__SH4A__) || defined(__SH5__)
# define rmb() asm volatile("synco" ::: "memory")
#else
@ -50,35 +48,30 @@ void get_term_dimensions(struct winsize *ws);
#endif
#ifdef __hppa__
#include "../../arch/parisc/include/asm/unistd.h"
#define rmb() asm volatile("" ::: "memory")
#define cpu_relax() asm volatile("" ::: "memory");
#define CPUINFO_PROC "cpu"
#endif
#ifdef __sparc__
#include "../../arch/sparc/include/uapi/asm/unistd.h"
#define rmb() asm volatile("":::"memory")
#define cpu_relax() asm volatile("":::"memory")
#define CPUINFO_PROC "cpu"
#endif
#ifdef __alpha__
#include "../../arch/alpha/include/asm/unistd.h"
#define rmb() asm volatile("mb" ::: "memory")
#define cpu_relax() asm volatile("" ::: "memory")
#define CPUINFO_PROC "cpu model"
#endif
#ifdef __ia64__
#include "../../arch/ia64/include/asm/unistd.h"
#define rmb() asm volatile ("mf" ::: "memory")
#define cpu_relax() asm volatile ("hint @pause" ::: "memory")
#define CPUINFO_PROC "model name"
#endif
#ifdef __arm__
#include "../../arch/arm/include/asm/unistd.h"
/*
* Use the __kuser_memory_barrier helper in the CPU helper page. See
* arch/arm/kernel/entry-armv.S in the kernel source for details.
@ -89,13 +82,11 @@ void get_term_dimensions(struct winsize *ws);
#endif
#ifdef __aarch64__
#include "../../arch/arm64/include/asm/unistd.h"
#define rmb() asm volatile("dmb ld" ::: "memory")
#define cpu_relax() asm volatile("yield" ::: "memory")
#endif
#ifdef __mips__
#include "../../arch/mips/include/asm/unistd.h"
#define rmb() asm volatile( \
".set mips2\n\t" \
"sync\n\t" \
@ -112,7 +103,7 @@ void get_term_dimensions(struct winsize *ws);
#include <sys/types.h>
#include <sys/syscall.h>
#include "../../include/uapi/linux/perf_event.h"
#include <linux/perf_event.h>
#include "util/types.h"
#include <stdbool.h>

View file

@ -3,8 +3,8 @@
#include "evsel.h"
#include "evlist.h"
#include "sysfs.h"
#include "../../../include/linux/hw_breakpoint.h"
#include "tests.h"
#include <linux/hw_breakpoint.h>
#define TEST_ASSERT_VAL(text, cond) \
do { \

View file

@ -18,8 +18,8 @@
#include "cpumap.h"
#include "thread_map.h"
#include "target.h"
#include "../../../include/linux/hw_breakpoint.h"
#include "../../../include/uapi/linux/perf_event.h"
#include <linux/hw_breakpoint.h>
#include <linux/perf_event.h>
#include "perf_regs.h"
#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))

View file

@ -4,7 +4,7 @@
#include <linux/list.h>
#include <stdbool.h>
#include <stddef.h>
#include "../../../include/uapi/linux/perf_event.h"
#include <linux/perf_event.h>
#include "types.h"
#include "xyarray.h"
#include "cgroup.h"

View file

@ -1379,6 +1379,8 @@ static void print_numa_topology(struct perf_header *ph, int fd __maybe_unused,
str = tmp + 1;
fprintf(fp, "# node%u cpu list : %s\n", c, str);
str += strlen(str) + 1;
}
return;
error:

View file

@ -1,7 +1,7 @@
#ifndef __PERF_HEADER_H
#define __PERF_HEADER_H
#include "../../../include/uapi/linux/perf_event.h"
#include <linux/perf_event.h>
#include <sys/types.h>
#include <stdbool.h>
#include "types.h"

View file

@ -1,4 +1,4 @@
#include "../../../include/linux/hw_breakpoint.h"
#include <linux/hw_breakpoint.h>
#include "util.h"
#include "../perf.h"
#include "evlist.h"

View file

@ -7,7 +7,7 @@
#include <linux/list.h>
#include <stdbool.h>
#include "types.h"
#include "../../../include/uapi/linux/perf_event.h"
#include <linux/perf_event.h>
#include "types.h"
struct list_head;

View file

@ -2,7 +2,7 @@
#define __PMU_H
#include <linux/bitops.h>
#include "../../../include/uapi/linux/perf_event.h"
#include <linux/perf_event.h>
enum {
PERF_PMU_FORMAT_VALUE_CONFIG,

View file

@ -8,7 +8,7 @@
#include "symbol.h"
#include "thread.h"
#include <linux/rbtree.h>
#include "../../../include/uapi/linux/perf_event.h"
#include <linux/perf_event.h>
struct sample_queue;
struct ip_callchain;

View file

@ -90,17 +90,17 @@ void strbuf_addf(struct strbuf *sb, const char *fmt, ...)
if (!strbuf_avail(sb))
strbuf_grow(sb, 64);
va_start(ap, fmt);
len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
va_end(ap);
if (len < 0)
die("your vscnprintf is broken");
die("your vsnprintf is broken");
if (len > strbuf_avail(sb)) {
strbuf_grow(sb, len);
va_start(ap, fmt);
len = vscnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap);
va_end(ap);
if (len > strbuf_avail(sb)) {
die("this should not happen, your snprintf is broken");
die("this should not happen, your vsnprintf is broken");
}
}
strbuf_setlen(sb, sb->len + len);

View file

@ -206,8 +206,10 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr)
retval = pread(fd, msr, sizeof *msr, offset);
close(fd);
if (retval != sizeof *msr)
if (retval != sizeof *msr) {
fprintf(stderr, "%s offset 0x%zx read failed\n", pathname, offset);
return -1;
}
return 0;
}
@ -1101,7 +1103,9 @@ void turbostat_loop()
restart:
retval = for_all_cpus(get_counters, EVEN_COUNTERS);
if (retval) {
if (retval < -1) {
exit(retval);
} else if (retval == -1) {
re_initialize();
goto restart;
}
@ -1114,7 +1118,9 @@ restart:
}
sleep(interval_sec);
retval = for_all_cpus(get_counters, ODD_COUNTERS);
if (retval) {
if (retval < -1) {
exit(retval);
} else if (retval == -1) {
re_initialize();
goto restart;
}
@ -1126,7 +1132,9 @@ restart:
flush_stdout();
sleep(interval_sec);
retval = for_all_cpus(get_counters, EVEN_COUNTERS);
if (retval) {
if (retval < -1) {
exit(retval);
} else if (retval == -1) {
re_initialize();
goto restart;
}
@ -1545,8 +1553,11 @@ void turbostat_init()
int fork_it(char **argv)
{
pid_t child_pid;
int status;
for_all_cpus(get_counters, EVEN_COUNTERS);
status = for_all_cpus(get_counters, EVEN_COUNTERS);
if (status)
exit(status);
/* clear affinity side-effect of get_counters() */
sched_setaffinity(0, cpu_present_setsize, cpu_present_set);
gettimeofday(&tv_even, (struct timezone *)NULL);
@ -1556,7 +1567,6 @@ int fork_it(char **argv)
/* child */
execvp(argv[0], argv);
} else {
int status;
/* parent */
if (child_pid == -1) {
@ -1568,7 +1578,7 @@ int fork_it(char **argv)
signal(SIGQUIT, SIG_IGN);
if (waitpid(child_pid, &status, 0) == -1) {
perror("wait");
exit(1);
exit(status);
}
}
/*
@ -1585,7 +1595,7 @@ int fork_it(char **argv)
fprintf(stderr, "%.6f sec\n", tv_delta.tv_sec + tv_delta.tv_usec/1000000.0);
return 0;
return status;
}
void cmdline(int argc, char **argv)
@ -1594,7 +1604,7 @@ void cmdline(int argc, char **argv)
progname = argv[0];
while ((opt = getopt(argc, argv, "+pPSvisc:sC:m:M:")) != -1) {
while ((opt = getopt(argc, argv, "+pPSvi:sc:sC:m:M:")) != -1) {
switch (opt) {
case 'p':
show_core_only++;

View file

@ -1740,8 +1740,10 @@ sub install {
open(IN, "$output_config") or dodie("Can't read config file");
while (<IN>) {
if (/CONFIG_MODULES(=y)?/) {
$install_mods = 1 if (defined($1));
last;
if (defined($1)) {
$install_mods = 1;
last;
}
}
}
close(IN);

View file

@ -1,4 +1,4 @@
TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug epoll
TARGETS = breakpoints kcmp mqueue vm cpu-hotplug memory-hotplug
all:
for TARGET in $(TARGETS); do \

View file

@ -1,11 +0,0 @@
# Makefile for epoll selftests
all: test_epoll
%: %.c
gcc -pthread -g -o $@ $^
run_tests: all
./test_epoll
clean:
$(RM) test_epoll

View file

@ -1,344 +0,0 @@
/*
* tools/testing/selftests/epoll/test_epoll.c
*
* Copyright 2012 Adobe Systems Incorporated
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Paton J. Lewis <palewis@adobe.com>
*
*/
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/socket.h>
/*
* A pointer to an epoll_item_private structure will be stored in the epoll
* item's event structure so that we can get access to the epoll_item_private
* data after calling epoll_wait:
*/
struct epoll_item_private {
int index; /* Position of this struct within the epoll_items array. */
int fd;
uint32_t events;
pthread_mutex_t mutex; /* Guards the following variables... */
int stop;
int status; /* Stores any error encountered while handling item. */
/* The following variable allows us to test whether we have encountered
a problem while attempting to cancel and delete the associated
event. When the test program exits, 'deleted' should be exactly
one. If it is greater than one, then the failed test reflects a real
world situation where we would have tried to access the epoll item's
private data after deleting it: */
int deleted;
};
struct epoll_item_private *epoll_items;
/*
* Delete the specified item from the epoll set. In a real-world secneario this
* is where we would free the associated data structure, but in this testing
* environment we retain the structure so that we can test for double-deletion:
*/
void delete_item(int index)
{
__sync_fetch_and_add(&epoll_items[index].deleted, 1);
}
/*
* A pointer to a read_thread_data structure will be passed as the argument to
* each read thread:
*/
struct read_thread_data {
int stop;
int status; /* Indicates any error encountered by the read thread. */
int epoll_set;
};
/*
* The function executed by the read threads:
*/
void *read_thread_function(void *function_data)
{
struct read_thread_data *thread_data =
(struct read_thread_data *)function_data;
struct epoll_event event_data;
struct epoll_item_private *item_data;
char socket_data;
/* Handle events until we encounter an error or this thread's 'stop'
condition is set: */
while (1) {
int result = epoll_wait(thread_data->epoll_set,
&event_data,
1, /* Number of desired events */
1000); /* Timeout in ms */
if (result < 0) {
/* Breakpoints signal all threads. Ignore that while
debugging: */
if (errno == EINTR)
continue;
thread_data->status = errno;
return 0;
} else if (thread_data->stop)
return 0;
else if (result == 0) /* Timeout */
continue;
/* We need the mutex here because checking for the stop
condition and re-enabling the epoll item need to be done
together as one atomic operation when EPOLL_CTL_DISABLE is
available: */
item_data = (struct epoll_item_private *)event_data.data.ptr;
pthread_mutex_lock(&item_data->mutex);
/* Remove the item from the epoll set if we want to stop
handling that event: */
if (item_data->stop)
delete_item(item_data->index);
else {
/* Clear the data that was written to the other end of
our non-blocking socket: */
do {
if (read(item_data->fd, &socket_data, 1) < 1) {
if ((errno == EAGAIN) ||
(errno == EWOULDBLOCK))
break;
else
goto error_unlock;
}
} while (item_data->events & EPOLLET);
/* The item was one-shot, so re-enable it: */
event_data.events = item_data->events;
if (epoll_ctl(thread_data->epoll_set,
EPOLL_CTL_MOD,
item_data->fd,
&event_data) < 0)
goto error_unlock;
}
pthread_mutex_unlock(&item_data->mutex);
}
error_unlock:
thread_data->status = item_data->status = errno;
pthread_mutex_unlock(&item_data->mutex);
return 0;
}
/*
* A pointer to a write_thread_data structure will be passed as the argument to
* the write thread:
*/
struct write_thread_data {
int stop;
int status; /* Indicates any error encountered by the write thread. */
int n_fds;
int *fds;
};
/*
* The function executed by the write thread. It writes a single byte to each
* socket in turn until the stop condition for this thread is set. If writing to
* a socket would block (i.e. errno was EAGAIN), we leave that socket alone for
* the moment and just move on to the next socket in the list. We don't care
* about the order in which we deliver events to the epoll set. In fact we don't
* care about the data we're writing to the pipes at all; we just want to
* trigger epoll events:
*/
void *write_thread_function(void *function_data)
{
const char data = 'X';
int index;
struct write_thread_data *thread_data =
(struct write_thread_data *)function_data;
while (!write_thread_data->stop)
for (index = 0;
!thread_data->stop && (index < thread_data->n_fds);
++index)
if ((write(thread_data->fds[index], &data, 1) < 1) &&
(errno != EAGAIN) &&
(errno != EWOULDBLOCK)) {
write_thread_data->status = errno;
return;
}
}
/*
* Arguments are currently ignored:
*/
int main(int argc, char **argv)
{
const int n_read_threads = 100;
const int n_epoll_items = 500;
int index;
int epoll_set = epoll_create1(0);
struct write_thread_data write_thread_data = {
0, 0, n_epoll_items, malloc(n_epoll_items * sizeof(int))
};
struct read_thread_data *read_thread_data =
malloc(n_read_threads * sizeof(struct read_thread_data));
pthread_t *read_threads = malloc(n_read_threads * sizeof(pthread_t));
pthread_t write_thread;
printf("-----------------\n");
printf("Runing test_epoll\n");
printf("-----------------\n");
epoll_items = malloc(n_epoll_items * sizeof(struct epoll_item_private));
if (epoll_set < 0 || epoll_items == 0 || write_thread_data.fds == 0 ||
read_thread_data == 0 || read_threads == 0)
goto error;
if (sysconf(_SC_NPROCESSORS_ONLN) < 2) {
printf("Error: please run this test on a multi-core system.\n");
goto error;
}
/* Create the socket pairs and epoll items: */
for (index = 0; index < n_epoll_items; ++index) {
int socket_pair[2];
struct epoll_event event_data;
if (socketpair(AF_UNIX,
SOCK_STREAM | SOCK_NONBLOCK,
0,
socket_pair) < 0)
goto error;
write_thread_data.fds[index] = socket_pair[0];
epoll_items[index].index = index;
epoll_items[index].fd = socket_pair[1];
if (pthread_mutex_init(&epoll_items[index].mutex, NULL) != 0)
goto error;
/* We always use EPOLLONESHOT because this test is currently
structured to demonstrate the need for EPOLL_CTL_DISABLE,
which only produces useful information in the EPOLLONESHOT
case (without EPOLLONESHOT, calling epoll_ctl with
EPOLL_CTL_DISABLE will never return EBUSY). If support for
testing events without EPOLLONESHOT is desired, it should
probably be implemented in a separate unit test. */
epoll_items[index].events = EPOLLIN | EPOLLONESHOT;
if (index < n_epoll_items / 2)
epoll_items[index].events |= EPOLLET;
epoll_items[index].stop = 0;
epoll_items[index].status = 0;
epoll_items[index].deleted = 0;
event_data.events = epoll_items[index].events;
event_data.data.ptr = &epoll_items[index];
if (epoll_ctl(epoll_set,
EPOLL_CTL_ADD,
epoll_items[index].fd,
&event_data) < 0)
goto error;
}
/* Create and start the read threads: */
for (index = 0; index < n_read_threads; ++index) {
read_thread_data[index].stop = 0;
read_thread_data[index].status = 0;
read_thread_data[index].epoll_set = epoll_set;
if (pthread_create(&read_threads[index],
NULL,
read_thread_function,
&read_thread_data[index]) != 0)
goto error;
}
if (pthread_create(&write_thread,
NULL,
write_thread_function,
&write_thread_data) != 0)
goto error;
/* Cancel all event pollers: */
#ifdef EPOLL_CTL_DISABLE
for (index = 0; index < n_epoll_items; ++index) {
pthread_mutex_lock(&epoll_items[index].mutex);
++epoll_items[index].stop;
if (epoll_ctl(epoll_set,
EPOLL_CTL_DISABLE,
epoll_items[index].fd,
NULL) == 0)
delete_item(index);
else if (errno != EBUSY) {
pthread_mutex_unlock(&epoll_items[index].mutex);
goto error;
}
/* EBUSY means events were being handled; allow the other thread
to delete the item. */
pthread_mutex_unlock(&epoll_items[index].mutex);
}
#else
for (index = 0; index < n_epoll_items; ++index) {
pthread_mutex_lock(&epoll_items[index].mutex);
++epoll_items[index].stop;
pthread_mutex_unlock(&epoll_items[index].mutex);
/* Wait in case a thread running read_thread_function is
currently executing code between epoll_wait and
pthread_mutex_lock with this item. Note that a longer delay
would make double-deletion less likely (at the expense of
performance), but there is no guarantee that any delay would
ever be sufficient. Note also that we delete all event
pollers at once for testing purposes, but in a real-world
environment we are likely to want to be able to cancel event
pollers at arbitrary times. Therefore we can't improve this
situation by just splitting this loop into two loops
(i.e. signal 'stop' for all items, sleep, and then delete all
items). We also can't fix the problem via EPOLL_CTL_DEL
because that command can't prevent the case where some other
thread is executing read_thread_function within the region
mentioned above: */
usleep(1);
pthread_mutex_lock(&epoll_items[index].mutex);
if (!epoll_items[index].deleted)
delete_item(index);
pthread_mutex_unlock(&epoll_items[index].mutex);
}
#endif
/* Shut down the read threads: */
for (index = 0; index < n_read_threads; ++index)
__sync_fetch_and_add(&read_thread_data[index].stop, 1);
for (index = 0; index < n_read_threads; ++index) {
if (pthread_join(read_threads[index], NULL) != 0)
goto error;
if (read_thread_data[index].status)
goto error;
}
/* Shut down the write thread: */
__sync_fetch_and_add(&write_thread_data.stop, 1);
if ((pthread_join(write_thread, NULL) != 0) || write_thread_data.status)
goto error;
/* Check for final error conditions: */
for (index = 0; index < n_epoll_items; ++index) {
if (epoll_items[index].status != 0)
goto error;
if (pthread_mutex_destroy(&epoll_items[index].mutex) < 0)
goto error;
}
for (index = 0; index < n_epoll_items; ++index)
if (epoll_items[index].deleted != 1) {
printf("Error: item data deleted %1d times.\n",
epoll_items[index].deleted);
goto error;
}
printf("[PASS]\n");
return 0;
error:
printf("[FAIL]\n");
return errno;
}

View file

@ -35,7 +35,7 @@
#include <sys/mount.h>
#include <sys/statfs.h>
#include "../../include/uapi/linux/magic.h"
#include "../../include/linux/kernel-page-flags.h"
#include "../../include/uapi/linux/kernel-page-flags.h"
#ifndef MAX_PATH