Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/usr.sbin/tprof Improve tprof(8)
details: https://anonhg.NetBSD.org/src/rev/e5943acac59c
branches: trunk
changeset: 372479:e5943acac59c
user: ryo <ryo%NetBSD.org@localhost>
date: Thu Dec 01 00:40:05 2022 +0000
description:
Improve tprof(8)
- Added "tprof count" subcommand to perform counts only.
- Event options (u,k) are now optional. The default value is both userland and kernel. (:uk)
- Event counters can be displayed with SIGINFO during `tprof monitor' or `tprof count'.
diffstat:
usr.sbin/tprof/tprof.8 | 19 +++-
usr.sbin/tprof/tprof.c | 222 +++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 203 insertions(+), 38 deletions(-)
diffs (truncated from 400 to 300 lines):
diff -r ffbb661e80f9 -r e5943acac59c usr.sbin/tprof/tprof.8
--- a/usr.sbin/tprof/tprof.8 Thu Dec 01 00:32:52 2022 +0000
+++ b/usr.sbin/tprof/tprof.8 Thu Dec 01 00:40:05 2022 +0000
@@ -1,4 +1,4 @@
-.\" $NetBSD: tprof.8,v 1.17 2022/12/01 00:32:52 ryo Exp $
+.\" $NetBSD: tprof.8,v 1.18 2022/12/01 00:40:05 ryo Exp $
.\"
.\" Copyright (c)2011 YAMAMOTO Takashi,
.\" All rights reserved.
@@ -66,7 +66,7 @@
Display a list of performance counter events available on the system.
.It monitor Xo
.Fl e
-.Ar name:option
+.Ar name[:option]
.Op Fl e Ar ...
.Op Fl o Ar outfile
.Ar command
@@ -81,12 +81,25 @@
.Ar u
(userland) and
.Ar k
-(kernel).
+(kernel). If omitted, it is assumed that both are specified.
The collected samples are written into the file
.Ar outfile
if specified.
The default is
.Dq Pa tprof.out .
+.It count Xo
+.Fl e
+.Ar name[:option]
+.Op Fl e Ar ...
+.Op Fl i Ar interval
+.Ar command
+.Xc
+Same as
+.Ar monitor ,
+but does not do any profiling,
+only outputs counters every
+.Ar interval
+second.
.It analyze Xo
.Op Fl CkLPs
.Op Fl p Ar pid
diff -r ffbb661e80f9 -r e5943acac59c usr.sbin/tprof/tprof.c
--- a/usr.sbin/tprof/tprof.c Thu Dec 01 00:32:52 2022 +0000
+++ b/usr.sbin/tprof/tprof.c Thu Dec 01 00:40:05 2022 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tprof.c,v 1.14 2022/12/01 00:32:52 ryo Exp $ */
+/* $NetBSD: tprof.c,v 1.15 2022/12/01 00:40:05 ryo Exp $ */
/*
* Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -57,10 +57,12 @@
#include <sys/cdefs.h>
#ifndef lint
-__RCSID("$NetBSD: tprof.c,v 1.14 2022/12/01 00:32:52 ryo Exp $");
+__RCSID("$NetBSD: tprof.c,v 1.15 2022/12/01 00:40:05 ryo Exp $");
#endif /* not lint */
+#include <sys/atomic.h>
#include <sys/ioctl.h>
+#include <sys/sysctl.h>
#include <sys/wait.h>
#include <dev/tprof/tprof_ioctl.h>
@@ -69,13 +71,16 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <math.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
+#include <util.h>
#include "tprof.h"
#define _PATH_TPROF "/dev/tprof"
@@ -84,10 +89,17 @@
u_int ncounters;
int devfd;
int outfd;
+int ncpu;
u_int nevent;
+double interval = 0xffffffff; /* XXX */
+const char *eventname[TPROF_MAXCOUNTERS];
+u_int eventnamewidth[TPROF_MAXCOUNTERS];
+#define COUNTER_COLUMNS_WIDTH 11
static void tprof_list(int, char **);
-static void tprof_monitor(int, char **) __dead;
+static void tprof_monitor_common(bool, int, char **) __dead;
+static void tprof_monitor(int, char **);
+static void tprof_count(int, char **);
static struct cmdtab {
const char *label;
@@ -97,6 +109,7 @@
} const tprof_cmdtab[] = {
{ "list", false, false, tprof_list },
{ "monitor", true, false, tprof_monitor },
+ { "count", true, false, tprof_count },
{ "analyze", true, true, tprof_analyze },
{ NULL, false, false, NULL },
};
@@ -109,15 +122,33 @@
fprintf(stderr, "\n");
fprintf(stderr, "\tlist\n");
fprintf(stderr, "\t\tList the available events.\n");
- fprintf(stderr, "\tmonitor -e name:option [-e ...] [-o outfile] command\n");
+ fprintf(stderr, "\tmonitor -e name[:option] [-e ...] [-o outfile] command\n");
fprintf(stderr, "\t\tMonitor the event 'name' with option 'option'\n"
"\t\tcounted during the execution of 'command'.\n");
+ fprintf(stderr, "\tcount -e name[:option] [-e ...] [-i interval]"
+ " command\n");
+ fprintf(stderr, "\t\tSame as monitor, but does not profile,"
+ " only outputs a counter.\n");
fprintf(stderr, "\tanalyze [-CkLPs] [-p pid] file\n");
fprintf(stderr, "\t\tAnalyze the samples of the file 'file'.\n");
exit(EXIT_FAILURE);
}
+static int
+getncpu(void)
+{
+ size_t size;
+ int mib[2];
+
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ size = sizeof(ncpu);
+ if (sysctl(mib, 2, &ncpu, &size, NULL, 0) == -1)
+ ncpu = 1;
+ return ncpu;
+}
+
static void *
process_samples(void *dummy)
{
@@ -150,13 +181,87 @@
}
static void
+show_counters(void)
+{
+ unsigned int i;
+ int n, ret;
+
+ fprintf(stderr, " ");
+ for (i = 0; i < nevent; i++)
+ fprintf(stderr, " %*s", eventnamewidth[i], eventname[i]);
+ fprintf(stderr, "\n");
+
+ for (n = 0; n < ncpu; n++) {
+ tprof_counts_t counts;
+
+ memset(&counts, 0, sizeof(counts));
+ counts.c_cpu = n;
+ ret = ioctl(devfd, TPROF_IOC_GETCOUNTS, &counts);
+ if (ret == -1)
+ err(EXIT_FAILURE, "TPROF_IOC_GETCOUNTS");
+
+ fprintf(stderr, "CPU%-3d", n);
+ for (i = 0; i < nevent; i++) {
+ fprintf(stderr, " %*"PRIu64,
+ eventnamewidth[i], counts.c_count[i]);
+ }
+ fprintf(stderr, "\n");
+ }
+}
+
+/* XXX: avoid mixing with the output of the child process SIGINFO handler... */
+static void
+output_delay(void)
+{
+ struct timespec delay_ts;
+
+ delay_ts.tv_sec = 0;
+ delay_ts.tv_nsec = 100000000;
+ nanosleep(&delay_ts, NULL);
+}
+
+static void
+siginfo_nothing(int signo)
+{
+ __nothing;
+}
+
+static void
+siginfo_showcount(int signo)
+{
+ output_delay();
+ show_counters();
+}
+
+static void *
+process_stat(void *arg)
+{
+ unsigned int *done = arg;
+ double ival, fval;
+ struct timespec ts;
+
+ ival = floor(interval);
+ fval = (1000000000 * (interval - ival));
+ ts.tv_sec = ival;
+ ts.tv_nsec = fval;
+
+ while (atomic_add_int_nv(done, 0) == 0) {
+ show_counters();
+ nanosleep(&ts, NULL);
+ if (errno == EINTR) /* interrupted by SIGINFO? */
+ output_delay();
+ }
+ return NULL;
+}
+
+static void
tprof_list(int argc, char **argv)
{
tprof_event_list();
}
static void
-tprof_monitor(int argc, char **argv)
+tprof_monitor_common(bool do_profile, int argc, char **argv)
{
const char *outfile = "tprof.out";
struct tprof_stat ts;
@@ -164,28 +269,43 @@
pid_t pid;
pthread_t pt;
int ret, ch, i;
- char *tokens[2];
+ char *tokens[2], *p;
tprof_countermask_t mask = TPROF_COUNTERMASK_ALL;
memset(params, 0, sizeof(params));
- while ((ch = getopt(argc, argv, "o:e:")) != -1) {
+ while ((ch = getopt(argc, argv, do_profile ? "o:e:" : "e:i:")) != -1) {
switch (ch) {
case 'o':
outfile = optarg;
break;
+ case 'i':
+ interval = strtod(optarg, &p);
+ if (*p != '\0' || interval <= 0)
+ errx(EXIT_FAILURE, "Bad/invalid interval: %s",
+ optarg);
+ break;
case 'e':
- tokens[0] = strtok(optarg, ":");
+ p = estrdup(optarg);
+ tokens[0] = strtok(p, ":");
tokens[1] = strtok(NULL, ":");
- if (tokens[1] == NULL)
- usage();
tprof_event_lookup(tokens[0], ¶ms[nevent]);
- if (strchr(tokens[1], 'u'))
- params[nevent].p_flags |= TPROF_PARAM_USER;
- if (strchr(tokens[1], 'k'))
- params[nevent].p_flags |= TPROF_PARAM_KERN;
- if (params[nevent].p_flags == 0)
- usage();
+
+ if (tokens[1] == NULL) {
+ params[nevent].p_flags |=
+ (TPROF_PARAM_USER | TPROF_PARAM_KERN);
+ } else {
+ if (strchr(tokens[1], 'u'))
+ params[nevent].p_flags |=
+ TPROF_PARAM_USER;
+ if (strchr(tokens[1], 'k'))
+ params[nevent].p_flags |=
+ TPROF_PARAM_KERN;
+ }
+ eventname[nevent] = tokens[0];
+ eventnamewidth[nevent] = strlen(eventname[nevent]);
+ if (eventnamewidth[nevent] < COUNTER_COLUMNS_WIDTH)
+ eventnamewidth[nevent] = COUNTER_COLUMNS_WIDTH;
nevent++;
if (nevent > __arraycount(params) ||
nevent > ncounters)
@@ -201,14 +321,17 @@
usage();
}
- outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
- if (outfd == -1) {
- err(EXIT_FAILURE, "%s", outfile);
+ if (do_profile) {
+ outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
Home |
Main Index |
Thread Index |
Old Index