Backed out 6 changesets (bug 1582741, bug 1593318, bug 1592625) for causing failures in test_feature_nativeallocations.js CLOSED TREE
authorNoemi Erli <nerli@mozilla.com>
Tue, 12 Nov 2019 23:19:44 +0200
changeset 501654 48f393dfe9ac8843956480c554d6160c5e50a7a8
parent 501653 1a1ba33e1c1e77ebe275e005601189f712f2518f
child 501655 2ea61656154e395c149f6a025cf53f1b0fd2b878
push id114172
push userdluca@mozilla.com
push dateTue, 19 Nov 2019 11:31:10 +0000
treeherdermozilla-inbound@b5c5ba07d3db [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1582741, 1593318, 1592625
milestone72.0a1
backs outfb009d42d01204cd1b2eeb55e8d9ddb82c3c4136
8a685f29970028ba5d40dc2211f73e68647db6b9
308028db97ef66a46d90b1d7adc854eff4389a42
cd7174320d45cc4d43412e9bc667d7a9bcc9559a
b48b1fa02fccc7e29748bc406eb6dcae03996f4e
e9714539ae904f92182379decdbf66d0fcb5c13b
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 6 changesets (bug 1582741, bug 1593318, bug 1592625) for causing failures in test_feature_nativeallocations.js CLOSED TREE Backed out changeset fb009d42d012 (bug 1582741) Backed out changeset 8a685f299700 (bug 1592625) Backed out changeset 308028db97ef (bug 1582741) Backed out changeset cd7174320d45 (bug 1582741) Backed out changeset b48b1fa02fcc (bug 1582741) Backed out changeset e9714539ae90 (bug 1593318)
tools/profiler/core/ProfilerMarkerPayload.cpp
tools/profiler/core/memory_hooks.cpp
tools/profiler/core/memory_hooks.h
tools/profiler/core/platform.cpp
tools/profiler/public/GeckoProfiler.h
tools/profiler/public/ProfilerMarkerPayload.h
tools/profiler/tests/browser/browser.ini
tools/profiler/tests/browser/browser_test_feature_nativeallocations.js
tools/profiler/tests/browser/head.js
tools/profiler/tests/gtest/GeckoProfiler.cpp
tools/profiler/tests/shared-head.js
tools/profiler/tests/xpcshell/head.js
tools/profiler/tests/xpcshell/head_profiler.js
tools/profiler/tests/xpcshell/test_feature_js.js
tools/profiler/tests/xpcshell/test_feature_mainthreadio.js
tools/profiler/tests/xpcshell/test_feature_nativeallocations.js
tools/profiler/tests/xpcshell/test_feature_stackwalking.js
tools/profiler/tests/xpcshell/test_merged_stacks.js
tools/profiler/tests/xpcshell/test_responsiveness.js
tools/profiler/tests/xpcshell/xpcshell.ini
--- a/tools/profiler/core/ProfilerMarkerPayload.cpp
+++ b/tools/profiler/core/ProfilerMarkerPayload.cpp
@@ -935,48 +935,42 @@ void JsAllocationMarkerPayload::StreamPa
   aWriter.StringProperty("coarseType", mCoarseType);
   aWriter.IntProperty("size", mSize);
   aWriter.BoolProperty("inNursery", mInNursery);
 }
 
 BlocksRingBuffer::Length
 NativeAllocationMarkerPayload::TagAndSerializationBytes() const {
   return CommonPropsTagAndSerializationBytes() +
-         BlocksRingBuffer::SumBytes(mSize, mThreadId, mMemoryAddress);
+         BlocksRingBuffer::SumBytes(mSize);
 }
 
 void NativeAllocationMarkerPayload::SerializeTagAndPayload(
     BlocksRingBuffer::EntryWriter& aEntryWriter) const {
   static const DeserializerTag tag = TagForDeserializer(Deserialize);
   SerializeTagAndCommonProps(tag, aEntryWriter);
   aEntryWriter.WriteObject(mSize);
-  aEntryWriter.WriteObject(mMemoryAddress);
-  aEntryWriter.WriteObject(mThreadId);
 }
 
 // static
 UniquePtr<ProfilerMarkerPayload> NativeAllocationMarkerPayload::Deserialize(
     BlocksRingBuffer::EntryReader& aEntryReader) {
   ProfilerMarkerPayload::CommonProps props =
       DeserializeCommonProps(aEntryReader);
   auto size = aEntryReader.ReadObject<int64_t>();
-  auto memoryAddress = aEntryReader.ReadObject<uintptr_t>();
-  auto threadId = aEntryReader.ReadObject<int>();
-  return UniquePtr<ProfilerMarkerPayload>(new NativeAllocationMarkerPayload(
-      std::move(props), size, memoryAddress, threadId));
+  return UniquePtr<ProfilerMarkerPayload>(
+      new NativeAllocationMarkerPayload(std::move(props), size));
 }
 
 void NativeAllocationMarkerPayload::StreamPayload(
     SpliceableJSONWriter& aWriter, const TimeStamp& aProcessStartTime,
     UniqueStacks& aUniqueStacks) const {
   StreamCommonProps("Native allocation", aWriter, aProcessStartTime,
                     aUniqueStacks);
   aWriter.IntProperty("size", mSize);
-  aWriter.IntProperty("memoryAddress", static_cast<int64_t>(mMemoryAddress));
-  aWriter.IntProperty("threadId", mThreadId);
 }
 
 BlocksRingBuffer::Length IPCMarkerPayload::TagAndSerializationBytes() const {
   return CommonPropsTagAndSerializationBytes() +
          BlocksRingBuffer::SumBytes(mOtherPid, mMessageSeqno, mMessageType,
                                     mSide, mDirection, mSync);
 }
 
--- a/tools/profiler/core/memory_hooks.cpp
+++ b/tools/profiler/core/memory_hooks.cpp
@@ -9,17 +9,16 @@
 #include "nscore.h"
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/FastBernoulliTrial.h"
 #include "mozilla/IntegerPrintfMacros.h"
 #include "mozilla/JSONWriter.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/PlatformMutex.h"
 #include "mozilla/ProfilerCounts.h"
 #include "mozilla/ThreadLocal.h"
 
 #include "GeckoProfiler.h"
 #include "prenv.h"
 #include "replace_malloc.h"
 
 #include <ctype.h>
@@ -90,165 +89,16 @@ static void EnsureBernoulliIsInstalled()
   if (!gBernoulli) {
     // This is only installed once. See the gBernoulli definition for more
     // information.
     gBernoulli =
         new FastBernoulliTrial(0.0003, 0x8e26eeee166bc8ca, 0x56820f304a9c9ae0);
   }
 }
 
-// This class provides infallible allocations (they abort on OOM) like
-// mozalloc's InfallibleAllocPolicy, except that memory hooks are bypassed. This
-// policy is used by the HashSet.
-class InfallibleAllocWithoutHooksPolicy {
-  static void ExitOnFailure(const void* aP) {
-    if (!aP) {
-      MOZ_CRASH("Profiler memory hooks out of memory; aborting");
-    }
-  }
-
- public:
-  template <typename T>
-  static T* maybe_pod_malloc(size_t aNumElems) {
-    if (aNumElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
-      return nullptr;
-    }
-    return (T*)gMallocTable.malloc(aNumElems * sizeof(T));
-  }
-
-  template <typename T>
-  static T* maybe_pod_calloc(size_t aNumElems) {
-    return (T*)gMallocTable.calloc(aNumElems, sizeof(T));
-  }
-
-  template <typename T>
-  static T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) {
-    if (aNewSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
-      return nullptr;
-    }
-    return (T*)gMallocTable.realloc(aPtr, aNewSize * sizeof(T));
-  }
-
-  template <typename T>
-  static T* pod_malloc(size_t aNumElems) {
-    T* p = maybe_pod_malloc<T>(aNumElems);
-    ExitOnFailure(p);
-    return p;
-  }
-
-  template <typename T>
-  static T* pod_calloc(size_t aNumElems) {
-    T* p = maybe_pod_calloc<T>(aNumElems);
-    ExitOnFailure(p);
-    return p;
-  }
-
-  template <typename T>
-  static T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) {
-    T* p = maybe_pod_realloc(aPtr, aOldSize, aNewSize);
-    ExitOnFailure(p);
-    return p;
-  }
-
-  template <typename T>
-  static void free_(T* aPtr, size_t aSize = 0) {
-    gMallocTable.free(aPtr);
-  }
-
-  static void reportAllocOverflow() { ExitOnFailure(nullptr); }
-  bool checkSimulatedOOM() const { return true; }
-};
-
-// We can't use mozilla::Mutex because it causes re-entry into the memory hooks.
-// Define a custom implementation here.
-class Mutex : private ::mozilla::detail::MutexImpl {
- public:
-  Mutex()
-      : ::mozilla::detail::MutexImpl(
-            ::mozilla::recordreplay::Behavior::DontPreserve) {}
-
-  void Lock() { ::mozilla::detail::MutexImpl::lock(); }
-  void Unlock() { ::mozilla::detail::MutexImpl::unlock(); }
-};
-
-class MutexAutoLock {
-  MutexAutoLock(const MutexAutoLock&) = delete;
-  void operator=(const MutexAutoLock&) = delete;
-
-  Mutex& mMutex;
-
- public:
-  explicit MutexAutoLock(Mutex& aMutex) : mMutex(aMutex) { mMutex.Lock(); }
-  ~MutexAutoLock() { mMutex.Unlock(); }
-};
-
-//---------------------------------------------------------------------------
-// Tracked allocations
-//---------------------------------------------------------------------------
-
-// The allocation tracker is shared between multiple threads, and is the
-// coordinator for knowing when allocations have been tracked. The mutable
-// internal state is protected by a mutex, and managed by the methods.
-//
-// The tracker knows about all the allocations that we have added to the
-// profiler. This way, whenever any given piece of memory is freed, we can see
-// if it was previously tracked, and we can track its deallocation.
-
-class AllocationTracker {
-  // This type tracks all of the allocations that we have captured. This way, we
-  // can see if a deallocation is inside of this set. We want to provide a
-  // balanced view into the allocations and deallocations.
-  typedef mozilla::HashSet<const void*, mozilla::DefaultHasher<const void*>,
-                           InfallibleAllocWithoutHooksPolicy>
-      AllocationSet;
-
- public:
-  AllocationTracker() : mAllocations(), mMutex() {}
-
-  void AddMemoryAddress(const void* memoryAddress) {
-    MutexAutoLock lock(mMutex);
-    if (!mAllocations.put(memoryAddress)) {
-      MOZ_CRASH("Out of memory while tracking native allocations.");
-    };
-  }
-
-  void Reset() {
-    MutexAutoLock lock(mMutex);
-    mAllocations.clearAndCompact();
-  }
-
-  // Returns true when the memory address is found and removed, otherwise that
-  // memory address is not being tracked and it returns false.
-  bool RemoveMemoryAddressIfFound(const void* memoryAddress) {
-    MutexAutoLock lock(mMutex);
-
-    auto ptr = mAllocations.lookup(memoryAddress);
-    if (ptr) {
-      // The memory was present. It no longer needs to be tracked.
-      mAllocations.remove(ptr);
-      return true;
-    }
-
-    return false;
-  }
-
- private:
-  AllocationSet mAllocations;
-  Mutex mMutex;
-};
-
-static AllocationTracker* gAllocationTracker;
-
-static void EnsureAllocationTrackerIsInstalled() {
-  if (!gAllocationTracker) {
-    // This is only installed once.
-    gAllocationTracker = new AllocationTracker();
-  }
-}
-
 //---------------------------------------------------------------------------
 // Per-thread blocking of intercepts
 //---------------------------------------------------------------------------
 
 // On MacOS, and Linux the first __thread/thread_local access calls malloc,
 // which leads to an infinite loop. So we use pthread-based TLS instead, which
 // somehow doesn't have this problem.
 #if !defined(XP_DARWIN) && !defined(XP_LINUX)
@@ -265,22 +115,16 @@ class ThreadIntercept {
   static PROFILER_THREAD_LOCAL(bool) tlsIsBlocked;
 
   // This is a quick flag to check and see if the allocations feature is enabled
   // or disabled.
   static mozilla::Atomic<bool, mozilla::Relaxed,
                          mozilla::recordreplay::Behavior::DontPreserve>
       sAllocationsFeatureEnabled;
 
-  // The markers will be stored on the main thread. Retain the id to the main
-  // thread of this process here.
-  static mozilla::Atomic<int, mozilla::Relaxed,
-                         mozilla::recordreplay::Behavior::DontPreserve>
-      sMainThreadId;
-
   ThreadIntercept() = default;
 
   // Only allow consumers to access this information if they run
   // ThreadIntercept::MaybeGet and ask through the non-static version.
   static bool IsBlocked_() {
     // When the native allocations feature is turned on, memory hooks run on
     // every single allocation. For a subset of these allocations, the stack
     // gets sampled by running profiler_get_backtrace(), which locks the
@@ -317,36 +161,26 @@ class ThreadIntercept {
 
   void Unblock() {
     MOZ_ASSERT(tlsIsBlocked.get());
     tlsIsBlocked.set(false);
   }
 
   bool IsBlocked() const { return ThreadIntercept::IsBlocked_(); }
 
-  static void EnableAllocationFeature(int aMainThreadId) {
-    sAllocationsFeatureEnabled = true;
-    sMainThreadId = aMainThreadId;
-  }
+  static void EnableAllocationFeature() { sAllocationsFeatureEnabled = true; }
 
   static void DisableAllocationFeature() { sAllocationsFeatureEnabled = false; }
-
-  static int MainThreadId() { return sMainThreadId; }
 };
 
 PROFILER_THREAD_LOCAL(bool) ThreadIntercept::tlsIsBlocked;
-
 mozilla::Atomic<bool, mozilla::Relaxed,
                 mozilla::recordreplay::Behavior::DontPreserve>
     ThreadIntercept::sAllocationsFeatureEnabled(false);
 
-mozilla::Atomic<int, mozilla::Relaxed,
-                mozilla::recordreplay::Behavior::DontPreserve>
-    ThreadIntercept::sMainThreadId(0);
-
 // An object of this class must be created (on the stack) before running any
 // code that might allocate.
 class AutoBlockIntercepts {
   ThreadIntercept& mThreadIntercept;
 
  public:
   // Disallow copy and assign.
   AutoBlockIntercepts(const AutoBlockIntercepts&) = delete;
@@ -389,42 +223,31 @@ static void AllocCallback(void* aPtr, si
   // hooks from recursing on any new allocations coming in.
   AutoBlockIntercepts block(threadIntercept.ref());
 
   // Perform a bernoulli trial, which will return true or false based on its
   // configured probability. It takes into account the byte size so that
   // larger allocations are weighted heavier than smaller allocations.
   MOZ_ASSERT(gBernoulli,
              "gBernoulli must be properly installed for the memory hooks.");
-  if (
-      // First perform the Bernoulli trial.
-      gBernoulli->trial(actualSize) &&
-      // Second, attempt to add a marker if the Bernoulli trial passed.
-      profiler_add_native_allocation_marker(
-          ThreadIntercept::MainThreadId(), static_cast<int64_t>(actualSize),
-          reinterpret_cast<uintptr_t>(aPtr))) {
-    MOZ_ASSERT(gAllocationTracker,
-               "gAllocationTracker must be properly installed for the memory "
-               "hooks.");
-    // Only track the memory if the allocation marker was actually added to the
-    // profiler.
-    gAllocationTracker->AddMemoryAddress(aPtr);
+  if (gBernoulli->trial(actualSize)) {
+    profiler_add_native_allocation_marker((int64_t)actualSize);
   }
 
   // We're ignoring aReqSize here
 }
 
 static void FreeCallback(void* aPtr) {
   if (!aPtr) {
     return;
   }
 
   // The first part of this function does not allocate.
   size_t unsignedSize = MallocSizeOf(aPtr);
-  int64_t signedSize = -(static_cast<int64_t>(unsignedSize));
+  int64_t signedSize = -((int64_t)unsignedSize);
   sCounter->Add(signedSize);
 
   auto threadIntercept = ThreadIntercept::MaybeGet();
   if (threadIntercept.isNothing()) {
     // Either the native allocations feature is not turned on, or we  may be
     // recursing into a memory hook, return. We'll still collect counter
     // information about this allocation, but no stack.
     return;
@@ -432,24 +255,20 @@ static void FreeCallback(void* aPtr) {
 
   // The next part of the function requires allocations, so block the memory
   // hooks from recursing on any new allocations coming in.
   AutoBlockIntercepts block(threadIntercept.ref());
 
   // Perform a bernoulli trial, which will return true or false based on its
   // configured probability. It takes into account the byte size so that
   // larger allocations are weighted heavier than smaller allocations.
-  MOZ_ASSERT(
-      gAllocationTracker,
-      "gAllocationTracker must be properly installed for the memory hooks.");
-  if (gAllocationTracker->RemoveMemoryAddressIfFound(aPtr)) {
-    // This size here is negative, indicating a deallocation.
-    profiler_add_native_allocation_marker(ThreadIntercept::MainThreadId(),
-                                          signedSize,
-                                          reinterpret_cast<uintptr_t>(aPtr));
+  MOZ_ASSERT(gBernoulli,
+             "gBernoulli must be properly installed for the memory hooks.");
+  if (gBernoulli->trial(unsignedSize)) {
+    profiler_add_native_allocation_marker(signedSize);
   }
 }
 
 }  // namespace profiler
 }  // namespace mozilla
 
 //---------------------------------------------------------------------------
 // malloc/free interception
@@ -574,18 +393,18 @@ void install_memory_hooks() {
 }
 
 // Remove the hooks, but leave the sCounter machinery. Deleting the counter
 // would race with any existing memory hooks that are currently running. Rather
 // than adding overhead here of mutexes it's cheaper for the performance to just
 // leak these values.
 void remove_memory_hooks() { jemalloc_replace_dynamic(nullptr); }
 
-void enable_native_allocations(int aMainThreadId) {
-  // The bloat log tracks allocations and deallocations. This can conflict
+void enable_native_allocations() {
+  // The bloat log tracks allocations and de-allocations. This can conflict
   // with the memory hook machinery, as the bloat log creates its own
   // allocations. This means we can re-enter inside the bloat log machinery. At
   // this time, the bloat log does not know about cannot handle the native
   // allocation feature. For now just disable the feature.
   //
   // At the time of this writing, we hit this assertion:
   // IsIdle(oldState) || IsRead(oldState) in Checker::StartReadOp()
   //
@@ -599,23 +418,19 @@ void enable_native_allocations(int aMain
   //    #08: PLDHashTable::Add(void const*, std::nothrow_t const&)
   //    #09: nsBaseHashtable<nsDepCharHashKey, nsAutoPtr<BloatEntry>, ...
   //    #10: GetBloatEntry(char const*, unsigned int)
   //    #11: NS_LogCtor
   //    #12: profiler_get_backtrace()
   //    ...
   if (!PR_GetEnv("XPCOM_MEM_BLOAT_LOG")) {
     EnsureBernoulliIsInstalled();
-    EnsureAllocationTrackerIsInstalled();
-    ThreadIntercept::EnableAllocationFeature(aMainThreadId);
+    ThreadIntercept::EnableAllocationFeature();
   }
 }
 
 // This is safe to call even if native allocations hasn't been enabled.
 void disable_native_allocations() {
   ThreadIntercept::DisableAllocationFeature();
-  if (gAllocationTracker) {
-    gAllocationTracker->Reset();
-  }
 }
 
 }  // namespace profiler
 }  // namespace mozilla
--- a/tools/profiler/core/memory_hooks.h
+++ b/tools/profiler/core/memory_hooks.h
@@ -8,16 +8,16 @@
 #define memory_hooks_h
 
 #if defined(MOZ_REPLACE_MALLOC) && defined(MOZ_PROFILER_MEMORY)
 namespace mozilla {
 namespace profiler {
 
 void install_memory_hooks();
 void remove_memory_hooks();
-void enable_native_allocations(int aMainThreadId);
+void enable_native_allocations();
 void disable_native_allocations();
 
 }  // namespace profiler
 }  // namespace mozilla
 #endif
 
 #endif
--- a/tools/profiler/core/platform.cpp
+++ b/tools/profiler/core/platform.cpp
@@ -3975,17 +3975,16 @@ static void locked_profiler_start(PSLock
       // in the Gecko Profiler profile, and shown as a new track under the
       // corresponding Gecko Profiler thread.
       ActivePS::AddBaseProfileThreads(aLock, std::move(baseprofile));
     }
   }
 #endif
 
   // Set up profiling for each registered thread, if appropriate.
-  Maybe<int> mainThreadId;
   int tid = profiler_current_thread_id();
   const Vector<UniquePtr<RegisteredThread>>& registeredThreads =
       CorePS::RegisteredThreads(aLock);
   for (auto& registeredThread : registeredThreads) {
     RefPtr<ThreadInfo> info = registeredThread->Info();
 
     if (ActivePS::ShouldProfileThread(aLock, info)) {
       registeredThread->RacyRegisteredThread().SetIsBeingProfiled(true);
@@ -4001,19 +4000,16 @@ static void locked_profiler_start(PSLock
           registeredThread->PollJSSampling();
         } else if (info->IsMainThread()) {
           // Dispatch a runnable to the main thread to call PollJSSampling(),
           // so that we don't have wait for the next JS interrupt callback in
           // order to start profiling JS.
           TriggerPollJSSamplingOnMainThread();
         }
       }
-      if (info->IsMainThread()) {
-        mainThreadId = Some(info->ThreadId());
-      }
       registeredThread->RacyRegisteredThread().ReinitializeOnResume();
       if (registeredThread->GetJSContext()) {
         profiledThreadData->NotifyReceivedJSContext(0);
       }
     }
   }
 
   // Setup support for pushing/popping labels in mozglue.
@@ -4033,24 +4029,17 @@ static void locked_profiler_start(PSLock
       javaInterval = 10;
     }
     java::GeckoJavaSampler::Start(javaInterval, 1000);
   }
 #endif
 
 #if defined(MOZ_REPLACE_MALLOC) && defined(MOZ_PROFILER_MEMORY)
   if (ActivePS::FeatureNativeAllocations(aLock)) {
-    if (mainThreadId.isSome()) {
-      mozilla::profiler::enable_native_allocations(mainThreadId.value());
-    } else {
-      NS_WARNING(
-          "The nativeallocations feature is turned on, but the main thread is "
-          "not being profiled. The allocations are only stored on the main "
-          "thread.");
-    }
+    mozilla::profiler::enable_native_allocations();
   }
 #endif
 
   // At the very end, set up RacyFeatures.
   RacyFeatures::SetActive(ActivePS::Features(aLock));
 }
 
 void profiler_start(PowerOfTwo32 aCapacity, double aInterval,
@@ -4649,28 +4638,24 @@ void profiler_add_js_allocation_marker(J
       JsAllocationMarkerPayload(TimeStamp::Now(), std::move(info),
                                 profiler_get_backtrace()));
 }
 
 bool profiler_is_locked_on_current_thread() {
   return gPSMutex.IsLockedOnCurrentThread();
 }
 
-bool profiler_add_native_allocation_marker(int aMainThreadId, int64_t aSize,
-                                           uintptr_t aMemoryAddress) {
+void profiler_add_native_allocation_marker(const int64_t aSize) {
   if (!profiler_can_accept_markers()) {
-    return false;
+    return;
   }
   AUTO_PROFILER_STATS(add_marker_with_NativeAllocationMarkerPayload);
-  profiler_add_marker_for_thread(
-      aMainThreadId, JS::ProfilingCategoryPair::OTHER, "Native allocation",
-      MakeUnique<NativeAllocationMarkerPayload>(
-          TimeStamp::Now(), aSize, aMemoryAddress, profiler_current_thread_id(),
-          profiler_get_backtrace()));
-  return true;
+  profiler_add_marker("Native allocation", JS::ProfilingCategoryPair::OTHER,
+                      NativeAllocationMarkerPayload(TimeStamp::Now(), aSize,
+                                                    profiler_get_backtrace()));
 }
 
 void profiler_add_network_marker(
     nsIURI* aURI, int32_t aPriority, uint64_t aChannelId, NetworkLoadType aType,
     mozilla::TimeStamp aStart, mozilla::TimeStamp aEnd, int64_t aCount,
     mozilla::net::CacheDisposition aCacheDisposition,
     const mozilla::net::TimingStruct* aTimings, nsIURI* aRedirectURI,
     UniqueProfilerBacktrace aSource) {
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -770,21 +770,17 @@ void profiler_add_marker(const char* aMa
     } while (false)
 
 void profiler_add_marker(const char* aMarkerName,
                          JS::ProfilingCategoryPair aCategoryPair,
                          const ProfilerMarkerPayload& aPayload);
 
 void profiler_add_js_marker(const char* aMarkerName);
 void profiler_add_js_allocation_marker(JS::RecordAllocationInfo&& info);
-
-// Returns true or or false depending on whether the marker was actually added
-// or not.
-bool profiler_add_native_allocation_marker(int aMainThreadId, int64_t aSize,
-                                           uintptr_t aMemorySize);
+void profiler_add_native_allocation_marker(int64_t aSize);
 
 // Returns true if the profiler lock is currently held *on the current thread*.
 // This may be used by re-entrant code that may call profiler functions while
 // the profiler already has the lock (which would deadlock).
 bool profiler_is_locked_on_current_thread();
 
 // Insert a marker in the profile timeline for a specified thread.
 void profiler_add_marker_for_thread(
--- a/tools/profiler/public/ProfilerMarkerPayload.h
+++ b/tools/profiler/public/ProfilerMarkerPayload.h
@@ -683,41 +683,30 @@ class JsAllocationMarkerPayload : public
 };
 
 // This payload is for collecting information about native allocations. There is
 // a memory hook into malloc and other memory functions that can sample a subset
 // of the allocations. This information is then stored in this payload.
 class NativeAllocationMarkerPayload : public ProfilerMarkerPayload {
  public:
   NativeAllocationMarkerPayload(const mozilla::TimeStamp& aStartTime,
-                                int64_t aSize, uintptr_t aMemoryAddress,
-                                int aThreadId, UniqueProfilerBacktrace aStack)
+                                const int64_t aSize,
+                                UniqueProfilerBacktrace aStack)
       : ProfilerMarkerPayload(aStartTime, aStartTime, mozilla::Nothing(),
                               std::move(aStack)),
-        mSize(aSize),
-        mMemoryAddress(aMemoryAddress),
-        mThreadId(aThreadId) {}
+        mSize(aSize) {}
 
   DECL_STREAM_PAYLOAD
 
  private:
-  NativeAllocationMarkerPayload(CommonProps&& aCommonProps, int64_t aSize,
-                                uintptr_t aMemoryAddress, int aThreadId)
-      : ProfilerMarkerPayload(std::move(aCommonProps)),
-        mSize(aSize),
-        mMemoryAddress(aMemoryAddress),
-        mThreadId(aThreadId) {}
+  NativeAllocationMarkerPayload(CommonProps&& aCommonProps, int64_t aSize)
+      : ProfilerMarkerPayload(std::move(aCommonProps)), mSize(aSize) {}
 
-  // The size in bytes of the allocation. If the number is negative then it
-  // represents a de-allocation.
+  // The size in bytes of the allocation or de-allocation.
   int64_t mSize;
-  // The memory address of the allocation or de-allocation.
-  uintptr_t mMemoryAddress;
-
-  int mThreadId;
 };
 
 class IPCMarkerPayload : public ProfilerMarkerPayload {
  public:
   IPCMarkerPayload(int32_t aOtherPid, int32_t aMessageSeqno,
                    IPC::Message::msgid_t aMessageType, mozilla::ipc::Side aSide,
                    mozilla::ipc::MessageDirection aDirection, bool aSync,
                    const mozilla::TimeStamp& aStartTime)
--- a/tools/profiler/tests/browser/browser.ini
+++ b/tools/profiler/tests/browser/browser.ini
@@ -1,16 +1,16 @@
 [DEFAULT]
 support-files =
-  ../shared-head.js
   head.js
   do_work_500ms.html
   fixed_height.html
   multi_frame.html
   simple.html
   single_frame.html
 
 [browser_test_feature_ipcmessages.js]
 [browser_test_feature_jsallocations.js]
 [browser_test_feature_nostacksampling.js]
 [browser_test_feature_preferencereads.js]
+[browser_test_feature_nativeallocations.js]
 [browser_test_profile_single_frame_page_info.js]
 [browser_test_profile_multi_frame_page_info.js]
new file mode 100644
--- /dev/null
+++ b/tools/profiler/tests/browser/browser_test_feature_nativeallocations.js
@@ -0,0 +1,107 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Test the native allocations feature. This is done as a browser test to ensure
+ * that we realistically try out how the native allocations are running. This
+ * ensures that we are collecting allocations for the content process and the
+ * parent process.
+ */
+add_task(async function test_profile_feature_nativeallocations() {
+  if (!AppConstants.MOZ_GECKO_PROFILER) {
+    return;
+  }
+  Assert.ok(
+    !Services.profiler.IsActive(),
+    "The profiler is not currently active"
+  );
+
+  info("Start the profiler to test the native allocations.");
+  startProfiler({
+    features: ["threads", "leaf", "nativeallocations"],
+  });
+
+  const env = Cc["@mozilla.org/process/environment;1"].getService(
+    Ci.nsIEnvironment
+  );
+
+  if (env.get("XPCOM_MEM_BLOAT_LOG")) {
+    info("Native allocations do not currently work with the bloat log.");
+    // Stop the profiler and exit. Note that this happens after we have already
+    // turned on the profiler so that we can still test this code path.
+    Services.profiler.StopProfiler();
+    return;
+  }
+
+  info("Launch a new tab to kick off a content process.");
+
+  const url = BASE_URL + "do_work_500ms.html";
+  await BrowserTestUtils.withNewTab(url, async contentBrowser => {
+    const contentPid = await ContentTask.spawn(
+      contentBrowser,
+      null,
+      () => Services.appinfo.processID
+    );
+
+    info("Wait 100ms so that we know some work has been done.");
+    await wait(100);
+
+    info(
+      "Check that we can get some allocations when the feature is turned on."
+    );
+    {
+      const { parentThread, contentThread } = await stopProfilerAndGetThreads(
+        contentPid
+      );
+      Assert.greater(
+        getPayloadsOfType(parentThread, "Native allocation").length,
+        0,
+        "Allocations were recorded for the parent process' main thread when the " +
+          "Native Allocation feature was turned on."
+      );
+      Assert.greater(
+        getPayloadsOfType(contentThread, "Native allocation").length,
+        0,
+        "Allocations were recorded for the content process' main thread when the " +
+          "Native Allocation feature was turned on."
+      );
+    }
+
+    info(
+      "Flush out any straggling allocation markers that may have not been " +
+        "collected yet by starting and stopping the profiler once."
+    );
+    startProfiler({ features: ["threads", "leaf"] });
+    await stopProfilerAndGetThreads(contentPid);
+
+    info("Now reload the tab with a clean run.");
+    gBrowser.reload();
+    await wait(100);
+    startProfiler({ features: ["threads", "leaf"] });
+
+    info(
+      "Check that no allocations were recorded, and allocation tracking was " +
+        "correctly turned off."
+    );
+
+    {
+      const { parentThread, contentThread } = await stopProfilerAndGetThreads(
+        contentPid
+      );
+      Assert.equal(
+        getPayloadsOfType(parentThread, "Native allocation").length,
+        0,
+        "No allocations were recorded for the parent processes' main thread when " +
+          "Native allocation was not turned on."
+      );
+
+      Assert.equal(
+        getPayloadsOfType(contentThread, "Native allocation").length,
+        0,
+        "No allocations were recorded for the content processes' main thread when " +
+          "Native allocation was not turned on."
+      );
+    }
+  });
+});
--- a/tools/profiler/tests/browser/head.js
+++ b/tools/profiler/tests/browser/head.js
@@ -1,21 +1,32 @@
-/* import-globals-from ../shared-head.js */
-
-Services.scriptloader.loadSubScript(
-  "chrome://mochitests/content/browser/tools/profiler/tests/browser/shared-head.js",
-  this
-);
-
 const { BrowserTestUtils } = ChromeUtils.import(
   "resource://testing-common/BrowserTestUtils.jsm"
 );
 
 const BASE_URL = "http://example.com/browser/tools/profiler/tests/browser/";
 
+const defaultSettings = {
+  entries: 1000000, // 9MB
+  interval: 1, // ms
+  features: ["threads"],
+  threads: ["GeckoMain"],
+};
+
+function startProfiler(callersSettings) {
+  const settings = Object.assign({}, defaultSettings, callersSettings);
+  Services.profiler.StartProfiler(
+    settings.entries,
+    settings.interval,
+    settings.features,
+    settings.threads,
+    settings.duration
+  );
+}
+
 /**
  * This is a helper function that will stop the profiler of the browser running
  * with PID contentPid.
  * This happens immediately, without waiting for any sampling to happen or
  * finish. Use stopProfilerAndGetThreads (without "Now") below instead to wait
  * for samples before stopping.
  *
  * @param {number} contentPid
@@ -54,8 +65,42 @@ async function stopProfilerNowAndGetThre
  * @param {number} contentPid
  * @returns {Promise}
  */
 async function stopProfilerAndGetThreads(contentPid) {
   await Services.profiler.waitOnePeriodicSampling();
 
   return stopProfilerNowAndGetThreads(contentPid);
 }
+
+/**
+ * This is a helper function be able to run `await wait(500)`. Unfortunately this
+ * is needed as the act of collecting functions relies on the periodic sampling of
+ * the threads. See: https://bugzilla.mozilla.org/show_bug.cgi?id=1529053
+ *
+ * @param {number} time
+ * @returns {Promise}
+ */
+function wait(time) {
+  return new Promise(resolve => {
+    // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+    setTimeout(resolve, time);
+  });
+}
+
+/**
+ * Get the payloads of a type from a single thread.
+ *
+ * @param {Object} thread The thread from a profile.
+ * @param {string} type The marker payload type, e.g. "DiskIO".
+ * @return {Array} The payloads.
+ */
+function getPayloadsOfType(thread, type) {
+  const { markers } = thread;
+  const results = [];
+  for (const markerTuple of markers.data) {
+    const payload = markerTuple[markers.schema.data];
+    if (payload && payload.type === type) {
+      results.push(payload);
+    }
+  }
+  return results;
+}
--- a/tools/profiler/tests/gtest/GeckoProfiler.cpp
+++ b/tools/profiler/tests/gtest/GeckoProfiler.cpp
@@ -703,17 +703,17 @@ TEST(GeckoProfiler, Markers)
   PROFILER_ADD_MARKER_WITH_PAYLOAD("LogMarkerPayload marker", OTHER,
                                    LogMarkerPayload, ("module", "text", ts1));
 
   PROFILER_ADD_MARKER_WITH_PAYLOAD("LongTaskMarkerPayload marker", OTHER,
                                    LongTaskMarkerPayload, (ts1, ts2));
 
   PROFILER_ADD_MARKER_WITH_PAYLOAD("NativeAllocationMarkerPayload marker",
                                    OTHER, NativeAllocationMarkerPayload,
-                                   (ts1, 9876543210, 1234, 5678, nullptr));
+                                   (ts1, 9876543210, nullptr));
 
   PROFILER_ADD_MARKER_WITH_PAYLOAD(
       "PrefMarkerPayload marker", OTHER, PrefMarkerPayload,
       ("preference name", mozilla::Nothing(), mozilla::Nothing(),
        NS_LITERAL_CSTRING("preference value"), ts1));
 
   nsCString screenshotURL = NS_LITERAL_CSTRING("url");
   PROFILER_ADD_MARKER_WITH_PAYLOAD(
@@ -1132,18 +1132,16 @@ TEST(GeckoProfiler, Markers)
                 state = State(S_NativeAllocationMarkerPayload + 1);
                 EXPECT_EQ(typeString, "Native allocation");
                 EXPECT_EQ_JSON(payload["startTime"], Double, ts1Double);
                 // Start timestamp is also stored in marker outside of payload.
                 EXPECT_EQ_JSON(marker[1], Double, ts1Double);
                 EXPECT_EQ_JSON(payload["endTime"], Double, ts1Double);
                 EXPECT_TRUE(payload["stack"].isNull());
                 EXPECT_EQ_JSON(payload["size"], Int64, 9876543210);
-                EXPECT_EQ_JSON(payload["memoryAddress"], Int64, 1234);
-                EXPECT_EQ_JSON(payload["threadId"], Int64, 5678);
 
               } else if (nameString == "PrefMarkerPayload marker") {
                 EXPECT_EQ(state, S_PrefMarkerPayload);
                 state = State(S_PrefMarkerPayload + 1);
                 EXPECT_EQ(typeString, "PreferenceRead");
                 EXPECT_EQ_JSON(payload["startTime"], Double, ts1Double);
                 // Start timestamp is also stored in marker outside of payload.
                 EXPECT_EQ_JSON(marker[1], Double, ts1Double);
deleted file mode 100644
--- a/tools/profiler/tests/shared-head.js
+++ /dev/null
@@ -1,122 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-/**
- * This file contains utilities that can be shared between xpcshell tests and mochitests.
- */
-
-// This Services declaration may shadow another from head.js, so define it as
-// a var rather than a const.
-var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-const defaultSettings = {
-  entries: 1000000, // 9MB
-  interval: 1, // ms
-  features: ["threads"],
-  threads: ["GeckoMain"],
-};
-
-function startProfiler(callersSettings) {
-  const settings = Object.assign({}, defaultSettings, callersSettings);
-  Services.profiler.StartProfiler(
-    settings.entries,
-    settings.interval,
-    settings.features,
-    settings.threads,
-    settings.duration
-  );
-}
-
-/**
- * This is a helper function be able to run `await wait(500)`. Unfortunately
- * this is needed as the act of collecting functions relies on the periodic
- * sampling of the threads. See:
- * https://bugzilla.mozilla.org/show_bug.cgi?id=1529053
- *
- * @param {number} time
- * @returns {Promise}
- */
-function wait(time) {
-  return new Promise(resolve => {
-    // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
-    setTimeout(resolve, time);
-  });
-}
-
-/**
- * Get the payloads of a type recursively, including from all subprocesses.
- *
- * @param {Object} profile The gecko profile.
- * @param {string} type The marker payload type, e.g. "DiskIO".
- * @param {Array} payloadTarget The recursive list of payloads.
- * @return {Array} The final payloads.
- */
-function getPayloadsOfTypeFromAllThreads(profile, type, payloadTarget = []) {
-  for (const { markers } of profile.threads) {
-    for (const markerTuple of markers.data) {
-      const payload = markerTuple[markers.schema.data];
-      if (payload && payload.type === type) {
-        payloadTarget.push(payload);
-      }
-    }
-  }
-
-  for (const subProcess of profile.processes) {
-    getPayloadsOfTypeFromAllThreads(subProcess, type, payloadTarget);
-  }
-
-  return payloadTarget;
-}
-
-/**
- * Get the payloads of a type from a single thread.
- *
- * @param {Object} thread The thread from a profile.
- * @param {string} type The marker payload type, e.g. "DiskIO".
- * @return {Array} The payloads.
- */
-function getPayloadsOfType(thread, type) {
-  const { markers } = thread;
-  const results = [];
-  for (const markerTuple of markers.data) {
-    const payload = markerTuple[markers.schema.data];
-    if (payload && payload.type === type) {
-      results.push(payload);
-    }
-  }
-  return results;
-}
-
-/**
- * It can be helpful to force the profiler to collect a JavaScript sample. This
- * function spins on a while loop until at least one more sample is collected.
- *
- * @return {number} The index of the collected sample.
- */
-function captureAtLeastOneJsSample() {
-  function getProfileSampleCount() {
-    const profile = Services.profiler.getProfileData();
-    return profile.threads[0].samples.data.length;
-  }
-
-  const sampleCount = getProfileSampleCount();
-  // Create an infinite loop until a sample has been collected.
-  while (true) {
-    if (sampleCount < getProfileSampleCount()) {
-      return sampleCount;
-    }
-  }
-}
-
-/**
- * This function pauses the profiler before getting the profile. Then after the
- * getting the data, the profiler is stopped, and all profiler data is removed.
- * @returns {Promise<Profile>}
- */
-async function stopAndGetProfile() {
-  Services.profiler.PauseSampling();
-  const profile = await Services.profiler.getProfileDataAsync();
-  Services.profiler.StopProfiler();
-  return profile;
-}
rename from tools/profiler/tests/xpcshell/head.js
rename to tools/profiler/tests/xpcshell/head_profiler.js
--- a/tools/profiler/tests/xpcshell/head.js
+++ b/tools/profiler/tests/xpcshell/head_profiler.js
@@ -1,32 +1,58 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/* import-globals-from ../shared-head.js */
-
-// This Services declaration may shadow another from head.js, so define it as
-// a var rather than a const.
 var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-
-const { AppConstants } = ChromeUtils.import(
+var { AppConstants } = ChromeUtils.import(
   "resource://gre/modules/AppConstants.jsm"
 );
-const { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
+var { setTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm");
+
+/**
+ * Get the payloads of a type recursively, including from all subprocesses.
+ *
+ * @param {Object} profile The gecko profile.
+ * @param {string} type The marker payload type, e.g. "DiskIO".
+ * @param {Array} payloadTarget The recursive list of payloads.
+ * @return {Array} The final payloads.
+ */
+function getAllPayloadsOfType(profile, type, payloadTarget = []) {
+  for (const { markers } of profile.threads) {
+    for (const markerTuple of markers.data) {
+      const payload = markerTuple[markers.schema.data];
+      if (payload && payload.type === type) {
+        payloadTarget.push(payload);
+      }
+    }
+  }
 
-// Load the shared head
-const sharedHead = do_get_file("shared-head.js", false);
-if (!sharedHead) {
-  throw new Error("Could not load the shared head.");
+  for (const subProcess of profile.processes) {
+    getAllPayloadsOfType(subProcess, type, payloadTarget);
+  }
+
+  return payloadTarget;
 }
-Services.scriptloader.loadSubScript(
-  Services.io.newFileURI(sharedHead).spec,
-  this
-);
+
+/**
+ * This is a helper function be able to run `await wait(500)`. Unfortunately
+ * this is needed as the act of collecting functions relies on the periodic
+ * sampling of the threads. See:
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=1529053
+ *
+ * @param {number} time
+ * @returns {Promise}
+ */
+function wait(time) {
+  return new Promise(resolve => {
+    // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+    setTimeout(resolve, time);
+  });
+}
 
 /**
  * This function takes a thread, and a sample tuple from the "data" array, and
  * inflates the frame to be an array of strings.
  *
  * @param {Object} thread - The thread from the profile.
  * @param {Array} sample - The tuple from the thread.samples.data array.
  * @returns {Array<string>} An array of function names.
@@ -51,16 +77,38 @@ function getInflatedStackLocations(threa
     stackIndex = stackEntry[STACK_PREFIX_SLOT];
   }
 
   // The profiler tree is inverted, so reverse the array.
   return locations.reverse();
 }
 
 /**
+ * It can be helpful to deterministically do at least one more profile sample.
+ * Sampling is done based on a timer. This function spins on a while loop until
+ * at least one more sample is collected.
+ *
+ * @return {number} The index of the collected sample.
+ */
+function doAtLeastOnePeriodicSample() {
+  function getProfileSampleCount() {
+    const profile = Services.profiler.getProfileData();
+    return profile.threads[0].samples.data.length;
+  }
+
+  const sampleCount = getProfileSampleCount();
+  // Create an infinite loop until a sample has been collected.
+  while (true) {
+    if (sampleCount < getProfileSampleCount()) {
+      return sampleCount;
+    }
+  }
+}
+
+/**
  * This utility matches up stacks to see if they contain a certain sequence of
  * stack frames. A correctly functioning profiler will have a certain sequence
  * of stacks, but we can't always determine exactly which stacks will show up
  * due to implementation changes, as well as memory addresses being arbitrary to
  * that particular build.
  *
  * This function triggers a test failure with a nice debug message when it
  * fails.
--- a/tools/profiler/tests/xpcshell/test_feature_js.js
+++ b/tools/profiler/tests/xpcshell/test_feature_js.js
@@ -12,17 +12,17 @@ add_task(async () => {
   const entries = 10000;
   const interval = 1;
   const threads = [];
   const features = ["js"];
 
   Services.profiler.StartProfiler(entries, interval, features, threads);
 
   // Call the following to get a nice stack in the profiler:
-  // functionA -> functionB -> functionC -> captureAtLeastOneJsSample
+  // functionA -> functionB -> functionC -> doAtLeastOnePeriodicSample
   const sampleIndex = await functionA();
 
   const profile = await Services.profiler.getProfileDataAsync();
   const [thread] = profile.threads;
   const { samples } = thread;
 
   const inflatedStackFrames = getInflatedStackLocations(
     thread,
@@ -54,10 +54,10 @@ function functionA() {
   return functionB();
 }
 
 function functionB() {
   return functionC();
 }
 
 async function functionC() {
-  return captureAtLeastOneJsSample();
+  return doAtLeastOnePeriodicSample();
 }
--- a/tools/profiler/tests/xpcshell/test_feature_mainthreadio.js
+++ b/tools/profiler/tests/xpcshell/test_feature_mainthreadio.js
@@ -108,17 +108,17 @@ async function startProfilerAndgetFileIO
   await wait(500);
 
   // Pause the profiler as we don't need to collect more samples as we retrieve
   // and serialize the profile.
   Services.profiler.PauseSampling();
 
   const profile = await Services.profiler.getProfileDataAsync();
   Services.profiler.StopProfiler();
-  return getPayloadsOfTypeFromAllThreads(profile, "FileIO");
+  return getAllPayloadsOfType(profile, "FileIO");
 }
 
 /**
  * See if a list of payloads has a write operation from a file.
  *
  * @param {Array<Object>} payloads The payloads captured from the profiler.
  * @param {string} filename The filename used to test a write operation.
  */
deleted file mode 100644
--- a/tools/profiler/tests/xpcshell/test_feature_nativeallocations.js
+++ /dev/null
@@ -1,156 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-add_task(async () => {
-  if (!AppConstants.MOZ_GECKO_PROFILER) {
-    return;
-  }
-  Assert.ok(
-    !Services.profiler.IsActive(),
-    "The profiler is not currently active"
-  );
-
-  info(
-    "Test that the profiler can install memory hooks and collect native allocation " +
-      "information in the marker payloads."
-  );
-  {
-    info("Start the profiler.");
-    startProfiler({
-      // Increase the entries so we don't overflow the buffer.
-      entries: 1e8,
-      // Only instrument the main thread.
-      threads: ["GeckoMain"],
-      features: ["threads", "leaf", "nativeallocations"],
-    });
-
-    info(
-      "Do some JS work for a little bit. This will increase the amount of allocations " +
-        "that take place."
-    );
-    doWork();
-
-    info("Get the profile data and analyze it.");
-    const profile = await stopAndGetProfile();
-
-    const {
-      allocationPayloads,
-      unmatchedAllocations,
-      logAllocationsAndDeallocations,
-    } = getAllocationInformation(profile);
-
-    Assert.greater(
-      allocationPayloads.length,
-      0,
-      "Native allocation payloads were recorded for the parent process' main thread when " +
-        "the Native Allocation feature was turned on."
-    );
-
-    if (unmatchedAllocations.length !== 0) {
-      info(
-        "There were unmatched allocations. Log all of the allocations and " +
-          "deallocations in order to aid debugging."
-      );
-      logAllocationsAndDeallocations();
-      ok(
-        false,
-        "Found a deallocation that did not have a matching allocation site. " +
-          "This could happen if balanced allocations is broken, or if the the " +
-          "buffer size of this test was too small, and some markers ended up " +
-          "rolling off."
-      );
-    }
-
-    ok(true, "All deallocation sites had matching allocations.");
-  }
-
-  info("Restart the profiler, to ensure that we get no more allocations.");
-  {
-    startProfiler({ features: ["threads", "leaf"] });
-    info("Do some work again.");
-    doWork();
-    info("Wait for the periodic sampling.");
-    await Services.profiler.waitOnePeriodicSampling();
-
-    const profile = await stopAndGetProfile();
-    const allocationPayloads = getPayloadsOfType(
-      profile.threads[0],
-      "Native allocation"
-    );
-
-    Assert.equal(
-      allocationPayloads.length,
-      0,
-      "No native allocations were collected when the feature was disabled."
-    );
-  }
-});
-
-function doWork() {
-  this.n = 0;
-  for (let i = 0; i < 1e5; i++) {
-    this.n += Math.random();
-  }
-}
-
-/**
- * Extract the allocation payloads, and find the unmatched allocations.
- */
-function getAllocationInformation(profile) {
-  // Get all of the allocation payloads.
-  const allocationPayloads = getPayloadsOfType(
-    profile.threads[0],
-    "Native allocation"
-  );
-
-  // Decide what is an allocation and deallocation.
-  const allocations = allocationPayloads.filter(
-    payload => ensureIsNumber(payload.size) >= 0
-  );
-  const deallocations = allocationPayloads.filter(
-    payload => ensureIsNumber(payload.size) < 0
-  );
-
-  // Now determine the unmatched allocations by building a set
-  const allocationSites = new Set(
-    allocations.map(({ memoryAddress }) => memoryAddress)
-  );
-
-  const unmatchedAllocations = deallocations.filter(
-    ({ memoryAddress }) => !allocationSites.has(memoryAddress)
-  );
-
-  // Provide a helper to log out the allocations and deallocations on failure.
-  function logAllocationsAndDeallocations() {
-    for (const { memoryAddress } of allocations) {
-      console.log("Allocations", formatHex(memoryAddress));
-      allocationSites.add(memoryAddress);
-    }
-
-    for (const { memoryAddress } of deallocations) {
-      console.log("Deallocations", formatHex(memoryAddress));
-    }
-
-    for (const { memoryAddress } of unmatchedAllocations) {
-      console.log("Deallocation with no allocation", formatHex(memoryAddress));
-    }
-  }
-
-  return {
-    allocationPayloads,
-    unmatchedAllocations,
-    logAllocationsAndDeallocations,
-  };
-}
-
-function ensureIsNumber(value) {
-  if (typeof value !== "number") {
-    throw new Error(`Expected a number: ${value}`);
-  }
-  return value;
-}
-
-function formatHex(number) {
-  return `0x${number.toString(16)}`;
-}
--- a/tools/profiler/tests/xpcshell/test_feature_stackwalking.js
+++ b/tools/profiler/tests/xpcshell/test_feature_stackwalking.js
@@ -13,17 +13,17 @@ add_task(async () => {
     return;
   }
   const entries = 10000;
   const interval = 1;
   const threads = [];
   const features = ["stackwalk"];
 
   Services.profiler.StartProfiler(entries, interval, features, threads);
-  const sampleIndex = await captureAtLeastOneJsSample();
+  const sampleIndex = await doAtLeastOnePeriodicSample();
 
   const profile = await Services.profiler.getProfileDataAsync();
   const [thread] = profile.threads;
   const { samples } = thread;
 
   const inflatedStackFrames = getInflatedStackLocations(
     thread,
     samples.data[sampleIndex]
--- a/tools/profiler/tests/xpcshell/test_merged_stacks.js
+++ b/tools/profiler/tests/xpcshell/test_merged_stacks.js
@@ -12,17 +12,17 @@ add_task(async () => {
   const entries = 10000;
   const interval = 1;
   const threads = [];
   const features = ["js", "stackwalk"];
 
   Services.profiler.StartProfiler(entries, interval, features, threads);
 
   // Call the following to get a nice stack in the profiler:
-  // functionA -> functionB -> functionC
+  // functionA -> functionB -> functionC -> doAtLeastOnePeriodicSample
   const sampleIndex = await functionA();
 
   const profile = await Services.profiler.getProfileDataAsync();
   const [thread] = profile.threads;
   const { samples } = thread;
 
   const inflatedStackFrames = getInflatedStackLocations(
     thread,
@@ -66,10 +66,10 @@ function functionA() {
   return functionB();
 }
 
 function functionB() {
   return functionC();
 }
 
 async function functionC() {
-  return captureAtLeastOneJsSample();
+  return doAtLeastOnePeriodicSample();
 }
--- a/tools/profiler/tests/xpcshell/test_responsiveness.js
+++ b/tools/profiler/tests/xpcshell/test_responsiveness.js
@@ -44,10 +44,10 @@ function doSyncWork(milliseconds) {
     if (Date.now() - start > milliseconds) {
       return;
     }
   }
 }
 
 function functionA() {
   doSyncWork(100);
-  captureAtLeastOneJsSample();
+  doAtLeastOnePeriodicSample();
 }
--- a/tools/profiler/tests/xpcshell/xpcshell.ini
+++ b/tools/profiler/tests/xpcshell/xpcshell.ini
@@ -1,12 +1,10 @@
 [DEFAULT]
-head = head.js
-support-files =
-  ../shared-head.js
+head = head_profiler.js
 skip-if = toolkit == 'android'
 
 [test_active_configuration.js]
 [test_start.js]
 skip-if = true
 [test_get_features.js]
 [test_responsiveness.js]
 [test_shared_library.js]
@@ -17,17 +15,16 @@ skip-if = true
 skip-if = (os == "win" && processor == "aarch64") # aarch64 due to 1536652
 [test_enterjit_osr_disabling.js]
 skip-if = !debug
 [test_enterjit_osr_enabling.js]
 skip-if = !debug
 [test_asm.js]
 [test_feature_mainthreadio.js]
 skip-if = release_or_beta || (os == "win" && processor == "aarch64") # The IOInterposer is in an ifdef, aarch64 due to 1536657
-[test_feature_nativeallocations.js]
 
 # Native stackwalking is somewhat unreliable depending on the platform.
 #
 # We don't have frame pointers on macOS release and beta, so stack walking does not
 # work. See Bug 1571216 for more details.
 #
 # Linux can be very unreliable when native stackwalking through JavaScript code.
 # See Bug 1434402 for more details.