diff options
| author | Takashi Iwai <tiwai@suse.de> | 2010-01-12 03:40:48 -0500 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2010-01-12 03:40:48 -0500 |
| commit | dba9532388b00d591d87c638a47dcc7ba3763fc5 (patch) | |
| tree | cc9de8cbc40d0e927b1924d1d943208e84e21d1f /kernel/trace/trace_ksym.c | |
| parent | 78b8d5d2ee280c463908fd75f3bdf246bcb6ac8d (diff) | |
| parent | c68db7175f4dcb3d5789bb50bea6376fb81f87fe (diff) | |
Merge remote branch 'alsa/fixes' into fix/misc
Diffstat (limited to 'kernel/trace/trace_ksym.c')
| -rw-r--r-- | kernel/trace/trace_ksym.c | 140 |
1 files changed, 57 insertions, 83 deletions
diff --git a/kernel/trace/trace_ksym.c b/kernel/trace/trace_ksym.c index faf37fa4408c..94103cdcf9d8 100644 --- a/kernel/trace/trace_ksym.c +++ b/kernel/trace/trace_ksym.c | |||
| @@ -26,12 +26,13 @@ | |||
| 26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
| 27 | 27 | ||
| 28 | #include "trace_output.h" | 28 | #include "trace_output.h" |
| 29 | #include "trace_stat.h" | ||
| 30 | #include "trace.h" | 29 | #include "trace.h" |
| 31 | 30 | ||
| 32 | #include <linux/hw_breakpoint.h> | 31 | #include <linux/hw_breakpoint.h> |
| 33 | #include <asm/hw_breakpoint.h> | 32 | #include <asm/hw_breakpoint.h> |
| 34 | 33 | ||
| 34 | #include <asm/atomic.h> | ||
| 35 | |||
| 35 | /* | 36 | /* |
| 36 | * For now, let us restrict the no. of symbols traced simultaneously to number | 37 | * For now, let us restrict the no. of symbols traced simultaneously to number |
| 37 | * of available hardware breakpoint registers. | 38 | * of available hardware breakpoint registers. |
| @@ -44,7 +45,7 @@ struct trace_ksym { | |||
| 44 | struct perf_event **ksym_hbp; | 45 | struct perf_event **ksym_hbp; |
| 45 | struct perf_event_attr attr; | 46 | struct perf_event_attr attr; |
| 46 | #ifdef CONFIG_PROFILE_KSYM_TRACER | 47 | #ifdef CONFIG_PROFILE_KSYM_TRACER |
| 47 | unsigned long counter; | 48 | atomic64_t counter; |
| 48 | #endif | 49 | #endif |
| 49 | struct hlist_node ksym_hlist; | 50 | struct hlist_node ksym_hlist; |
| 50 | }; | 51 | }; |
| @@ -69,9 +70,8 @@ void ksym_collect_stats(unsigned long hbp_hit_addr) | |||
| 69 | 70 | ||
| 70 | rcu_read_lock(); | 71 | rcu_read_lock(); |
| 71 | hlist_for_each_entry_rcu(entry, node, &ksym_filter_head, ksym_hlist) { | 72 | hlist_for_each_entry_rcu(entry, node, &ksym_filter_head, ksym_hlist) { |
| 72 | if ((entry->attr.bp_addr == hbp_hit_addr) && | 73 | if (entry->attr.bp_addr == hbp_hit_addr) { |
| 73 | (entry->counter <= MAX_UL_INT)) { | 74 | atomic64_inc(&entry->counter); |
| 74 | entry->counter++; | ||
| 75 | break; | 75 | break; |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| @@ -197,7 +197,6 @@ int process_new_ksym_entry(char *ksymname, int op, unsigned long addr) | |||
| 197 | entry->attr.bp_addr = addr; | 197 | entry->attr.bp_addr = addr; |
| 198 | entry->attr.bp_len = HW_BREAKPOINT_LEN_4; | 198 | entry->attr.bp_len = HW_BREAKPOINT_LEN_4; |
| 199 | 199 | ||
| 200 | ret = -EAGAIN; | ||
| 201 | entry->ksym_hbp = register_wide_hw_breakpoint(&entry->attr, | 200 | entry->ksym_hbp = register_wide_hw_breakpoint(&entry->attr, |
| 202 | ksym_hbp_handler); | 201 | ksym_hbp_handler); |
| 203 | 202 | ||
| @@ -300,8 +299,8 @@ static ssize_t ksym_trace_filter_write(struct file *file, | |||
| 300 | * 2: echo 0 > ksym_trace_filter | 299 | * 2: echo 0 > ksym_trace_filter |
| 301 | * 3: echo "*:---" > ksym_trace_filter | 300 | * 3: echo "*:---" > ksym_trace_filter |
| 302 | */ | 301 | */ |
| 303 | if (!buf[0] || !strcmp(buf, "0") || | 302 | if (!input_string[0] || !strcmp(input_string, "0") || |
| 304 | !strcmp(buf, "*:---")) { | 303 | !strcmp(input_string, "*:---")) { |
| 305 | __ksym_trace_reset(); | 304 | __ksym_trace_reset(); |
| 306 | ret = 0; | 305 | ret = 0; |
| 307 | goto out; | 306 | goto out; |
| @@ -444,102 +443,77 @@ struct tracer ksym_tracer __read_mostly = | |||
| 444 | .print_line = ksym_trace_output | 443 | .print_line = ksym_trace_output |
| 445 | }; | 444 | }; |
| 446 | 445 | ||
| 447 | __init static int init_ksym_trace(void) | ||
| 448 | { | ||
| 449 | struct dentry *d_tracer; | ||
| 450 | struct dentry *entry; | ||
| 451 | |||
| 452 | d_tracer = tracing_init_dentry(); | ||
| 453 | ksym_filter_entry_count = 0; | ||
| 454 | |||
| 455 | entry = debugfs_create_file("ksym_trace_filter", 0644, d_tracer, | ||
| 456 | NULL, &ksym_tracing_fops); | ||
| 457 | if (!entry) | ||
| 458 | pr_warning("Could not create debugfs " | ||
| 459 | "'ksym_trace_filter' file\n"); | ||
| 460 | |||
| 461 | return register_tracer(&ksym_tracer); | ||
| 462 | } | ||
| 463 | device_initcall(init_ksym_trace); | ||
| 464 | |||
| 465 | |||
| 466 | #ifdef CONFIG_PROFILE_KSYM_TRACER | 446 | #ifdef CONFIG_PROFILE_KSYM_TRACER |
| 467 | static int ksym_tracer_stat_headers(struct seq_file *m) | 447 | static int ksym_profile_show(struct seq_file *m, void *v) |
| 468 | { | 448 | { |
| 449 | struct hlist_node *node; | ||
| 450 | struct trace_ksym *entry; | ||
| 451 | int access_type = 0; | ||
| 452 | char fn_name[KSYM_NAME_LEN]; | ||
| 453 | |||
| 469 | seq_puts(m, " Access Type "); | 454 | seq_puts(m, " Access Type "); |
| 470 | seq_puts(m, " Symbol Counter\n"); | 455 | seq_puts(m, " Symbol Counter\n"); |
| 471 | seq_puts(m, " ----------- "); | 456 | seq_puts(m, " ----------- "); |
| 472 | seq_puts(m, " ------ -------\n"); | 457 | seq_puts(m, " ------ -------\n"); |
| 473 | return 0; | ||
| 474 | } | ||
| 475 | 458 | ||
| 476 | static int ksym_tracer_stat_show(struct seq_file *m, void *v) | 459 | rcu_read_lock(); |
| 477 | { | 460 | hlist_for_each_entry_rcu(entry, node, &ksym_filter_head, ksym_hlist) { |
| 478 | struct hlist_node *stat = v; | ||
| 479 | struct trace_ksym *entry; | ||
| 480 | int access_type = 0; | ||
| 481 | char fn_name[KSYM_NAME_LEN]; | ||
| 482 | 461 | ||
| 483 | entry = hlist_entry(stat, struct trace_ksym, ksym_hlist); | 462 | access_type = entry->attr.bp_type; |
| 484 | 463 | ||
| 485 | access_type = entry->attr.bp_type; | 464 | switch (access_type) { |
| 465 | case HW_BREAKPOINT_R: | ||
| 466 | seq_puts(m, " R "); | ||
| 467 | break; | ||
| 468 | case HW_BREAKPOINT_W: | ||
| 469 | seq_puts(m, " W "); | ||
| 470 | break; | ||
| 471 | case HW_BREAKPOINT_R | HW_BREAKPOINT_W: | ||
| 472 | seq_puts(m, " RW "); | ||
| 473 | break; | ||
| 474 | default: | ||
| 475 | seq_puts(m, " NA "); | ||
| 476 | } | ||
| 486 | 477 | ||
| 487 | switch (access_type) { | 478 | if (lookup_symbol_name(entry->attr.bp_addr, fn_name) >= 0) |
| 488 | case HW_BREAKPOINT_R: | 479 | seq_printf(m, " %-36s", fn_name); |
| 489 | seq_puts(m, " R "); | 480 | else |
| 490 | break; | 481 | seq_printf(m, " %-36s", "<NA>"); |
| 491 | case HW_BREAKPOINT_W: | 482 | seq_printf(m, " %15llu\n", |
| 492 | seq_puts(m, " W "); | 483 | (unsigned long long)atomic64_read(&entry->counter)); |
| 493 | break; | ||
| 494 | case HW_BREAKPOINT_R | HW_BREAKPOINT_W: | ||
| 495 | seq_puts(m, " RW "); | ||
| 496 | break; | ||
| 497 | default: | ||
| 498 | seq_puts(m, " NA "); | ||
| 499 | } | 484 | } |
| 500 | 485 | rcu_read_unlock(); | |
| 501 | if (lookup_symbol_name(entry->attr.bp_addr, fn_name) >= 0) | ||
| 502 | seq_printf(m, " %-36s", fn_name); | ||
| 503 | else | ||
| 504 | seq_printf(m, " %-36s", "<NA>"); | ||
| 505 | seq_printf(m, " %15lu\n", entry->counter); | ||
| 506 | 486 | ||
| 507 | return 0; | 487 | return 0; |
| 508 | } | 488 | } |
| 509 | 489 | ||
| 510 | static void *ksym_tracer_stat_start(struct tracer_stat *trace) | 490 | static int ksym_profile_open(struct inode *node, struct file *file) |
| 511 | { | 491 | { |
| 512 | return ksym_filter_head.first; | 492 | return single_open(file, ksym_profile_show, NULL); |
| 513 | } | ||
| 514 | |||
| 515 | static void * | ||
| 516 | ksym_tracer_stat_next(void *v, int idx) | ||
| 517 | { | ||
| 518 | struct hlist_node *stat = v; | ||
| 519 | |||
| 520 | return stat->next; | ||
| 521 | } | 493 | } |
| 522 | 494 | ||
| 523 | static struct tracer_stat ksym_tracer_stats = { | 495 | static const struct file_operations ksym_profile_fops = { |
| 524 | .name = "ksym_tracer", | 496 | .open = ksym_profile_open, |
| 525 | .stat_start = ksym_tracer_stat_start, | 497 | .read = seq_read, |
| 526 | .stat_next = ksym_tracer_stat_next, | 498 | .llseek = seq_lseek, |
| 527 | .stat_headers = ksym_tracer_stat_headers, | 499 | .release = single_release, |
| 528 | .stat_show = ksym_tracer_stat_show | ||
| 529 | }; | 500 | }; |
| 501 | #endif /* CONFIG_PROFILE_KSYM_TRACER */ | ||
| 530 | 502 | ||
| 531 | __init static int ksym_tracer_stat_init(void) | 503 | __init static int init_ksym_trace(void) |
| 532 | { | 504 | { |
| 533 | int ret; | 505 | struct dentry *d_tracer; |
| 534 | 506 | ||
| 535 | ret = register_stat_tracer(&ksym_tracer_stats); | 507 | d_tracer = tracing_init_dentry(); |
| 536 | if (ret) { | ||
| 537 | printk(KERN_WARNING "Warning: could not register " | ||
| 538 | "ksym tracer stats\n"); | ||
| 539 | return 1; | ||
| 540 | } | ||
| 541 | 508 | ||
| 542 | return 0; | 509 | trace_create_file("ksym_trace_filter", 0644, d_tracer, |
| 510 | NULL, &ksym_tracing_fops); | ||
| 511 | |||
| 512 | #ifdef CONFIG_PROFILE_KSYM_TRACER | ||
| 513 | trace_create_file("ksym_profile", 0444, d_tracer, | ||
| 514 | NULL, &ksym_profile_fops); | ||
| 515 | #endif | ||
| 516 | |||
| 517 | return register_tracer(&ksym_tracer); | ||
| 543 | } | 518 | } |
| 544 | fs_initcall(ksym_tracer_stat_init); | 519 | device_initcall(init_ksym_trace); |
| 545 | #endif /* CONFIG_PROFILE_KSYM_TRACER */ | ||
