diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index a180abf76d4e..c212c379a172 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -1526,6 +1526,7 @@ extern struct list_head ftrace_events;
 
 extern const struct file_operations event_trigger_fops;
 extern const struct file_operations event_hist_fops;
+extern const struct file_operations event_hist_json_fops;
 extern const struct file_operations event_hist_debug_fops;
 extern const struct file_operations event_inject_fops;
 
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 80e96989770e..e5e8ec1cb5d0 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -2432,6 +2432,8 @@ event_create_dir(struct dentry *parent, struct trace_event_file *file)
 #ifdef CONFIG_HIST_TRIGGERS
 	trace_create_file("hist", 0444, file->dir, file,
 			  &event_hist_fops);
+	trace_create_file("hist_json", 0444, file->dir, file,
+			  &event_hist_json_fops);
 #endif
 #ifdef CONFIG_HIST_TRIGGERS_DEBUG
 	trace_create_file("hist_debug", 0444, file->dir, file,
diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 9d91b1c06957..5221522d9a3d 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -2903,6 +2903,176 @@ static bool check_track_val(struct tracing_map_elt *elt,
 	return data->track_data.check_val(track_val, var_val);
 }
 
+enum show_format {
+	TEXT,
+	JSON,
+};
+
+static void indent(struct seq_file *m, int *level)
+{
+#define JSON_INDENT	2
+
+	int indent_spaces = *level * JSON_INDENT;
+
+	seq_printf(m, "%*c", indent_spaces, ' ');
+}
+
+static void __print_obj_name(struct seq_file *m, const char *name,
+			     enum show_format format)
+{
+	if (!name)
+		return;
+
+	if (format == JSON)
+		seq_printf(m, "\"%s\":", name);
+	else if (format == TEXT)
+		seq_printf(m, "%s:", name);
+}
+
+static void __start_json_obj(struct seq_file *m, const char *name, int *level,
+			     const char *bracket)
+{
+	indent(m, level);
+	__print_obj_name(m, name, JSON);
+	seq_puts(m, bracket);
+	(*level)++;
+}
+
+static void __end_json_obj(struct seq_file *m, int *level, const char *bracket)
+{
+	(*level)--;
+	indent(m, level);
+	seq_puts(m, bracket);
+}
+
+static void print_json_obj_start(struct seq_file *m,
+				 const char *name, int *level)
+{
+	__start_json_obj(m, name, level, "{\n");
+}
+
+static void print_json_obj_end(struct seq_file *m, int *level)
+{
+	__end_json_obj(m, level, "},\n");
+}
+
+static void __start_obj(struct seq_file *m, const char *name,
+			enum show_format format, int *level)
+{
+	if (format == JSON)
+		print_json_obj_start(m, name, level);
+}
+
+static void __end_obj(struct seq_file *m, enum show_format format, int *level)
+{
+	if (format == JSON)
+		print_json_obj_end(m, level);
+}
+
+static void __start_json_array(struct seq_file *m, const char *name,
+			       int *level)
+{
+	__start_json_obj(m, name, level, "[\n");
+}
+
+static void __end_json_array(struct seq_file *m, int *level)
+{
+	__end_json_obj(m, level, "],\n");
+}
+
+static void print_hist_start(struct seq_file *m, int nth_hist,
+			     enum show_format format, int *level)
+{
+	if (nth_hist > 0 && format == TEXT)
+		seq_puts(m, "\n\n");
+
+	__start_obj(m, "hist", format, level);
+}
+
+#define print_hist_end(m, format, level) \
+	__end_obj(m, format, level)
+#define print_map_start(m, format, level) \
+	__start_obj(m, "map", format, level)
+#define print_map_end(m, format, level) \
+	__end_obj(m, format, level)
+#define print_entry_start(m, format, level) \
+	__start_obj(m, "entry", format, level)
+#define print_entry_end(m, format, level) \
+	__end_obj(m, format, level)
+#define print_action_start(m, format, level) \
+	__start_obj(m, "action", format, level)
+#define print_action_end(m, format, level) \
+	__end_obj(m, format, level)
+#define print_snapshot_action_start(m, format, level) \
+	__start_obj(m, "snapshot", format, level)
+#define print_snapshot_action_end(m, format, level) \
+	__end_obj(m, format, level)
+#define print_key_start(m, format, level) \
+	__start_obj(m, NULL, format, level)
+#define print_key_end(m, format, level) \
+	__end_obj(m, format, level)
+#define print_val_end(m, format, level) \
+	__end_obj(m, format, level)
+
+static void print_val_start(struct seq_file *m,
+			    enum show_format format, int *level)
+{
+	if (format == JSON)
+		print_json_obj_start(m, NULL, level);
+	else if (format == TEXT)
+		seq_putc(m, ' ');
+}
+
+static void print_keys_start(struct seq_file *m,
+			     enum show_format format, int *level)
+{
+	if (format == JSON)
+		__start_json_array(m, "keys", level);
+	else if (format == TEXT)
+		seq_puts(m, "{ ");
+}
+
+static void print_keys_end(struct seq_file *m,
+			   enum show_format format, int *level)
+{
+	if (format == JSON)
+		__end_json_array(m, level);
+	else if (format == TEXT)
+		seq_puts(m, "}");
+}
+
+static void print_vals_start(struct seq_file *m,
+			     enum show_format format, int *level)
+{
+	if (format == JSON)
+		__start_json_array(m, "vals", level);
+}
+
+static void print_vals_end(struct seq_file *m,
+			   enum show_format format, int *level)
+{
+	if (format == JSON)
+		__end_json_array(m, level);
+}
+
+static void print_pair_start(struct seq_file *m, const char *name,
+			     enum show_format format, int *level)
+{
+	if (format == JSON)
+		indent(m, level);
+
+	__print_obj_name(m, name, format);
+}
+
+static void print_pair_end(struct seq_file *m, const char *val,
+			   enum show_format format)
+{
+	if (format == JSON)
+		seq_printf(m, "\"%s\",\n", val);
+	else if (format == TEXT)
+		seq_puts(m, val);
+}
+
 #ifdef CONFIG_TRACER_SNAPSHOT
 static bool cond_snapshot_update(struct trace_array *tr, void *cond_data)
 {
@@ -2956,7 +3126,8 @@ static void save_track_data_snapshot(struct hist_trigger_data *hist_data,
 static void hist_trigger_print_key(struct seq_file *m,
 				   struct hist_trigger_data *hist_data,
 				   void *key,
-				   struct tracing_map_elt *elt);
+				   struct tracing_map_elt *elt,
+				   enum show_format format, int *level);
 
 static struct action_data *snapshot_action(struct hist_trigger_data *hist_data)
 {
@@ -2976,11 +3147,13 @@ static struct action_data *snapshot_action(struct hist_trigger_data *hist_data)
 }
 
 static void track_data_snapshot_print(struct seq_file *m,
-				      struct hist_trigger_data *hist_data)
+				      struct hist_trigger_data *hist_data,
+				      enum show_format format, int *level)
 {
 	struct trace_event_file *file = hist_data->event_file;
 	struct track_data *track_data;
 	struct action_data *action;
+	char str[MAX_FILTER_STR_VAL];
 
 	track_data = tracing_cond_snapshot_data(file->tr);
 	if (!track_data)
@@ -2993,14 +3166,32 @@ static void track_data_snapshot_print(struct seq_file *m,
 	if (!action)
 		return;
 
-	seq_puts(m, "\nSnapshot taken (see tracing/snapshot).  Details:\n");
-	seq_printf(m, "\ttriggering value { %s(%s) }: %10llu",
-		   action->handler == HANDLER_ONMAX ? "onmax" : "onchange",
-		   action->track_data.var_str, track_data->track_val);
+	if (format == JSON) {
+		print_snapshot_action_start(m, format, level);
+		print_pair_start(m, "handler", format, level);
+		if (action->handler == HANDLER_ONMAX)
+			print_pair_end(m, "onmax", format);
+		else
+			print_pair_end(m, "onchange", format);
 
-	seq_puts(m, "\ttriggered by event with key: ");
-	hist_trigger_print_key(m, hist_data, track_data->key, &track_data->elt);
-	seq_putc(m, '\n');
+		print_pair_start(m, action->track_data.var_str, format, level);
+		snprintf(str, sizeof(str), "%10llu", track_data->track_val);
+		print_pair_end(m, strim(str), format);
+	} else if (format == TEXT) {
+		seq_puts(m, "\nSnapshot taken (see tracing/snapshot).  Details:\n");
+		seq_printf(m, "\ttriggering value { %s(%s) }: %10llu",
+			   action->handler == HANDLER_ONMAX ? "onmax" : "onchange",
+			   action->track_data.var_str, track_data->track_val);
+
+		seq_puts(m, "\ttriggered by event with key: ");
+	}
+
+	hist_trigger_print_key(m, hist_data, track_data->key, &track_data->elt,
+			       format, level);
+	if (format == JSON)
+		print_snapshot_action_end(m, format, level);
+	else
+		seq_putc(m, '\n');
 }
 #else
 static bool cond_snapshot_update(struct trace_array *tr, void *cond_data)
@@ -3014,24 +3205,71 @@ static void save_track_data_snapshot(struct hist_trigger_data *hist_data,
 				     struct action_data *data,
 				     u64 *var_ref_vals) {}
 static void track_data_snapshot_print(struct seq_file *m,
-				      struct hist_trigger_data *hist_data) {}
+				      struct hist_trigger_data *hist_data,
+				      enum show_format format, int *level) {}
 #endif /* CONFIG_TRACER_SNAPSHOT */
 
+static void print_track_val(struct seq_file *m, const char *handler,
+			    u64 track_val, enum show_format format, int *level)
+{
+	char str[MAX_FILTER_STR_VAL];
+
+	if (format == JSON) {
+		print_pair_start(m, handler, format, level);
+		snprintf(str, sizeof(str), "%10llu", track_val);
+		print_pair_end(m, strim(str), format);
+	} else if (format == TEXT) {
+		seq_printf(m, "\n\t%s: %10llu", handler, track_val);
+	}
+}
+
+static void print_variable(struct seq_file *m, const char *var_name, u64 val,
+			   bool is_string, enum show_format format, int *level)
+{
+	char str[MAX_FILTER_STR_VAL];
+
+	if (is_string) {
+		if (format == JSON) {
+			snprintf(str, sizeof(str), "%s", var_name);
+			print_pair_start(m, str, format, level);
+			snprintf(str, sizeof(str), "%-32s", (char *)(uintptr_t)(val));
+			print_pair_end(m, strim(str), format);
+		} else if (format == TEXT) {
+			seq_printf(m, "  %s: %-32s", var_name,
+				   (char *)(uintptr_t)(val));
+		}
+	} else {
+		if (format == JSON) {
+			snprintf(str, sizeof(str), "%s", var_name);
+			print_pair_start(m, str, format, level);
+			snprintf(str, sizeof(str), "%10llu", val);
+			print_pair_end(m, strim(str), format);
+		} else {
+			seq_printf(m, "  %s: %10llu", var_name, val);
+		}
+	}
+}
+
 static void track_data_print(struct seq_file *m,
 			     struct hist_trigger_data *hist_data,
 			     struct tracing_map_elt *elt,
-			     struct action_data *data)
+			     struct action_data *data,
+			     enum show_format format, int *level)
 {
 	u64 track_val = get_track_val(hist_data, elt, data);
 	unsigned int i, save_var_idx;
 
+	print_action_start(m, format, level);
+
 	if (data->handler == HANDLER_ONMAX)
-		seq_printf(m, "\n\tmax: %10llu", track_val);
+		print_track_val(m, "max", track_val, format, level);
 	else if (data->handler == HANDLER_ONCHANGE)
-		seq_printf(m, "\n\tchanged: %10llu", track_val);
+		print_track_val(m, "changed", track_val, format, level);
 
-	if (data->action == ACTION_SNAPSHOT)
+	if (data->action == ACTION_SNAPSHOT) {
+		print_action_end(m, format, level);
 		return;
+	}
 
 	for (i = 0; i < hist_data->n_save_vars; i++) {
 		struct hist_field *save_val = hist_data->save_vars[i]->val;
@@ -3042,12 +3280,12 @@ static void track_data_print(struct seq_file *m,
 
 		val = tracing_map_read_var(elt, save_var_idx);
 
-		if (save_val->flags & HIST_FIELD_FL_STRING) {
-			seq_printf(m, "  %s: %-32s", save_var->var.name,
-				   (char *)(uintptr_t)(val));
-		} else
-			seq_printf(m, "  %s: %10llu", save_var->var.name, val);
+		print_variable(m, save_var->var.name, val,
+			       save_val->flags & HIST_FIELD_FL_STRING,
+			       format, level);
 	}
+
+	print_action_end(m, format, level);
 }
 
 static void ontrack_action(struct hist_trigger_data *hist_data,
@@ -4276,7 +4514,8 @@ static int create_actions(struct hist_trigger_data *hist_data)
 
 static void print_actions(struct seq_file *m,
 			  struct hist_trigger_data *hist_data,
-			  struct tracing_map_elt *elt)
+			  struct tracing_map_elt *elt,
+			  enum show_format format, int *level)
 {
 	unsigned int i;
 
@@ -4288,7 +4527,7 @@ static void print_actions(struct seq_file *m,
 
 		if (data->handler == HANDLER_ONMAX ||
 		    data->handler == HANDLER_ONCHANGE)
-			track_data_print(m, hist_data, elt, data);
+			track_data_print(m, hist_data, elt, data, format, level);
 	}
 }
 
@@ -4694,7 +4933,8 @@ static void event_hist_trigger(struct event_trigger_data *data,
 
 static void hist_trigger_stacktrace_print(struct seq_file *m,
 					  unsigned long *stacktrace_entries,
-					  unsigned int max_entries)
+					  unsigned int max_entries,
+					  enum show_format format, int *level)
 {
 	char str[KSYM_SYMBOL_LEN];
 	unsigned int spaces = 8;
@@ -4704,7 +4944,10 @@ static void hist_trigger_stacktrace_print(struct seq_file *m,
 		if (!stacktrace_entries[i])
 			return;
 
-		seq_printf(m, "%*c", 1 + spaces, ' ');
+		if (format == JSON)
+			indent(m, level);
+		else if (format == TEXT)
+			seq_printf(m, "%*c", 1 + spaces, ' ');
 		sprint_symbol(str, stacktrace_entries[i]);
 		seq_printf(m, "%s\n", str);
 	}
@@ -4713,8 +4956,10 @@ static void hist_trigger_stacktrace_print(struct seq_file *m,
 static void hist_trigger_print_key(struct seq_file *m,
 				   struct hist_trigger_data *hist_data,
 				   void *key,
-				   struct tracing_map_elt *elt)
+				   struct tracing_map_elt *elt,
+				   enum show_format format, int *level)
 {
+	char key_str[MAX_FILTER_STR_VAL];
 	struct hist_field *key_field;
 	char str[KSYM_SYMBOL_LEN];
 	bool multiline = false;
@@ -4722,29 +4967,36 @@ static void hist_trigger_print_key(struct seq_file *m,
 	unsigned int i;
 	u64 uval;
 
-	seq_puts(m, "{ ");
+	print_keys_start(m, format, level);
 
 	for_each_hist_key_field(i, hist_data) {
 		key_field = hist_data->fields[i];
 
-		if (i > hist_data->n_vals)
+		if (i > hist_data->n_vals && format == TEXT)
 			seq_puts(m, ", ");
 
-		field_name = hist_field_name(key_field, 0);
+		print_key_start(m, format, level);
+
+		if (key_field->flags & HIST_FIELD_FL_STACKTRACE)
+			field_name = "stacktrace";
+		else
+			field_name = hist_field_name(key_field, 0);
+
+		print_pair_start(m, field_name, format, level);
 
 		if (key_field->flags & HIST_FIELD_FL_HEX) {
 			uval = *(u64 *)(key + key_field->offset);
-			seq_printf(m, "%s: %llx", field_name, uval);
+			snprintf(key_str, sizeof(key_str), "%llx", uval);
 		} else if (key_field->flags & HIST_FIELD_FL_SYM) {
 			uval = *(u64 *)(key + key_field->offset);
 			sprint_symbol_no_offset(str, uval);
-			seq_printf(m, "%s: [%llx] %-45s", field_name,
-				   uval, str);
+			snprintf(key_str, sizeof(key_str), "[%llx] %-45s",
+				 uval, str);
 		} else if (key_field->flags & HIST_FIELD_FL_SYM_OFFSET) {
 			uval = *(u64 *)(key + key_field->offset);
 			sprint_symbol(str, uval);
-			seq_printf(m, "%s: [%llx] %-55s", field_name,
-				   uval, str);
+			snprintf(key_str, sizeof(key_str), "[%llx] %-55s",
+				 uval, str);
 		} else if (key_field->flags & HIST_FIELD_FL_EXECNAME) {
 			struct hist_elt_data *elt_data = elt->private_data;
 			char *comm;
@@ -4755,8 +5007,8 @@ static void hist_trigger_print_key(struct seq_file *m,
 			comm = elt_data->comm;
 
 			uval = *(u64 *)(key + key_field->offset);
-			seq_printf(m, "%s: %-16s[%10llu]", field_name,
-				   comm, uval);
+			snprintf(key_str, sizeof(key_str), "%-16s[%10llu]",
+				 comm, uval);
 		} else if (key_field->flags & HIST_FIELD_FL_SYSCALL) {
 			const char *syscall_name;
 
@@ -4765,49 +5017,72 @@ static void hist_trigger_print_key(struct seq_file *m,
 			if (!syscall_name)
 				syscall_name = "unknown_syscall";
 
-			seq_printf(m, "%s: %-30s[%3llu]", field_name,
-				   syscall_name, uval);
+			snprintf(key_str, sizeof(key_str), "%-30s[%3llu]",
+				 syscall_name, uval);
 		} else if (key_field->flags & HIST_FIELD_FL_STACKTRACE) {
-			seq_puts(m, "stacktrace:\n");
+			if (format == JSON)
+				seq_puts(m, "\"\n");
+			else if (format == TEXT)
+				seq_puts(m, "\n");
 			hist_trigger_stacktrace_print(m,
 						      key + key_field->offset,
-						      HIST_STACKTRACE_DEPTH);
+						      HIST_STACKTRACE_DEPTH,
+						      format, level);
 			multiline = true;
 		} else if (key_field->flags & HIST_FIELD_FL_LOG2) {
-			seq_printf(m, "%s: ~ 2^%-2llu", field_name,
-				   *(u64 *)(key + key_field->offset));
+			snprintf(key_str, sizeof(key_str), "~ 2^%-2llu",
+				 *(u64 *)(key + key_field->offset));
 		} else if (key_field->flags & HIST_FIELD_FL_BUCKET) {
 			unsigned long buckets = key_field->buckets;
 			uval = *(u64 *)(key + key_field->offset);
-			seq_printf(m, "%s: ~ %llu-%llu", field_name,
-				   uval, uval + buckets -1);
+			snprintf(key_str, sizeof(key_str), "~ %llu-%llu",
+				 uval, uval + buckets - 1);
 		} else if (key_field->flags & HIST_FIELD_FL_STRING) {
-			seq_printf(m, "%s: %-50s", field_name,
-				   (char *)(key + key_field->offset));
+			snprintf(key_str, sizeof(key_str), "%-50s",
+				 (char *)(key + key_field->offset));
 		} else {
 			uval = *(u64 *)(key + key_field->offset);
-			seq_printf(m, "%s: %10llu", field_name, uval);
+			snprintf(key_str, sizeof(key_str), "%10llu", uval);
 		}
+		if (key_field->flags & HIST_FIELD_FL_STACKTRACE) {
+			if (format == JSON) {
+				indent(m, level);
+				seq_puts(m, "\"\n");
+			}
+		} else {
+			print_pair_end(m, strim(key_str), format);
+		}
+		print_key_end(m, format, level);
 	}
 
-	if (!multiline)
+	if (!multiline && format == TEXT)
 		seq_puts(m, " ");
 
-	seq_puts(m, "}");
+	print_keys_end(m, format, level);
 }
 
 static void hist_trigger_entry_print(struct seq_file *m,
 				     struct hist_trigger_data *hist_data,
 				     void *key,
-				     struct tracing_map_elt *elt)
+				     struct tracing_map_elt *elt,
+				     enum show_format format, int *level)
 {
+	char val_str[MAX_FILTER_STR_VAL];
 	const char *field_name;
 	unsigned int i;
 
-	hist_trigger_print_key(m, hist_data, key, elt);
+	print_entry_start(m, format, level);
+
+	hist_trigger_print_key(m, hist_data, key, elt, format, level);
 
-	seq_printf(m, " hitcount: %10llu",
-		   tracing_map_read_sum(elt, HITCOUNT_IDX));
+	print_vals_start(m, format, level);
+
+	print_val_start(m, format, level);
+	print_pair_start(m, "hitcount", format, level);
+	snprintf(val_str, sizeof(val_str), "%10llu",
+		 tracing_map_read_sum(elt, HITCOUNT_IDX));
+	print_pair_end(m, strim(val_str), format);
+	print_val_end(m, format, level);
 
 	for (i = 1; i < hist_data->n_vals; i++) {
 		field_name = hist_field_name(hist_data->fields[i], 0);
@@ -4816,22 +5091,34 @@ static void hist_trigger_entry_print(struct seq_file *m,
 		    hist_data->fields[i]->flags & HIST_FIELD_FL_EXPR)
 			continue;
 
+		print_val_start(m, format, level);
+		print_pair_start(m, field_name, format, level);
+
 		if (hist_data->fields[i]->flags & HIST_FIELD_FL_HEX) {
-			seq_printf(m, "  %s: %10llx", field_name,
-				   tracing_map_read_sum(elt, i));
+			snprintf(val_str, sizeof(val_str), "%10llx",
+				 tracing_map_read_sum(elt, i));
 		} else {
-			seq_printf(m, "  %s: %10llu", field_name,
-				   tracing_map_read_sum(elt, i));
+			snprintf(val_str, sizeof(val_str), "%10llu",
+				 tracing_map_read_sum(elt, i));
 		}
+
+		print_pair_end(m, strim(val_str), format);
+		print_val_end(m, format, level);
 	}
 
-	print_actions(m, hist_data, elt);
+	print_vals_end(m, format, level);
+
+	print_actions(m, hist_data, elt, format, level);
+
+	print_entry_end(m, format, level);
 
-	seq_puts(m, "\n");
+	if (format != JSON)
+		seq_puts(m, "\n");
 }
 
 static int print_entries(struct seq_file *m,
-			 struct hist_trigger_data *hist_data)
+			 struct hist_trigger_data *hist_data,
+			 enum show_format format, int *level)
 {
 	struct tracing_map_sort_entry **sort_entries = NULL;
 	struct tracing_map *map = hist_data->map;
@@ -4846,43 +5133,97 @@ static int print_entries(struct seq_file *m,
 	for (i = 0; i < n_entries; i++)
 		hist_trigger_entry_print(m, hist_data,
 					 sort_entries[i]->key,
-					 sort_entries[i]->elt);
+					 sort_entries[i]->elt, format, level);
 
 	tracing_map_destroy_sort_entries(sort_entries, n_entries);
 
 	return n_entries;
 }
 
+static void show_hist_info(struct seq_file *m, struct event_trigger_data *data,
+			   enum show_format format, int *level)
+{
+	if (format == JSON) {
+		print_json_obj_start(m, "info", level);
+		print_pair_start(m, "trigger", format, level);
+		seq_puts(m, "\"");
+	} else if (format == TEXT) {
+		seq_puts(m, "# event histogram\n#\n# trigger info: ");
+	}
+
+	data->ops->print(m, data->ops, data);
+
+	if (format == JSON) {
+		seq_puts(m, "\"\n");
+		print_json_obj_end(m, level);
+	} else {
+		seq_puts(m, "#\n\n");
+	}
+}
+
+static void print_hist_totals(struct seq_file *m,
+			      struct hist_trigger_data *hist_data, int n_entries,
+			      enum show_format format, int *level)
+{
+	char str[MAX_FILTER_STR_VAL];
+
+	if (format == JSON) {
+		print_json_obj_start(m, "totals", level);
+
+		print_pair_start(m, "hits", format, level);
+		snprintf(str, sizeof(str), "%llu",
+			 (u64)atomic64_read(&hist_data->map->hits));
+		print_pair_end(m, strim(str), format);
+
+		print_pair_start(m, "entries", format, level);
+		snprintf(str, sizeof(str), "%u", n_entries);
+		print_pair_end(m, strim(str), format);
+
+		print_pair_start(m, "dropped", format, level);
+		snprintf(str, sizeof(str), "%llu",
+			 (u64)atomic64_read(&hist_data->map->drops));
+		print_pair_end(m, strim(str), format);
+
+		print_json_obj_end(m, level);
+	} else if (format == TEXT) {
+		seq_printf(m, "\nTotals:\n    Hits: %llu\n    Entries: %u\n    Dropped: %llu\n",
+			   (u64)atomic64_read(&hist_data->map->hits),
+			   n_entries, (u64)atomic64_read(&hist_data->map->drops));
+	}
+}
+
 static void hist_trigger_show(struct seq_file *m,
-			      struct event_trigger_data *data, int n)
+			      struct event_trigger_data *data, int n,
+			      enum show_format format, int *level)
 {
 	struct hist_trigger_data *hist_data;
 	int n_entries;
 
-	if (n > 0)
-		seq_puts(m, "\n\n");
+	print_hist_start(m, n, format, level);
 
-	seq_puts(m, "# event histogram\n#\n# trigger info: ");
-	data->ops->print(m, data->ops, data);
-	seq_puts(m, "#\n\n");
+	show_hist_info(m, data, format, level);
+
+	print_map_start(m, format, level);
 
 	hist_data = data->private_data;
-	n_entries = print_entries(m, hist_data);
+	n_entries = print_entries(m, hist_data, format, level);
 	if (n_entries < 0)
 		n_entries = 0;
 
-	track_data_snapshot_print(m, hist_data);
+	print_map_end(m, format, level);
 
-	seq_printf(m, "\nTotals:\n    Hits: %llu\n    Entries: %u\n    Dropped: %llu\n",
-		   (u64)atomic64_read(&hist_data->map->hits),
-		   n_entries, (u64)atomic64_read(&hist_data->map->drops));
+	track_data_snapshot_print(m, hist_data, format, level);
+
+	print_hist_totals(m, hist_data, n_entries, format, level);
+
+	print_hist_end(m, format, level);
 }
 
 static int hist_show(struct seq_file *m, void *v)
 {
 	struct event_trigger_data *data;
 	struct trace_event_file *event_file;
-	int n = 0, ret = 0;
+	int n = 0, ret = 0, level = 1;
 
 	mutex_lock(&event_mutex);
 
@@ -4894,7 +5235,7 @@ static int hist_show(struct seq_file *m, void *v)
 
 	list_for_each_entry(data, &event_file->triggers, list) {
 		if (data->cmd_ops->trigger_type == ETT_EVENT_HIST)
-			hist_trigger_show(m, data, n++);
+			hist_trigger_show(m, data, n++, TEXT, &level);
 	}
 
  out_unlock:
@@ -4921,6 +5262,53 @@ const struct file_operations event_hist_fops = {
 	.release = single_release,
 };
 
+static int hist_json_show(struct seq_file *m, void *v)
+{
+	struct event_trigger_data *data;
+	struct trace_event_file *event_file;
+	int n = 0, ret = 0, level = 1;
+
+	mutex_lock(&event_mutex);
+
+	event_file = event_file_data(m->private);
+	if (unlikely(!event_file)) {
+		ret = -ENODEV;
+		goto out_unlock;
+	}
+
+	seq_puts(m, "[\n");
+
+	list_for_each_entry(data, &event_file->triggers, list) {
+		if (data->cmd_ops->trigger_type == ETT_EVENT_HIST)
+			hist_trigger_show(m, data, n++, JSON, &level);
+	}
+
+	seq_puts(m, "]\n");
+
+out_unlock:
+	mutex_unlock(&event_mutex);
+
+	return ret;
+}
+
+static int event_hist_json_open(struct inode *inode, struct file *file)
+{
+	int ret;
+
+	ret = security_locked_down(LOCKDOWN_TRACEFS);
+	if (ret)
+		return ret;
+
+	return single_open(file, hist_json_show, file);
+}
+
+const struct file_operations event_hist_json_fops = {
+	.open = event_hist_json_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 #ifdef CONFIG_HIST_TRIGGERS_DEBUG
 static void hist_field_debug_show_flags(struct seq_file *m,
 					unsigned long flags)
