#include "util/thread.h"
 #include "util/thread_map.h"
 #include "util/counts.h"
+#include "util/session.h"
 
 #include <stdlib.h>
 #include <sys/prctl.h>
 static const char              *output_name;
 static int                     output_fd;
 
+struct perf_stat {
+       bool                     record;
+       struct perf_data_file    file;
+       struct perf_session     *session;
+       u64                      bytes_written;
+};
+
+static struct perf_stat                perf_stat;
+#define STAT_RECORD            perf_stat.record
+
 static volatile int done = 0;
 
 static struct perf_stat_config stat_config = {
         * like tracepoints. Clear it up for counting.
         */
        attr->sample_period = 0;
-       attr->sample_type   = 0;
+       /*
+        * But set sample_type to PERF_SAMPLE_IDENTIFIER, which should be harmless
+        * while avoiding that older tools show confusing messages.
+        */
+       attr->sample_type   = PERF_SAMPLE_IDENTIFIER;
 
        /*
         * Disabling all counters initially, they will be enabled
        return 0;
 }
 
+static int perf_stat__write(struct perf_stat *stat, void *bf, size_t size)
+{
+       if (perf_data_file__write(stat->session->file, bf, size) < 0) {
+               pr_err("failed to write perf data, error: %m\n");
+               return -1;
+       }
+
+       stat->bytes_written += size;
+       return 0;
+}
+
+static int process_synthesized_event(struct perf_tool *tool,
+                                    union perf_event *event,
+                                    struct perf_sample *sample __maybe_unused,
+                                    struct machine *machine __maybe_unused)
+{
+       struct perf_stat *stat = (void *)tool;
+       return perf_stat__write(stat, event, event->header.size);
+}
+
 /*
  * Read out the results of a single counter:
  * do not aggregate counts across CPUs in system-wide mode
                return -1;
        }
 
+       if (STAT_RECORD) {
+               int err, fd = perf_data_file__fd(&perf_stat.file);
+
+               err = perf_session__write_header(perf_stat.session, evsel_list,
+                                                fd, false);
+               if (err < 0)
+                       return err;
+       }
+
        /*
         * Enable counters and exec the command:
         */
        return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs);
 }
 
+static const char * const recort_usage[] = {
+       "perf stat record [<options>]",
+       NULL,
+};
+
+static int __cmd_record(int argc, const char **argv)
+{
+       struct perf_session *session;
+       struct perf_data_file *file = &perf_stat.file;
+
+       argc = parse_options(argc, argv, stat_options, record_usage,
+                            PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (output_name)
+               file->path = output_name;
+
+       session = perf_session__new(file, false, NULL);
+       if (session == NULL) {
+               pr_err("Perf session creation failed.\n");
+               return -1;
+       }
+
+       /* No pipe support ATM */
+       if (perf_stat.file.is_pipe)
+               return -EINVAL;
+
+       session->evlist   = evsel_list;
+       perf_stat.session = session;
+       perf_stat.record  = true;
+       return argc;
+}
+
 int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        const char * const stat_usage[] = {
        const char *mode;
        FILE *output = stderr;
        unsigned int interval;
+       const char * const stat_subcommands[] = { "record" };
 
        setlocale(LC_ALL, "");
 
        if (evsel_list == NULL)
                return -ENOMEM;
 
-       argc = parse_options(argc, argv, stat_options, stat_usage,
-               PARSE_OPT_STOP_AT_NON_OPTION);
+       argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
+                                       (const char **) stat_usage,
+                                       PARSE_OPT_STOP_AT_NON_OPTION);
+
+       if (argc && !strncmp(argv[0], "rec", 3)) {
+               argc = __cmd_record(argc, argv);
+               if (argc < 0)
+                       return -1;
+       }
 
        interval = stat_config.interval;
 
-       if (output_name && strcmp(output_name, "-"))
+       /*
+        * For record command the -o is already taken care of.
+        */
+       if (!STAT_RECORD && output_name && strcmp(output_name, "-"))
                output = NULL;
 
        if (output_name && output_fd) {
        if (!forever && status != -1 && !interval)
                print_counters(NULL, argc, argv);
 
+       if (STAT_RECORD) {
+               /*
+                * We synthesize the kernel mmap record just so that older tools
+                * don't emit warnings about not being able to resolve symbols
+                * due to /proc/sys/kernel/kptr_restrict settings and instear provide
+                * a saner message about no samples being in the perf.data file.
+                *
+                * This also serves to suppress a warning about f_header.data.size == 0
+                * in header.c.  -acme
+                */
+               int fd = perf_data_file__fd(&perf_stat.file);
+               int err = perf_event__synthesize_kernel_mmap((void *)&perf_stat,
+                                                            process_synthesized_event,
+                                                            &perf_stat.session->machines.host);
+               if (err) {
+                       pr_warning("Couldn't synthesize the kernel mmap record, harmless, "
+                                  "older tools may produce warnings about this file\n.");
+               }
+
+               perf_stat.session->header.data_size += perf_stat.bytes_written;
+               perf_session__write_header(perf_stat.session, evsel_list, fd, true);
+
+               perf_session__delete(perf_stat.session);
+       }
+
        perf_stat__exit_aggr_mode();
        perf_evlist__free_stats(evsel_list);
 out: