From: Mark Geisert <mark@maxrnd.com>
To: cygwin-patches@cygwin.com
Subject: [PATCH 2/3] Cygwin: New tool: gmondump
Date: Thu, 15 Jul 2021 21:49:56 -0700 [thread overview]
Message-ID: <20210716044957.5298-2-mark@maxrnd.com> (raw)
In-Reply-To: <20210716044957.5298-1-mark@maxrnd.com>
This new tool was formerly part of 'profiler' but was spun out thanks to
Jon T's reasonable review comment. Gmondump is more of a debugging tool
than something users might have need for. Users would more likely use
gprof to make use of symbolic info like function names and source line
numbers.
---
winsup/utils/gmondump.c | 255 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 255 insertions(+)
create mode 100644 winsup/utils/gmondump.c
diff --git a/winsup/utils/gmondump.c b/winsup/utils/gmondump.c
new file mode 100644
index 000000000..e469f01f1
--- /dev/null
+++ b/winsup/utils/gmondump.c
@@ -0,0 +1,255 @@
+/*
+ gmondump.c
+ Displays summary info about given profile data file(s).
+
+ Written by Mark Geisert <mark@maxrnd.com>.
+
+ This file is part of Cygwin.
+
+ This software is a copyrighted work licensed under the terms of the
+ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details.
+*/
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include "cygwin/version.h"
+
+typedef unsigned short ushort;
+typedef uint16_t u_int16_t; // Non-standard sized type needed by ancient gmon.h
+#include "gmon.h"
+
+FILE *ofile;
+const char *pgm = "gmondump";
+int verbose = 0;
+
+void __attribute__ ((__noreturn__))
+usage (FILE *where)
+{
+ fprintf (where, "\
+Usage: %s [OPTIONS] FILENAME...\n\
+\n\
+Display formatted contents of profile data file(s).\n\
+Such files usually have names starting with \"gmon.out\".\n\
+OPTIONS are:\n\
+\n\
+ -h, --help Display usage information and exit\n\
+ -v, --verbose Display more file details (toggle: default false)\n\
+ -V, --version Display version information and exit\n\
+\n", pgm);
+
+ exit (where == stderr ? 1 : 0 );
+}
+
+void
+note (const char *fmt, ...)
+{
+ va_list args;
+ char buf[4096];
+
+ va_start (args, fmt);
+ vsprintf (buf, fmt, args);
+ va_end (args);
+
+ fputs (buf, ofile);
+ fflush (ofile);
+}
+
+void
+warn (int geterrno, const char *fmt, ...)
+{
+ va_list args;
+ char buf[4096];
+
+ va_start (args, fmt);
+ sprintf (buf, "%s: ", pgm);
+ vsprintf (strchr (buf, '\0'), fmt, args);
+ va_end (args);
+ if (geterrno)
+ perror (buf);
+ else
+ {
+ fputs (buf, ofile);
+ fputs ("\n", ofile);
+ fflush (ofile);
+ }
+}
+
+void __attribute__ ((noreturn))
+error (int geterrno, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ warn (geterrno, fmt, args);
+ va_end (args);
+
+ exit (1);
+}
+
+void
+gmondump1 (char *filename)
+{
+ ushort *bucket = NULL;
+ int fd;
+ struct gmonhdr hdr;
+ int hitbuckets;
+ int hitcount;
+ int numbuckets;
+ int numrawarcs;
+ struct rawarc *rawarc = NULL;
+ int res;
+ struct stat stat;
+
+ fd = open (filename, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ {
+ note ("file%s %s couldn't be opened; continuing\n",
+ strchr (filename, '*') ? "s" : "", filename);
+ return;
+ }
+
+ /* Read and sanity-check what should be a gmon header. */
+ res = fstat (fd, &stat);
+ if (res < 0)
+ goto notgmon;
+ if (S_IFREG != (stat.st_mode & S_IFMT))
+ goto notgmon;
+ res = read (fd, &hdr, sizeof (hdr));
+ if (res != sizeof (hdr))
+ goto notgmon;
+ if (hdr.lpc >= hdr.hpc)
+ goto notgmon;
+ numbuckets = (hdr.ncnt - sizeof (hdr)) / sizeof (short);
+ if (numbuckets != (hdr.hpc - hdr.lpc) / 4)
+ goto notgmon;
+ numrawarcs = 0;
+ if (stat.st_size != hdr.ncnt)
+ {
+ numrawarcs = stat.st_size - hdr.ncnt;
+ if (numrawarcs !=
+ (int) sizeof (rawarc) * (numrawarcs / (int) sizeof (rawarc)))
+ goto notgmon;
+ numrawarcs /= (int) sizeof (rawarc);
+ }
+
+ /* Looks good, so read and display the profiling info. */
+ bucket = (ushort *) calloc (numbuckets, sizeof (ushort));
+ res = read (fd, bucket, hdr.ncnt - sizeof (hdr));
+ if (res != hdr.ncnt - (int) sizeof (hdr))
+ goto notgmon;
+ hitcount = hitbuckets = 0;
+ for (res = 0; res < numbuckets; ++bucket, ++res)
+ if (*bucket)
+ {
+ ++hitbuckets;
+ hitcount += *bucket;
+ }
+ bucket -= numbuckets;
+
+ note ("file %s, gmon version 0x%x, sample rate %d\n",
+ filename, hdr.version, hdr.profrate);
+ note (" address range 0x%p..0x%p\n", hdr.lpc, hdr.hpc);
+ note (" numbuckets %d, hitbuckets %d, hitcount %d, numrawarcs %d\n",
+ numbuckets, hitbuckets, hitcount, numrawarcs);
+
+ /* If verbose is set, display contents of buckets and rawarcs arrays. */
+ if (verbose)
+ {
+ if (hitbuckets)
+ note (" bucket data follows...\n");
+ char *addr = (char *) hdr.lpc;
+ int incr = (hdr.hpc - hdr.lpc) / numbuckets;
+ for (res = 0; res < numbuckets; ++bucket, ++res, addr += incr)
+ if (*bucket)
+ note (" address 0x%p, hitcount %d\n", addr, *bucket);
+ bucket -= numbuckets;
+
+ if (numrawarcs)
+ {
+ rawarc = (struct rawarc *) calloc (numrawarcs, sizeof (rawarc));
+ res = read (fd, rawarc, numrawarcs * (int) sizeof (rawarc));
+ if (res != numrawarcs * (int) sizeof (rawarc))
+ error (0, "unable to read rawarc data");
+ note (" rawarc data follows...\n");
+ for (res = 0; res < numrawarcs; ++rawarc, ++res)
+ note (" from 0x%p, self 0x%p, count %d\n",
+ rawarc->raw_frompc, rawarc->raw_selfpc, rawarc->raw_count);
+ }
+ }
+
+ note ("\n");
+ if (0)
+ {
+notgmon:
+ note ("file %s isn't a profile data file; continuing\n", filename);
+ }
+ if (rawarc)
+ free (rawarc);
+ if (bucket)
+ free (bucket);
+ close (fd);
+}
+
+struct option longopts[] = {
+ {"help", no_argument, NULL, 'h'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"version", no_argument, NULL, 'V'},
+ {NULL, 0, NULL, 0 }
+};
+
+const char *const opts = "+hvV";
+
+void __attribute__ ((__noreturn__))
+print_version ()
+{
+ char *year_of_build = strrchr (__DATE__, ' ') + 1;
+ printf ("gmondump (cygwin) %d.%d.%d\n"
+ "Profiler data file viewer\n"
+ "Copyright (C) %s%s Cygwin Authors\n"
+ "This is free software; see the source for copying conditions. "
+ "There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS "
+ "FOR A PARTICULAR PURPOSE.\n",
+ CYGWIN_VERSION_DLL_MAJOR / 1000,
+ CYGWIN_VERSION_DLL_MAJOR % 1000,
+ CYGWIN_VERSION_DLL_MINOR,
+ strncmp (year_of_build, "2021", 4) ? "2021 - " : "",
+ year_of_build);
+ exit (0);
+}
+
+int
+main(int argc, char **argv)
+{
+ ofile = stdout;
+ int opt;
+
+ while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
+ switch (opt)
+ {
+ case 'h':
+ /* Print help and exit. */
+ usage (ofile);
+
+ case 'v':
+ verbose ^= 1;
+ break;
+
+ case 'V':
+ /* Print version and exit. */
+ print_version ();
+
+ default:
+ ;
+ }
+
+ for (int i = optind; i < argc; i++)
+ gmondump1 (argv[i]);
+
+ return 0;
+}
--
2.31.1
next prev parent reply other threads:[~2021-07-16 4:50 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-07-16 4:49 [PATCH 1/3] Cygwin: New tool: profiler Mark Geisert
2021-07-16 4:49 ` Mark Geisert [this message]
2021-07-16 4:49 ` [PATCH 3/3] Cygwin: updates to wire in profiler, gmondump Mark Geisert
2021-07-19 10:04 ` [PATCH 1/3] Cygwin: New tool: profiler Corinna Vinschen
2021-07-19 14:23 ` Jon Turney
2021-07-19 15:43 ` Jon Turney
2021-07-21 8:00 ` [PATCH] Cygwin: fix format warnings in profiler.cc Mark Geisert
2021-07-21 8:09 ` Corinna Vinschen
2021-07-21 8:07 ` [PATCH 1/3] Cygwin: New tool: profiler Corinna Vinschen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210716044957.5298-2-mark@maxrnd.com \
--to=mark@maxrnd.com \
--cc=cygwin-patches@cygwin.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).