#include "util/strlist.h"
 #include "util/intlist.h"
 #include "util/thread_map.h"
+#include "util/stat.h"
 
 #include <libaudit.h>
 #include <stdlib.h>
                int       max;
                char      **table;
        } paths;
+
+       struct intlist *syscall_stats;
 };
 
 static struct thread_trace *thread_trace__new(void)
        if (ttrace)
                ttrace->paths.max = -1;
 
+       ttrace->syscall_stats = intlist__new(NULL);
+
        return ttrace;
 }
 
        struct intlist          *pid_list;
        bool                    sched;
        bool                    multiple_threads;
+       bool                    summary;
        bool                    show_comm;
        double                  duration_filter;
        double                  runtime_ms;
                                  struct perf_sample *sample);
 
 static struct syscall *trace__syscall_info(struct trace *trace,
-                                          struct perf_evsel *evsel,
-                                          struct perf_sample *sample)
+                                          struct perf_evsel *evsel, int id)
 {
-       int id = perf_evsel__intval(evsel, sample, "id");
 
        if (id < 0) {
 
        return NULL;
 }
 
+static void thread__update_stats(struct thread_trace *ttrace,
+                                int id, struct perf_sample *sample)
+{
+       struct int_node *inode;
+       struct stats *stats;
+       u64 duration = 0;
+
+       inode = intlist__findnew(ttrace->syscall_stats, id);
+       if (inode == NULL)
+               return;
+
+       stats = inode->priv;
+       if (stats == NULL) {
+               stats = malloc(sizeof(struct stats));
+               if (stats == NULL)
+                       return;
+               init_stats(stats);
+               inode->priv = stats;
+       }
+
+       if (ttrace->entry_time && sample->time > ttrace->entry_time)
+               duration = sample->time - ttrace->entry_time;
+
+       update_stats(stats, duration);
+}
+
 static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel,
                            struct perf_sample *sample)
 {
        void *args;
        size_t printed = 0;
        struct thread *thread;
-       struct syscall *sc = trace__syscall_info(trace, evsel, sample);
+       int id = perf_evsel__intval(evsel, sample, "id");
+       struct syscall *sc = trace__syscall_info(trace, evsel, id);
        struct thread_trace *ttrace;
 
        if (sc == NULL)
        int ret;
        u64 duration = 0;
        struct thread *thread;
-       struct syscall *sc = trace__syscall_info(trace, evsel, sample);
+       int id = perf_evsel__intval(evsel, sample, "id");
+       struct syscall *sc = trace__syscall_info(trace, evsel, id);
        struct thread_trace *ttrace;
 
        if (sc == NULL)
        if (ttrace == NULL)
                return -1;
 
+       if (trace->summary)
+               thread__update_stats(ttrace, id, sample);
+
        ret = perf_evsel__intval(evsel, sample, "ret");
 
        ttrace = thread->priv;
        return cmd_record(i, rec_argv, NULL);
 }
 
+static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp);
+
 static int trace__run(struct trace *trace, int argc, const char **argv)
 {
        struct perf_evlist *evlist = perf_evlist__new();
        goto again;
 
 out_unmap_evlist:
+       if (!err && trace->summary)
+               trace__fprintf_thread_summary(trace, trace->output);
+
        perf_evlist__munmap(evlist);
 out_close_evlist:
        perf_evlist__close(evlist);
        if (err)
                pr_err("Failed to process events, error %d", err);
 
+       else if (trace->summary)
+               trace__fprintf_thread_summary(trace, trace->output);
+
 out:
        perf_session__delete(session);
 
 {
        size_t printed;
 
-       printed  = fprintf(fp, "\n _____________________________________________________________________\n");
-       printed += fprintf(fp," __)    Summary of events    (__\n\n");
-       printed += fprintf(fp,"              [ task - pid ]     [ events ] [ ratio ]  [ runtime ]\n");
-       printed += fprintf(fp," _____________________________________________________________________\n\n");
+       printed  = fprintf(fp, "\n _____________________________________________________________________________\n");
+       printed += fprintf(fp, " __)    Summary of events    (__\n\n");
+       printed += fprintf(fp, "              [ task - pid ]     [ events ] [ ratio ]  [ runtime ]\n");
+       printed += fprintf(fp, "                                  syscall  count    min     max    avg  stddev\n");
+       printed += fprintf(fp, "                                                   msec    msec   msec     %%\n");
+       printed += fprintf(fp, " _____________________________________________________________________________\n\n");
+
+       return printed;
+}
+
+static size_t thread__dump_stats(struct thread_trace *ttrace,
+                                struct trace *trace, FILE *fp)
+{
+       struct stats *stats;
+       size_t printed = 0;
+       struct syscall *sc;
+       struct int_node *inode = intlist__first(ttrace->syscall_stats);
+
+       if (inode == NULL)
+               return 0;
+
+       printed += fprintf(fp, "\n");
+
+       /* each int_node is a syscall */
+       while (inode) {
+               stats = inode->priv;
+               if (stats) {
+                       double min = (double)(stats->min) / NSEC_PER_MSEC;
+                       double max = (double)(stats->max) / NSEC_PER_MSEC;
+                       double avg = avg_stats(stats);
+                       double pct;
+                       u64 n = (u64) stats->n;
+
+                       pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0;
+                       avg /= NSEC_PER_MSEC;
+
+                       sc = &trace->syscalls.table[inode->i];
+                       printed += fprintf(fp, "%24s  %14s : ", "", sc->name);
+                       printed += fprintf(fp, "%5" PRIu64 "  %8.3f  %8.3f",
+                                          n, min, max);
+                       printed += fprintf(fp, "  %8.3f  %6.2f\n", avg, pct);
+               }
+
+               inode = intlist__next(inode);
+       }
+
+       printed += fprintf(fp, "\n\n");
 
        return printed;
 }
        printed += fprintf(fp, " - %-5d :%11lu   [", thread->tid, ttrace->nr_events);
        printed += color_fprintf(fp, color, "%5.1f%%", ratio);
        printed += fprintf(fp, " ] %10.3f ms\n", ttrace->runtime_ms);
+       printed += thread__dump_stats(ttrace, trace, fp);
 
        data->printed += printed;
 
        OPT_INCR('v', "verbose", &verbose, "be more verbose"),
        OPT_BOOLEAN('T', "time", &trace.full_time,
                    "Show full timestamp, not time relative to first start"),
+       OPT_BOOLEAN(0, "summary", &trace.summary,
+                   "Show syscall summary with statistics"),
        OPT_END()
        };
        int err;
        else
                err = trace__run(&trace, argc, argv);
 
-       if (trace.sched && !err)
-               trace__fprintf_thread_summary(&trace, trace.output);
-
 out_close:
        if (output_name != NULL)
                fclose(trace.output);