diff options
Diffstat (limited to 'REORG.TODO/malloc/memusagestat.c')
-rw-r--r-- | REORG.TODO/malloc/memusagestat.c | 587 |
1 files changed, 587 insertions, 0 deletions
diff --git a/REORG.TODO/malloc/memusagestat.c b/REORG.TODO/malloc/memusagestat.c new file mode 100644 index 0000000000..0bd158bd1e --- /dev/null +++ b/REORG.TODO/malloc/memusagestat.c @@ -0,0 +1,587 @@ +/* Generate graphic from memory profiling data. + Copyright (C) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see <http://www.gnu.org/licenses/>. */ + +#define _FILE_OFFSET_BITS 64 + +#include <argp.h> +#include <assert.h> +#include <errno.h> +#include <error.h> +#include <fcntl.h> +#include <getopt.h> +#include <inttypes.h> +#include <libintl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdint.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <gd.h> +#include <gdfontl.h> +#include <gdfonts.h> + +#include "../version.h" +#define PACKAGE _libc_intl_domainname + +/* Default size of the generated image. */ +#define XSIZE 800 +#define YSIZE 600 + +#ifndef N_ +# define N_(Arg) Arg +#endif + + +/* Definitions of arguments for argp functions. */ +static const struct argp_option options[] = +{ + { "output", 'o', N_ ("FILE"), 0, N_ ("Name output file") }, + { "string", 's', N_ ("STRING"), 0, N_ ("Title string used in output graphic") }, + { "time", 't', NULL, 0, N_ ("\ +Generate output linear to time (default is linear to number of function calls)\ +") }, + { "total", 'T', NULL, 0, + N_ ("Also draw graph for total memory consumption") }, + { "x-size", 'x', N_ ("VALUE"), 0, + N_ ("Make output graphic VALUE pixels wide") }, + { "y-size", 'y', "VALUE", 0, N_ ("Make output graphic VALUE pixels high") }, + { NULL, 0, NULL, 0, NULL } +}; + +/* Short description of program. */ +static const char doc[] = N_ ("Generate graphic from memory profiling data"); + +/* Strings for arguments in help texts. */ +static const char args_doc[] = N_ ("DATAFILE [OUTFILE]"); + +/* Prototype for option handler. */ +static error_t parse_opt (int key, char *arg, struct argp_state *state); + +/* Function to print some extra text in the help message. */ +static char *more_help (int key, const char *text, void *input); + +/* Name and version of program. */ +static void print_version (FILE *stream, struct argp_state *state); +void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version; + +/* Data structure to communicate with argp functions. */ +static struct argp argp = +{ + options, parse_opt, args_doc, doc, NULL, more_help +}; + + +struct entry +{ + uint64_t heap; + uint64_t stack; + uint32_t time_low; + uint32_t time_high; +}; + + +/* Size of the image. */ +static size_t xsize; +static size_t ysize; + +/* Name of the output file. */ +static char *outname; + +/* Title string for the graphic. */ +static const char *string; + +/* Nonzero if graph should be generated linear in time. */ +static int time_based; + +/* Nonzero if graph to display total use of memory should be drawn as well. */ +static int also_total = 0; + + +int +main (int argc, char *argv[]) +{ + int remaining; + const char *inname; + gdImagePtr im_out; + int grey, blue, red, green, yellow, black; + int fd; + struct stat st; + size_t maxsize_heap; + size_t maxsize_stack; + size_t maxsize_total; + uint64_t total; + uint64_t cnt, cnt2; + FILE *outfile; + char buf[30]; + size_t last_heap; + size_t last_stack; + size_t last_total; + struct entry headent[2]; + uint64_t start_time; + uint64_t end_time; + uint64_t total_time; + const char *heap_format, *stack_format; + int heap_scale, stack_scale, line; + + outname = NULL; + xsize = XSIZE; + ysize = YSIZE; + string = NULL; + + /* Parse and process arguments. */ + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + + if (remaining >= argc || remaining + 2 < argc) + { + argp_help (&argp, stdout, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR, + program_invocation_short_name); + exit (1); + } + + inname = argv[remaining++]; + + if (remaining < argc) + outname = argv[remaining]; + else if (outname == NULL) + { + size_t len = strlen (inname); + outname = alloca (len + 5); + stpcpy (stpcpy (outname, inname), ".png"); + } + + /* Open for read/write since we try to repair the file in case the + application hasn't terminated cleanly. */ + fd = open (inname, O_RDWR); + if (fd == -1) + error (EXIT_FAILURE, errno, "cannot open input file"); + if (fstat (fd, &st) != 0) + { + close (fd); + error (EXIT_FAILURE, errno, "cannot get size of input file"); + } + /* Test whether the file contains only full records. */ + if ((st.st_size % sizeof (struct entry)) != 0 + /* The file must at least contain the two administrative records. */ + || st.st_size < 2 * sizeof (struct entry)) + { + close (fd); + error (EXIT_FAILURE, 0, "input file has incorrect size"); + } + /* Compute number of data entries. */ + total = st.st_size / sizeof (struct entry) - 2; + + /* Read the administrative information. */ + read (fd, headent, sizeof (headent)); + maxsize_heap = headent[1].heap; + maxsize_stack = headent[1].stack; + maxsize_total = headent[0].stack; + + if (maxsize_heap == 0 && maxsize_stack == 0) + { + /* The program aborted before memusage was able to write the + information about the maximum heap and stack use. Repair + the file now. */ + struct entry next; + + while (1) + { + if (read (fd, &next, sizeof (next)) == 0) + break; + if (next.heap > maxsize_heap) + maxsize_heap = next.heap; + if (next.stack > maxsize_stack) + maxsize_stack = next.stack; + if (maxsize_heap + maxsize_stack > maxsize_total) + maxsize_total = maxsize_heap + maxsize_stack; + } + + headent[0].stack = maxsize_total; + headent[1].heap = maxsize_heap; + headent[1].stack = maxsize_stack; + headent[1].time_low = next.time_low; + headent[1].time_high = next.time_high; + + /* Write the computed values in the file. */ + lseek (fd, 0, SEEK_SET); + write (fd, headent, 2 * sizeof (struct entry)); + } + + if (also_total) + { + /* We use one scale and since we also draw the total amount of + memory used we have to adapt the maximum. */ + maxsize_heap = maxsize_total; + maxsize_stack = maxsize_total; + } + + start_time = ((uint64_t) headent[0].time_high) << 32 | headent[0].time_low; + end_time = ((uint64_t) headent[1].time_high) << 32 | headent[1].time_low; + total_time = end_time - start_time; + + if (xsize < 100) + xsize = 100; + if (ysize < 80) + ysize = 80; + + /* Create output image with the specified size. */ + im_out = gdImageCreate (xsize, ysize); + + /* First color allocated is background. */ + grey = gdImageColorAllocate (im_out, 224, 224, 224); + + /* Set transparent color. */ + gdImageColorTransparent (im_out, grey); + + /* These are all the other colors we need (in the moment). */ + red = gdImageColorAllocate (im_out, 255, 0, 0); + green = gdImageColorAllocate (im_out, 0, 130, 0); + blue = gdImageColorAllocate (im_out, 0, 0, 255); + yellow = gdImageColorAllocate (im_out, 154, 205, 50); + black = gdImageColorAllocate (im_out, 0, 0, 0); + + gdImageRectangle (im_out, 40, 20, xsize - 40, ysize - 20, blue); + + if (maxsize_heap < 1024) + { + heap_format = "%Zu"; + heap_scale = 1; + } + else if (maxsize_heap < 1024 * 1024 * 100) + { + heap_format = "%Zuk"; + heap_scale = 1024; + } + else + { + heap_format = "%ZuM"; + heap_scale = 1024 * 1024; + } + + if (maxsize_stack < 1024) + { + stack_format = "%Zu"; + stack_scale = 1; + } + else if (maxsize_stack < 1024 * 1024 * 100) + { + stack_format = "%Zuk"; + stack_scale = 1024; + } + else + { + stack_format = "%ZuM"; + stack_scale = 1024 * 1024; + } + + gdImageString (im_out, gdFontSmall, 38, ysize - 14, (unsigned char *) "0", + blue); + snprintf (buf, sizeof (buf), heap_format, 0); + gdImageString (im_out, gdFontSmall, maxsize_heap < 1024 ? 32 : 26, + ysize - 26, (unsigned char *) buf, red); + snprintf (buf, sizeof (buf), stack_format, 0); + gdImageString (im_out, gdFontSmall, xsize - 37, ysize - 26, + (unsigned char *) buf, green); + + if (string != NULL) + gdImageString (im_out, gdFontLarge, (xsize - strlen (string) * 8) / 2, + 2, (unsigned char *) string, green); + + gdImageStringUp (im_out, gdFontSmall, 1, ysize / 2 - 10, + (unsigned char *) "allocated", red); + gdImageStringUp (im_out, gdFontSmall, 11, ysize / 2 - 10, + (unsigned char *) "memory", red); + + gdImageStringUp (im_out, gdFontSmall, xsize - 39, ysize / 2 - 10, + (unsigned char *) "used", green); + gdImageStringUp (im_out, gdFontSmall, xsize - 27, ysize / 2 - 10, + (unsigned char *) "stack", green); + + snprintf (buf, sizeof (buf), heap_format, maxsize_heap / heap_scale); + gdImageString (im_out, gdFontSmall, 39 - strlen (buf) * 6, 14, + (unsigned char *) buf, red); + snprintf (buf, sizeof (buf), stack_format, maxsize_stack / stack_scale); + gdImageString (im_out, gdFontSmall, xsize - 37, 14, + (unsigned char *) buf, green); + + for (line = 1; line <= 3; ++line) + { + if (maxsize_heap > 0) + { + cnt = (((ysize - 40) * (maxsize_heap / 4 * line / heap_scale)) + / (maxsize_heap / heap_scale)); + gdImageDashedLine (im_out, 40, ysize - 20 - cnt, xsize - 40, + ysize - 20 - cnt, red); + snprintf (buf, sizeof (buf), heap_format, + maxsize_heap / 4 * line / heap_scale); + gdImageString (im_out, gdFontSmall, 39 - strlen (buf) * 6, + ysize - 26 - cnt, (unsigned char *) buf, red); + } + else + cnt = 0; + + if (maxsize_stack > 0) + cnt2 = (((ysize - 40) * (maxsize_stack / 4 * line / stack_scale)) + / (maxsize_stack / stack_scale)); + else + cnt2 = 0; + + if (cnt != cnt2) + gdImageDashedLine (im_out, 40, ysize - 20 - cnt2, xsize - 40, + ysize - 20 - cnt2, green); + snprintf (buf, sizeof (buf), stack_format, maxsize_stack / 4 * line / + stack_scale); + gdImageString (im_out, gdFontSmall, xsize - 37, ysize - 26 - cnt2, + (unsigned char *) buf, green); + } + + snprintf (buf, sizeof (buf), "%llu", (unsigned long long) total); + gdImageString (im_out, gdFontSmall, xsize - 50, ysize - 14, + (unsigned char *) buf, blue); + + if (!time_based) + { + uint64_t previously = start_time; + + gdImageString (im_out, gdFontSmall, 40 + (xsize - 32 * 6 - 80) / 2, + ysize - 12, + (unsigned char *) "# memory handling function calls", + blue); + + + last_stack = last_heap = last_total = ysize - 20; + for (cnt = 1; cnt <= total; ++cnt) + { + struct entry entry; + size_t new[2]; + uint64_t now; + + read (fd, &entry, sizeof (entry)); + + now = ((uint64_t) entry.time_high) << 32 | entry.time_low; + + if ((((previously - start_time) * 100) / total_time) % 10 < 5) + gdImageFilledRectangle (im_out, + 40 + ((cnt - 1) * (xsize - 80)) / total, + ysize - 19, + 39 + (cnt * (xsize - 80)) / total, + ysize - 14, yellow); + previously = now; + + if (also_total && maxsize_heap > 0) + { + size_t new3; + + new3 = (ysize - 20) - ((((unsigned long long int) (ysize - 40)) + * (entry.heap + entry.stack)) + / maxsize_heap); + gdImageLine (im_out, 40 + ((xsize - 80) * (cnt - 1)) / total, + last_total, + 40 + ((xsize - 80) * cnt) / total, new3, + black); + last_total = new3; + } + + if (maxsize_heap > 0) + { + new[0] = ((ysize - 20) + - ((((unsigned long long int) (ysize - 40)) + * entry.heap) / maxsize_heap)); + gdImageLine (im_out, 40 + ((xsize - 80) * (cnt - 1)) / total, + last_heap, 40 + ((xsize - 80) * cnt) / total, + new[0], red); + last_heap = new[0]; + } + + if (maxsize_stack > 0) + { + new[1] = ((ysize - 20) + - ((((unsigned long long int) (ysize - 40)) + * entry.stack) / maxsize_stack)); + gdImageLine (im_out, 40 + ((xsize - 80) * (cnt - 1)) / total, + last_stack, 40 + ((xsize - 80) * cnt) / total, + new[1], green); + last_stack = new[1]; + } + } + + cnt = 0; + while (cnt < total) + { + gdImageLine (im_out, 40 + ((xsize - 80) * cnt) / total, ysize - 20, + 40 + ((xsize - 80) * cnt) / total, ysize - 15, blue); + cnt += MAX (1, total / 20); + } + gdImageLine (im_out, xsize - 40, ysize - 20, xsize - 40, ysize - 15, + blue); + } + else + { + uint64_t next_tick = MAX (1, total / 20); + size_t last_xpos = 40; + + gdImageString (im_out, gdFontSmall, 40 + (xsize - 39 * 6 - 80) / 2, + ysize - 12, + (unsigned char *) " \ +# memory handling function calls / time", blue); + + for (cnt = 0; cnt < 20; cnt += 2) + gdImageFilledRectangle (im_out, + 40 + (cnt * (xsize - 80)) / 20, ysize - 19, + 39 + ((cnt + 1) * (xsize - 80)) / 20, + ysize - 14, yellow); + + last_stack = last_heap = last_total = ysize - 20; + for (cnt = 1; cnt <= total; ++cnt) + { + struct entry entry; + size_t new[2]; + size_t xpos; + uint64_t now; + + read (fd, &entry, sizeof (entry)); + + now = ((uint64_t) entry.time_high) << 32 | entry.time_low; + xpos = 40 + ((xsize - 80) * (now - start_time)) / total_time; + + if (cnt == next_tick) + { + gdImageLine (im_out, xpos, ysize - 20, xpos, ysize - 15, blue); + next_tick += MAX (1, total / 20); + } + + if (also_total && maxsize_heap > 0) + { + size_t new3; + + new3 = (ysize - 20) - ((((unsigned long long int) (ysize - 40)) + * (entry.heap + entry.stack)) + / maxsize_heap); + gdImageLine (im_out, last_xpos, last_total, xpos, new3, black); + last_total = new3; + } + + if (maxsize_heap > 0) + { + new[0] = ((ysize - 20) + - ((((unsigned long long int) (ysize - 40)) + * entry.heap) / maxsize_heap)); + gdImageLine (im_out, last_xpos, last_heap, xpos, new[0], red); + last_heap = new[0]; + } + + if (maxsize_stack > 0) + { + new[1] = ((ysize - 20) + - ((((unsigned long long int) (ysize - 40)) + * entry.stack) / maxsize_stack)); + gdImageLine (im_out, last_xpos, last_stack, xpos, new[1], + green); + last_stack = new[1]; + } + + last_xpos = xpos; + } + } + + /* Write out the result. */ + outfile = fopen (outname, "w"); + if (outfile == NULL) + error (EXIT_FAILURE, errno, "cannot open output file"); + + gdImagePng (im_out, outfile); + + fclose (outfile); + + gdImageDestroy (im_out); + + return 0; +} + + +/* Handle program arguments. */ +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + switch (key) + { + case 'o': + outname = arg; + break; + case 's': + string = arg; + break; + case 't': + time_based = 1; + break; + case 'T': + also_total = 1; + break; + case 'x': + xsize = atoi (arg); + if (xsize == 0) + xsize = XSIZE; + break; + case 'y': + ysize = atoi (arg); + if (ysize == 0) + ysize = XSIZE; + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + + +static char * +more_help (int key, const char *text, void *input) +{ + char *tp; + + switch (key) + { + case ARGP_KEY_HELP_EXTRA: + /* We print some extra information. */ + if (asprintf (&tp, gettext ("\ +For bug reporting instructions, please see:\n\ +%s.\n"), REPORT_BUGS_TO) < 0) + return NULL; + + return tp; + + default: + break; + } + return (char *) text; +} + +/* Print the version information. */ +static void +print_version (FILE *stream, struct argp_state *state) +{ + fprintf (stream, "memusagestat %s%s\n", PKGVERSION, VERSION); + fprintf (stream, gettext ("\ +Copyright (C) %s Free Software Foundation, Inc.\n\ +This is free software; see the source for copying conditions. There is NO\n\ +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\ +"), "2017"); + fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper"); +} |