Back to index

glibc  2.9
Classes | Defines | Enumerations | Functions | Variables
memusage.c File Reference
#include <atomic.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <memusage.h>

Go to the source code of this file.

Classes

struct  header
struct  entry

Defines

#define MAGIC   0xfeedbeaf
#define peak_heap   peak_use[0]
#define peak_stack   peak_use[1]
#define peak_total   peak_use[2]
#define DEFAULT_BUFFER_SIZE   1024

Enumerations

enum  {
  idx_malloc = 0, idx_realloc, idx_calloc, idx_free,
  idx_mmap_r, idx_mmap_w, idx_mmap_a, idx_mremap,
  idx_munmap, idx_last
}

Functions

static void update_data (struct header *result, size_t len, size_t old_len)
static void int_handler (int signo)
static void me (void)
static void __attribute__ ((constructor))
void * malloc (size_t len)
void * realloc (void *old, size_t len)
void * calloc (size_t n, size_t len)
void free (void *ptr)
void * mmap (void *start, size_t len, int prot, int flags, int fd, off_t offset)
void * mmap64 (void *start, size_t len, int prot, int flags, int fd, off64_t offset)
void * mremap (void *start, size_t old_len, size_t len, int flags,...)
int munmap (void *start, size_t len)
static void __attribute__ ((destructor))

Variables

static void *(* mallocp )(size_t)
static void *(* reallocp )(void *, size_t)
static void *(* callocp )(size_t, size_t)
static void(* freep )(void *)
static void *(* mmapp )(void *, size_t, int, int, int, off_t)
static void *(* mmap64p )(void *, size_t, int, int, int, off64_t)
static int(* munmapp )(void *, size_t)
static void *(* mremapp )(void *, size_t, size_t, int, void *)
static memusage_cntr_t calls [idx_last]
static memusage_cntr_t failed [idx_last]
static memusage_size_t total [idx_last]
static memusage_size_t grand_total
static memusage_cntr_t histogram [65536/16]
static memusage_cntr_t large
static memusage_cntr_t calls_total
static memusage_cntr_t inplace
static memusage_cntr_t decreasing
static memusage_cntr_t realloc_free
static memusage_cntr_t inplace_mremap
static memusage_cntr_t decreasing_mremap
static memusage_size_t current_heap
static memusage_size_t peak_use [3]
static __thread uintptr_t start_sp
static size_t buffer_size
static int fd = -1
static bool not_me
static int initialized
static bool trace_mmap
const char * __progname
static struct entry [2 *DEFAULT_BUFFER_SIZE]
static uatomic32_t buffer_cnt

Class Documentation

struct header

Definition at line 98 of file hurdmalloc.c.

Class Members
long check
size_t length
size_t magic
const char *const * maybe
const char * name
size_t nmaybe
size_t nsyms
const char * subset
const char *const * syms
union header u
struct entry

Definition at line 105 of file memusage.c.

Class Members
void * data
uint64_t heap
char * key
uint64_t stack
const char * str
uint32_t time_high
uint32_t time_low
int val

Define Documentation

#define DEFAULT_BUFFER_SIZE   1024

Definition at line 95 of file memusage.c.

#define MAGIC   0xfeedbeaf

Definition at line 71 of file memusage.c.

#define peak_heap   peak_use[0]

Definition at line 91 of file memusage.c.

#define peak_stack   peak_use[1]

Definition at line 92 of file memusage.c.

#define peak_total   peak_use[2]

Definition at line 93 of file memusage.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
idx_malloc 
idx_realloc 
idx_calloc 
idx_free 
idx_mmap_r 
idx_mmap_w 
idx_mmap_a 
idx_mremap 
idx_munmap 
idx_last 

Definition at line 50 of file memusage.c.


Function Documentation

static void __attribute__ ( (constructor)  ) [static]

Definition at line 313 of file memusage.c.

{
  start_sp = GETSP ();
  if (! initialized)
    me ();
}

Here is the call graph for this function:

static void __attribute__ ( (destructor)  ) [static]

Definition at line 776 of file memusage.c.

{
  int percent, cnt;
  unsigned long int maxcalls;

  /* If we haven't done anything here just return.  */
  if (not_me)
    return;
  /* If we should call any of the memory functions don't do any profiling.  */
  not_me = true;

  /* Finish the output file.  */
  if (fd != -1)
    {
      /* Write the partially filled buffer.  */
      if (buffer_cnt > buffer_size)
       write (fd, buffer + buffer_size,
              (buffer_cnt - buffer_size) * sizeof (struct entry));
      else
       write (fd, buffer, buffer_cnt * sizeof (struct entry));

      /* Go back to the beginning of the file.  We allocated two records
        here when we opened the file.  */
      lseek (fd, 0, SEEK_SET);
      /* Write out a record containing the total size.  */
      first.stack = peak_total;
      write (fd, &first, sizeof (struct entry));
      /* Write out another record containing the maximum for heap and
         stack.  */
      first.heap = peak_heap;
      first.stack = peak_stack;
      GETTIME (first.time_low, first.time_high);
      write (fd, &first, sizeof (struct entry));

      /* Close the file.  */
      close (fd);
      fd = -1;
    }

  /* Write a colorful statistic.  */
  fprintf (stderr, "\n\
\e[01;32mMemory usage summary:\e[0;0m heap total: %llu, heap peak: %lu, stack peak: %lu\n\
\e[04;34m         total calls   total memory   failed calls\e[0m\n\
\e[00;34m malloc|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n\
\e[00;34mrealloc|\e[0m %10lu   %12llu   %s%12lu\e[00;00m  (nomove:%ld, dec:%ld, free:%ld)\n\
\e[00;34m calloc|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n\
\e[00;34m   free|\e[0m %10lu   %12llu\n",
          (unsigned long long int) grand_total, (unsigned long int) peak_heap,
          (unsigned long int) peak_stack,
          (unsigned long int) calls[idx_malloc],
          (unsigned long long int) total[idx_malloc],
          failed[idx_malloc] ? "\e[01;41m" : "",
          (unsigned long int) failed[idx_malloc],
          (unsigned long int) calls[idx_realloc],
          (unsigned long long int) total[idx_realloc],
          failed[idx_realloc] ? "\e[01;41m" : "",
          (unsigned long int) failed[idx_realloc],
          (unsigned long int) inplace,
          (unsigned long int) decreasing,
          (unsigned long int) realloc_free,
          (unsigned long int) calls[idx_calloc],
          (unsigned long long int) total[idx_calloc],
          failed[idx_calloc] ? "\e[01;41m" : "",
          (unsigned long int) failed[idx_calloc],
          (unsigned long int) calls[idx_free],
          (unsigned long long int) total[idx_free]);

  if (trace_mmap)
    fprintf (stderr, "\
\e[00;34mmmap(r)|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n\
\e[00;34mmmap(w)|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n\
\e[00;34mmmap(a)|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n\
\e[00;34m mremap|\e[0m %10lu   %12llu   %s%12lu\e[00;00m  (nomove: %ld, dec:%ld)\n\
\e[00;34m munmap|\e[0m %10lu   %12llu   %s%12lu\e[00;00m\n",
            (unsigned long int) calls[idx_mmap_r],
            (unsigned long long int) total[idx_mmap_r],
            failed[idx_mmap_r] ? "\e[01;41m" : "",
            (unsigned long int) failed[idx_mmap_r],
            (unsigned long int) calls[idx_mmap_w],
            (unsigned long long int) total[idx_mmap_w],
            failed[idx_mmap_w] ? "\e[01;41m" : "",
            (unsigned long int) failed[idx_mmap_w],
            (unsigned long int) calls[idx_mmap_a],
            (unsigned long long int) total[idx_mmap_a],
            failed[idx_mmap_a] ? "\e[01;41m" : "",
            (unsigned long int) failed[idx_mmap_a],
            (unsigned long int) calls[idx_mremap],
            (unsigned long long int) total[idx_mremap],
            failed[idx_mremap] ? "\e[01;41m" : "",
            (unsigned long int) failed[idx_mremap],
            (unsigned long int) inplace_mremap,
            (unsigned long int) decreasing_mremap,
            (unsigned long int) calls[idx_munmap],
            (unsigned long long int) total[idx_munmap],
            failed[idx_munmap] ? "\e[01;41m" : "",
            (unsigned long int) failed[idx_munmap]);

  /* Write out a histoogram of the sizes of the allocations.  */
  fprintf (stderr, "\e[01;32mHistogram for block sizes:\e[0;0m\n");

  /* Determine the maximum of all calls for each size range.  */
  maxcalls = large;
  for (cnt = 0; cnt < 65536; cnt += 16)
    if (histogram[cnt / 16] > maxcalls)
      maxcalls = histogram[cnt / 16];

  for (cnt = 0; cnt < 65536; cnt += 16)
    /* Only write out the nonzero entries.  */
    if (histogram[cnt / 16] != 0)
      {
       percent = (histogram[cnt / 16] * 100) / calls_total;
       fprintf (stderr, "%5d-%-5d%12lu ", cnt, cnt + 15,
               (unsigned long int) histogram[cnt / 16]);
       if (percent == 0)
         fputs (" <1% \e[41;37m", stderr);
       else
         fprintf (stderr, "%3d%% \e[41;37m", percent);

       /* Draw a bar with a length corresponding to the current
           percentage.  */
       percent = (histogram[cnt / 16] * 50) / maxcalls;
       while (percent-- > 0)
         fputc ('=', stderr);
        fputs ("\e[0;0m\n", stderr);
      }

  if (large != 0)
    {
      percent = (large * 100) / calls_total;
      fprintf (stderr, "   large   %12lu ", (unsigned long int) large);
      if (percent == 0)
       fputs (" <1% \e[41;37m", stderr);
      else
       fprintf (stderr, "%3d%% \e[41;37m", percent);
      percent = (large * 50) / maxcalls;
      while (percent-- > 0)
        fputc ('=', stderr);
      fputs ("\e[0;0m\n", stderr);
    }

  /* Any following malloc/free etc. calls should generate statistics again,
     because otherwise freeing something that has been malloced before
     this destructor (including struct header in front of it) wouldn't
     be properly freed.  */
  not_me = false;
}

Here is the call graph for this function:

void* calloc ( size_t  n,
size_t  len 
)

Definition at line 467 of file memusage.c.

{
  struct header *result;
  size_t size = n * len;

  /* Determine real implementation if not already happened.  */
  if (__builtin_expect (initialized <= 0, 0))
    {
      if (initialized == -1)
       return NULL;
      me ();
    }

  /* If this is not the correct program just use the normal function.  */
  if (not_me)
    return (*callocp) (n, len);

  /* Keep track of number of calls.  */
  catomic_increment (&calls[idx_calloc]);
  /* Keep track of total memory consumption for `calloc'.  */
  catomic_add (&total[idx_calloc], size);
  /* Keep track of total memory requirement.  */
  catomic_add (&grand_total, size);
  /* Remember the size of the request.  */
  if (size < 65536)
    catomic_increment (&histogram[size / 16]);
  else
    catomic_increment (&large);
  /* Total number of calls of any of the functions.  */
  ++calls_total;

  /* Do the real work.  */
  result = (struct header *) (*mallocp) (size + sizeof (struct header));
  if (result == NULL)
    {
      catomic_increment (&failed[idx_calloc]);
      return NULL;
    }

  /* Update the allocation data and write out the records if necessary.  */
  update_data (result, size, 0);

  /* Do what `calloc' would have done and return the buffer to the caller.  */
  return memset (result + 1, '\0', size);
}

Here is the call graph for this function:

void free ( void *  ptr)

Definition at line 517 of file memusage.c.

{
  struct header *real;

  /* Determine real implementation if not already happened.  */
  if (__builtin_expect (initialized <= 0, 0))
    {
      if (initialized == -1)
       return;
      me ();
    }

  /* If this is not the correct program just use the normal function.  */
  if (not_me)
    {
      (*freep) (ptr);
      return;
    }

  /* `free (NULL)' has no effect.  */
  if (ptr == NULL)
    {
      catomic_increment (&calls[idx_free]);
      return;
    }

  /* Determine the pointer to the header.  */
  real = ((struct header *) ptr) - 1;
  if (real->magic != MAGIC)
    {
      /* This block wasn't allocated here.  */
      (*freep) (ptr);
      return;
    }

  /* Keep track of number of calls.  */
  catomic_increment (&calls[idx_free]);
  /* Keep track of total memory freed using `free'.  */
  catomic_add (&total[idx_free], real->length);

  /* Update the allocation data and write out the records if necessary.  */
  update_data (NULL, 0, real->length);

  /* Do the real work.  */
  (*freep) (real);
}

Here is the call graph for this function:

static void int_handler ( int  signo) [static]

Definition at line 191 of file memusage.c.

{
  /* Nothing gets allocated.  Just record the stack pointer position.  */
  update_data (NULL, 0, 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* malloc ( size_t  len)

Definition at line 325 of file memusage.c.

{
  struct header *result = NULL;

  /* Determine real implementation if not already happened.  */
  if (__builtin_expect (initialized <= 0, 0))
    {
      if (initialized == -1)
       return NULL;
      me ();
    }

  /* If this is not the correct program just use the normal function.  */
  if (not_me)
    return (*mallocp) (len);

  /* Keep track of number of calls.  */
  catomic_increment (&calls[idx_malloc]);
  /* Keep track of total memory consumption for `malloc'.  */
  catomic_add (&total[idx_malloc], len);
  /* Keep track of total memory requirement.  */
  catomic_add (&grand_total, len);
  /* Remember the size of the request.  */
  if (len < 65536)
    catomic_increment (&histogram[len / 16]);
  else
    catomic_increment (&large);
  /* Total number of calls of any of the functions.  */
  catomic_increment (&calls_total);

  /* Do the real work.  */
  result = (struct header *) (*mallocp) (len + sizeof (struct header));
  if (result == NULL)
    {
      catomic_increment (&failed[idx_malloc]);
      return NULL;
    }

  /* Update the allocation data and write out the records if necessary.  */
  update_data (result, len, 0);

  /* Return the pointer to the user buffer.  */
  return (void *) (result + 1);
}

Here is the call graph for this function:

static void me ( void  ) [static]

Definition at line 215 of file memusage.c.

{
  const char *env = getenv ("MEMUSAGE_PROG_NAME");
  size_t prog_len = strlen (__progname);

  initialized = -1;
  mallocp = (void *(*) (size_t)) dlsym (RTLD_NEXT, "malloc");
  reallocp = (void *(*) (void *, size_t)) dlsym (RTLD_NEXT, "realloc");
  callocp = (void *(*) (size_t, size_t)) dlsym (RTLD_NEXT, "calloc");
  freep = (void (*) (void *)) dlsym (RTLD_NEXT, "free");

  mmapp = (void *(*) (void *, size_t, int, int, int, off_t)) dlsym (RTLD_NEXT,
                                                            "mmap");
  mmap64p =
    (void *(*) (void *, size_t, int, int, int, off64_t)) dlsym (RTLD_NEXT,
                                                        "mmap64");
  mremapp = (void *(*) (void *, size_t, size_t, int, void *)) dlsym (RTLD_NEXT,
                                                             "mremap");
  munmapp = (int (*) (void *, size_t)) dlsym (RTLD_NEXT, "munmap");
  initialized = 1;

  if (env != NULL)
    {
      /* Check for program name.  */
      size_t len = strlen (env);
      if (len > prog_len || strcmp (env, &__progname[prog_len - len]) != 0
         || (prog_len != len && __progname[prog_len - len - 1] != '/'))
       not_me = true;
    }

  /* Only open the file if it's really us.  */
  if (!not_me && fd == -1)
    {
      const char *outname;

      if (!start_sp)
       start_sp = GETSP ();

      outname = getenv ("MEMUSAGE_OUTPUT");
      if (outname != NULL && outname[0] != '\0'
         && (access (outname, R_OK | W_OK) == 0 || errno == ENOENT))
       {
         fd = creat64 (outname, 0666);

         if (fd == -1)
           /* Don't do anything in future calls if we cannot write to
              the output file.  */
           not_me = true;
         else
           {
             /* Write the first entry.  */
             first.heap = 0;
             first.stack = 0;
             GETTIME (first.time_low, first.time_high);
             /* Write it two times since we need the starting and end time. */
             write (fd, &first, sizeof (first));
             write (fd, &first, sizeof (first));

             /* Determine the buffer size.  We use the default if the
               environment variable is not present.  */
             buffer_size = DEFAULT_BUFFER_SIZE;
             if (getenv ("MEMUSAGE_BUFFER_SIZE") != NULL)
              {
                buffer_size = atoi (getenv ("MEMUSAGE_BUFFER_SIZE"));
                if (buffer_size == 0 || buffer_size > DEFAULT_BUFFER_SIZE)
                  buffer_size = DEFAULT_BUFFER_SIZE;
              }

             /* Possibly enable timer-based stack pointer retrieval.  */
             if (getenv ("MEMUSAGE_NO_TIMER") == NULL)
              {
                struct sigaction act;

                act.sa_handler = (sighandler_t) &int_handler;
                act.sa_flags = SA_RESTART;
                sigfillset (&act.sa_mask);

                if (sigaction (SIGPROF, &act, NULL) >= 0)
                  {
                    struct itimerval timer;

                    timer.it_value.tv_sec = 0;
                    timer.it_value.tv_usec = 1;
                    timer.it_interval = timer.it_value;
                    setitimer (ITIMER_PROF, &timer, NULL);
                  }
              }
           }
       }

      if (!not_me && getenv ("MEMUSAGE_TRACE_MMAP") != NULL)
       trace_mmap = true;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* mmap ( void *  start,
size_t  len,
int  prot,
int  flags,
int  fd,
off_t  offset 
)

Definition at line 568 of file memusage.c.

{
  void *result = NULL;

  /* Determine real implementation if not already happened.  */
  if (__builtin_expect (initialized <= 0, 0))
    {
      if (initialized == -1)
       return NULL;
      me ();
    }

  /* Always get a block.  We don't need extra memory.  */
  result = (*mmapp) (start, len, prot, flags, fd, offset);

  if (!not_me && trace_mmap)
    {
      int idx = (flags & MAP_ANON
               ? idx_mmap_a : prot & PROT_WRITE ? idx_mmap_w : idx_mmap_r);

      /* Keep track of number of calls.  */
      catomic_increment (&calls[idx]);
      /* Keep track of total memory consumption for `malloc'.  */
      catomic_add (&total[idx], len);
      /* Keep track of total memory requirement.  */
      catomic_add (&grand_total, len);
      /* Remember the size of the request.  */
      if (len < 65536)
       catomic_increment (&histogram[len / 16]);
      else
       catomic_increment (&large);
      /* Total number of calls of any of the functions.  */
      catomic_increment (&calls_total);

      /* Check for failures.  */
      if (result == NULL)
       catomic_increment (&failed[idx]);
      else if (idx == idx_mmap_w)
       /* Update the allocation data and write out the records if
          necessary.  Note the first parameter is NULL which means
          the size is not tracked.  */
       update_data (NULL, len, 0);
    }

  /* Return the pointer to the user buffer.  */
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* mmap64 ( void *  start,
size_t  len,
int  prot,
int  flags,
int  fd,
off64_t  offset 
)

Definition at line 620 of file memusage.c.

{
  void *result = NULL;

  /* Determine real implementation if not already happened.  */
  if (__builtin_expect (initialized <= 0, 0))
    {
      if (initialized == -1)
       return NULL;
      me ();
    }

  /* Always get a block.  We don't need extra memory.  */
  result = (*mmap64p) (start, len, prot, flags, fd, offset);

  if (!not_me && trace_mmap)
    {
      int idx = (flags & MAP_ANON
               ? idx_mmap_a : prot & PROT_WRITE ? idx_mmap_w : idx_mmap_r);

      /* Keep track of number of calls.  */
      catomic_increment (&calls[idx]);
      /* Keep track of total memory consumption for `malloc'.  */
      catomic_add (&total[idx], len);
      /* Keep track of total memory requirement.  */
      catomic_add (&grand_total, len);
      /* Remember the size of the request.  */
      if (len < 65536)
       catomic_increment (&histogram[len / 16]);
      else
       catomic_increment (&large);
      /* Total number of calls of any of the functions.  */
      catomic_increment (&calls_total);

      /* Check for failures.  */
      if (result == NULL)
       catomic_increment (&failed[idx]);
      else if (idx == idx_mmap_w)
       /* Update the allocation data and write out the records if
          necessary.  Note the first parameter is NULL which means
          the size is not tracked.  */
       update_data (NULL, len, 0);
    }

  /* Return the pointer to the user buffer.  */
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* mremap ( void *  start,
size_t  old_len,
size_t  len,
int  flags,
  ... 
)

Definition at line 672 of file memusage.c.

{
  void *result = NULL;
  va_list ap;

  va_start (ap, flags);
  void *newaddr = (flags & MREMAP_FIXED) ? va_arg (ap, void *) : NULL;
  va_end (ap);

  /* Determine real implementation if not already happened.  */
  if (__builtin_expect (initialized <= 0, 0))
    {
      if (initialized == -1)
       return NULL;
      me ();
    }

  /* Always get a block.  We don't need extra memory.  */
  result = (*mremapp) (start, old_len, len, flags, newaddr);

  if (!not_me && trace_mmap)
    {
      /* Keep track of number of calls.  */
      catomic_increment (&calls[idx_mremap]);
      if (len > old_len)
       {
         /* Keep track of total memory consumption for `malloc'.  */
         catomic_add (&total[idx_mremap], len - old_len);
         /* Keep track of total memory requirement.  */
         catomic_add (&grand_total, len - old_len);
       }
      /* Remember the size of the request.  */
      if (len < 65536)
       catomic_increment (&histogram[len / 16]);
      else
       catomic_increment (&large);
      /* Total number of calls of any of the functions.  */
      catomic_increment (&calls_total);

      /* Check for failures.  */
      if (result == NULL)
       catomic_increment (&failed[idx_mremap]);
      else
       {
         /* Record whether the reduction/increase happened in place.  */
         if (start == result)
           catomic_increment (&inplace_mremap);
         /* Was the buffer increased?  */
         if (old_len > len)
           catomic_increment (&decreasing_mremap);

         /* Update the allocation data and write out the records if
            necessary.  Note the first parameter is NULL which means
            the size is not tracked.  */
         update_data (NULL, len, old_len);
       }
    }

  /* Return the pointer to the user buffer.  */
  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int munmap ( void *  start,
size_t  len 
)

Definition at line 737 of file memusage.c.

{
  int result;

  /* Determine real implementation if not already happened.  */
  if (__builtin_expect (initialized <= 0, 0))
    {
      if (initialized == -1)
       return -1;
      me ();
    }

  /* Do the real work.  */
  result = (*munmapp) (start, len);

  if (!not_me && trace_mmap)
    {
      /* Keep track of number of calls.  */
      catomic_increment (&calls[idx_munmap]);

      if (__builtin_expect (result == 0, 1))
       {
         /* Keep track of total memory freed using `free'.  */
         catomic_add (&total[idx_munmap], len);

         /* Update the allocation data and write out the records if
            necessary.  */
         update_data (NULL, 0, len);
       }
      else
       catomic_increment (&failed[idx_munmap]);
    }

  return result;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* realloc ( void *  old,
size_t  len 
)

Definition at line 374 of file memusage.c.

{
  struct header *result = NULL;
  struct header *real;
  size_t old_len;

  /* Determine real implementation if not already happened.  */
  if (__builtin_expect (initialized <= 0, 0))
    {
      if (initialized == -1)
       return NULL;
      me ();
    }

  /* If this is not the correct program just use the normal function.  */
  if (not_me)
    return (*reallocp) (old, len);

  if (old == NULL)
    {
      /* This is really a `malloc' call.  */
      real = NULL;
      old_len = 0;
    }
  else
    {
      real = ((struct header *) old) - 1;
      if (real->magic != MAGIC)
       /* This is no memory allocated here.  */
       return (*reallocp) (old, len);
      old_len = real->length;
    }

  /* Keep track of number of calls.  */
  catomic_increment (&calls[idx_realloc]);
  if (len > old_len)
    {
      /* Keep track of total memory consumption for `realloc'.  */
      catomic_add (&total[idx_realloc], len - old_len);
      /* Keep track of total memory requirement.  */
      catomic_add (&grand_total, len - old_len);
    }

  if (len == 0 && old != NULL)
    {
      /* Special case.  */
      catomic_increment (&realloc_free);
      /* Keep track of total memory freed using `free'.  */
      catomic_add (&total[idx_free], real->length);

      /* Update the allocation data and write out the records if necessary.  */
      update_data (NULL, 0, old_len);

      /* Do the real work.  */
      (*freep) (real);

      return NULL;
    }

  /* Remember the size of the request.  */
  if (len < 65536)
    catomic_increment (&histogram[len / 16]);
  else
    catomic_increment (&large);
  /* Total number of calls of any of the functions.  */
  catomic_increment (&calls_total);

  /* Do the real work.  */
  result = (struct header *) (*reallocp) (real, len + sizeof (struct header));
  if (result == NULL)
    {
      catomic_increment (&failed[idx_realloc]);
      return NULL;
    }

  /* Record whether the reduction/increase happened in place.  */
  if (real == result)
    catomic_increment (&inplace);
  /* Was the buffer increased?  */
  if (old_len > len)
    catomic_increment (&decreasing);

  /* Update the allocation data and write out the records if necessary.  */
  update_data (result, len, old_len);

  /* Return the pointer to the user buffer.  */
  return (void *) (result + 1);
}

Here is the call graph for this function:

static void update_data ( struct header result,
size_t  len,
size_t  old_len 
) [static]

Definition at line 120 of file memusage.c.

{
  if (result != NULL)
    {
      /* Record the information we need and mark the block using a
         magic number.  */
      result->length = len;
      result->magic = MAGIC;
    }

  /* Compute current heap usage and compare it with the maximum value.  */
  memusage_size_t heap
    = catomic_exchange_and_add (&current_heap, len - old_len) + len - old_len;
  catomic_max (&peak_heap, heap);

  /* Compute current stack usage and compare it with the maximum
     value.  The base stack pointer might not be set if this is not
     the main thread and it is the first call to any of these
     functions.  */
  if (__builtin_expect (!start_sp, 0))
    start_sp = GETSP ();

  uintptr_t sp = GETSP ();
#ifdef STACK_GROWS_UPWARD
  /* This can happen in threads where we didn't catch the thread's
     stack early enough.  */
  if (__builtin_expect (sp < start_sp, 0))
    start_sp = sp;
  size_t current_stack = sp - start_sp;
#else
  /* This can happen in threads where we didn't catch the thread's
     stack early enough.  */
  if (__builtin_expect (sp > start_sp, 0))
    start_sp = sp;
  size_t current_stack = start_sp - sp;
#endif
  catomic_max (&peak_stack, current_stack);

  /* Add up heap and stack usage and compare it with the maximum value.  */
  catomic_max (&peak_total, heap + current_stack);

  /* Store the value only if we are writing to a file.  */
  if (fd != -1)
    {
      uatomic32_t idx = catomic_exchange_and_add (&buffer_cnt, 1);
      if (idx >= 2 * buffer_size)
       {
         /* We try to reset the counter to the correct range.  If
            this fails because of another thread increasing the
            counter it does not matter since that thread will take
            care of the correction.  */
         unsigned int reset = idx - 2 * buffer_size;
         catomic_compare_and_exchange_val_acq (&buffer_size, reset, idx);
         idx = reset;
       }

      buffer[idx].heap = current_heap;
      buffer[idx].stack = current_stack;
      GETTIME (buffer[idx].time_low, buffer[idx].time_high);

      /* Write out buffer if it is full.  */
      if (idx + 1 == buffer_size)
       write (fd, buffer, buffer_size * sizeof (struct entry));
      else if (idx + 1 == 2 * buffer_size)
       write (fd, &buffer[buffer_size], buffer_size * sizeof (struct entry));
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 24 of file init-misc.c.

Definition at line 114 of file memusage.c.

size_t buffer_size [static]

Definition at line 96 of file memusage.c.

void*(* callocp)(size_t, size_t) [static]

Definition at line 42 of file memusage.c.

Definition at line 74 of file memusage.c.

Definition at line 80 of file memusage.c.

Definition at line 86 of file memusage.c.

Definition at line 82 of file memusage.c.

Definition at line 85 of file memusage.c.

static struct entry [static]

Definition at line 113 of file memusage.c.

Definition at line 75 of file memusage.c.

int fd = -1 [static]

Definition at line 98 of file memusage.c.

void(* freep)(void *) [static]

Definition at line 43 of file memusage.c.

Definition at line 77 of file memusage.c.

memusage_cntr_t histogram[65536/16] [static]

Definition at line 78 of file memusage.c.

int initialized [static]

Definition at line 101 of file memusage.c.

Definition at line 81 of file memusage.c.

Definition at line 84 of file memusage.c.

Definition at line 79 of file memusage.c.

void*(* mallocp)(size_t) [static]

Definition at line 40 of file memusage.c.

void*(* mmap64p)(void *, size_t, int, int, int, off64_t) [static]

Definition at line 46 of file memusage.c.

void*(* mmapp)(void *, size_t, int, int, int, off_t) [static]

Definition at line 45 of file memusage.c.

void*(* mremapp)(void *, size_t, size_t, int, void *) [static]

Definition at line 48 of file memusage.c.

int(* munmapp)(void *, size_t) [static]

Definition at line 47 of file memusage.c.

bool not_me [static]

Definition at line 100 of file memusage.c.

Definition at line 87 of file memusage.c.

Definition at line 83 of file memusage.c.

void*(* reallocp)(void *, size_t) [static]

Definition at line 41 of file memusage.c.

__thread uintptr_t start_sp [static]

Definition at line 88 of file memusage.c.

Definition at line 76 of file memusage.c.

bool trace_mmap [static]

Definition at line 102 of file memusage.c.