Release `graveyard_.init_mu` early in `SampleRecorder<T>::PopDead` right before `sample->PrepareForSampling(...)`.

Holding the global `graveyard_.init_mu` during the full `PrepareForSampling(...)` execution (which unwinds stack traces and records timestamps) causes heavy lock contention across threads when creating/destroying hashtables frequently. Releasing `graveyard_.init_mu` early while keeping `sample->init_mu` allows multiple threads to perform sampling setup in parallel.

PiperOrigin-RevId: 958747232
Change-Id: I9fd5a09e7874f7e8ec7b289ab9d2da479e1761fd
diff --git a/absl/profiling/internal/sample_recorder.h b/absl/profiling/internal/sample_recorder.h
index 88a4b27..c0e4ebc 100644
--- a/absl/profiling/internal/sample_recorder.h
+++ b/absl/profiling/internal/sample_recorder.h
@@ -168,7 +168,7 @@
 template <typename T>
 template <typename... Targs>
 T* SampleRecorder<T>::PopDead(Targs... args) {
-  absl::MutexLock graveyard_lock(graveyard_.init_mu);
+  absl::ReleasableMutexLock graveyard_lock(graveyard_.init_mu);
 
   // The list is circular, so eventually it collapses down to
   //   graveyard_.dead == &graveyard_
@@ -178,6 +178,11 @@
 
   absl::MutexLock sample_lock(sample->init_mu);
   graveyard_.dead = sample->dead;
+  // Release the global graveyard lock early, before the potentially slow
+  // preparation.
+  graveyard_lock.Release();
+  // Prepare the sample while still holding the per-sample lock.
+  // `Iterate` will wait for the lock to be released.
   sample->dead = nullptr;
   sample->PrepareForSampling(std::forward<Targs>(args)...);
   return sample;