]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - tools/perf/builtin-lock.c
Input: edt-ft5x06 - add a missing condition
[karo-tx-linux.git] / tools / perf / builtin-lock.c
index d3188629cbafbb99eb65f2c4d5f493531056244f..33c7253295b966b8a6c4a20753fd5cfdead12048 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);
@@ -514,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;
@@ -568,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;
@@ -684,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]);
@@ -701,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)");
@@ -732,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 ?
@@ -816,6 +827,18 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
        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 */
@@ -823,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);
-}
+       if (select_key())
+               goto out_delete;
 
-static void sort_result(void)
-{
-       unsigned int i;
-       struct lock_stat *st;
+       err = perf_session__process_events(session, &eops);
+       if (err)
+               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);
-               }
-       }
-}
-
-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)
@@ -875,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++) {
@@ -892,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++)
@@ -908,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)
@@ -928,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()
        };
@@ -966,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);
@@ -979,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);
        }