Add per-thread stats to have an idea what's happening
in the main reading loop.

  $ perf --debug threads=2 record ...
  SNIP
            pid      write       poll       skip
      1s   8914       136B          1          0
      2s   8914       512K         43         79
      3s   8914         3M        214        385
      4s   8914         3M        121        291

  $ perf --debug threads=2 record --threads ...
  SNIP
            pid      write       poll       skip
     1s   9770       144B          1          0
          9772         0B          1          0
          9773         0B          1          0
          9774         0B          1          0
     2s   9770       290K         35         37
          9772       272K         36         34
          9773       274K         35         35
          9774       304K         39         39
     3s   9770      1120K        140        140
          9772      1088K        138        138
          9773      1120K        140        140
          9774      1123K        140        140
     4s   9770      1161K        146        146
          9772      1121K        142        142
          9773      1135K        142        142
          9774      1159K        145        145

Link: http://lkml.kernel.org/n/tip-z9un5mjzsh47u9m12ijn7...@git.kernel.org
Signed-off-by: Jiri Olsa <jo...@kernel.org>
---
 tools/perf/builtin-record.c | 79 +++++++++++++++++++++++++++++++++++--
 1 file changed, 76 insertions(+), 3 deletions(-)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index ada6f795d492..ec487d1f2b0b 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -70,7 +70,14 @@ enum {
        RECORD_THREAD__STOP     = 1,
 };
 
+struct thread_stat {
+       u64     bytes_written;
+       u64     poll;
+       u64     poll_skip;
+};
+
 struct record_thread {
+       int                       pid;
        struct perf_mmap        **mmap;
        int                       mmap_nr;
        struct perf_mmap        **ovw_mmap;
@@ -81,6 +88,7 @@ struct record_thread {
        u64                       bytes_written;
        pthread_t                 pt;
        int                       state;
+       struct thread_stat        stats;
 };
 
 struct record {
@@ -149,7 +157,8 @@ static int record__write(struct record *rec, struct 
perf_mmap *map,
                return -1;
        }
 
-       thread->bytes_written += size;
+       thread->bytes_written       += size;
+       thread->stats.bytes_written += size;
 
        if (switch_output_size(rec))
                trigger_hit(&switch_output_trigger);
@@ -1186,6 +1195,11 @@ record__threads_config(struct record *rec)
        return ret;
 }
 
+static inline pid_t gettid(void)
+{
+       return (pid_t) syscall(__NR_gettid);
+}
+
 static void*
 record_thread__process(struct record *rec)
 {
@@ -1197,6 +1211,8 @@ record_thread__process(struct record *rec)
                        break;
 
                if (hits == thread->samples) {
+                       thread->stats.poll++;
+
                        err = fdarray__poll(&thread->pollfd, 500);
                        /*
                         * Propagate error, only if there's any. Ignore positive
@@ -1209,6 +1225,8 @@ record_thread__process(struct record *rec)
                        if (fdarray__filter(&thread->pollfd, POLLERR|POLLHUP,
                                            perf_mmap__put_filtered, NULL) == 0)
                                break;
+               } else {
+                       thread->stats.poll_skip++;
                }
        }
 
@@ -1241,6 +1259,7 @@ static void *worker(void *arg)
        struct record *rec = th->rec;
 
        thread        = th;
+       thread->pid   = gettid();
        thread->state = RECORD_THREAD__RUNNING;
 
        signal_main(rec);
@@ -1287,6 +1306,50 @@ static int record__threads_stop(struct record *rec)
        return err;
 }
 
+static void record_thread__display(struct record_thread *t, unsigned long s)
+{
+       char buf_size[20];
+       char buf_time[20];
+
+       unit_number__scnprintf(buf_size, sizeof(buf_size), 
t->stats.bytes_written);
+
+       if (s)
+               scnprintf(buf_time, sizeof(buf_time), "%5lus", s);
+       else
+               buf_time[0] = 0;
+
+       fprintf(stderr, "%6s %6d %10s %10" PRIu64" %10" PRIu64"\n",
+               buf_time, t->pid, buf_size, t->stats.poll, t->stats.poll_skip);
+}
+
+static void record__threads_stats(struct record *rec)
+{
+       struct record_thread *threads = rec->threads;
+       static time_t last, last_header, start;
+       time_t current = time(NULL);
+       int i;
+
+       if (last == current)
+               return;
+
+       if (!start)
+               start = current - 1;
+
+       last = current;
+
+       if (!last_header || (last_header + 10 < current)) {
+               fprintf(stderr, "%6s %6s %10s %10s %10s\n", " ", "pid", 
"write", "poll", "skip");
+               last_header = current;
+       }
+
+       for (i = 0; i < rec->threads_cnt; i++) {
+               struct record_thread *t = threads + i;
+
+               record_thread__display(t, !i ? current - start : 0);
+               memset(&t->stats, 0, sizeof(t->stats));
+       }
+}
+
 static int __cmd_record(struct record *rec, int argc, const char **argv)
 {
        int err;
@@ -1371,6 +1434,7 @@ static int __cmd_record(struct record *rec, int argc, 
const char **argv)
        }
 
        thread = &rec->threads[0];
+       thread->pid = gettid();
 
        err = bpf__apply_obj_config();
        if (err) {
@@ -1573,7 +1637,10 @@ static int __cmd_record(struct record *rec, int argc, 
const char **argv)
                if (hits == thread->samples) {
                        if (done || draining)
                                break;
-                       err = fdarray__poll(&thread->pollfd, -1);
+
+                       err = fdarray__poll(&thread->pollfd, 1000);
+                       thread->stats.poll++;
+
                        /*
                         * Propagate error, only if there's any. Ignore positive
                         * number of returned events and interrupt error.
@@ -1582,10 +1649,16 @@ static int __cmd_record(struct record *rec, int argc, 
const char **argv)
                                err = 0;
                        rec->waking++;
 
-                       if (perf_evlist__filter_pollfd(rec->evlist, POLLERR | 
POLLHUP) == 0)
+                       if (fdarray__filter(&thread->pollfd, POLLERR|POLLHUP,
+                                           perf_mmap__put_filtered, NULL) == 0)
                                draining = true;
+               } else {
+                       thread->stats.poll_skip++;
                }
 
+               if (debug_threads)
+                       record__threads_stats(rec);
+
                /*
                 * When perf is starting the traced process, at the end events
                 * die with the process and we wait for that. Thus no need to
-- 
2.17.1

Reply via email to