Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/tprof - Add support select(2)/poll(2) on /dev/tprof.



details:   https://anonhg.NetBSD.org/src/rev/3a4e7cdca76d
branches:  trunk
changeset: 372650:3a4e7cdca76d
user:      ryo <ryo%NetBSD.org@localhost>
date:      Fri Dec 16 07:59:42 2022 +0000

description:
- Add support select(2)/poll(2) on /dev/tprof.
- Changed sampling buffer switching frequency (which is the frequency of tprof_worker()
  calls and also the maximum block time of read(2) of /dev/tprof) from 1sec to 125ms.
  This improve tprof top responsiveness.
- The maximum number of sampling buffers is now adjusted according to the number of CPUs.
  Previously it was fixed at 100 and was insufficient if ncpu was greater than this.

The maximum number of samples per second per CPU is calculated by
"TPROF_MAX_SAMPLES_PER_BUF * (HZ of tprof_worker)".
Therefore, currently, 10000 * (1000/125) = 80000 maximum samplings per CPU.
The actual value will vary slightly from this due to tprof_worker and read(2) timing.
This value may need to be adjusted more in the future.

diffstat:

 sys/dev/tprof/tprof.c |  105 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 94 insertions(+), 11 deletions(-)

diffs (217 lines):

diff -r 3aa72b133951 -r 3a4e7cdca76d sys/dev/tprof/tprof.c
--- a/sys/dev/tprof/tprof.c     Fri Dec 16 00:05:01 2022 +0000
+++ b/sys/dev/tprof/tprof.c     Fri Dec 16 07:59:42 2022 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: tprof.c,v 1.20 2022/12/11 01:36:49 chs Exp $   */
+/*     $NetBSD: tprof.c,v 1.21 2022/12/16 07:59:42 ryo Exp $   */
 
 /*-
  * Copyright (c)2008,2009,2010 YAMAMOTO Takashi,
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tprof.c,v 1.20 2022/12/11 01:36:49 chs Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tprof.c,v 1.21 2022/12/16 07:59:42 ryo Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -39,8 +39,10 @@
 #include <sys/kmem.h>
 #include <sys/module.h>
 #include <sys/percpu.h>
+#include <sys/poll.h>
 #include <sys/proc.h>
 #include <sys/queue.h>
+#include <sys/select.h>
 #include <sys/workqueue.h>
 #include <sys/xcall.h>
 
@@ -78,9 +80,7 @@
 } tprof_buf_t;
 #define        TPROF_BUF_BYTESIZE(sz) \
        (sizeof(tprof_buf_t) + (sz) * sizeof(tprof_sample_t))
-#define        TPROF_MAX_SAMPLES_PER_BUF       (TPROF_HZ * 2)
-
-#define        TPROF_MAX_BUF                   100
+#define        TPROF_MAX_SAMPLES_PER_BUF       TPROF_HZ
 
 typedef struct {
        tprof_buf_t *c_buf;
@@ -111,6 +111,7 @@
 static struct workqueue *tprof_wq;
 static struct percpu *tprof_cpus __read_mostly;        /* tprof_cpu_t * */
 static u_int tprof_samples_per_buf;
+static u_int tprof_max_buf;
 
 tprof_backend_t *tprof_backend;        /* S: */
 static LIST_HEAD(, tprof_backend) tprof_backends =
@@ -122,6 +123,7 @@
 
 static kmutex_t tprof_startstop_lock;
 static kcondvar_t tprof_cv;            /* L: */
+static struct selinfo tprof_selp;      /* L: */
 
 static struct tprof_stat tprof_stat;   /* L: */
 
@@ -229,13 +231,14 @@
        }
        if (buf->b_used == 0) {
                tprof_stat.ts_emptybuf++;
-       } else if (tprof_nbuf_on_list < TPROF_MAX_BUF) {
+       } else if (tprof_nbuf_on_list < tprof_max_buf) {
                tprof_stat.ts_sample += buf->b_used;
                tprof_stat.ts_overflow += buf->b_overflow;
                tprof_stat.ts_buf++;
                STAILQ_INSERT_TAIL(&tprof_list, buf, b_list);
                tprof_nbuf_on_list++;
                buf = NULL;
+               selnotify(&tprof_selp, 0, NOTE_SUBMIT);
                cv_broadcast(&tprof_reader_cv);
        } else {
                tprof_stat.ts_dropbuf_sample += buf->b_used;
@@ -246,7 +249,7 @@
                tprof_buf_free(buf);
        }
        if (!shouldstop) {
-               callout_schedule(&c->c_callout, hz);
+               callout_schedule(&c->c_callout, hz / 8);
        }
 }
 
@@ -364,6 +367,7 @@
                }
 
                tprof_samples_per_buf = TPROF_MAX_SAMPLES_PER_BUF;
+               tprof_max_buf = ncpu * 3;
                error = workqueue_create(&tprof_wq, "tprofmv", tprof_worker,
                    NULL, PRI_NONE, IPL_SOFTCLOCK, WQ_MPSAFE | WQ_PERCPU);
                if (error != 0) {
@@ -860,12 +864,89 @@
 }
 
 static int
+tprof_poll(dev_t dev, int events, struct lwp *l)
+{
+       int revents;
+
+       revents = events & (POLLIN | POLLRDNORM);
+       if (revents == 0)
+               return 0;
+
+       mutex_enter(&tprof_lock);
+       if (STAILQ_EMPTY(&tprof_list)) {
+               revents = 0;
+               selrecord(l, &tprof_selp);
+       }
+       mutex_exit(&tprof_lock);
+
+       return revents;
+}
+
+static void
+filt_tprof_read_detach(struct knote *kn)
+{
+       mutex_spin_enter(&tprof_lock);
+       selremove_knote(&tprof_selp, kn);
+       mutex_spin_exit(&tprof_lock);
+}
+
+static int
+filt_tprof_read_event(struct knote *kn, long hint)
+{
+       int rv = 0;
+
+       if ((hint & NOTE_SUBMIT) == 0)
+               mutex_spin_enter(&tprof_lock);
+
+       if (!STAILQ_EMPTY(&tprof_list)) {
+               tprof_buf_t *buf;
+               int64_t n = 0;
+
+               STAILQ_FOREACH(buf, &tprof_list, b_list) {
+                       n += buf->b_used;
+               }
+               kn->kn_data = n * sizeof(tprof_sample_t);
+
+               rv = 1;
+       }
+
+       if ((hint & NOTE_SUBMIT) == 0)
+               mutex_spin_exit(&tprof_lock);
+
+       return rv;
+}
+
+static const struct filterops tprof_read_filtops = {
+       .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE,
+       .f_attach = NULL,
+       .f_detach = filt_tprof_read_detach,
+       .f_event = filt_tprof_read_event,
+};
+
+static int
+tprof_kqfilter(dev_t dev, struct knote *kn)
+{
+       switch (kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &tprof_read_filtops;
+               mutex_spin_enter(&tprof_lock);
+               selrecord_knote(&tprof_selp, kn);
+               mutex_spin_exit(&tprof_lock);
+               break;
+       default:
+               return EINVAL;
+       }
+
+       return 0;
+}
+
+static int
 tprof_read(dev_t dev, struct uio *uio, int flags)
 {
        tprof_buf_t *buf;
        size_t bytes;
        size_t resid;
-       size_t done;
+       size_t done = 0;
        int error = 0;
 
        KASSERT(minor(dev) == 0);
@@ -877,7 +958,7 @@
                mutex_enter(&tprof_lock);
                buf = STAILQ_FIRST(&tprof_list);
                if (buf == NULL) {
-                       if (tprof_nworker == 0) {
+                       if (tprof_nworker == 0 || done != 0) {
                                mutex_exit(&tprof_lock);
                                error = 0;
                                break;
@@ -988,9 +1069,9 @@
        .d_ioctl = tprof_ioctl,
        .d_stop = nostop,
        .d_tty = notty,
-       .d_poll = nopoll,
+       .d_poll = tprof_poll,
        .d_mmap = nommap,
-       .d_kqfilter = nokqfilter,
+       .d_kqfilter = tprof_kqfilter,
        .d_discard = nodiscard,
        .d_flag = D_OTHER | D_MPSAFE
 };
@@ -1034,6 +1115,7 @@
        mutex_init(&tprof_lock, MUTEX_DEFAULT, IPL_NONE);
        mutex_init(&tprof_reader_lock, MUTEX_DEFAULT, IPL_NONE);
        mutex_init(&tprof_startstop_lock, MUTEX_DEFAULT, IPL_NONE);
+       selinit(&tprof_selp);
        cv_init(&tprof_cv, "tprof");
        cv_init(&tprof_reader_cv, "tprof_rd");
        STAILQ_INIT(&tprof_list);
@@ -1049,6 +1131,7 @@
        mutex_destroy(&tprof_lock);
        mutex_destroy(&tprof_reader_lock);
        mutex_destroy(&tprof_startstop_lock);
+       seldestroy(&tprof_selp);
        cv_destroy(&tprof_cv);
        cv_destroy(&tprof_reader_cv);
 }



Home | Main Index | Thread Index | Old Index