@@ -130,10 +130,11 @@ static char *trim_whitespace(char *line) {
130
130
131
131
static int64_t parse_number (char **ptr, int line_num, int base) {
132
132
*ptr = trim_whitespace (*ptr);
133
+ char *line = *ptr;
133
134
134
135
char *new_ptr;
135
- int64_t n = strtoll (*ptr , &new_ptr, base);
136
- ba_replay_assert (n >= 0 , " malformed trace" , *ptr , line_num);
136
+ int64_t n = strtoll (line , &new_ptr, base);
137
+ ba_replay_assert (n >= 0 , " malformed trace" , line , line_num);
137
138
*ptr = new_ptr;
138
139
return n;
139
140
}
@@ -147,30 +148,35 @@ static uint64_t parse_uint64(char **ptr, int line_num) {
147
148
}
148
149
149
150
static string parse_token (char **ptr, int line_num) {
150
- char *line = trim_whitespace (*ptr);
151
+ *ptr = trim_whitespace (*ptr);
152
+ char *line = *ptr;
151
153
152
154
// parse the first token, which represents the traced function
153
155
char token[64 ];
154
- int r = sscanf (line , " %64s" , token);
156
+ int r = sscanf (*ptr , " %64s" , token);
155
157
ba_replay_assert (r == 1 , " malformed trace" , line, line_num);
156
158
*ptr += strlen (token);
157
159
return string (token);
158
160
}
159
161
160
162
static block_allocator::blockpair parse_blockpair (char **ptr, int line_num) {
161
- char *line = trim_whitespace (*ptr);
163
+ *ptr = trim_whitespace (*ptr);
164
+ char *line = *ptr;
165
+
162
166
uint64_t offset, size;
163
167
int bytes_read;
164
168
int r = sscanf (line, " [%" PRIu64 " %" PRIu64 " ]%n" , &offset, &size, &bytes_read);
165
- ba_replay_assert (r == 3 , " malformed trace" , line, line_num);
169
+ ba_replay_assert (r == 2 , " malformed trace" , line, line_num);
166
170
*ptr += bytes_read;
167
171
return block_allocator::blockpair (offset, size);
168
172
}
169
173
170
174
static char *strip_newline (char *line, bool *found) {
171
175
char *ptr = strchr (line, ' \n ' );
172
176
if (ptr != nullptr ) {
173
- *found = true ;
177
+ if (found != nullptr ) {
178
+ *found = true ;
179
+ }
174
180
*ptr = ' \0 ' ;
175
181
}
176
182
return line;
@@ -192,7 +198,7 @@ static char *read_trace_line(FILE *file) {
192
198
}
193
199
}
194
200
std::string s = ss.str ();
195
- return toku_strdup (s.c_str ());
201
+ return s. size () ? toku_strdup (s.c_str ()) : nullptr ;
196
202
}
197
203
198
204
static vector<string> canonicalize_trace_from (FILE *file) {
@@ -209,6 +215,7 @@ static vector<string> canonicalize_trace_from(FILE *file) {
209
215
// allocated offset -> allocation seq num
210
216
//
211
217
uint64_t allocation_seq_num = 0 ;
218
+ static const uint64_t ASN_NONE = (uint64_t ) -1 ;
212
219
typedef map<uint64_t , uint64_t > offset_seq_map;
213
220
214
221
// raw allocator id -> offset_seq_map that tracks its allocations
@@ -232,6 +239,19 @@ static vector<string> canonicalize_trace_from(FILE *file) {
232
239
allocator_ids[allocator_id] = allocator_id_seq_num;
233
240
ss << fn << ' ' << allocator_id_seq_num << ' ' << trim_whitespace (ptr) << std::endl;
234
241
allocator_id_seq_num++;
242
+
243
+ // For each blockpair created by this traceline, add its offset to the offset seq map
244
+ // with asn ASN_NONE so that later canonicalizations of `free' know whether to write
245
+ // down the asn or the raw offset.
246
+ //
247
+ // First, read passed the reserve / alignment values.
248
+ (void ) parse_uint64 (&ptr, line_num);
249
+ (void ) parse_uint64 (&ptr, line_num);
250
+ offset_seq_map *map = &offset_to_seq_num_maps[allocator_id];
251
+ while (*trim_whitespace (ptr) != ' \0 ' ) {
252
+ const block_allocator::blockpair bp = parse_blockpair (&ptr, line_num);
253
+ (*map)[bp.offset ] = ASN_NONE;
254
+ }
235
255
} else if (allocator_ids.count (allocator_id) > 0 ) {
236
256
// this allocator is part of the canonical trace
237
257
uint64_t canonical_allocator_id = allocator_ids[allocator_id];
@@ -259,8 +279,14 @@ static vector<string> canonicalize_trace_from(FILE *file) {
259
279
const uint64_t asn = (*map)[offset];
260
280
map->erase (offset);
261
281
262
- // translate `free(offset)' to `free(asn)'
263
- ss << fn << ' ' << canonical_allocator_id << ' ' << asn << std::endl;
282
+ // if there's an asn, then a corresponding ba_trace_alloc occurred and we should
283
+ // write `free(asn)'. otherwise, the blockpair was initialized from create_from_blockpairs
284
+ // and we write the original offset.
285
+ if (asn != ASN_NONE) {
286
+ ss << " ba_trace_free_asn" << ' ' << canonical_allocator_id << ' ' << asn << std::endl;
287
+ } else {
288
+ ss << " ba_trace_free_offset" << ' ' << canonical_allocator_id << ' ' << offset << std::endl;
289
+ }
264
290
} else if (fn == " ba_trace_destroy" ) {
265
291
// Remove this allocator from both maps
266
292
allocator_ids.erase (allocator_id);
@@ -293,6 +319,7 @@ static void replay_canonicalized_trace(const vector<string> &canonicalized_trace
293
319
line_num++;
294
320
295
321
char *line = toku_strdup (it->c_str ());
322
+ line = strip_newline (line, nullptr );
296
323
297
324
if (verbose) {
298
325
printf (" playing canonical trace line #%d: %s" , line_num, line);
@@ -318,7 +345,7 @@ static void replay_canonicalized_trace(const vector<string> &canonicalized_trace
318
345
" corrupted canonical trace: bad create fn" , line, line_num);
319
346
vector<block_allocator::blockpair> pairs;
320
347
while (*trim_whitespace (ptr) != ' \0 ' ) {
321
- block_allocator::blockpair bp = parse_blockpair (&ptr, line_num);
348
+ const block_allocator::blockpair bp = parse_blockpair (&ptr, line_num);
322
349
pairs.push_back (bp);
323
350
}
324
351
ba->create_from_blockpairs (reserve_at_beginning, alignment, &pairs[0 ], pairs.size ());
@@ -333,6 +360,7 @@ static void replay_canonicalized_trace(const vector<string> &canonicalized_trace
333
360
334
361
block_allocator *ba = (*allocator_map)[allocator_id];
335
362
if (fn == " ba_trace_alloc" ) {
363
+ // replay an `alloc' whose result will be associated with a certain asn
336
364
const uint64_t size = parse_uint64 (&ptr, line_num);
337
365
const uint64_t heat = parse_uint64 (&ptr, line_num);
338
366
const uint64_t asn = parse_uint64 (&ptr, line_num);
@@ -342,14 +370,19 @@ static void replay_canonicalized_trace(const vector<string> &canonicalized_trace
342
370
uint64_t offset;
343
371
ba->alloc_block (size, heat, &offset);
344
372
seq_num_to_offset[asn] = offset;
345
- } else if (fn == " ba_trace_free" ) {
373
+ } else if (fn == " ba_trace_free_asn" ) {
374
+ // replay a `free' on a block whose offset is the result of an alloc with an asn
346
375
const uint64_t asn = parse_uint64 (&ptr, line_num);
347
376
ba_replay_assert (seq_num_to_offset.count (asn) == 1 ,
348
377
" corrupted canonical trace: double free (asn unused)" , line, line_num);
349
378
350
- uint64_t offset = seq_num_to_offset[asn];
379
+ const uint64_t offset = seq_num_to_offset[asn];
351
380
ba->free_block (offset);
352
381
seq_num_to_offset.erase (asn);
382
+ } else if (fn == " ba_trace_free_offset" ) {
383
+ // replay a `free' on a block whose offset was explicitly set during a create_from_blockpairs
384
+ const uint64_t offset = parse_uint64 (&ptr, line_num);
385
+ ba->free_block (offset);
353
386
} else if (fn == " ba_trace_destroy" ) {
354
387
// TODO: Clean this up - we won't be able to catch no such allocator errors
355
388
// if we don't actually not the destroy. We only do it here so that the caller
0 commit comments