perf lock: Add -F/--field option to control output
authorNamhyung Kim <namhyung@kernel.org>
Wed, 23 Mar 2022 23:02:59 +0000 (16:02 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 25 Mar 2022 18:24:50 +0000 (15:24 -0300)
The -F/--field option is to customize the list of fields to output:

  $ perf lock report -F contended,wait_max -k avg_wait
                  Name  contended   max wait (ns)   avg wait (ns)

        slock-AF_INET6          1           23543           23543
     &lruvec->lru_lock          5           18317           11254
        slock-AF_INET6          1           10379           10379
            rcu_node_1          1            2104            2104
   &dentry->d_lockr...          1            1844            1844
   &dentry->d_lockr...          1            1672            1672
      &newf->file_lock         15            2279            1025
   &dentry->d_lockr...          1             792             792

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20220323230259.288494-3-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/Documentation/perf-lock.txt
tools/perf/builtin-lock.c

index f5eb957..b432222 100644 (file)
@@ -54,6 +54,12 @@ REPORT OPTIONS
         Sorting key. Possible values: acquired (default), contended,
        avg_wait, wait_total, wait_max, wait_min.
 
+-F::
+--field=<value>::
+        Output fields. By default it shows all the fields but users can
+       customize that using this.  Possible values: acquired, contended,
+       avg_wait, wait_total, wait_max, wait_min.
+
 -c::
 --combine-locks::
        Merge lock instances in the same class (based on name).
index c2ecb6a..a708976 100644 (file)
@@ -282,6 +282,7 @@ static struct rb_root               sorted; /* place to store intermediate data */
 static struct rb_root          result; /* place to store sorted data */
 
 static LIST_HEAD(lock_keys);
+static const char              *output_fields;
 
 #define DEF_KEY_LOCK(name, header, fn_suffix, len)                     \
        { #name, header, len, lock_stat_key_ ## fn_suffix, lock_stat_key_print_ ## fn_suffix, {} }
@@ -304,23 +305,65 @@ static int select_key(void)
        for (i = 0; keys[i].name; i++) {
                if (!strcmp(keys[i].name, sort_key)) {
                        compare = keys[i].key;
+
+                       /* selected key should be in the output fields */
+                       if (list_empty(&keys[i].list))
+                               list_add_tail(&keys[i].list, &lock_keys);
+
                        return 0;
                }
        }
 
        pr_err("Unknown compare key: %s\n", sort_key);
-
        return -1;
 }
 
-static int setup_output_field(void)
+static int add_output_field(struct list_head *head, char *name)
 {
        int i;
 
+       for (i = 0; keys[i].name; i++) {
+               if (strcmp(keys[i].name, name))
+                       continue;
+
+               /* prevent double link */
+               if (list_empty(&keys[i].list))
+                       list_add_tail(&keys[i].list, head);
+
+               return 0;
+       }
+
+       pr_err("Unknown output field: %s\n", name);
+       return -1;
+}
+
+static int setup_output_field(const char *str)
+{
+       char *tok, *tmp, *orig;
+       int i, ret = 0;
+
+       /* no output field given: use all of them */
+       if (str == NULL) {
+               for (i = 0; keys[i].name; i++)
+                       list_add_tail(&keys[i].list, &lock_keys);
+               return 0;
+       }
+
        for (i = 0; keys[i].name; i++)
-               list_add_tail(&keys[i].list, &lock_keys);
+               INIT_LIST_HEAD(&keys[i].list);
 
-       return 0;
+       orig = tmp = strdup(str);
+       if (orig == NULL)
+               return -ENOMEM;
+
+       while ((tok = strsep(&tmp, ",")) != NULL){
+               ret = add_output_field(&lock_keys, tok);
+               if (ret < 0)
+                       break;
+       }
+       free(orig);
+
+       return ret;
 }
 
 static void combine_lock_stats(struct lock_stat *st)
@@ -1002,7 +1045,7 @@ static int __cmd_report(bool display_info)
                goto out_delete;
        }
 
-       if (setup_output_field())
+       if (setup_output_field(output_fields))
                goto out_delete;
 
        if (select_key())
@@ -1090,6 +1133,8 @@ int cmd_lock(int argc, const char **argv)
        const struct option report_options[] = {
        OPT_STRING('k', "key", &sort_key, "acquired",
                    "key for sorting (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
+       OPT_STRING('F', "field", &output_fields, NULL,
+                   "output fields (acquired / contended / avg_wait / wait_total / wait_max / wait_min)"),
        /* TODO: type */
        OPT_BOOLEAN('c', "combine-locks", &combine_locks,
                    "combine locks in the same class"),