Source-Changes-HG archive

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

[src/trunk]: src/usr.sbin/tprof Merge tpfmt(1) into tprof(8). We want to have...



details:   https://anonhg.NetBSD.org/src/rev/828e1d08eb35
branches:  trunk
changeset: 324625:828e1d08eb35
user:      maxv <maxv%NetBSD.org@localhost>
date:      Fri Jul 13 11:03:36 2018 +0000

description:
Merge tpfmt(1) into tprof(8). We want to have access to everything with
only one tool. The code is copied mostly as-is, and the functionality is
available via the "analyze" command.

Eg:
        tprof monitor -e llc-misses:k -o myfile.out sleep 20
        tprof analyze < myfile.out

Will move soon, I don't like the reading via stdin.

diffstat:

 usr.sbin/tprof/Makefile        |    8 +-
 usr.sbin/tprof/tprof.8         |   34 +++-
 usr.sbin/tprof/tprof.c         |    9 +-
 usr.sbin/tprof/tprof.h         |    3 +-
 usr.sbin/tprof/tprof_analyze.c |  437 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 484 insertions(+), 7 deletions(-)

diffs (truncated from 579 to 300 lines):

diff -r 06574ce8d04e -r 828e1d08eb35 usr.sbin/tprof/Makefile
--- a/usr.sbin/tprof/Makefile   Fri Jul 13 10:49:17 2018 +0000
+++ b/usr.sbin/tprof/Makefile   Fri Jul 13 11:03:36 2018 +0000
@@ -1,10 +1,10 @@
-#      $NetBSD: Makefile,v 1.4 2018/07/13 07:56:29 maxv Exp $
+#      $NetBSD: Makefile,v 1.5 2018/07/13 11:03:36 maxv Exp $
 
 .PATH: ${.CURDIR}/arch
 
 PROG=  tprof
 MAN=   tprof.8
-SRCS=  tprof.c
+SRCS=  tprof.c tprof_analyze.c
 
 .if    ${MACHINE_ARCH} == "i386" || ${MACHINE_ARCH} == "x86_64"
 SRCS+= tprof_x86.c
@@ -15,7 +15,11 @@
 CPPFLAGS+= -I${NETBSDSRCDIR}/sys/
 
 LDADD+= -lpthread
+LDADD+= -lelf
+LDADD+= -lutil
 DPADD+= ${LIBPTHREAD}
+DPADD+= ${LIBELF}
+DPADD+= ${LIBUTIL}
 
 .include <bsd.own.mk>
 .include <bsd.prog.mk>
diff -r 06574ce8d04e -r 828e1d08eb35 usr.sbin/tprof/tprof.8
--- a/usr.sbin/tprof/tprof.8    Fri Jul 13 10:49:17 2018 +0000
+++ b/usr.sbin/tprof/tprof.8    Fri Jul 13 11:03:36 2018 +0000
@@ -1,4 +1,4 @@
-.\"    $NetBSD: tprof.8,v 1.5 2018/07/13 09:04:31 maxv Exp $
+.\"    $NetBSD: tprof.8,v 1.6 2018/07/13 11:03:36 maxv Exp $
 .\"
 .\" Copyright (c)2011 YAMAMOTO Takashi,
 .\" All rights reserved.
@@ -83,11 +83,43 @@
 if specified.
 The default is
 .Dq Pa tprof.out .
+.It analyze Xo
+.Op Fl C
+.Op Fl k
+.Op Fl L
+.Op Fl P
+.Op Fl p Ar pid
+.Op Fl s
+.Xc
+Analyze the samples produced by a previous run of
+.Nm tprof ,
+and generate a plain text
+representation.
+.It Fl C
+Don't distinguish CPUs.
+All samples are treated as its CPU number is 0.
+.It Fl k
+Kernel only.
+Ignore samples for userland code.
+.It Fl L
+Don't distinguish LWPs.
+All samples are treated as its LWP ID is 0.
+.It Fl P
+Don't distinguish processes.
+All samples are treated as its PID is 0.
+.It Fl p Ar pid
+Process only samples for the process with PID
+.Ar pid
+and ignore the rest.
+.It Fl s
+Per symbol.
 .El
 .Sh EXAMPLES
 The following command profiles the system during 20 seconds and writes the
 samples into the file myfile.out.
 .Dl # tprof monitor -e llc-misses:k -o myfile.out sleep 20
+The following command displays the results of the sampling.
+.Dl # tprof analyze < myfile.out
 .Ed
 .Sh DIAGNOSTICS
 The
diff -r 06574ce8d04e -r 828e1d08eb35 usr.sbin/tprof/tprof.c
--- a/usr.sbin/tprof/tprof.c    Fri Jul 13 10:49:17 2018 +0000
+++ b/usr.sbin/tprof/tprof.c    Fri Jul 13 11:03:36 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: tprof.c,v 1.7 2018/07/13 09:04:31 maxv Exp $   */
+/*     $NetBSD: tprof.c,v 1.8 2018/07/13 11:03:36 maxv Exp $   */
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -57,7 +57,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: tprof.c,v 1.7 2018/07/13 09:04:31 maxv Exp $");
+__RCSID("$NetBSD: tprof.c,v 1.8 2018/07/13 11:03:36 maxv Exp $");
 #endif /* not lint */
 
 #include <sys/ioctl.h>
@@ -94,6 +94,7 @@
 } const tprof_cmdtab[] = {
        { "list",       false, false, tprof_list },
        { "monitor",    true,  false, tprof_monitor },
+       { "analyze",    true,  true,  tprof_analyze },
        { NULL,         false, false, NULL },
 };
 
@@ -101,13 +102,15 @@
 usage(void)
 {
 
-       fprintf(stderr, "%s [op] [options] [command]\n", getprogname());
+       fprintf(stderr, "%s op [arguments]\n", getprogname());
        fprintf(stderr, "\n");
        fprintf(stderr, "\tlist\n");
        fprintf(stderr, "\t\tList the available events.\n");
        fprintf(stderr, "\tmonitor -e name:option [-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, "\tanalyze [-C] [-k] [-L] [-P] [-p pid] [-s]\n");
+       fprintf(stderr, "\t\tAnalyze the samples from stdin.\n");
 
        exit(EXIT_FAILURE);
 }
diff -r 06574ce8d04e -r 828e1d08eb35 usr.sbin/tprof/tprof.h
--- a/usr.sbin/tprof/tprof.h    Fri Jul 13 10:49:17 2018 +0000
+++ b/usr.sbin/tprof/tprof.h    Fri Jul 13 11:03:36 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: tprof.h,v 1.1 2018/07/13 07:56:29 maxv Exp $   */
+/*     $NetBSD: tprof.h,v 1.2 2018/07/13 11:03:36 maxv Exp $   */
 
 /*
  * Copyright (c) 2018 The NetBSD Foundation, Inc.
@@ -33,3 +33,4 @@
 void tprof_event_list(void);
 void tprof_event_lookup(const char *, struct tprof_param *);
 
+void tprof_analyze(int, char **);
diff -r 06574ce8d04e -r 828e1d08eb35 usr.sbin/tprof/tprof_analyze.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/usr.sbin/tprof/tprof_analyze.c    Fri Jul 13 11:03:36 2018 +0000
@@ -0,0 +1,437 @@
+/*     $NetBSD: tprof_analyze.c,v 1.1 2018/07/13 11:03:36 maxv Exp $   */
+
+/*
+ * Copyright (c) 2010,2011,2012 YAMAMOTO Takashi,
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__RCSID("$NetBSD: tprof_analyze.c,v 1.1 2018/07/13 11:03:36 maxv Exp $");
+#endif /* not lint */
+
+#include <assert.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <inttypes.h>
+#include <libelf.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <util.h>
+#include <dev/tprof/tprof_ioctl.h>
+#include "tprof.h"
+
+#define        _PATH_KSYMS     "/dev/ksyms"
+
+#include <sys/rbtree.h>
+
+static bool filter_by_pid;
+static pid_t target_pid;
+static bool per_symbol;
+
+struct addr {
+       struct rb_node node;
+       uint64_t addr;          /* address */
+       uint32_t pid;           /* process id */
+       uint32_t lwpid;         /* lwp id */
+       uint32_t cpuid;         /* cpu id */
+       bool in_kernel;         /* if addr is in the kernel address space */
+       unsigned int nsamples;  /* number of samples taken for the address */
+};
+
+static rb_tree_t addrtree;
+
+struct sym {
+       char *name;
+       uint64_t value;
+       uint64_t size;
+};
+
+static struct sym **syms = NULL;
+static size_t nsyms = 0;
+
+static int
+compare_value(const void *p1, const void *p2)
+{
+       const struct sym *s1 = *(const struct sym * const *)p1;
+       const struct sym *s2 = *(const struct sym * const *)p2;
+
+       if (s1->value > s2->value) {
+               return -1;
+       } else if (s1->value < s2->value) {
+               return 1;
+       }
+       /*
+        * to produce a stable result, it's better not to return 0
+        * even for __strong_alias.
+        */
+       if (s1->size > s2->size) {
+               return -1;
+       } else if (s1->size < s2->size) {
+               return 1;
+       }
+       return strcmp(s1->name, s2->name);
+}
+
+static void
+ksymload(void)
+{
+       Elf *e;
+       Elf_Scn *s;
+       GElf_Shdr sh_store;
+       GElf_Shdr *sh;
+       Elf_Data *d;
+       int fd;
+       size_t size, i;
+
+       fd = open(_PATH_KSYMS, O_RDONLY);
+       if (fd == -1) {
+               err(EXIT_FAILURE, "open");
+       }
+       if (elf_version(EV_CURRENT) == EV_NONE) {
+               goto elffail;
+       }
+       e = elf_begin(fd, ELF_C_READ, NULL);
+       if (e == NULL) {
+               goto elffail;
+       }
+       for (s = elf_nextscn(e, NULL); s != NULL; s = elf_nextscn(e, s)) {
+               sh = gelf_getshdr(s, &sh_store);
+               if (sh == NULL) {
+                       goto elffail;
+               }
+               if (sh->sh_type == SHT_SYMTAB) {
+                       break;
+               }
+       }
+       if (s == NULL) {
+               errx(EXIT_FAILURE, "no symtab");
+       }
+       d = elf_getdata(s, NULL);
+       if (d == NULL) {
+               goto elffail;
+       }
+       assert(sh->sh_size == d->d_size);
+       size = sh->sh_size / sh->sh_entsize;
+       for (i = 1; i < size; i++) {
+               GElf_Sym st_store;
+               GElf_Sym *st;
+               struct sym *sym;
+
+               st = gelf_getsym(d, (int)i, &st_store);
+               if (st == NULL) {
+                       goto elffail;
+               }
+               if (ELF_ST_TYPE(st->st_info) != STT_FUNC) {
+                       continue;
+               }
+               sym = emalloc(sizeof(*sym));
+               sym->name = estrdup(elf_strptr(e, sh->sh_link, st->st_name));
+               sym->value = (uint64_t)st->st_value;
+               sym->size = st->st_size;
+               nsyms++;



Home | Main Index | Thread Index | Old Index