libmtracectl-routines = mtrace-ctl
libmtracectl-inhibit-o = $(filter-out .os,$(object-suffixes))
+others: $(objpfx)trace_run
+install-bin = trace_run
+install-bin-script = trace2dat
+
+$(objpfx)trace_run: $(objpfx)trace_run.o
+ $(LINK.o) -o $@ $(objpfx)trace_run.o -lpthread
+
$(objpfx)tst-malloc-backtrace: $(shared-thread-library)
$(objpfx)tst-malloc-thread-exit: $(shared-thread-library)
$(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
# The Perl script to analyze the output of the mtrace functions.
ifneq ($(PERL),no)
-install-bin-script = mtrace
+install-bin-script += mtrace
generated += mtrace
# The Perl script will print addresses and to do this nicely we must know
# If the gd library is available we build the `memusagestat' program.
ifneq ($(LIBGD),no)
others: $(objpfx)memusage
-install-bin = memusagestat
+install-bin += memusagestat
install-bin-script += memusage
generated += memusagestat memusage
extra-objs += memusagestat.o
sLIBdir := $(shell echo $(slibdir) | sed 's,lib\(\|64\)$$,\\\\$$LIB,')
+$(objpfx)trace2dat: trace2dat
+ cp $^ $@ && chmod +x $@
+
$(objpfx)mtrace: mtrace.pl
rm -f $@.new
sed -e 's|@PERL@|$(PERL)|' -e 's|@XXX@|$(address-width)|' \
static __thread __malloc_trace_buffer_ptr trace_ptr;
static void
-__mtb_trace_entry (uint32_t type, int64_t size, void *ptr1)
+__mtb_trace_entry (uint32_t type, size_t size, void *ptr1)
{
size_t head1;
trace_ptr->path_m_f_realloc = 0;
trace_ptr->path = 0;
trace_ptr->size = size;
- trace_ptr->ptr1 = (uint64_t) ptr1;
+ trace_ptr->ptr1 = ptr1;
trace_ptr->ptr2 = 0;
}
#define __MTB_TRACE_SET(var,value) \
if (__builtin_expect (trace_ptr != NULL, 1)) \
- trace_ptr->var = (uint64_t) value;
+ trace_ptr->var = value;
#else
#define __MTB_TRACE_ENTRY(type,size,ptr1)
#define USE_TCACHE 1
#if USE_TCACHE
-#define TCACHE_SHIFT 4
/* we want 64 entries */
-#define MAX_TCACHE_SIZE (1024 - (1 << TCACHE_SHIFT))
-#define TCACHE_IDX ((MAX_TCACHE_SIZE >> TCACHE_SHIFT)+1)
-#define size2tidx(bytes) (((bytes)+(1<<TCACHE_SHIFT)-1)>>TCACHE_SHIFT)
+#define MAX_TCACHE_SIZE (MALLOC_ALIGNMENT * 63)
+#define TCACHE_IDX ((MAX_TCACHE_SIZE / MALLOC_ALIGNMENT) + 1)
+#define size2tidx(bytes) (((bytes) + MALLOC_ALIGNMENT - 1) / MALLOC_ALIGNMENT)
/* Rounds up, so...
idx 0 bytes 0
&& tcache.initted == 1)
{
void *ent;
- size_t tc_bytes = tc_idx << TCACHE_SHIFT;
+ size_t tc_bytes = tc_idx * MALLOC_ALIGNMENT;
size_t tc_ibytes;
size_t total_bytes;
int i;
#if USE_TCACHE
{
- int tc_idx = size2tidx (size - SIZE_SZ*2);
+ int tc_idx = size2tidx (size - SIZE_SZ);
if (size < MAX_TCACHE_SIZE
&& tcache.counts[tc_idx] < TCACHE_FILL_COUNT
#include <unistd.h>
#include <sys/mman.h>
-/* Build like this:
+/* This module is a stand-alone control program for malloc's internal
+ trace buffer. It is intended to be preloaded like this:
- gcc -shared -fpic mtrace-ctl.c -o /tmp/mtrace-ctl.so ../../glibc.build/libc.so
+ LD_PRELOAD=/usr/lib/libmtracectl.so ./myprog
- Invoke like this:
+ This module uses the following environment variables:
- LD_PRELOAD=/tmp/mtrace-ctl.so ./myprog
+ MTRACE_CTL_COUNT - how many records to store (default: 1000). Each
+ record is 32 bytes, and the entire buffer is mmap'd at once. If
+ the buffer isn't big enough, it will overwrite early records with
+ newer ones. The total number of trace records is reported in the
+ output file so that a larger buffer may be allocated on future runs.
+
+ MTRACE_CTL_FILE - the output file name (default:
+ /tmp/mtrace-$$.out). Note that the default is per-pid but there is
+ no way to specify a per-pid pattern via this environment variable.
+
+ The output file will contain a header that says how many trace
+ records were seen (which is usually more or less than the trace
+ buffer size). The trace buffer is then dumped one entry per line.
*/
t->path_munmap ? 'U' : '-',
t->path_m_f_realloc ? 'R' : '-',
t->path_hook ? 'H' : '-',
- (long long unsigned int) t->ptr1,
+ (long long unsigned int) (size_t) t->ptr1,
(long long unsigned int) t->size,
- (long long unsigned int) t->ptr2);
+ (long long unsigned int) (size_t) t->ptr2);
break;
}
}
#define C_NTHREADS 10
#define C_START_THREAD 11
-static __inline__ int64_t rdtsc_s(void)
+#ifdef x86_64
+
+#define ticks_t int64_t
+
+static __inline__ ticks_t rdtsc_s(void)
{
unsigned a, d;
asm volatile("cpuid" ::: "%rax", "%rbx", "%rcx", "%rdx");
return ((unsigned long)a) | (((unsigned long)d) << 32);
}
-static __inline__ int64_t rdtsc_e(void)
+static __inline__ ticks_t rdtsc_e(void)
{
unsigned a, d;
asm volatile("rdtscp" : "=a" (a), "=d" (d));
return ((unsigned long)a) | (((unsigned long)d) << 32);
}
-static int64_t diff_timeval (struct timeval e, struct timeval s)
+#else
+
+#define ticks_t int32_t
+
+static __inline__ ticks_t rdtsc_s(void)
+{
+ unsigned a, d;
+ asm volatile("cpuid" ::: "%ax", "%bx", "%cx", "%dx");
+ asm volatile("rdtsc" : "=a" (a), "=d" (d));
+ return ((unsigned long)a) | (((unsigned long)d) << 16);
+}
+
+static __inline__ ticks_t rdtsc_e(void)
+{
+ unsigned a, d;
+ asm volatile("rdtscp" : "=a" (a), "=d" (d));
+ asm volatile("cpuid" ::: "%ax", "%bx", "%cx", "%dx");
+ return ((unsigned long)a) | (((unsigned long)d) << 16);
+}
+
+#endif
+
+static ticks_t diff_timeval (struct timeval e, struct timeval s)
{
- int64_t usec;
+ ticks_t usec;
if (e.tv_usec < s.tv_usec)
usec = (e.tv_usec + 1000000 - s.tv_usec) + (e.tv_sec-1 - s.tv_sec)*1000000;
else
static char cbuf[NCBUF][30];
static int ci = 0;
-char *comma(int64_t x)
+char *comma(ticks_t x)
{
char buf[30], *bs, *bd;
int l, i, idx;
bs = buf;
bd = cbuf[idx];
- sprintf(buf, "%lld", x);
+ sprintf(buf, "%lld", (long long int)x);
l = strlen(buf);
i = l;
while (*bs)
static size_t n_data;
static pthread_mutex_t stat_mutex = PTHREAD_MUTEX_INITIALIZER;
-int64_t malloc_time = 0, malloc_count = 0;
-int64_t calloc_time = 0, calloc_count = 0;
-int64_t realloc_time = 0, realloc_count = 0;
-int64_t free_time = 0, free_count = 0;
+ticks_t malloc_time = 0, malloc_count = 0;
+ticks_t calloc_time = 0, calloc_count = 0;
+ticks_t realloc_time = 0, realloc_count = 0;
+ticks_t free_time = 0, free_count = 0;
pthread_mutex_t stop_mutex = PTHREAD_MUTEX_INITIALIZER;
int threads_done = 0;
//#define dprintf printf
-#define dprintf(...) 1
+#define dprintf(...) (void)1
//#define mprintf printf
-#define mprintf(...) 1
+//#define MDEBUG 1
+#define mprintf(...) (void)1
#define myabort() my_abort_2(me, __LINE__)
+void
my_abort_2 (pthread_t me, int line)
{
fprintf(stderr, "Abort thread %d at line %d\n", (int)me, line);
{
char *p = (char *)ptr;
int i;
- size_t sz;
if (!p)
return;
- // sz = *((size_t *)ptr-1) & ~7;
- // fprintf(stderr, "wmem: %p size %x csize %x\n", ptr,
- // count, sz);
- // if (sz < 4*sizeof(size_t))
- // abort();
for (i=0; i<count; i+=8)
p[i] = 0x11;
}
pthread_t me = pthread_self ();
size_t p1, p2, sz;
unsigned char *cp = my_data_v;
- int64_t my_malloc_time = 0, my_malloc_count = 0;
- int64_t my_calloc_time = 0, my_calloc_count = 0;
- int64_t my_realloc_time = 0, my_realloc_count = 0;
- int64_t my_free_time = 0, my_free_count = 0;
- int64_t stime;
+ ticks_t my_malloc_time = 0, my_malloc_count = 0;
+ ticks_t my_calloc_time = 0, my_calloc_count = 0;
+ ticks_t my_realloc_time = 0, my_realloc_count = 0;
+ ticks_t my_free_time = 0, my_free_count = 0;
+ ticks_t stime;
+#ifdef MDEBUG
volatile void *tmp;
+#endif
while (1)
{
myabort();
stime = rdtsc_s();
Q1;
+#ifdef MDEBUG
tmp = ptrs[p1];
+#endif
ptrs[p2] = realloc ((void *)ptrs[p1], sz);
mprintf("%p = relloc(%p,%lx)\n", ptrs[p2], tmp,sz);
Q2;
static pthread_t *thread_ids;
void *
-my_malloc (char *msg, int size, unsigned char **cp, size_t *psz, size_t count)
+my_malloc (const char *msg, int size, unsigned char **cp, size_t *psz, size_t count)
{
void *rv;
if (psz)
void
malloc_scan_callback (void *ptr, size_t length, int type)
{
- printf("%s: ptr %p length %llx\n", scan_names[type], ptr, length);
+ printf("%s: ptr %p length %llx\n", scan_names[type], ptr, (long long)length);
}
#define MY_ALLOC(T, psz) \
int
main(int argc, char **argv)
{
- int64_t start;
- int64_t end;
- int64_t usec;
+ ticks_t start=0;
+ ticks_t end;
+ ticks_t usec;
struct timeval tv_s, tv_e;
int fd;
struct stat statb;
unsigned char *cp;
int thread_idx = 0;
int i;
- size_t n_threads;
+ size_t n_threads = 0;
size_t idx;
struct rusage res_start, res_end;
printf("%s usec wall time\n", comma(usec));
usec = diff_timeval (res_end.ru_utime, res_start.ru_utime);
- printf("%s usec across %d thread%s\n", comma(usec), n_threads, n_threads == 1 ? "" : "s");
+ printf("%s usec across %d thread%s\n", comma(usec), (int)n_threads, n_threads == 1 ? "" : "s");
printf("%s Kb Max RSS (%s -> %s)\n",
comma(res_end.ru_maxrss - res_start.ru_maxrss),
comma(res_start.ru_maxrss), comma(res_end.ru_maxrss));
}
#endif
+#if 0
/* This will fail (crash) for system glibc but that's OK. */
__malloc_scan_chunks(malloc_scan_callback);
malloc_info (0, stdout);
+#endif
-#if 1
+#if 0
/* ...or report them as used. */
for (idx=0; idx<n_ptrs; idx++)
if (ptrs[idx])