Fix prof_realloc() regression.
Mostly revert the prof_realloc() changes in498856f44a
(Move slabs out of chunks.) so that prof_free_sampled_object() is called when appropriate. Leave the prof_tctx_[re]set() optimization in place, but add an assertion to verify that all eight cases are correctly handled. Add a comment to make clear the code ordering, so that the regression originally fixed byea8d97b897
(Fix prof_{malloc,free}_sample_object() call order in prof_realloc().) is not repeated. This resolves #499.
This commit is contained in:
@@ -369,6 +369,7 @@ prof_boot0
|
||||
prof_boot1
|
||||
prof_boot2
|
||||
prof_bt_count
|
||||
prof_cnt_all
|
||||
prof_dump_header
|
||||
prof_dump_open
|
||||
prof_free
|
||||
|
@@ -48,11 +48,12 @@ prof_tctx_t *prof_lookup(tsd_t *tsd, prof_bt_t *bt);
|
||||
#ifdef JEMALLOC_JET
|
||||
size_t prof_tdata_count(void);
|
||||
size_t prof_bt_count(void);
|
||||
const prof_cnt_t *prof_cnt_all(void);
|
||||
typedef int (prof_dump_open_t)(bool, const char *);
|
||||
extern prof_dump_open_t *prof_dump_open;
|
||||
typedef bool (prof_dump_header_t)(tsdn_t *, bool, const prof_cnt_t *);
|
||||
extern prof_dump_header_t *prof_dump_header;
|
||||
void prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes,
|
||||
uint64_t *accumobjs, uint64_t *accumbytes);
|
||||
#endif
|
||||
void prof_idump(tsdn_t *tsdn);
|
||||
bool prof_mdump(tsd_t *tsd, const char *filename);
|
||||
|
@@ -194,30 +194,39 @@ prof_realloc(tsd_t *tsd, extent_t *extent, const void *ptr, size_t usize,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following code must differentiate among eight possible cases,
|
||||
* based on three boolean conditions.
|
||||
*/
|
||||
sampled = ((uintptr_t)tctx > (uintptr_t)1U);
|
||||
old_sampled = ((uintptr_t)old_tctx > (uintptr_t)1U);
|
||||
moved = (ptr != old_ptr);
|
||||
|
||||
/*
|
||||
* The following block must only execute if this is a non-moving
|
||||
* reallocation, because for moving reallocation the old allocation will
|
||||
* be deallocated via a separate call.
|
||||
*/
|
||||
if (unlikely(old_sampled) && !moved)
|
||||
prof_free_sampled_object(tsd, old_usize, old_tctx);
|
||||
|
||||
if (unlikely(sampled)) {
|
||||
prof_malloc_sample_object(tsd_tsdn(tsd), extent, ptr, usize,
|
||||
tctx);
|
||||
} else if (moved) {
|
||||
prof_tctx_set(tsd_tsdn(tsd), extent, ptr, usize,
|
||||
(prof_tctx_t *)(uintptr_t)1U);
|
||||
} else if (unlikely(old_sampled))
|
||||
} else if (unlikely(old_sampled)) {
|
||||
/*
|
||||
* prof_tctx_set() would work for the !moved case as well, but
|
||||
* prof_tctx_reset() is slightly cheaper, and the proper thing
|
||||
* to do here in the presence of explicit knowledge re: moved
|
||||
* state.
|
||||
*/
|
||||
prof_tctx_reset(tsd_tsdn(tsd), extent, ptr, tctx);
|
||||
} else {
|
||||
assert((uintptr_t)prof_tctx_get(tsd_tsdn(tsd), extent, ptr) ==
|
||||
(uintptr_t)1U);
|
||||
}
|
||||
|
||||
/*
|
||||
* The prof_free_sampled_object() call must come after the
|
||||
* prof_malloc_sample_object() call, because tctx and old_tctx may be
|
||||
* the same, in which case reversing the call order could cause the tctx
|
||||
* to be prematurely destroyed as a side effect of momentarily zeroed
|
||||
* counters.
|
||||
*/
|
||||
if (unlikely(old_sampled)) {
|
||||
prof_free_sampled_object(tsd, old_usize, old_tctx);
|
||||
}
|
||||
}
|
||||
|
||||
JEMALLOC_ALWAYS_INLINE void
|
||||
|
Reference in New Issue
Block a user