Merge branch 'perf/urgent' into perf/core
Ingo Molnar [Tue, 20 Oct 2009 05:51:41 +0000 (07:51 +0200)]
Merge reason: Queue up dependent patch.

Signed-off-by: Ingo Molnar <mingo@elte.hu>

1  2 
kernel/perf_event.c
tools/perf/builtin-top.c

diff --combined kernel/perf_event.c
@@@ -28,7 -28,6 +28,7 @@@
  #include <linux/anon_inodes.h>
  #include <linux/kernel_stat.h>
  #include <linux/perf_event.h>
 +#include <linux/ftrace_event.h>
  
  #include <asm/irq_regs.h>
  
@@@ -1356,7 -1355,7 +1356,7 @@@ static void perf_ctx_adjust_freq(struc
        u64 interrupts, freq;
  
        spin_lock(&ctx->lock);
-       list_for_each_entry(event, &ctx->group_list, group_entry) {
+       list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
                if (event->state != PERF_EVENT_STATE_ACTIVE)
                        continue;
  
@@@ -1659,8 -1658,6 +1659,8 @@@ static struct perf_event_context *find_
        return ERR_PTR(err);
  }
  
 +static void perf_event_free_filter(struct perf_event *event);
 +
  static void free_event_rcu(struct rcu_head *head)
  {
        struct perf_event *event;
        event = container_of(head, struct perf_event, rcu_head);
        if (event->ns)
                put_pid_ns(event->ns);
 +      perf_event_free_filter(event);
        kfree(event);
  }
  
@@@ -1978,8 -1974,7 +1978,8 @@@ unlock
        return ret;
  }
  
 -int perf_event_set_output(struct perf_event *event, int output_fd);
 +static int perf_event_set_output(struct perf_event *event, int output_fd);
 +static int perf_event_set_filter(struct perf_event *event, void __user *arg);
  
  static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
  {
        case PERF_EVENT_IOC_SET_OUTPUT:
                return perf_event_set_output(event, arg);
  
 +      case PERF_EVENT_IOC_SET_FILTER:
 +              return perf_event_set_filter(event, (void __user *)arg);
 +
        default:
                return -ENOTTY;
        }
@@@ -3814,14 -3806,9 +3814,14 @@@ static int perf_swevent_is_counting(str
        return 1;
  }
  
 +static int perf_tp_event_match(struct perf_event *event,
 +                              struct perf_sample_data *data);
 +
  static int perf_swevent_match(struct perf_event *event,
                                enum perf_type_id type,
 -                              u32 event_id, struct pt_regs *regs)
 +                              u32 event_id,
 +                              struct perf_sample_data *data,
 +                              struct pt_regs *regs)
  {
        if (!perf_swevent_is_counting(event))
                return 0;
                        return 0;
        }
  
 +      if (event->attr.type == PERF_TYPE_TRACEPOINT &&
 +          !perf_tp_event_match(event, data))
 +              return 0;
 +
        return 1;
  }
  
@@@ -3859,7 -3842,7 +3859,7 @@@ static void perf_swevent_ctx_event(stru
  
        rcu_read_lock();
        list_for_each_entry_rcu(event, &ctx->event_list, event_entry) {
 -              if (perf_swevent_match(event, type, event_id, regs))
 +              if (perf_swevent_match(event, type, event_id, data, regs))
                        perf_swevent_add(event, nr, nmi, data, regs);
        }
        rcu_read_unlock();
@@@ -4103,7 -4086,6 +4103,7 @@@ static const struct pmu perf_ops_task_c
  };
  
  #ifdef CONFIG_EVENT_PROFILE
 +
  void perf_tp_event(int event_id, u64 addr, u64 count, void *record,
                          int entry_size)
  {
  }
  EXPORT_SYMBOL_GPL(perf_tp_event);
  
 -extern int ftrace_profile_enable(int);
 -extern void ftrace_profile_disable(int);
 +static int perf_tp_event_match(struct perf_event *event,
 +                              struct perf_sample_data *data)
 +{
 +      void *record = data->raw->data;
 +
 +      if (likely(!event->filter) || filter_match_preds(event->filter, record))
 +              return 1;
 +      return 0;
 +}
  
  static void tp_perf_event_destroy(struct perf_event *event)
  {
@@@ -4160,53 -4135,12 +4160,53 @@@ static const struct pmu *tp_perf_event_
  
        return &perf_ops_generic;
  }
 +
 +static int perf_event_set_filter(struct perf_event *event, void __user *arg)
 +{
 +      char *filter_str;
 +      int ret;
 +
 +      if (event->attr.type != PERF_TYPE_TRACEPOINT)
 +              return -EINVAL;
 +
 +      filter_str = strndup_user(arg, PAGE_SIZE);
 +      if (IS_ERR(filter_str))
 +              return PTR_ERR(filter_str);
 +
 +      ret = ftrace_profile_set_filter(event, event->attr.config, filter_str);
 +
 +      kfree(filter_str);
 +      return ret;
 +}
 +
 +static void perf_event_free_filter(struct perf_event *event)
 +{
 +      ftrace_profile_free_filter(event);
 +}
 +
  #else
 +
 +static int perf_tp_event_match(struct perf_event *event,
 +                              struct perf_sample_data *data)
 +{
 +      return 1;
 +}
 +
  static const struct pmu *tp_perf_event_init(struct perf_event *event)
  {
        return NULL;
  }
 -#endif
 +
 +static int perf_event_set_filter(struct perf_event *event, void __user *arg)
 +{
 +      return -ENOENT;
 +}
 +
 +static void perf_event_free_filter(struct perf_event *event)
 +{
 +}
 +
 +#endif /* CONFIG_EVENT_PROFILE */
  
  atomic_t perf_swevent_enabled[PERF_COUNT_SW_MAX];
  
@@@ -4460,7 -4394,7 +4460,7 @@@ err_size
        goto out;
  }
  
 -int perf_event_set_output(struct perf_event *event, int output_fd)
 +static int perf_event_set_output(struct perf_event *event, int output_fd)
  {
        struct perf_event *output_event = NULL;
        struct file *output_file = NULL;
diff --combined tools/perf/builtin-top.c
@@@ -22,7 -22,6 +22,7 @@@
  
  #include "util/symbol.h"
  #include "util/color.h"
 +#include "util/thread.h"
  #include "util/util.h"
  #include <linux/rbtree.h>
  #include "util/parse-options.h"
  
  static int                    fd[MAX_NR_CPUS][MAX_COUNTERS];
  
 -static int                    system_wide                     =  0;
 +static int                    system_wide                     =      0;
  
 -static int                    default_interval                = 100000;
 +static int                    default_interval                =      0;
  
 -static int                    count_filter                    =  5;
 -static int                    print_entries                   = 15;
 +static int                    count_filter                    =      5;
 +static int                    print_entries                   =     15;
  
 -static int                    target_pid                      = -1;
 -static int                    inherit                         =  0;
 -static int                    profile_cpu                     = -1;
 -static int                    nr_cpus                         =  0;
 -static unsigned int           realtime_prio                   =  0;
 -static int                    group                           =  0;
 +static int                    target_pid                      =     -1;
 +static int                    inherit                         =      0;
 +static int                    profile_cpu                     =     -1;
 +static int                    nr_cpus                         =      0;
 +static unsigned int           realtime_prio                   =      0;
 +static int                    group                           =      0;
  static unsigned int           page_size;
 -static unsigned int           mmap_pages                      = 16;
 -static int                    freq                            =  0;
 +static unsigned int           mmap_pages                      =     16;
 +static int                    freq                            =   1000; /* 1 KHz */
  
 -static int                    delay_secs                      =  2;
 -static int                    zero;
 -static int                    dump_symtab;
 +static int                    delay_secs                      =      2;
 +static int                    zero                            =      0;
 +static int                    dump_symtab                     =      0;
  
  /*
   * Source
@@@ -87,16 -86,19 +87,16 @@@ struct source_line 
        struct source_line      *next;
  };
  
 -static char                   *sym_filter                     =  NULL;
 -struct sym_entry              *sym_filter_entry               =  NULL;
 -static int                    sym_pcnt_filter                 =  5;
 -static int                    sym_counter                     =  0;
 -static int                    display_weighted                = -1;
 +static char                   *sym_filter                     =   NULL;
 +struct sym_entry              *sym_filter_entry               =   NULL;
 +static int                    sym_pcnt_filter                 =      5;
 +static int                    sym_counter                     =      0;
 +static int                    display_weighted                =     -1;
  
  /*
   * Symbols
   */
  
 -static u64                    min_ip;
 -static u64                    max_ip = -1ll;
 -
  struct sym_entry {
        struct rb_node          rb_node;
        struct list_head        node;
        unsigned long           snap_count;
        double                  weight;
        int                     skip;
 +      struct map              *map;
        struct source_line      *source;
        struct source_line      *lines;
        struct source_line      **lines_tail;
  static void parse_source(struct sym_entry *syme)
  {
        struct symbol *sym;
 -      struct module *module;
 -      struct section *section = NULL;
 +      struct map *map;
        FILE *file;
        char command[PATH_MAX*2];
 -      const char *path = vmlinux_name;
 -      u64 start, end, len;
 +      const char *path;
 +      u64 len;
  
        if (!syme)
                return;
        }
  
        sym = (struct symbol *)(syme + 1);
 -      module = sym->module;
 -
 -      if (module)
 -              path = module->path;
 -      if (!path)
 -              return;
 -
 -      start = sym->obj_start;
 -      if (!start)
 -              start = sym->start;
 +      map = syme->map;
 +      path = map->dso->long_name;
  
 -      if (module) {
 -              section = module->sections->find_section(module->sections, ".text");
 -              if (section)
 -                      start -= section->vma;
 -      }
 -
 -      end = start + sym->end - sym->start + 1;
        len = sym->end - sym->start;
  
 -      sprintf(command, "objdump --start-address=0x%016Lx --stop-address=0x%016Lx -dS %s", start, end, path);
 +      sprintf(command,
 +              "objdump --start-address=0x%016Lx "
 +                       "--stop-address=0x%016Lx -dS %s",
 +              sym->start, sym->end, path);
  
        file = popen(command, "r");
        if (!file)
  
                if (strlen(src->line)>8 && src->line[8] == ':') {
                        src->eip = strtoull(src->line, NULL, 16);
 -                      if (section)
 -                              src->eip += section->vma;
 +                      src->eip += map->start;
                }
                if (strlen(src->line)>8 && src->line[16] == ':') {
                        src->eip = strtoull(src->line, NULL, 16);
 -                      if (section)
 -                              src->eip += section->vma;
 +                      src->eip += map->start;
                }
        }
        pclose(file);
@@@ -229,9 -245,16 +229,9 @@@ static void lookup_sym_source(struct sy
        struct symbol *symbol = (struct symbol *)(syme + 1);
        struct source_line *line;
        char pattern[PATH_MAX];
  
        sprintf(pattern, "<%s>:", symbol->name);
  
 -      if (symbol->module) {
 -              idx = strstr(pattern, "\t");
 -              if (idx)
 -                      *idx = 0;
 -      }
 -
        pthread_mutex_lock(&syme->source_lock);
        for (line = syme->lines; line; line = line->next) {
                if (strstr(line->line, pattern)) {
@@@ -493,8 -516,8 +493,8 @@@ static void print_sym_table(void
                if (verbose)
                        printf(" - %016llx", sym->start);
                printf(" : %s", sym->name);
 -              if (sym->module)
 -                      printf("\t[%s]", sym->module->name);
 +              if (syme->map->dso->name[0] == '[')
 +                      printf(" \t%s", syme->map->dso->name);
                printf("\n");
        }
  }
@@@ -663,6 -686,8 +663,8 @@@ static void handle_keypress(int c
        switch (c) {
                case 'd':
                        prompt_integer(&delay_secs, "Enter display delay");
+                       if (delay_secs < 1)
+                               delay_secs = 1;
                        break;
                case 'e':
                        prompt_integer(&print_entries, "Enter display entries (lines)");
@@@ -765,7 -790,7 +767,7 @@@ static const char *skip_symbols[] = 
        NULL
  };
  
 -static int symbol_filter(struct dso *self, struct symbol *sym)
 +static int symbol_filter(struct map *map, struct symbol *sym)
  {
        struct sym_entry *syme;
        const char *name = sym->name;
            strstr(name, "_text_end"))
                return 1;
  
 -      syme = dso__sym_priv(self, sym);
 +      syme = dso__sym_priv(map->dso, sym);
 +      syme->map = map;
        pthread_mutex_init(&syme->source_lock, NULL);
        if (!sym_filter_entry && sym_filter && !strcmp(name, sym_filter))
                sym_filter_entry = syme;
  
  static int parse_symbols(void)
  {
 -      struct rb_node *node;
 -      struct symbol  *sym;
 -      int use_modules = vmlinux_name ? 1 : 0;
 -
 -      kernel_dso = dso__new("[kernel]", sizeof(struct sym_entry));
 -      if (kernel_dso == NULL)
 +      if (dsos__load_kernel(vmlinux_name, sizeof(struct sym_entry),
 +                            symbol_filter, verbose, 1) <= 0)
                return -1;
  
 -      if (dso__load_kernel(kernel_dso, vmlinux_name, symbol_filter, verbose, use_modules) <= 0)
 -              goto out_delete_dso;
 -
 -      node = rb_first(&kernel_dso->syms);
 -      sym = rb_entry(node, struct symbol, rb_node);
 -      min_ip = sym->start;
 -
 -      node = rb_last(&kernel_dso->syms);
 -      sym = rb_entry(node, struct symbol, rb_node);
 -      max_ip = sym->end;
 -
        if (dump_symtab)
 -              dso__fprintf(kernel_dso, stderr);
 +              dsos__fprintf(stderr);
  
        return 0;
 -
 -out_delete_dso:
 -      dso__delete(kernel_dso);
 -      kernel_dso = NULL;
 -      return -1;
  }
  
  /*
   */
  static void record_ip(u64 ip, int counter)
  {
 -      struct symbol *sym = dso__find_symbol(kernel_dso, ip);
 +      struct map *map;
 +      struct symbol *sym = kernel_maps__find_symbol(ip, &map);
  
        if (sym != NULL) {
 -              struct sym_entry *syme = dso__sym_priv(kernel_dso, sym);
 +              struct sym_entry *syme = dso__sym_priv(map->dso, sym);
  
                if (!syme->skip) {
                        syme->count[counter]++;
@@@ -870,6 -913,8 +872,6 @@@ static unsigned int mmap_read_head(stru
        return head;
  }
  
 -struct timeval last_read, this_read;
 -
  static void mmap_read_counter(struct mmap_data *md)
  {
        unsigned int head = mmap_read_head(md);
        unsigned char *data = md->base + page_size;
        int diff;
  
 -      gettimeofday(&this_read, NULL);
 -
        /*
         * If we're further behind than half the buffer, there's a chance
         * the writer will bite our tail and mess up the samples under us.
         */
        diff = head - old;
        if (diff > md->mask / 2 || diff < 0) {
 -              struct timeval iv;
 -              unsigned long msecs;
 -
 -              timersub(&this_read, &last_read, &iv);
 -              msecs = iv.tv_sec*1000 + iv.tv_usec/1000;
 -
 -              fprintf(stderr, "WARNING: failed to keep up with mmap data."
 -                              "  Last read %lu msecs ago.\n", msecs);
 +              fprintf(stderr, "WARNING: failed to keep up with mmap data.\n");
  
                /*
                 * head points to a known good entry, start there.
                old = head;
        }
  
 -      last_read = this_read;
 -
        for (; old != head;) {
                event_t *event = (event_t *)&data[old & md->mask];
  
@@@ -962,13 -1018,7 +964,13 @@@ static void start_counter(int i, int co
        attr = attrs + counter;
  
        attr->sample_type       = PERF_SAMPLE_IP | PERF_SAMPLE_TID;
 -      attr->freq              = freq;
 +
 +      if (freq) {
 +              attr->sample_type       |= PERF_SAMPLE_PERIOD;
 +              attr->freq              = 1;
 +              attr->sample_freq       = freq;
 +      }
 +
        attr->inherit           = (cpu < 0) && inherit;
  
  try_again:
@@@ -1123,6 -1173,11 +1125,6 @@@ int cmd_top(int argc, const char **argv
        if (argc)
                usage_with_options(top_usage, options);
  
 -      if (freq) {
 -              default_interval = freq;
 -              freq = 1;
 -      }
 -
        /* CPU and PID are mutually exclusive */
        if (target_pid != -1 && profile_cpu != -1) {
                printf("WARNING: PID switch overriding CPU\n");
        parse_symbols();
        parse_source(sym_filter_entry);
  
 +
 +      /*
 +       * User specified count overrides default frequency.
 +       */
 +      if (default_interval)
 +              freq = 0;
 +      else if (freq) {
 +              default_interval = freq;
 +      } else {
 +              fprintf(stderr, "frequency and count are zero, aborting\n");
 +              exit(EXIT_FAILURE);
 +      }
 +
        /*
         * Fill in the ones not specifically initialized via -c:
         */