Merge branch 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-drm-fsl-dcu.git] / tools / perf / builtin-lock.c
index ee33ba2f05dd8b2f1f9c90f1820e0eab93b86f8b..c852c7a85d3236e86781b15616858a76b56c6206 100644 (file)
@@ -15,6 +15,7 @@
 #include "util/debug.h"
 #include "util/session.h"
 #include "util/tool.h"
+#include "util/data.h"
 
 #include <sys/types.h>
 #include <sys/prctl.h>
@@ -56,7 +57,9 @@ struct lock_stat {
 
        unsigned int            nr_readlock;
        unsigned int            nr_trylock;
+
        /* these times are in nano sec. */
+       u64                     avg_wait_time;
        u64                     wait_time_total;
        u64                     wait_time_min;
        u64                     wait_time_max;
@@ -208,6 +211,7 @@ static struct thread_stat *thread_stat_findnew_first(u32 tid)
 
 SINGLE_KEY(nr_acquired)
 SINGLE_KEY(nr_contended)
+SINGLE_KEY(avg_wait_time)
 SINGLE_KEY(wait_time_total)
 SINGLE_KEY(wait_time_max)
 
@@ -244,6 +248,7 @@ static struct rb_root               result; /* place to store sorted data */
 struct lock_key keys[] = {
        DEF_KEY_LOCK(acquired, nr_acquired),
        DEF_KEY_LOCK(contended, nr_contended),
+       DEF_KEY_LOCK(avg_wait, avg_wait_time),
        DEF_KEY_LOCK(wait_total, wait_time_total),
        DEF_KEY_LOCK(wait_min, wait_time_min),
        DEF_KEY_LOCK(wait_max, wait_time_max),
@@ -321,10 +326,12 @@ static struct lock_stat *lock_stat_findnew(void *addr, const char *name)
 
        new->addr = addr;
        new->name = zalloc(sizeof(char) * strlen(name) + 1);
-       if (!new->name)
+       if (!new->name) {
+               free(new);
                goto alloc_failed;
-       strcpy(new->name, name);
+       }
 
+       strcpy(new->name, name);
        new->wait_time_min = ULLONG_MAX;
 
        list_add(&new->hash_entry, entry);
@@ -400,17 +407,17 @@ static int report_lock_acquire_event(struct perf_evsel *evsel,
 
        ls = lock_stat_findnew(addr, name);
        if (!ls)
-               return -1;
+               return -ENOMEM;
        if (ls->discard)
                return 0;
 
        ts = thread_stat_findnew(sample->tid);
        if (!ts)
-               return -1;
+               return -ENOMEM;
 
        seq = get_seq(ts, addr);
        if (!seq)
-               return -1;
+               return -ENOMEM;
 
        switch (seq->state) {
        case SEQ_STATE_UNINITIALIZED:
@@ -446,7 +453,6 @@ broken:
                list_del(&seq->list);
                free(seq);
                goto end;
-               break;
        default:
                BUG_ON("Unknown state of lock sequence found!\n");
                break;
@@ -473,17 +479,17 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
 
        ls = lock_stat_findnew(addr, name);
        if (!ls)
-               return -1;
+               return -ENOMEM;
        if (ls->discard)
                return 0;
 
        ts = thread_stat_findnew(sample->tid);
        if (!ts)
-               return -1;
+               return -ENOMEM;
 
        seq = get_seq(ts, addr);
        if (!seq)
-               return -1;
+               return -ENOMEM;
 
        switch (seq->state) {
        case SEQ_STATE_UNINITIALIZED:
@@ -508,8 +514,6 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
                list_del(&seq->list);
                free(seq);
                goto end;
-               break;
-
        default:
                BUG_ON("Unknown state of lock sequence found!\n");
                break;
@@ -517,6 +521,7 @@ static int report_lock_acquired_event(struct perf_evsel *evsel,
 
        seq->state = SEQ_STATE_ACQUIRED;
        ls->nr_acquired++;
+       ls->avg_wait_time = ls->nr_contended ? ls->wait_time_total/ls->nr_contended : 0;
        seq->prev_event_time = sample->time;
 end:
        return 0;
@@ -536,17 +541,17 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
 
        ls = lock_stat_findnew(addr, name);
        if (!ls)
-               return -1;
+               return -ENOMEM;
        if (ls->discard)
                return 0;
 
        ts = thread_stat_findnew(sample->tid);
        if (!ts)
-               return -1;
+               return -ENOMEM;
 
        seq = get_seq(ts, addr);
        if (!seq)
-               return -1;
+               return -ENOMEM;
 
        switch (seq->state) {
        case SEQ_STATE_UNINITIALIZED:
@@ -564,7 +569,6 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
                list_del(&seq->list);
                free(seq);
                goto end;
-               break;
        default:
                BUG_ON("Unknown state of lock sequence found!\n");
                break;
@@ -572,6 +576,7 @@ static int report_lock_contended_event(struct perf_evsel *evsel,
 
        seq->state = SEQ_STATE_CONTENDED;
        ls->nr_contended++;
+       ls->avg_wait_time = ls->wait_time_total/ls->nr_contended;
        seq->prev_event_time = sample->time;
 end:
        return 0;
@@ -591,22 +596,21 @@ static int report_lock_release_event(struct perf_evsel *evsel,
 
        ls = lock_stat_findnew(addr, name);
        if (!ls)
-               return -1;
+               return -ENOMEM;
        if (ls->discard)
                return 0;
 
        ts = thread_stat_findnew(sample->tid);
        if (!ts)
-               return -1;
+               return -ENOMEM;
 
        seq = get_seq(ts, addr);
        if (!seq)
-               return -1;
+               return -ENOMEM;
 
        switch (seq->state) {
        case SEQ_STATE_UNINITIALIZED:
                goto end;
-               break;
        case SEQ_STATE_ACQUIRED:
                break;
        case SEQ_STATE_READ_ACQUIRED:
@@ -624,7 +628,6 @@ static int report_lock_release_event(struct perf_evsel *evsel,
                ls->discard = 1;
                bad_hist[BROKEN_RELEASE]++;
                goto free_seq;
-               break;
        default:
                BUG_ON("Unknown state of lock sequence found!\n");
                break;
@@ -690,7 +693,7 @@ static void print_bad_events(int bad, int total)
 
        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("bad rate: %.2f %%\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]);
@@ -707,6 +710,7 @@ static void print_result(void)
        pr_info("%10s ", "acquired");
        pr_info("%10s ", "contended");
 
+       pr_info("%15s ", "avg wait (ns)");
        pr_info("%15s ", "total wait (ns)");
        pr_info("%15s ", "max wait (ns)");
        pr_info("%15s ", "min wait (ns)");
@@ -738,6 +742,7 @@ static void print_result(void)
                pr_info("%10u ", st->nr_acquired);
                pr_info("%10u ", st->nr_contended);
 
+               pr_info("%15" PRIu64 " ", st->avg_wait_time);
                pr_info("%15" PRIu64 " ", st->wait_time_total);
                pr_info("%15" PRIu64 " ", st->wait_time_max);
                pr_info("%15" PRIu64 " ", st->wait_time_min == ULLONG_MAX ?
@@ -762,7 +767,7 @@ static void dump_threads(void)
        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);
+               pr_info("%10d: %s\n", st->tid, thread__comm_str(t));
                node = rb_next(node);
        };
 }
@@ -814,14 +819,26 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
                return -1;
        }
 
-       if (evsel->handler.func != NULL) {
-               tracepoint_handler f = evsel->handler.func;
+       if (evsel->handler != NULL) {
+               tracepoint_handler f = evsel->handler;
                return f(evsel, sample);
        }
 
        return 0;
 }
 
+static void sort_result(void)
+{
+       unsigned int i;
+       struct lock_stat *st;
+
+       for (i = 0; i < LOCKHASH_SIZE; i++) {
+               list_for_each_entry(st, &lockhash_table[i], hash_entry) {
+                       insert_to_result(st, compare);
+               }
+       }
+}
+
 static const struct perf_evsel_str_handler lock_tracepoints[] = {
        { "lock:lock_acquire",   perf_evsel__process_lock_acquire,   }, /* CONFIG_LOCKDEP */
        { "lock:lock_acquired",  perf_evsel__process_lock_acquired,  }, /* CONFIG_LOCKDEP, CONFIG_LOCK_STAT */
@@ -829,51 +846,51 @@ static const struct perf_evsel_str_handler lock_tracepoints[] = {
        { "lock:lock_release",   perf_evsel__process_lock_release,   }, /* CONFIG_LOCKDEP */
 };
 
-static int read_events(void)
+static int __cmd_report(bool display_info)
 {
+       int err = -EINVAL;
        struct perf_tool eops = {
                .sample          = process_sample_event,
                .comm            = perf_event__process_comm,
                .ordered_samples = true,
        };
-       session = perf_session__new(input_name, O_RDONLY, 0, false, &eops);
+       struct perf_data_file file = {
+               .path = input_name,
+               .mode = PERF_DATA_MODE_READ,
+       };
+
+       session = perf_session__new(&file, false, &eops);
        if (!session) {
                pr_err("Initializing perf session failed\n");
-               return -1;
+               return -ENOMEM;
        }
 
+       if (!perf_session__has_traces(session, "lock record"))
+               goto out_delete;
+
        if (perf_session__set_tracepoints_handlers(session, lock_tracepoints)) {
                pr_err("Initializing perf session tracepoint handlers failed\n");
-               return -1;
+               goto out_delete;
        }
 
-       return perf_session__process_events(session, &eops);
-}
-
-static void sort_result(void)
-{
-       unsigned int i;
-       struct lock_stat *st;
+       if (select_key())
+               goto out_delete;
 
-       for (i = 0; i < LOCKHASH_SIZE; i++) {
-               list_for_each_entry(st, &lockhash_table[i], hash_entry) {
-                       insert_to_result(st, compare);
-               }
-       }
-}
+       err = perf_session__process_events(session, &eops);
+       if (err)
+               goto out_delete;
 
-static int __cmd_report(void)
-{
        setup_pager();
+       if (display_info) /* used for info subcommand */
+               err = dump_info();
+       else {
+               sort_result();
+               print_result();
+       }
 
-       if ((select_key() != 0) ||
-           (read_events() != 0))
-               return -1;
-
-       sort_result();
-       print_result();
-
-       return 0;
+out_delete:
+       perf_session__delete(session);
+       return err;
 }
 
 static int __cmd_record(int argc, const char **argv)
@@ -881,7 +898,7 @@ static int __cmd_record(int argc, const char **argv)
        const char *record_args[] = {
                "record", "-R", "-m", "1024", "-c", "1",
        };
-       unsigned int rec_argc, i, j;
+       unsigned int rec_argc, i, j, ret;
        const char **rec_argv;
 
        for (i = 0; i < ARRAY_SIZE(lock_tracepoints); i++) {
@@ -898,7 +915,7 @@ static int __cmd_record(int argc, const char **argv)
        rec_argc += 2 * ARRAY_SIZE(lock_tracepoints);
 
        rec_argv = calloc(rec_argc + 1, sizeof(char *));
-       if (rec_argv == NULL)
+       if (!rec_argv)
                return -ENOMEM;
 
        for (i = 0; i < ARRAY_SIZE(record_args); i++)
@@ -914,7 +931,9 @@ static int __cmd_record(int argc, const char **argv)
 
        BUG_ON(i != rec_argc);
 
-       return cmd_record(i, rec_argv, NULL);
+       ret = cmd_record(i, rec_argv, NULL);
+       free(rec_argv);
+       return ret;
 }
 
 int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
@@ -934,7 +953,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
        };
        const struct option report_options[] = {
        OPT_STRING('k', "key", &sort_key, "acquired",
-                   "key for sorting (acquired / contended / wait_total / wait_max / wait_min)"),
+                   "key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
        /* TODO: type */
        OPT_END()
        };
@@ -972,7 +991,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
                        if (argc)
                                usage_with_options(report_usage, report_options);
                }
-               __cmd_report();
+               rc = __cmd_report(false);
        } else if (!strcmp(argv[0], "script")) {
                /* Aliased to 'perf script' */
                return cmd_script(argc, argv, prefix);
@@ -985,11 +1004,7 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
                }
                /* recycling report_lock_ops */
                trace_handler = &report_lock_ops;
-               setup_pager();
-               if (read_events() != 0)
-                       rc = -1;
-               else
-                       rc = dump_info();
+               rc = __cmd_report(true);
        } else {
                usage_with_options(lock_usage, lock_options);
        }