From d35e84028cdade623838130dd4df3d0b22a13446 Mon Sep 17 00:00:00 2001 From: DJ Delorie Date: Fri, 19 Feb 2016 17:10:24 -0500 Subject: Add trace2c script Usage: trace2c /tmp/mtrace.out > sample.c Converts a trace file to a compilable program that "somewhat" reflects the same malloc workload as the program which was traced. --- malloc/trace2c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 malloc/trace2c (limited to 'malloc') diff --git a/malloc/trace2c b/malloc/trace2c new file mode 100644 index 0000000000..8d3eb743d8 --- /dev/null +++ b/malloc/trace2c @@ -0,0 +1,192 @@ +#!/usr/bin/perl +# -*- perl -*- + +# Arrays starting with c_ are source code to be emitted later + +$last_idx = 0; +sub ptr2idx { + my ($ptr) = @_; + if ($ptr2idx{$ptr}) { + return $ptr2idx{$ptr}; + } + # we intentionally never return zero + $last_idx ++; + $ptr2idx{$ptr} = $last_idx; + push (@c_ptrvars, "volatile void *p$last_idx;"); + return $last_idx; +} + +$sync_counter = 0; + +# thread 2 waits for thread 1 +sub sync { + my ($thread1, $thread2) = @_; + if (! $sync_init{$thread1}) { + push (@c_sync, "volatile char sync_${thread1} = 0;"); + $sync_init{$thread1} = 1; + } + $sync_counter ++; + push (@{$c_threads{$thread1}}, " sync_${thread1} = $sync_counter;"); + push (@{$c_threads{$thread1}}, " __sync_synchronize ();"); + push (@{$c_threads{$thread2}}, " while (sync_${thread1} < $sync_counter)"); + push (@{$c_threads{$thread2}}, " __sync_synchronize ();"); +} + +sub acq_ptr { + my ($ptr) = @_; + if ($owner{$ptr} && $owner{$ptr} ne $thread) { + &sync ($owner{$ptr}, $thread); + } + $owner{$ptr} = $thread; +} + +$master_thread = undef; + +$line = 0; +while (<>) { + $line ++; + next if /^threadid/; + next if /out of/; + + ($thread, $type, $path, $ptr1, $size, $ptr2) = split(' '); + $size = hex($size); + $idx1 = &ptr2idx($ptr1); + $idx2 = &ptr2idx($ptr2); + + if (! $master_thread) { + $master_thread = $thread; + } elsif (! $threads{$thread}) { + # make new thread start at the "right" time + &sync ($master_thread, $thread); + } + + $threads{$thread} = 1; + + if ($type eq "malloc") { + # In case another thread needs to free this chunk first + &acq_ptr($ptr2); + push (@{$c_threads{$thread}}, sprintf (" p%d = malloc (%d); // %d %s", $idx2, $size, $line, $ptr2)); + push (@{$c_threads{$thread}}, sprintf (" wmem (p%d, %d);", $idx2, $size)); + $leak{$ptr2} = $size; + $owner{$ptr2} = $thread; + $valid{$ptr2} = 1; + } + + if ($type eq "calloc") { + # In case another thread needs to free this chunk first + &acq_ptr($ptr2); + push (@{$c_threads{$thread}}, sprintf (" p%d = calloc (%d,1); // %d %s", $idx2, $size, $line, $ptr2)); + push (@{$c_threads{$thread}}, sprintf (" wmem (p%d, %d);", $idx2, $size)); + $leak{$ptr2} = $size; + $owner{$ptr2} = $thread; + $valid{$ptr2} = 1; + } + + if ($type eq "free") { + if ($ptr1 =~ /^0+$/) { + push (@{$c_threads{$thread}}, sprintf(" free (NULL);")); + } elsif ($valid{$ptr1}) { + # if it was allocated in another thread + &acq_ptr($ptr1); + push (@{$c_threads{$thread}}, sprintf(" free ((void *)p%d); // %d %s", $idx1, $line, $ptr1)); + delete $leak{$ptr1}; + $valid{$ptr1} = 0; + } else { + push (@{$c_threads{$thread}}, sprintf(" // free (p%s) (invalid ptr $ptr1 in thread $thread)", $idx1)); + } + } + + if ($type eq "realloc") { + if ($owner{$ptr1}) { + &acq_ptr($ptr1); + &acq_ptr($ptr2); + push (@{$c_threads{$thread}}, sprintf(" p%d = realloc ((void *)p%d, %d);", $idx2, $idx1, $size)); + push (@{$c_threads{$thread}}, sprintf (" wmem (p%d, %d);", $idx2, $size)); + # ptr1 might be the same as ptr2, so sequence matters + delete $leak{$ptr1}; + $leak{$ptr2} = $size; + $valid{$ptr1} = 0; + $valid{$ptr2} = 1; + } + } +} + +print ' +#include +#include +#include +#include + +static void +wmem (volatile void *ptr, int count) +{ + char *p = (char *)ptr; + int i; + for (i=0; i