Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
[linux-2.6-block.git] / tools / perf / builtin-lock.c
index 6605000ed73d0b8c7a56d4319e34fbbf351b880e..821c1586a22b7da92cd732ad1a4ee4e05b037085 100644 (file)
@@ -387,7 +387,20 @@ static struct lock_seq_stat *get_seq(struct thread_stat *ts, void *addr)
        return seq;
 }
 
-static int bad_hist[4];
+enum broken_state {
+       BROKEN_ACQUIRE,
+       BROKEN_ACQUIRED,
+       BROKEN_CONTENDED,
+       BROKEN_RELEASE,
+       BROKEN_MAX,
+};
+
+static int bad_hist[BROKEN_MAX];
+
+enum acquire_flags {
+       TRY_LOCK = 1,
+       READ_LOCK = 2,
+};
 
 static void
 report_lock_acquire_event(struct trace_acquire_event *acquire_event,
@@ -413,9 +426,9 @@ report_lock_acquire_event(struct trace_acquire_event *acquire_event,
                if (!acquire_event->flag) {
                        seq->state = SEQ_STATE_ACQUIRING;
                } else {
-                       if (acquire_event->flag & 1)
+                       if (acquire_event->flag & TRY_LOCK)
                                ls->nr_trylock++;
-                       if (acquire_event->flag & 2)
+                       if (acquire_event->flag & READ_LOCK)
                                ls->nr_readlock++;
                        seq->state = SEQ_STATE_READ_ACQUIRED;
                        seq->read_count = 1;
@@ -423,7 +436,7 @@ report_lock_acquire_event(struct trace_acquire_event *acquire_event,
                }
                break;
        case SEQ_STATE_READ_ACQUIRED:
-               if (acquire_event->flag & 2) {
+               if (acquire_event->flag & READ_LOCK) {
                        seq->read_count++;
                        ls->nr_acquired++;
                        goto end;
@@ -437,7 +450,7 @@ report_lock_acquire_event(struct trace_acquire_event *acquire_event,
 broken:
                /* broken lock sequence, discard it */
                ls->discard = 1;
-               bad_hist[0]++;
+               bad_hist[BROKEN_ACQUIRE]++;
                list_del(&seq->list);
                free(seq);
                goto end;
@@ -481,10 +494,9 @@ report_lock_acquired_event(struct trace_acquired_event *acquired_event,
        case SEQ_STATE_CONTENDED:
                contended_term = timestamp - seq->prev_event_time;
                ls->wait_time_total += contended_term;
-
                if (contended_term < ls->wait_time_min)
                        ls->wait_time_min = contended_term;
-               else if (ls->wait_time_max < contended_term)
+               if (ls->wait_time_max < contended_term)
                        ls->wait_time_max = contended_term;
                break;
        case SEQ_STATE_RELEASED:
@@ -492,7 +504,7 @@ report_lock_acquired_event(struct trace_acquired_event *acquired_event,
        case SEQ_STATE_READ_ACQUIRED:
                /* broken lock sequence, discard it */
                ls->discard = 1;
-               bad_hist[1]++;
+               bad_hist[BROKEN_ACQUIRED]++;
                list_del(&seq->list);
                free(seq);
                goto end;
@@ -540,7 +552,7 @@ report_lock_contended_event(struct trace_contended_event *contended_event,
        case SEQ_STATE_CONTENDED:
                /* broken lock sequence, discard it */
                ls->discard = 1;
-               bad_hist[2]++;
+               bad_hist[BROKEN_CONTENDED]++;
                list_del(&seq->list);
                free(seq);
                goto end;
@@ -594,7 +606,7 @@ report_lock_release_event(struct trace_release_event *release_event,
        case SEQ_STATE_RELEASED:
                /* broken lock sequence, discard it */
                ls->discard = 1;
-               bad_hist[3]++;
+               bad_hist[BROKEN_RELEASE]++;
                goto free_seq;
                break;
        default:
@@ -713,6 +725,21 @@ process_raw_event(void *data, int cpu, u64 timestamp, struct thread *thread)
                process_lock_release_event(data, event, cpu, timestamp, thread);
 }
 
+static void print_bad_events(int bad, int total)
+{
+       /* Output for debug, this have to be removed */
+       int i;
+       const char *name[4] =
+               { "acquire", "acquired", "contended", "release" };
+
+       pr_info("\n=== output for debug===\n\n");
+       pr_info("bad: %d, total: %d\n", bad, total);
+       pr_info("bad rate: %f %%\n", (double)bad / (double)total * 100);
+       pr_info("histogram of events caused bad sequence\n");
+       for (i = 0; i < BROKEN_MAX; i++)
+               pr_info(" %10s: %d\n", name[i], bad_hist[i]);
+}
+
 /* TODO: various way to print, coloring, nano or milli sec */
 static void print_result(void)
 {
@@ -720,15 +747,15 @@ static void print_result(void)
        char cut_name[20];
        int bad, total;
 
-       printf("%20s ", "Name");
-       printf("%10s ", "acquired");
-       printf("%10s ", "contended");
+       pr_info("%20s ", "Name");
+       pr_info("%10s ", "acquired");
+       pr_info("%10s ", "contended");
 
-       printf("%15s ", "total wait (ns)");
-       printf("%15s ", "max wait (ns)");
-       printf("%15s ", "min wait (ns)");
+       pr_info("%15s ", "total wait (ns)");
+       pr_info("%15s ", "max wait (ns)");
+       pr_info("%15s ", "min wait (ns)");
 
-       printf("\n\n");
+       pr_info("\n\n");
 
        bad = total = 0;
        while ((st = pop_from_result())) {
@@ -741,7 +768,7 @@ static void print_result(void)
 
                if (strlen(st->name) < 16) {
                        /* output raw name */
-                       printf("%20s ", st->name);
+                       pr_info("%20s ", st->name);
                } else {
                        strncpy(cut_name, st->name, 16);
                        cut_name[16] = '.';
@@ -749,33 +776,39 @@ static void print_result(void)
                        cut_name[18] = '.';
                        cut_name[19] = '\0';
                        /* cut off name for saving output style */
-                       printf("%20s ", cut_name);
+                       pr_info("%20s ", cut_name);
                }
 
-               printf("%10u ", st->nr_acquired);
-               printf("%10u ", st->nr_contended);
+               pr_info("%10u ", st->nr_acquired);
+               pr_info("%10u ", st->nr_contended);
 
-               printf("%15llu ", st->wait_time_total);
-               printf("%15llu ", st->wait_time_max);
-               printf("%15llu ", st->wait_time_min == ULLONG_MAX ?
+               pr_info("%15llu ", st->wait_time_total);
+               pr_info("%15llu ", st->wait_time_max);
+               pr_info("%15llu ", st->wait_time_min == ULLONG_MAX ?
                       0 : st->wait_time_min);
-               printf("\n");
+               pr_info("\n");
        }
 
-       {
-               /* Output for debug, this have to be removed */
-               int i;
-               const char *name[4] =
-                       { "acquire", "acquired", "contended", "release" };
+       print_bad_events(bad, total);
+}
 
-               printf("\n=== output for debug===\n\n");
-               printf("bad:%d, total:%d\n", bad, total);
-               printf("bad rate:%f\n", (double)(bad / total));
+static bool info_threads, info_map;
 
-               printf("histogram of events caused bad sequence\n");
-               for (i = 0; i < 4; i++)
-                       printf(" %10s: %d\n", name[i], bad_hist[i]);
-       }
+static void dump_threads(void)
+{
+       struct thread_stat *st;
+       struct rb_node *node;
+       struct thread *t;
+
+       pr_info("%10s: comm\n", "Thread ID");
+
+       node = rb_first(&thread_stats);
+       while (node) {
+               st = container_of(node, struct thread_stat, rb);
+               t = perf_session__findnew(session, st->tid);
+               pr_info("%10d: %s\n", st->tid, t->comm);
+               node = rb_next(node);
+       };
 }
 
 static void dump_map(void)
@@ -783,13 +816,24 @@ static void dump_map(void)
        unsigned int i;
        struct lock_stat *st;
 
+       pr_info("Address of instance: name of class\n");
        for (i = 0; i < LOCKHASH_SIZE; i++) {
                list_for_each_entry(st, &lockhash_table[i], hash_entry) {
-                       printf("%p: %s\n", st->addr, st->name);
+                       pr_info(" %p: %s\n", st->addr, st->name);
                }
        }
 }
 
+static void dump_info(void)
+{
+       if (info_threads)
+               dump_threads();
+       else if (info_map)
+               dump_map();
+       else
+               die("Unknown type of information\n");
+}
+
 static int process_sample_event(event_t *self, struct perf_session *s)
 {
        struct sample_data data;
@@ -858,6 +902,19 @@ static const struct option report_options[] = {
        OPT_END()
 };
 
+static const char * const info_usage[] = {
+       "perf lock info [<options>]",
+       NULL
+};
+
+static const struct option info_options[] = {
+       OPT_BOOLEAN('t', "threads", &info_threads,
+                   "dump thread list in perf.data"),
+       OPT_BOOLEAN('m', "map", &info_map,
+                   "map of lock instances (name:address table)"),
+       OPT_END()
+};
+
 static const char * const lock_usage[] = {
        "perf lock [<options>] {record|trace|report}",
        NULL
@@ -872,7 +929,6 @@ static const struct option lock_options[] = {
 
 static const char *record_args[] = {
        "record",
-       "-a",
        "-R",
        "-f",
        "-m", "1024",
@@ -929,12 +985,18 @@ int cmd_lock(int argc, const char **argv, const char *prefix __used)
        } else if (!strcmp(argv[0], "trace")) {
                /* Aliased to 'perf trace' */
                return cmd_trace(argc, argv, prefix);
-       } else if (!strcmp(argv[0], "map")) {
+       } else if (!strcmp(argv[0], "info")) {
+               if (argc) {
+                       argc = parse_options(argc, argv,
+                                            info_options, info_usage, 0);
+                       if (argc)
+                               usage_with_options(info_usage, info_options);
+               }
                /* recycling report_lock_ops */
                trace_handler = &report_lock_ops;
                setup_pager();
                read_events();
-               dump_map();
+               dump_info();
        } else {
                usage_with_options(lock_usage, lock_options);
        }