HIST_FIELD_FL_BUCKET            = 1 << 17,
        HIST_FIELD_FL_CONST             = 1 << 18,
        HIST_FIELD_FL_PERCENT           = 1 << 19,
+       HIST_FIELD_FL_GRAPH             = 1 << 20,
 };
 
 struct var_defs {
                flags_str = "usecs";
        else if (hist_field->flags & HIST_FIELD_FL_PERCENT)
                flags_str = "percent";
+       else if (hist_field->flags & HIST_FIELD_FL_GRAPH)
+               flags_str = "graph";
 
        return flags_str;
 }
                        if (*flags & (HIST_FIELD_FL_VAR | HIST_FIELD_FL_KEY))
                                goto error;
                        *flags |= HIST_FIELD_FL_PERCENT;
+               } else if (strncmp(modifier, "graph", 5) == 0) {
+                       if (*flags & (HIST_FIELD_FL_VAR | HIST_FIELD_FL_KEY))
+                               goto error;
+                       *flags |= HIST_FIELD_FL_GRAPH;
                } else {
  error:
                        hist_err(tr, HIST_ERR_BAD_FIELD_MODIFIER, errpos(modifier));
        return val ? UINT_MAX : 0;
 }
 
+#define BAR_CHAR '#'
+
+static inline const char *__fill_bar_str(char *buf, int size, u64 val, u64 max)
+{
+       unsigned int len = __get_percentage(val, max);
+       int i;
+
+       if (len == UINT_MAX) {
+               snprintf(buf, size, "[ERROR]");
+               return buf;
+       }
+
+       len = len * size / 10000;
+       for (i = 0; i < len && i < size; i++)
+               buf[i] = BAR_CHAR;
+       while (i < size)
+               buf[i++] = ' ';
+       buf[size] = '\0';
+
+       return buf;
+}
+
+struct hist_val_stat {
+       u64 max;
+       u64 total;
+};
+
 static void hist_trigger_print_val(struct seq_file *m, unsigned int idx,
                                   const char *field_name, unsigned long flags,
-                                  u64 *totals, struct tracing_map_elt *elt)
+                                  struct hist_val_stat *stats,
+                                  struct tracing_map_elt *elt)
 {
        u64 val = tracing_map_read_sum(elt, idx);
        unsigned int pc;
+       char bar[21];
 
        if (flags & HIST_FIELD_FL_PERCENT) {
-               pc = __get_percentage(val, totals[idx]);
+               pc = __get_percentage(val, stats[idx].total);
                if (pc == UINT_MAX)
                        seq_printf(m, " %s (%%):[ERROR]", field_name);
                else
                        seq_printf(m, " %s (%%): %3u.%02u", field_name,
                                        pc / 100, pc % 100);
+       } else if (flags & HIST_FIELD_FL_GRAPH) {
+               seq_printf(m, " %s: %20s", field_name,
+                          __fill_bar_str(bar, 20, val, stats[idx].max));
        } else if (flags & HIST_FIELD_FL_HEX) {
                seq_printf(m, " %s: %10llx", field_name, val);
        } else {
 
 static void hist_trigger_entry_print(struct seq_file *m,
                                     struct hist_trigger_data *hist_data,
-                                    u64 *totals,
+                                    struct hist_val_stat *stats,
                                     void *key,
                                     struct tracing_map_elt *elt)
 {
        hist_trigger_print_key(m, hist_data, key, elt);
 
        /* At first, show the raw hitcount always */
-       hist_trigger_print_val(m, i, "hitcount", 0, totals, elt);
+       hist_trigger_print_val(m, i, "hitcount", 0, stats, elt);
 
        for (i = 1; i < hist_data->n_vals; i++) {
                field_name = hist_field_name(hist_data->fields[i], 0);
                        continue;
 
                seq_puts(m, " ");
-               hist_trigger_print_val(m, i, field_name, flags, totals, elt);
+               hist_trigger_print_val(m, i, field_name, flags, stats, elt);
        }
 
        print_actions(m, hist_data, elt);
        struct tracing_map_sort_entry **sort_entries = NULL;
        struct tracing_map *map = hist_data->map;
        int i, j, n_entries;
-       u64 *totals = NULL;
+       struct hist_val_stat *stats = NULL;
+       u64 val;
 
        n_entries = tracing_map_sort_entries(map, hist_data->sort_keys,
                                             hist_data->n_sort_keys,
        if (n_entries < 0)
                return n_entries;
 
+       /* Calculate the max and the total for each field if needed. */
        for (j = 0; j < hist_data->n_vals; j++) {
-               if (!(hist_data->fields[j]->flags & HIST_FIELD_FL_PERCENT))
+               if (!(hist_data->fields[j]->flags &
+                       (HIST_FIELD_FL_PERCENT | HIST_FIELD_FL_GRAPH)))
                        continue;
-               if (!totals) {
-                       totals = kcalloc(hist_data->n_vals, sizeof(u64),
-                                        GFP_KERNEL);
-                       if (!totals) {
+               if (!stats) {
+                       stats = kcalloc(hist_data->n_vals, sizeof(*stats),
+                                      GFP_KERNEL);
+                       if (!stats) {
                                n_entries = -ENOMEM;
                                goto out;
                        }
                }
-               for (i = 0; i < n_entries; i++)
-                       totals[j] += tracing_map_read_sum(
-                                       sort_entries[i]->elt, j);
+               for (i = 0; i < n_entries; i++) {
+                       val = tracing_map_read_sum(sort_entries[i]->elt, j);
+                       stats[j].total += val;
+                       if (stats[j].max < val)
+                               stats[j].max = val;
+               }
        }
 
        for (i = 0; i < n_entries; i++)
-               hist_trigger_entry_print(m, hist_data, totals,
+               hist_trigger_entry_print(m, hist_data, stats,
                                         sort_entries[i]->key,
                                         sort_entries[i]->elt);
 
-       kfree(totals);
+       kfree(stats);
 out:
        tracing_map_destroy_sort_entries(sort_entries, n_entries);