Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / tools / perf / builtin-stat.c
index 076eda5..1e5e9b2 100644 (file)
@@ -182,8 +182,8 @@ static int                  run_count                       =  1;
 static bool                    no_inherit                      = false;
 static bool                    scale                           =  true;
 static bool                    no_aggr                         = false;
-static pid_t                   target_pid                      = -1;
-static pid_t                   target_tid                      = -1;
+static const char              *target_pid;
+static const char              *target_tid;
 static pid_t                   child_pid                       = -1;
 static bool                    null_run                        =  false;
 static int                     detailed_run                    =  0;
@@ -278,9 +278,16 @@ struct stats                       runtime_itlb_cache_stats[MAX_NR_CPUS];
 struct stats                   runtime_dtlb_cache_stats[MAX_NR_CPUS];
 struct stats                   walltime_nsecs_stats;
 
-static int create_perf_stat_counter(struct perf_evsel *evsel)
+static int create_perf_stat_counter(struct perf_evsel *evsel,
+                                   struct perf_evsel *first)
 {
        struct perf_event_attr *attr = &evsel->attr;
+       struct xyarray *group_fd = NULL;
+       bool exclude_guest_missing = false;
+       int ret;
+
+       if (group && evsel != first)
+               group_fd = first->fd;
 
        if (scale)
                attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED |
@@ -288,15 +295,39 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
 
        attr->inherit = !no_inherit;
 
-       if (system_wide)
-               return perf_evsel__open_per_cpu(evsel, evsel_list->cpus, group);
+retry:
+       if (exclude_guest_missing)
+               evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
+
+       if (system_wide) {
+               ret = perf_evsel__open_per_cpu(evsel, evsel_list->cpus,
+                                               group, group_fd);
+               if (ret)
+                       goto check_ret;
+               return 0;
+       }
 
-       if (target_pid == -1 && target_tid == -1) {
+       if (!target_pid && !target_tid && (!group || evsel == first)) {
                attr->disabled = 1;
                attr->enable_on_exec = 1;
        }
 
-       return perf_evsel__open_per_thread(evsel, evsel_list->threads, group);
+       ret = perf_evsel__open_per_thread(evsel, evsel_list->threads,
+                                         group, group_fd);
+       if (!ret)
+               return 0;
+       /* fall through */
+check_ret:
+       if (ret && errno == EINVAL) {
+               if (!exclude_guest_missing &&
+                   (evsel->attr.exclude_guest || evsel->attr.exclude_host)) {
+                       pr_debug("Old kernel, cannot exclude "
+                                "guest or host samples.\n");
+                       exclude_guest_missing = true;
+                       goto retry;
+               }
+       }
+       return ret;
 }
 
 /*
@@ -396,7 +427,7 @@ static int read_counter(struct perf_evsel *counter)
 static int run_perf_stat(int argc __used, const char **argv)
 {
        unsigned long long t0, t1;
-       struct perf_evsel *counter;
+       struct perf_evsel *counter, *first;
        int status = 0;
        int child_ready_pipe[2], go_pipe[2];
        const bool forks = (argc > 0);
@@ -440,7 +471,7 @@ static int run_perf_stat(int argc __used, const char **argv)
                        exit(-1);
                }
 
-               if (target_tid == -1 && target_pid == -1 && !system_wide)
+               if (!target_tid && !target_pid && !system_wide)
                        evsel_list->threads->map[0] = child_pid;
 
                /*
@@ -453,9 +484,17 @@ static int run_perf_stat(int argc __used, const char **argv)
                close(child_ready_pipe[0]);
        }
 
+       first = list_entry(evsel_list->entries.next, struct perf_evsel, node);
+
        list_for_each_entry(counter, &evsel_list->entries, node) {
-               if (create_perf_stat_counter(counter) < 0) {
-                       if (errno == EINVAL || errno == ENOSYS || errno == ENOENT) {
+               if (create_perf_stat_counter(counter, first) < 0) {
+                       /*
+                        * PPC returns ENXIO for HW counters until 2.6.37
+                        * (behavior changed with commit b0a873e).
+                        */
+                       if (errno == EINVAL || errno == ENOSYS ||
+                           errno == ENOENT || errno == EOPNOTSUPP ||
+                           errno == ENXIO) {
                                if (verbose)
                                        ui__warning("%s event is not supported by the kernel.\n",
                                                    event_name(counter));
@@ -495,6 +534,8 @@ static int run_perf_stat(int argc __used, const char **argv)
        if (forks) {
                close(go_pipe[1]);
                wait(&status);
+               if (WIFSIGNALED(status))
+                       psignal(WTERMSIG(status), argv[0]);
        } else {
                while(!done) sleep(1);
        }
@@ -565,6 +606,35 @@ static void nsec_printout(int cpu, struct perf_evsel *evsel, double avg)
        if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
                fprintf(output, " # %8.3f CPUs utilized          ",
                        avg / avg_stats(&walltime_nsecs_stats));
+       else
+               fprintf(output, "                                   ");
+}
+
+/* used for get_ratio_color() */
+enum grc_type {
+       GRC_STALLED_CYCLES_FE,
+       GRC_STALLED_CYCLES_BE,
+       GRC_CACHE_MISSES,
+       GRC_MAX_NR
+};
+
+static const char *get_ratio_color(enum grc_type type, double ratio)
+{
+       static const double grc_table[GRC_MAX_NR][3] = {
+               [GRC_STALLED_CYCLES_FE] = { 50.0, 30.0, 10.0 },
+               [GRC_STALLED_CYCLES_BE] = { 75.0, 50.0, 20.0 },
+               [GRC_CACHE_MISSES]      = { 20.0, 10.0, 5.0 },
+       };
+       const char *color = PERF_COLOR_NORMAL;
+
+       if (ratio > grc_table[type][0])
+               color = PERF_COLOR_RED;
+       else if (ratio > grc_table[type][1])
+               color = PERF_COLOR_MAGENTA;
+       else if (ratio > grc_table[type][2])
+               color = PERF_COLOR_YELLOW;
+
+       return color;
 }
 
 static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __used, double avg)
@@ -577,13 +647,7 @@ static void print_stalled_cycles_frontend(int cpu, struct perf_evsel *evsel __us
        if (total)
                ratio = avg / total * 100.0;
 
-       color = PERF_COLOR_NORMAL;
-       if (ratio > 50.0)
-               color = PERF_COLOR_RED;
-       else if (ratio > 30.0)
-               color = PERF_COLOR_MAGENTA;
-       else if (ratio > 10.0)
-               color = PERF_COLOR_YELLOW;
+       color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio);
 
        fprintf(output, " #  ");
        color_fprintf(output, color, "%6.2f%%", ratio);
@@ -600,13 +664,7 @@ static void print_stalled_cycles_backend(int cpu, struct perf_evsel *evsel __use
        if (total)
                ratio = avg / total * 100.0;
 
-       color = PERF_COLOR_NORMAL;
-       if (ratio > 75.0)
-               color = PERF_COLOR_RED;
-       else if (ratio > 50.0)
-               color = PERF_COLOR_MAGENTA;
-       else if (ratio > 20.0)
-               color = PERF_COLOR_YELLOW;
+       color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio);
 
        fprintf(output, " #  ");
        color_fprintf(output, color, "%6.2f%%", ratio);
@@ -623,13 +681,7 @@ static void print_branch_misses(int cpu, struct perf_evsel *evsel __used, double
        if (total)
                ratio = avg / total * 100.0;
 
-       color = PERF_COLOR_NORMAL;
-       if (ratio > 20.0)
-               color = PERF_COLOR_RED;
-       else if (ratio > 10.0)
-               color = PERF_COLOR_MAGENTA;
-       else if (ratio > 5.0)
-               color = PERF_COLOR_YELLOW;
+       color = get_ratio_color(GRC_CACHE_MISSES, ratio);
 
        fprintf(output, " #  ");
        color_fprintf(output, color, "%6.2f%%", ratio);
@@ -646,13 +698,7 @@ static void print_l1_dcache_misses(int cpu, struct perf_evsel *evsel __used, dou
        if (total)
                ratio = avg / total * 100.0;
 
-       color = PERF_COLOR_NORMAL;
-       if (ratio > 20.0)
-               color = PERF_COLOR_RED;
-       else if (ratio > 10.0)
-               color = PERF_COLOR_MAGENTA;
-       else if (ratio > 5.0)
-               color = PERF_COLOR_YELLOW;
+       color = get_ratio_color(GRC_CACHE_MISSES, ratio);
 
        fprintf(output, " #  ");
        color_fprintf(output, color, "%6.2f%%", ratio);
@@ -669,13 +715,7 @@ static void print_l1_icache_misses(int cpu, struct perf_evsel *evsel __used, dou
        if (total)
                ratio = avg / total * 100.0;
 
-       color = PERF_COLOR_NORMAL;
-       if (ratio > 20.0)
-               color = PERF_COLOR_RED;
-       else if (ratio > 10.0)
-               color = PERF_COLOR_MAGENTA;
-       else if (ratio > 5.0)
-               color = PERF_COLOR_YELLOW;
+       color = get_ratio_color(GRC_CACHE_MISSES, ratio);
 
        fprintf(output, " #  ");
        color_fprintf(output, color, "%6.2f%%", ratio);
@@ -692,13 +732,7 @@ static void print_dtlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
        if (total)
                ratio = avg / total * 100.0;
 
-       color = PERF_COLOR_NORMAL;
-       if (ratio > 20.0)
-               color = PERF_COLOR_RED;
-       else if (ratio > 10.0)
-               color = PERF_COLOR_MAGENTA;
-       else if (ratio > 5.0)
-               color = PERF_COLOR_YELLOW;
+       color = get_ratio_color(GRC_CACHE_MISSES, ratio);
 
        fprintf(output, " #  ");
        color_fprintf(output, color, "%6.2f%%", ratio);
@@ -715,13 +749,7 @@ static void print_itlb_cache_misses(int cpu, struct perf_evsel *evsel __used, do
        if (total)
                ratio = avg / total * 100.0;
 
-       color = PERF_COLOR_NORMAL;
-       if (ratio > 20.0)
-               color = PERF_COLOR_RED;
-       else if (ratio > 10.0)
-               color = PERF_COLOR_MAGENTA;
-       else if (ratio > 5.0)
-               color = PERF_COLOR_YELLOW;
+       color = get_ratio_color(GRC_CACHE_MISSES, ratio);
 
        fprintf(output, " #  ");
        color_fprintf(output, color, "%6.2f%%", ratio);
@@ -738,13 +766,7 @@ static void print_ll_cache_misses(int cpu, struct perf_evsel *evsel __used, doub
        if (total)
                ratio = avg / total * 100.0;
 
-       color = PERF_COLOR_NORMAL;
-       if (ratio > 20.0)
-               color = PERF_COLOR_RED;
-       else if (ratio > 10.0)
-               color = PERF_COLOR_MAGENTA;
-       else if (ratio > 5.0)
-               color = PERF_COLOR_YELLOW;
+       color = get_ratio_color(GRC_CACHE_MISSES, ratio);
 
        fprintf(output, " #  ");
        color_fprintf(output, color, "%6.2f%%", ratio);
@@ -854,12 +876,18 @@ static void abs_printout(int cpu, struct perf_evsel *evsel, double avg)
 
                fprintf(output, " # %8.3f GHz                    ", ratio);
        } else if (runtime_nsecs_stats[cpu].n != 0) {
+               char unit = 'M';
+
                total = avg_stats(&runtime_nsecs_stats[cpu]);
 
                if (total)
                        ratio = 1000.0 * avg / total;
+               if (ratio < 0.001) {
+                       ratio *= 1000;
+                       unit = 'K';
+               }
 
-               fprintf(output, " # %8.3f M/sec                  ", ratio);
+               fprintf(output, " # %8.3f %c/sec                  ", ratio, unit);
        } else {
                fprintf(output, "                                   ");
        }
@@ -970,14 +998,14 @@ static void print_stat(int argc, const char **argv)
        if (!csv_output) {
                fprintf(output, "\n");
                fprintf(output, " Performance counter stats for ");
-               if(target_pid == -1 && target_tid == -1) {
+               if (!target_pid && !target_tid) {
                        fprintf(output, "\'%s", argv[0]);
                        for (i = 1; i < argc; i++)
                                fprintf(output, " %s", argv[i]);
-               } else if (target_pid != -1)
-                       fprintf(output, "process id \'%d", target_pid);
+               } else if (target_pid)
+                       fprintf(output, "process id \'%s", target_pid);
                else
-                       fprintf(output, "thread id \'%d", target_tid);
+                       fprintf(output, "thread id \'%s", target_tid);
 
                fprintf(output, "\'");
                if (run_count > 1)
@@ -1051,10 +1079,10 @@ static const struct option options[] = {
                     "event filter", parse_filter),
        OPT_BOOLEAN('i', "no-inherit", &no_inherit,
                    "child tasks do not inherit counters"),
-       OPT_INTEGER('p', "pid", &target_pid,
-                   "stat events on existing process id"),
-       OPT_INTEGER('t', "tid", &target_tid,
-                   "stat events on existing thread id"),
+       OPT_STRING('p', "pid", &target_pid, "pid",
+                  "stat events on existing process id"),
+       OPT_STRING('t', "tid", &target_tid, "tid",
+                  "stat events on existing thread id"),
        OPT_BOOLEAN('a', "all-cpus", &system_wide,
                    "system-wide collection from all CPUs"),
        OPT_BOOLEAN('g', "group", &group,
@@ -1097,22 +1125,13 @@ static const struct option options[] = {
  */
 static int add_default_attributes(void)
 {
-       struct perf_evsel *pos;
-       size_t attr_nr = 0;
-       size_t c;
-
        /* Set attrs if no event is selected and !null_run: */
        if (null_run)
                return 0;
 
        if (!evsel_list->nr_entries) {
-               for (c = 0; c < ARRAY_SIZE(default_attrs); c++) {
-                       pos = perf_evsel__new(default_attrs + c, c + attr_nr);
-                       if (pos == NULL)
-                               return -1;
-                       perf_evlist__add(evsel_list, pos);
-               }
-               attr_nr += c;
+               if (perf_evlist__add_attrs_array(evsel_list, default_attrs) < 0)
+                       return -1;
        }
 
        /* Detailed events get appended to the event list: */
@@ -1121,38 +1140,21 @@ static int add_default_attributes(void)
                return 0;
 
        /* Append detailed run extra attributes: */
-       for (c = 0; c < ARRAY_SIZE(detailed_attrs); c++) {
-               pos = perf_evsel__new(detailed_attrs + c, c + attr_nr);
-               if (pos == NULL)
-                       return -1;
-               perf_evlist__add(evsel_list, pos);
-       }
-       attr_nr += c;
+       if (perf_evlist__add_attrs_array(evsel_list, detailed_attrs) < 0)
+               return -1;
 
        if (detailed_run < 2)
                return 0;
 
        /* Append very detailed run extra attributes: */
-       for (c = 0; c < ARRAY_SIZE(very_detailed_attrs); c++) {
-               pos = perf_evsel__new(very_detailed_attrs + c, c + attr_nr);
-               if (pos == NULL)
-                       return -1;
-               perf_evlist__add(evsel_list, pos);
-       }
+       if (perf_evlist__add_attrs_array(evsel_list, very_detailed_attrs) < 0)
+               return -1;
 
        if (detailed_run < 3)
                return 0;
 
        /* Append very, very detailed run extra attributes: */
-       for (c = 0; c < ARRAY_SIZE(very_very_detailed_attrs); c++) {
-               pos = perf_evsel__new(very_very_detailed_attrs + c, c + attr_nr);
-               if (pos == NULL)
-                       return -1;
-               perf_evlist__add(evsel_list, pos);
-       }
-
-
-       return 0;
+       return perf_evlist__add_attrs_array(evsel_list, very_very_detailed_attrs);
 }
 
 int cmd_stat(int argc, const char **argv, const char *prefix __used)
@@ -1198,16 +1200,18 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
                }
        }
 
-       if (csv_sep)
+       if (csv_sep) {
                csv_output = true;
-       else
+               if (!strcmp(csv_sep, "\\t"))
+                       csv_sep = "\t";
+       } else
                csv_sep = DEFAULT_SEPARATOR;
 
        /*
         * let the spreadsheet do the pretty-printing
         */
        if (csv_output) {
-               /* User explicitely passed -B? */
+               /* User explicitly passed -B? */
                if (big_num_opt == 1) {
                        fprintf(stderr, "-B option not supported with -x\n");
                        usage_with_options(stat_usage, options);
@@ -1216,7 +1220,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
        } else if (big_num_opt == 0) /* User passed --no-big-num */
                big_num = false;
 
-       if (!argc && target_pid == -1 && target_tid == -1)
+       if (!argc && !target_pid && !target_tid)
                usage_with_options(stat_usage, options);
        if (run_count <= 0)
                usage_with_options(stat_usage, options);
@@ -1232,10 +1236,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
        if (add_default_attributes())
                goto out;
 
-       if (target_pid != -1)
+       if (target_pid)
                target_tid = target_pid;
 
-       evsel_list->threads = thread_map__new(target_pid, target_tid);
+       evsel_list->threads = thread_map__new_str(target_pid,
+                                                 target_tid, UINT_MAX);
        if (evsel_list->threads == NULL) {
                pr_err("Problems finding threads of monitor\n");
                usage_with_options(stat_usage, options);
@@ -1254,8 +1259,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __used)
 
        list_for_each_entry(pos, &evsel_list->entries, node) {
                if (perf_evsel__alloc_stat_priv(pos) < 0 ||
-                   perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0 ||
-                   perf_evsel__alloc_fd(pos, evsel_list->cpus->nr, evsel_list->threads->nr) < 0)
+                   perf_evsel__alloc_counts(pos, evsel_list->cpus->nr) < 0)
                        goto out_free_fd;
        }