Blame malloc/memusagestat.c

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