@@ -133,13 +133,18 @@ EmpiricalData::EmpiricalData(size_t seed, const absl::Span<const Entry> weights,
133133 }
134134
135135 SnapshotLiveObjects ();
136+
137+ for (auto & s : state_) {
138+ for (size_t i = 0 ; i < s.objs .size (); ++i) {
139+ s.objs_indices_after_recording .push_back ({.born = false , .index = i});
140+ }
141+ }
136142}
137143
138144EmpiricalData::~EmpiricalData () {
139145 for (auto & s : state_) {
140- const size_t size = s.size ;
141146 for (auto p : s.objs ) {
142- dealloc_ (p, size);
147+ dealloc_ (p, s. size );
143148 }
144149 }
145150}
@@ -173,6 +178,7 @@ void EmpiricalData::RecordBirth(const size_t i) {
173178 birth_or_death_.push_back (true );
174179 birth_or_death_sizes_.push_back (i);
175180 SizeState& s = state_[i];
181+ birth_or_death_actual_sizes_.push_back (s.size );
176182 death_sampler_.AdjustWeight (i, s.death_rate );
177183 num_allocated_recorded_++;
178184 bytes_allocated_recorded_ += s.size ;
@@ -181,13 +187,14 @@ void EmpiricalData::RecordBirth(const size_t i) {
181187 // when building the trace we can just push nullptr to keep the length of live
182188 // object lists consistent with what it should have been after a true birth.
183189 s.objs .push_back (nullptr );
190+ s.objs_indices_after_recording .push_back (
191+ {.born = true , .index = birth_object_index_});
192+ ++birth_object_index_;
184193}
185194
186- void * EmpiricalData::ReplayBirth (const size_t i) {
187- SizeState& s = state_[i];
188- const size_t size = s.size ;
195+ void * EmpiricalData::ReplayBirth (const size_t size) {
189196 void * p = alloc_ (size);
190- s. objs . push_back (p) ;
197+ *birth_pointers_[birth_object_index_] = p ;
191198 return p;
192199}
193200
@@ -196,21 +203,22 @@ void EmpiricalData::RecordDeath(const size_t i) {
196203 SizeState& s = state_[i];
197204 CHECK (!s.objs .empty ());
198205 birth_or_death_sizes_.push_back (i);
206+ birth_or_death_actual_sizes_.push_back (s.size );
199207 auto to_free = absl::uniform_int_distribution<int >(
200208 0 , std::max (0 , static_cast <int >(s.objs .size ()) - 1 ))(rng_);
201209 death_sampler_.AdjustWeight (i, -s.death_rate );
202210 s.objs [to_free] = s.objs .back ();
203211 s.objs .pop_back ();
204- death_objects_.push_back (to_free);
212+
213+ death_obj_indices_.push_back (s.objs_indices_after_recording [to_free]);
214+ s.objs_indices_after_recording [to_free] =
215+ s.objs_indices_after_recording .back ();
216+ s.objs_indices_after_recording .pop_back ();
205217}
206218
207- void EmpiricalData::ReplayDeath (const size_t i, uint64_t index) {
208- SizeState& s = state_[i];
209- CHECK (!s.objs .empty ());
210- void * p = s.objs [index];
211- s.objs [index] = s.objs .back ();
212- s.objs .pop_back ();
213- dealloc_ (p, s.size );
219+ void EmpiricalData::ReplayDeath (const size_t size) {
220+ void * p = death_objects_[death_object_index_];
221+ dealloc_ (p, size);
214222}
215223
216224void EmpiricalData::RecordNext () {
@@ -230,29 +238,43 @@ void EmpiricalData::RecordNext() {
230238}
231239
232240void EmpiricalData::ReplayTrace () {
233- for (birth_or_death_index_ = 0 , death_object_index_ = 0 ;
234- birth_or_death_index_ < birth_or_death_.size ();
235- ++birth_or_death_index_) {
236- bool do_birth = birth_or_death_[birth_or_death_index_];
241+ for (birth_object_index_ = 0 , death_object_index_ = 0 ;
242+ birth_object_index_ + death_object_index_ < birth_or_death_.size ();) {
243+ size_t birth_or_death_index = birth_object_index_ + death_object_index_;
244+ bool do_birth = birth_or_death_[birth_or_death_index];
245+ size_t size = birth_or_death_actual_sizes_[birth_or_death_index];
246+
237247 if (do_birth) {
238- void * allocated =
239- ReplayBirth (birth_or_death_sizes_[birth_or_death_index_]);
248+ void * allocated = ReplayBirth (size);
240249 TouchAllocated (allocated);
250+ ++birth_object_index_;
241251 } else {
242- ReplayDeath (birth_or_death_sizes_[birth_or_death_index_],
243- death_objects_[death_object_index_]);
244- __builtin_prefetch (death_object_pointers_[death_object_index_], /* rw=*/ 1 ,
245- /* locality*/ 3 );
252+ ReplayDeath (size);
246253 ++death_object_index_;
247254 }
248255 }
249256 total_num_allocated_ += num_allocated_recorded_;
250257 total_bytes_allocated_ += bytes_allocated_recorded_;
251258}
252259
260+ void EmpiricalData::PrepareNextReplay () {
261+ for (auto & s : state_) {
262+ for (const auto & update : s.obj_update ) {
263+ s.objs [update.to ] = s.objs [update.from ];
264+ }
265+ for (const auto & update : s.birth_update ) {
266+ s.objs [update.to ] = birth_objects_[update.from ];
267+ }
268+ for (const auto & update : s.death_update ) {
269+ death_objects_[update.to ] = s.objs [update.from ];
270+ }
271+ }
272+ }
273+
253274void EmpiricalData::SnapshotLiveObjects () {
254275 for (const auto & s : state_) {
255- snapshot_state_.push_back ({s.size , s.death_rate , s.objs });
276+ snapshot_state_.push_back (
277+ {s.size , s.death_rate , s.objs , s.objs_indices_after_recording });
256278 }
257279}
258280
@@ -262,53 +284,46 @@ void EmpiricalData::RestoreSnapshot() {
262284 }
263285}
264286
265- void EmpiricalData::ReserveSizeClassObjects () {
266- // Keep a running sum and high water mark for the delta in the size class
267- // object arrays.
268- std::vector< int32_t > max_object_size_delta (state_ .size (), 0 );
269- std::vector< int32_t > cur_object_size_delta (state_. size (), 0 );
270- for (int i = 0 ; i < birth_or_death_.size (); i++ ) {
271- auto size_class = birth_or_death_sizes_[i];
287+ void EmpiricalData::BuildUpdateVectors () {
288+ birth_pointers_. resize (birth_object_index_);
289+ birth_objects_. resize (birth_object_index_);
290+ death_objects_. resize (death_obj_indices_ .size ());
291+
292+ for (size_t i = 0 , death_index = 0 ; i < birth_or_death_.size (); ++i ) {
293+ // Skip births
272294 if (birth_or_death_[i]) {
273- cur_object_size_delta[size_class]++;
274- max_object_size_delta[size_class] = std::max (
275- max_object_size_delta[size_class], cur_object_size_delta[size_class]);
276- } else {
277- cur_object_size_delta[size_class]--;
295+ continue ;
278296 }
279- }
280297
281- for (int i = 0 ; i < state_.size (); i++) {
282- state_[i].objs .reserve (state_[i].objs .size () + max_object_size_delta[i]);
298+ const ObjectIndex& death_obj_index = death_obj_indices_[death_index];
299+ if (!death_obj_index.born ) {
300+ SizeState& s = state_[birth_or_death_sizes_[i]];
301+ size_t from = death_obj_index.index ;
302+ size_t to = death_index;
303+ s.death_update .push_back ({.from = from, .to = to});
304+ death_objects_[to] = s.objs [from];
305+ } else {
306+ size_t birth_index = death_obj_index.index ;
307+ birth_pointers_[birth_index] = &death_objects_[death_index];
308+ }
309+ ++death_index;
283310 }
284- }
285311
286- void EmpiricalData::BuildDeathObjectPointers () {
287- constexpr uint32_t kPrefetchDistance = 64 ;
288-
289- // This is a bit ugly but because the below code can create pointers past the
290- // end of the current objects arrays we need to first need to reserve their
291- // capacity at the maximum capacity they will ever hit to ensure they won't
292- // grow and possibly be reallocated. They will never grow beyond the size
293- // calculated by this function.
294- ReserveSizeClassObjects ();
295-
296- // The easiest way to compute the prefetch objects is to get the pointers
297- // corresponding to each death_objects_[] and then rotating the array so the
298- // N + prefetch_distance object is stored at index N.
299- uint32_t death_index = 0 ;
300- for (int i = 0 ; i < birth_or_death_.size (); i++) {
301- // Skip births
302- if (birth_or_death_[i]) {
303- continue ;
312+ for (SizeState& s : state_) {
313+ for (size_t i = 0 ; i < s.objs_indices_after_recording .size (); ++i) {
314+ if (!s.objs_indices_after_recording [i].born ) {
315+ size_t from = s.objs_indices_after_recording [i].index ;
316+ size_t to = i;
317+ if (from != to) {
318+ s.obj_update .push_back ({.from = from, .to = to});
319+ }
320+ } else {
321+ size_t birth_index = s.objs_indices_after_recording [i].index ;
322+ birth_pointers_[birth_index] = &birth_objects_[birth_index];
323+ s.birth_update .push_back ({.from = birth_index, .to = i});
324+ }
304325 }
305- SizeState& s = state_[birth_or_death_sizes_[i]];
306- death_object_pointers_.push_back (s.objs .data () +
307- death_objects_[death_index++]);
308326 }
309- std::rotate (death_object_pointers_.begin (),
310- death_object_pointers_.begin () + kPrefetchDistance ,
311- death_object_pointers_.end ());
312327}
313328
314329void EmpiricalData::RecordRepairToSnapshotState () {
0 commit comments