diff options
author | Ulrich Drepper <drepper@redhat.com> | 2000-06-20 04:46:22 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2000-06-20 04:46:22 +0000 |
commit | ba80a015ee80c01be5100b8b94794b8784aa562b (patch) | |
tree | 7bb6db1e6fa726246c08346ce0732e393f174450 /malloc/memprof.c | |
parent | ea97f90c9a84ce5c8a7c60695f05adfd2b6bb295 (diff) | |
download | glibc-ba80a015ee80c01be5100b8b94794b8784aa562b.tar glibc-ba80a015ee80c01be5100b8b94794b8784aa562b.tar.gz glibc-ba80a015ee80c01be5100b8b94794b8784aa562b.tar.bz2 glibc-ba80a015ee80c01be5100b8b94794b8784aa562b.zip |
Update.
* malloc/Makefile: Change all references to memprof into memusage.
* malloc/memprof.c: Rename to...
* malloc/memusage.c: ...this. New file.
* malloc/memprof.sh: Rename to...
* malloc/memusage.sh: ...this. New file.
* malloc/memprofstat.c: Rename to...
* malloc/memusagestat.c: ...this. New file.
Diffstat (limited to 'malloc/memprof.c')
-rw-r--r-- | malloc/memprof.c | 573 |
1 files changed, 0 insertions, 573 deletions
diff --git a/malloc/memprof.c b/malloc/memprof.c deleted file mode 100644 index 56d3ac556e..0000000000 --- a/malloc/memprof.c +++ /dev/null @@ -1,573 +0,0 @@ -/* Profile heap and stack memory usage of running program. - Copyright (C) 1998, 1999 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - The GNU C Library 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 - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ - -#include <dlfcn.h> -#include <fcntl.h> -#include <inttypes.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/time.h> - -#include <memprof.h> - -/* Pointer to the real functions. These are determined used `dlsym' - when really needed. */ -static void *(*mallocp) (size_t); -static void *(*reallocp) (void *, size_t); -static void *(*callocp) (size_t, size_t); -static void (*freep) (void *); - -enum -{ - idx_malloc = 0, - idx_realloc, - idx_calloc, - idx_free, - idx_last -}; - - -struct header -{ - size_t length; - size_t magic; -}; - -#define MAGIC 0xfeedbeaf - - -static unsigned long int calls[idx_last]; -static unsigned long int failed[idx_last]; -static unsigned long long int total[idx_last]; -static unsigned long long int grand_total; -static unsigned long int histogram[65536 / 16]; -static unsigned long int large; -static unsigned long int calls_total; -static unsigned long int inplace; -static unsigned long int decreasing; -static long int current_use[2]; -static long int peak_use[3]; -static uintptr_t start_sp; - -/* A few macros to make the source more readable. */ -#define current_heap current_use[0] -#define current_stack current_use[1] -#define peak_heap peak_use[0] -#define peak_stack peak_use[1] -#define peak_total peak_use[2] - -#define DEFAULT_BUFFER_SIZE 1024 -static size_t buffer_size; - -static int fd = -1; - -static int not_me; -extern const char *__progname; - -struct entry -{ - size_t heap; - size_t stack; - uint32_t time_low; - uint32_t time_high; -}; - -static struct entry buffer[DEFAULT_BUFFER_SIZE]; -static size_t buffer_cnt; -static struct entry first; - - -/* Update the global data after a successful function call. */ -static void -update_data (struct header *result, size_t len, size_t old_len) -{ - long int total_use; - - 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. */ - current_heap += len - old_len; - if (current_heap > peak_heap) - peak_heap = current_heap; - - /* Compute current stack usage and compare it with the maximum value. */ - current_stack = start_sp - GETSP (); - if (current_stack > peak_stack) - peak_stack = current_stack; - - /* Add up heap and stack usage and compare it with the maximum value. */ - total_use = current_heap + current_stack; - if (total_use > peak_total) - peak_total = total_use; - - /* Store the value only if we are writing to a file. */ - if (fd != -1) - { - buffer[buffer_cnt].heap = current_heap; - buffer[buffer_cnt].stack = current_stack; - GETTIME (buffer[buffer_cnt].time_low, buffer[buffer_cnt].time_high); - ++buffer_cnt; - - /* Write out buffer if it is full. */ - if (buffer_cnt == buffer_size) - { - write (fd, buffer, buffer_cnt * sizeof (struct entry)); - buffer_cnt = 0; - } - } -} - - -/* Interrupt handler. */ -static void -int_handler (int signo) -{ - /* Nothing gets allocated. Just record the stack pointer position. */ - update_data (NULL, 0, 0); -} - - -/* Record the initial stack position. */ -static void -__attribute__ ((constructor)) -init (void) -{ - start_sp = GETSP (); -} - - -/* Find out whether this is the program we are supposed to profile. - For this the name in the variable `__progname' must match the one - given in the environment variable MEMPROF_PROG_NAME. If the variable - is not present every program assumes it should be profiling. - - If this is the program open a file descriptor to the output file. - We will write to it whenever the buffer overflows. The name of the - output file is determined by the environment variable MEMPROF_OUTPUT. - - If the environment variable MEMPROF_BUFFER_SIZE is set its numerical - value determines the size of the internal buffer. The number gives - the number of elements in the buffer. By setting the number to one - one effectively selects unbuffered operation. - - If MEMPROF_NO_TIMER is not present an alarm handler is installed - which at the highest possible frequency records the stack pointer. */ -static void -me (void) -{ - const char *env = getenv ("MEMPROF_PROG_NAME"); - size_t prog_len = strlen (__progname); - 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 = 1; - } - - /* Only open the file if it's really us. */ - if (!not_me && fd == -1) - { - const char *outname = getenv ("MEMPROF_OUTPUT"); - if (outname != NULL) - { - fd = creat (outname, 0666); - - if (fd == -1) - /* Don't do anything in future calls if we cannot write to - the output file. */ - not_me = 1; - 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)); - - /* Determine the buffer size. We use the default if the - environment variable is not present. */ - buffer_size = DEFAULT_BUFFER_SIZE; - if (getenv ("MEMPROF_BUFFER_SIZE") != NULL) - { - buffer_size = atoi (getenv ("MEMPROF_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 ("MEMPROF_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); - } - } - } - } - } -} - - -/* `malloc' replacement. We keep track of the memory usage if this is the - correct program. */ -void * -malloc (size_t len) -{ - struct header *result = NULL; - - /* Determine real implementation if not already happened. */ - if (mallocp == NULL) - { - me (); - mallocp = (void *(*) (size_t)) dlsym (RTLD_NEXT, "malloc"); - } - - /* If this is not the correct program just use the normal function. */ - if (not_me) - return (*mallocp) (len); - - /* Keep track of number of calls. */ - ++calls[idx_malloc]; - /* Keep track of total memory consumption for `malloc'. */ - total[idx_malloc] += len; - /* Keep track of total memory requirement. */ - grand_total += len; - /* Remember the size of the request. */ - if (len < 65536) - ++histogram[len / 16]; - else - ++large; - /* Total number of calls of any of the functions. */ - ++calls_total; - - /* Do the real work. */ - result = (struct header *) (*mallocp) (len + sizeof (struct header)); - - if (result == NULL) - ++failed[idx_malloc]; - else - /* Update the allocation data and write out the records if necessary. */ - update_data (result, len, 0); - - /* Return the pointer to the user buffer. */ - return result ? (void *) (result + 1) : NULL; -} - - -/* `realloc' replacement. We keep track of the memory usage if this is the - correct program. */ -void * -realloc (void *old, size_t len) -{ - struct header *result = NULL; - struct header *real; - size_t old_len; - - /* Determine real implementation if not already happened. */ - if (reallocp == NULL) - { - me (); - reallocp = (void *(*) (void *, size_t)) dlsym (RTLD_NEXT, "realloc"); - } - - /* 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. */ - ++calls[idx_realloc]; - /* Keep track of total memory consumption for `realloc'. */ - total[idx_realloc] += len; - /* Keep track of total memory requirement. */ - grand_total += len; - /* Remember the size of the request. */ - if (len < 65536) - ++histogram[len / 16]; - else - ++large; - /* Total number of calls of any of the functions. */ - ++calls_total; - - /* Do the real work. */ - result = (struct header *) (*reallocp) (real, len + sizeof (struct header)); - - if (result == NULL) - ++failed[idx_realloc]; - else - { - /* Record whether the reduction/increase happened in place. */ - if (real == result) - ++inplace; - /* Was the buffer increased? */ - if (old_len > len) - ++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 result ? (void *) (result + 1) : NULL; -} - - -/* `calloc' replacement. We keep track of the memory usage if this is the - correct program. */ -void * -calloc (size_t n, size_t len) -{ - struct header *result; - size_t size = n * len; - - /* Determine real implementation if not already happened. We are - searching for the `malloc' implementation since it is not always - efficiently possible to use `calloc' because we have to add a bit - room to the allocation to put the header in. */ - if (mallocp == NULL) - { - me (); - mallocp = (void *(*) (size_t)) dlsym (RTLD_NEXT, "malloc"); - } - - /* If this is not the correct program just use the normal function. */ - if (not_me) - { - callocp = (void *(*) (size_t, size_t)) dlsym (RTLD_NEXT, "calloc"); - - return (*callocp) (n, len); - } - - /* Keep track of number of calls. */ - ++calls[idx_calloc]; - /* Keep track of total memory consumption for `calloc'. */ - total[idx_calloc] += size; - /* Keep track of total memory requirement. */ - grand_total += size; - /* Remember the size of the request. */ - if (size < 65536) - ++histogram[size / 16]; - else - ++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) - memset (result + 1, '\0', size); - - if (result == NULL) - ++failed[idx_calloc]; - else - /* Update the allocation data and write out the records if necessary. */ - update_data (result, size, 0); - - /* Return the pointer to the user buffer. */ - return result ? (void *) (result + 1) : NULL; -} - - -/* `free' replacement. We keep track of the memory usage if this is the - correct program. */ -void -free (void *ptr) -{ - struct header *real; - - /* `free (NULL)' has no effect. */ - if (ptr == NULL) - { - ++calls[idx_free]; - return; - } - - /* Determine real implementation if not already happened. */ - if (freep == NULL) - { - me (); - freep = (void (*) (void *)) dlsym (RTLD_NEXT, "free"); - } - - /* If this is not the correct program just use the normal function. */ - if (not_me) - { - (*freep) (ptr); - 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. */ - ++calls[idx_free]; - /* Keep track of total memory freed using `free'. */ - 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); -} - - -/* Write some statistics to standard error. */ -static void -__attribute__ ((destructor)) -dest (void) -{ - 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 = 1; - - /* Finish the output file. */ - if (fd != -1) - { - /* Write the partially filled buffer. */ - 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 (in place: %ld, dec: %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", - grand_total, (unsigned long int) peak_heap, - (unsigned long int) peak_stack, - calls[idx_malloc], total[idx_malloc], - failed[idx_malloc] ? "\e[01;41m" : "", failed[idx_malloc], - calls[idx_realloc], total[idx_realloc], - failed[idx_realloc] ? "\e[01;41m" : "", failed[idx_realloc], - inplace, decreasing, - calls[idx_calloc], total[idx_calloc], - failed[idx_calloc] ? "\e[01;41m" : "", failed[idx_calloc], - calls[idx_free], total[idx_free]); - - /* 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, - 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 ", 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); - } -} |