Skip to content

Commit

Permalink
Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…linux/kernel/git/tip/linux-2.6-tip

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  perf tools: Fix sample size bit operations
  perf tools: Fix ommitted mmap data update on remap
  watchdog: Change the default timeout and configure nmi watchdog period based on watchdog_thresh
  watchdog: Disable watchdog when thresh is zero
  watchdog: Only disable/enable watchdog if neccessary
  watchdog: Fix rounding bug in get_sample_period()
  perf tools: Propagate event parse error handling
  perf tools: Robustify dynamic sample content fetch
  perf tools: Pre-check sample size before parsing
  perf tools: Move evlist sample helpers to evlist area
  perf tools: Remove junk code in mmap size handling
  perf tools: Check we are able to read the event size on mmap
  • Loading branch information
torvalds committed May 23, 2011
2 parents 57d19e8 + 3cb6d15 commit 1950482
Show file tree
Hide file tree
Showing 18 changed files with 216 additions and 100 deletions.
4 changes: 2 additions & 2 deletions arch/x86/kernel/apic/hw_nmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
#include <linux/delay.h>

#ifdef CONFIG_HARDLOCKUP_DETECTOR
u64 hw_nmi_get_sample_period(void)
u64 hw_nmi_get_sample_period(int watchdog_thresh)
{
return (u64)(cpu_khz) * 1000 * 60;
return (u64)(cpu_khz) * 1000 * watchdog_thresh;
}
#endif

Expand Down
7 changes: 4 additions & 3 deletions include/linux/nmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,12 @@ static inline bool trigger_all_cpu_backtrace(void)

#ifdef CONFIG_LOCKUP_DETECTOR
int hw_nmi_is_cpu_stuck(struct pt_regs *);
u64 hw_nmi_get_sample_period(void);
u64 hw_nmi_get_sample_period(int watchdog_thresh);
extern int watchdog_enabled;
extern int watchdog_thresh;
struct ctl_table;
extern int proc_dowatchdog_enabled(struct ctl_table *, int ,
void __user *, size_t *, loff_t *);
extern int proc_dowatchdog(struct ctl_table *, int ,
void __user *, size_t *, loff_t *);
#endif

#endif
1 change: 0 additions & 1 deletion include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,6 @@ extern int proc_dowatchdog_thresh(struct ctl_table *table, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos);
extern unsigned int softlockup_panic;
extern int softlockup_thresh;
void lockup_detector_init(void);
#else
static inline void touch_softlockup_watchdog(void)
Expand Down
12 changes: 8 additions & 4 deletions kernel/sysctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,14 +730,16 @@ static struct ctl_table kern_table[] = {
.data = &watchdog_enabled,
.maxlen = sizeof (int),
.mode = 0644,
.proc_handler = proc_dowatchdog_enabled,
.proc_handler = proc_dowatchdog,
.extra1 = &zero,
.extra2 = &one,
},
{
.procname = "watchdog_thresh",
.data = &softlockup_thresh,
.data = &watchdog_thresh,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dowatchdog_thresh,
.proc_handler = proc_dowatchdog,
.extra1 = &neg_one,
.extra2 = &sixty,
},
Expand All @@ -755,7 +757,9 @@ static struct ctl_table kern_table[] = {
.data = &watchdog_enabled,
.maxlen = sizeof (int),
.mode = 0644,
.proc_handler = proc_dowatchdog_enabled,
.proc_handler = proc_dowatchdog,
.extra1 = &zero,
.extra2 = &one,
},
#endif
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
Expand Down
52 changes: 30 additions & 22 deletions kernel/watchdog.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include <linux/perf_event.h>

int watchdog_enabled = 1;
int __read_mostly softlockup_thresh = 60;
int __read_mostly watchdog_thresh = 10;

static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts);
static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog);
Expand Down Expand Up @@ -91,6 +91,17 @@ static int __init nosoftlockup_setup(char *str)
__setup("nosoftlockup", nosoftlockup_setup);
/* */

/*
* Hard-lockup warnings should be triggered after just a few seconds. Soft-
* lockups can have false positives under extreme conditions. So we generally
* want a higher threshold for soft lockups than for hard lockups. So we couple
* the thresholds with a factor: we make the soft threshold twice the amount of
* time the hard threshold is.
*/
static int get_softlockup_thresh()
{
return watchdog_thresh * 2;
}

/*
* Returns seconds, approximately. We don't need nanosecond
Expand All @@ -105,12 +116,12 @@ static unsigned long get_timestamp(int this_cpu)
static unsigned long get_sample_period(void)
{
/*
* convert softlockup_thresh from seconds to ns
* convert watchdog_thresh from seconds to ns
* the divide by 5 is to give hrtimer 5 chances to
* increment before the hardlockup detector generates
* a warning
*/
return softlockup_thresh / 5 * NSEC_PER_SEC;
return get_softlockup_thresh() * (NSEC_PER_SEC / 5);
}

/* Commands for resetting the watchdog */
Expand Down Expand Up @@ -182,7 +193,7 @@ static int is_softlockup(unsigned long touch_ts)
unsigned long now = get_timestamp(smp_processor_id());

/* Warn about unreasonable delays: */
if (time_after(now, touch_ts + softlockup_thresh))
if (time_after(now, touch_ts + get_softlockup_thresh()))
return now - touch_ts;

return 0;
Expand Down Expand Up @@ -359,7 +370,7 @@ static int watchdog_nmi_enable(int cpu)

/* Try to register using hardware perf events */
wd_attr = &wd_hw_attr;
wd_attr->sample_period = hw_nmi_get_sample_period();
wd_attr->sample_period = hw_nmi_get_sample_period(watchdog_thresh);
event = perf_event_create_kernel_counter(wd_attr, cpu, NULL, watchdog_overflow_callback);
if (!IS_ERR(event)) {
printk(KERN_INFO "NMI watchdog enabled, takes one hw-pmu counter.\n");
Expand Down Expand Up @@ -501,28 +512,25 @@ static void watchdog_disable_all_cpus(void)
/* sysctl functions */
#ifdef CONFIG_SYSCTL
/*
* proc handler for /proc/sys/kernel/nmi_watchdog
* proc handler for /proc/sys/kernel/nmi_watchdog,watchdog_thresh
*/

int proc_dowatchdog_enabled(struct ctl_table *table, int write,
void __user *buffer, size_t *length, loff_t *ppos)
int proc_dowatchdog(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
proc_dointvec(table, write, buffer, length, ppos);
int ret;

if (write) {
if (watchdog_enabled)
watchdog_enable_all_cpus();
else
watchdog_disable_all_cpus();
}
return 0;
}
ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
if (ret || !write)
goto out;

int proc_dowatchdog_thresh(struct ctl_table *table, int write,
void __user *buffer,
size_t *lenp, loff_t *ppos)
{
return proc_dointvec_minmax(table, write, buffer, lenp, ppos);
if (watchdog_enabled && watchdog_thresh)
watchdog_enable_all_cpus();
else
watchdog_disable_all_cpus();

out:
return ret;
}
#endif /* CONFIG_SYSCTL */

Expand Down
9 changes: 8 additions & 1 deletion tools/perf/builtin-test.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ static int test__basic_mmap(void)
unsigned int nr_events[nsyscalls],
expected_nr_events[nsyscalls], i, j;
struct perf_evsel *evsels[nsyscalls], *evsel;
int sample_size = perf_sample_size(attr.sample_type);

for (i = 0; i < nsyscalls; ++i) {
char name[64];
Expand Down Expand Up @@ -558,7 +559,13 @@ static int test__basic_mmap(void)
goto out_munmap;
}

perf_event__parse_sample(event, attr.sample_type, false, &sample);
err = perf_event__parse_sample(event, attr.sample_type, sample_size,
false, &sample);
if (err) {
pr_err("Can't parse sample, err = %d\n", err);
goto out_munmap;
}

evsel = perf_evlist__id2evsel(evlist, sample.id);
if (evsel == NULL) {
pr_debug("event with id %" PRIu64
Expand Down
7 changes: 6 additions & 1 deletion tools/perf/builtin-top.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,9 +805,14 @@ static void perf_session__mmap_read_idx(struct perf_session *self, int idx)
{
struct perf_sample sample;
union perf_event *event;
int ret;

while ((event = perf_evlist__mmap_read(top.evlist, idx)) != NULL) {
perf_session__parse_sample(self, event, &sample);
ret = perf_session__parse_sample(self, event, &sample);
if (ret) {
pr_err("Can't parse sample, err = %d\n", ret);
continue;
}

if (event->header.type == PERF_RECORD_SAMPLE)
perf_event__process_sample(event, &sample, self);
Expand Down
46 changes: 31 additions & 15 deletions tools/perf/util/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@
#include "thread_map.h"

static const char *perf_event__names[] = {
[0] = "TOTAL",
[PERF_RECORD_MMAP] = "MMAP",
[PERF_RECORD_LOST] = "LOST",
[PERF_RECORD_COMM] = "COMM",
[PERF_RECORD_EXIT] = "EXIT",
[PERF_RECORD_THROTTLE] = "THROTTLE",
[PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
[PERF_RECORD_FORK] = "FORK",
[PERF_RECORD_READ] = "READ",
[PERF_RECORD_SAMPLE] = "SAMPLE",
[PERF_RECORD_HEADER_ATTR] = "ATTR",
[PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
[PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
[PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
[PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
[0] = "TOTAL",
[PERF_RECORD_MMAP] = "MMAP",
[PERF_RECORD_LOST] = "LOST",
[PERF_RECORD_COMM] = "COMM",
[PERF_RECORD_EXIT] = "EXIT",
[PERF_RECORD_THROTTLE] = "THROTTLE",
[PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE",
[PERF_RECORD_FORK] = "FORK",
[PERF_RECORD_READ] = "READ",
[PERF_RECORD_SAMPLE] = "SAMPLE",
[PERF_RECORD_HEADER_ATTR] = "ATTR",
[PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE",
[PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
[PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
[PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
};

const char *perf_event__name(unsigned int id)
Expand All @@ -35,6 +35,22 @@ const char *perf_event__name(unsigned int id)
return perf_event__names[id];
}

int perf_sample_size(u64 sample_type)
{
u64 mask = sample_type & PERF_SAMPLE_MASK;
int size = 0;
int i;

for (i = 0; i < 64; i++) {
if (mask & (1UL << i))
size++;
}

size *= sizeof(u64);

return size;
}

static struct perf_sample synth_sample = {
.pid = -1,
.tid = -1,
Expand Down
12 changes: 11 additions & 1 deletion tools/perf/util/event.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ struct read_event {
u64 id;
};


#define PERF_SAMPLE_MASK \
(PERF_SAMPLE_IP | PERF_SAMPLE_TID | \
PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | \
PERF_SAMPLE_ID | PERF_SAMPLE_STREAM_ID | \
PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)

struct sample_event {
struct perf_event_header header;
u64 array[];
Expand All @@ -75,6 +82,8 @@ struct perf_sample {
struct ip_callchain *callchain;
};

int perf_sample_size(u64 sample_type);

#define BUILD_ID_SIZE 20

struct build_id_event {
Expand Down Expand Up @@ -178,6 +187,7 @@ int perf_event__preprocess_sample(const union perf_event *self,
const char *perf_event__name(unsigned int id);

int perf_event__parse_sample(const union perf_event *event, u64 type,
bool sample_id_all, struct perf_sample *sample);
int sample_size, bool sample_id_all,
struct perf_sample *sample);

#endif /* __PERF_RECORD_H */
31 changes: 31 additions & 0 deletions tools/perf/util/evlist.c
Original file line number Diff line number Diff line change
Expand Up @@ -459,3 +459,34 @@ int perf_evlist__set_filters(struct perf_evlist *evlist)

return 0;
}

u64 perf_evlist__sample_type(struct perf_evlist *evlist)
{
struct perf_evsel *pos;
u64 type = 0;

list_for_each_entry(pos, &evlist->entries, node) {
if (!type)
type = pos->attr.sample_type;
else if (type != pos->attr.sample_type)
die("non matching sample_type");
}

return type;
}

bool perf_evlist__sample_id_all(const struct perf_evlist *evlist)
{
bool value = false, first = true;
struct perf_evsel *pos;

list_for_each_entry(pos, &evlist->entries, node) {
if (first) {
value = pos->attr.sample_id_all;
first = false;
} else if (value != pos->attr.sample_id_all)
die("non matching sample_id_all");
}

return value;
}
3 changes: 3 additions & 0 deletions tools/perf/util/evlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,7 @@ int perf_evlist__create_maps(struct perf_evlist *evlist, pid_t target_pid,
void perf_evlist__delete_maps(struct perf_evlist *evlist);
int perf_evlist__set_filters(struct perf_evlist *evlist);

u64 perf_evlist__sample_type(struct perf_evlist *evlist);
bool perf_evlist__sample_id_all(const struct perf_evlist *evlist);

#endif /* __PERF_EVLIST_H */
Loading

0 comments on commit 1950482

Please sign in to comment.