# Global Metrics

path: .metrics.nargs.average
old: 1.0
new: 0.38596491228070173
path: .metrics.nargs.sum
old: 1.0
new: 22.0
path: .metrics.nom.total
old: 1.0
new: 57.0
path: .metrics.nom.functions
old: 1.0
new: 57.0
path: .metrics.cyclomatic.sum
old: 7.0
new: 89.0
path: .metrics.cyclomatic.average
old: 1.4
new: 1.3484848484848484
path: .metrics.nexits.sum
old: 2.0
new: 31.0
path: .metrics.nexits.average
old: 2.0
new: 0.543859649122807
path: .metrics.loc.cloc
old: 23.0
new: 165.0
path: .metrics.loc.lloc
old: 4.0
new: 110.0
path: .metrics.loc.ploc
old: 44.0
new: 342.0
path: .metrics.loc.blank
old: 0.0
new: 93.0
path: .metrics.loc.sloc
old: 62.0
new: 600.0
path: .metrics.mi.mi_original
old: 67.10090624720338
new: -1.5887386974619204
path: .metrics.mi.mi_sei
old: 62.30092892477686
new: -32.633823726143206
path: .metrics.mi.mi_visual_studio
old: 39.24029605099613
new: 0.0
path: .metrics.halstead.n1
old: 14.0
new: 26.0
path: .metrics.halstead.bugs
old: 0.14931062316774507
new: 1.8862755307696113
path: .metrics.halstead.length
old: 156.0
new: 1447.0
path: .metrics.halstead.purity_ratio
old: 1.8373868805192093
new: 1.0722012790942994
path: .metrics.halstead.effort
old: 9480.209704882453
new: 425686.2071051973
path: .metrics.halstead.volume
old: 909.9308422096996
new: 11211.635053355947
path: .metrics.halstead.difficulty
old: 10.418604651162791
new: 37.96825396825397
path: .metrics.halstead.time
old: 526.678316937914
new: 23649.233728066516
path: .metrics.halstead.n2
old: 43.0
new: 189.0
path: .metrics.halstead.N1
old: 92.0
new: 895.0
path: .metrics.halstead.estimated_program_length
old: 286.63235336099666
new: 1551.4752508494512
path: .metrics.halstead.level
old: 0.09598214285714284
new: 0.026337792642140468
path: .metrics.halstead.N2
old: 64.0
new: 552.0
path: .metrics.halstead.vocabulary
old: 57.0
new: 215.0
path: .metrics.cognitive.average
old: 3.0
new: 0.42105263157894735
path: .metrics.cognitive.sum
old: 3.0
new: 24.0

# Spaces Data

## Minimal test - lines (64, 431)

path: .spaces[0].metrics.cyclomatic.sum
old: 6.0
new: 65.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.5
new: 1.4130434782608696
path: .spaces[0].metrics.mi.mi_original
old: 71.56693902882205
new: 14.420469391682047
path: .spaces[0].metrics.mi.mi_visual_studio
old: 41.852011127966115
new: 8.433023036071372
path: .spaces[0].metrics.mi.mi_sei
old: 64.24332017089552
new: -12.429360889555994
path: .spaces[0].metrics.nexits.average
old: 2.0
new: 0.5128205128205128
path: .spaces[0].metrics.nexits.sum
old: 2.0
new: 20.0
path: .spaces[0].metrics.loc.lloc
old: 4.0
new: 70.0
path: .spaces[0].metrics.loc.ploc
old: 41.0
new: 209.0
path: .spaces[0].metrics.loc.sloc
old: 48.0
new: 368.0
path: .spaces[0].metrics.loc.blank
old: 0.0
new: 61.0
path: .spaces[0].metrics.loc.cloc
old: 13.0
new: 98.0
path: .spaces[0].metrics.nom.functions
old: 1.0
new: 39.0
path: .spaces[0].metrics.nom.total
old: 1.0
new: 39.0
path: .spaces[0].metrics.nargs.average
old: 1.0
new: 0.38461538461538464
path: .spaces[0].metrics.nargs.sum
old: 1.0
new: 15.0
path: .spaces[0].metrics.halstead.volume
old: 894.3326579968709
new: 6839.688727594546
path: .spaces[0].metrics.halstead.n2
old: 42.0
new: 122.0
path: .spaces[0].metrics.halstead.length
old: 154.0
new: 950.0
path: .spaces[0].metrics.halstead.difficulty
old: 10.333333333333334
new: 35.040983606557376
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.816755199126717
new: 1.0122593262389898
path: .spaces[0].metrics.halstead.estimated_program_length
old: 279.7803006655144
new: 961.6463599270404
path: .spaces[0].metrics.halstead.bugs
old: 0.14679291610919937
new: 1.286136793401003
path: .spaces[0].metrics.halstead.level
old: 0.0967741935483871
new: 0.028538011695906435
path: .spaces[0].metrics.halstead.N2
old: 62.0
new: 342.0
path: .spaces[0].metrics.halstead.n1
old: 14.0
new: 25.0
path: .spaces[0].metrics.halstead.time
old: 513.4131925537592
new: 13314.967809866432
path: .spaces[0].metrics.halstead.N1
old: 92.0
new: 608.0
path: .spaces[0].metrics.halstead.vocabulary
old: 56.0
new: 147.0
path: .spaces[0].metrics.halstead.effort
old: 9241.437465967669
new: 239669.42057759577
path: .spaces[0].metrics.cognitive.sum
old: 3.0
new: 19.0
path: .spaces[0].metrics.cognitive.average
old: 3.0
new: 0.4871794871794872

### Code

    namespace mozilla::profiler {

    //---------------------------------------------------------------------------
    // Utilities
    //---------------------------------------------------------------------------

    static malloc_table_t gMallocTable;

    // This is only needed because of the |const void*| vs |void*| arg mismatch.
    static size_t MallocSizeOf(const void* aPtr) {
      return gMallocTable.malloc_usable_size(const_cast(aPtr));
    }

    // The values for the Bernoulli trial are taken from DMD. According to DMD:
    //
    //   In testing, a probability of 0.003 resulted in ~25% of heap blocks getting
    //   a stack trace and ~80% of heap bytes getting a stack trace. (This is
    //   possible because big heap blocks are more likely to get a stack trace.)
    //
    //   The random number seeds are arbitrary and were obtained from random.org.
    //
    // However this value resulted in a lot of slowdown since the profiler stacks
    // are pretty heavy to collect. The value was lowered to 10% of the original to
    // 0.0003.
    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
      static T* maybe_pod_malloc(size_t aNumElems) {
        if (aNumElems & mozilla::tl::MulOverflowMask::value) {
          return nullptr;
        }
        return (T*)gMallocTable.malloc(aNumElems * sizeof(T));
      }

      template
      static T* maybe_pod_calloc(size_t aNumElems) {
        return (T*)gMallocTable.calloc(aNumElems, sizeof(T));
      }

      template
      static T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) {
        if (aNewSize & mozilla::tl::MulOverflowMask::value) {
          return nullptr;
        }
        return (T*)gMallocTable.realloc(aPtr, aNewSize * sizeof(T));
      }

      template
      static T* pod_malloc(size_t aNumElems) {
        T* p = maybe_pod_malloc(aNumElems);
        ExitOnFailure(p);
        return p;
      }

      template
      static T* pod_calloc(size_t aNumElems) {
        T* p = maybe_pod_calloc(aNumElems);
        ExitOnFailure(p);
        return p;
      }

      template
      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
      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() {}

      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,
                               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)
    #  define PROFILER_THREAD_LOCAL(T) MOZ_THREAD_LOCAL(T)
    #else
    #  define PROFILER_THREAD_LOCAL(T) \
        ::mozilla::detail::ThreadLocal
    #endif

    class ThreadIntercept {
      // When set to true, malloc does not intercept additional allocations. This is
      // needed because collecting stacks creates new allocations. When blocked,
      // these allocations are then ignored by the memory hook.
      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 sAllocationsFeatureEnabled;

      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
        // profiler mutex.
        //
        // An issue arises when allocating while the profiler is locked FOR THE
        // CURRENT THREAD. In this situation, if profiler_get_backtrace() were to be
        // run, it would try to re-acquire this lock and deadlock. In order to guard
        // against this deadlock, we check to see if the mutex is already locked by
        // this thread.
        return tlsIsBlocked.get() || profiler_is_locked_on_current_thread();
      }

     public:
      static void Init() { tlsIsBlocked.infallibleInit(); }

      // The ThreadIntercept object can only be created through this method, the
      // constructor is private. This is so that we only check to see if the native
      // allocations are turned on once, and not multiple times through the calls.
      // The feature maybe be toggled between different stages of the memory hook.
      static Maybe MaybeGet() {
        if (sAllocationsFeatureEnabled && !ThreadIntercept::IsBlocked_()) {
          // Only return thread intercepts when the native allocations feature is
          // enabled and we aren't blocked.
          return Some(ThreadIntercept());
        }
        return Nothing();
      }

      void Block() {
        MOZ_ASSERT(!tlsIsBlocked.get());
        tlsIsBlocked.set(true);
      }

      void Unblock() {
        MOZ_ASSERT(tlsIsBlocked.get());
        tlsIsBlocked.set(false);
      }

      bool IsBlocked() const { return ThreadIntercept::IsBlocked_(); }

      static void EnableAllocationFeature() { sAllocationsFeatureEnabled = true; }

      static void DisableAllocationFeature() { sAllocationsFeatureEnabled = false; }
    };

    PROFILER_THREAD_LOCAL(bool) ThreadIntercept::tlsIsBlocked;

    mozilla::Atomic
        ThreadIntercept::sAllocationsFeatureEnabled(false);

    // 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;
      void operator=(const AutoBlockIntercepts&) = delete;

      explicit AutoBlockIntercepts(ThreadIntercept& aThreadIntercept)
          : mThreadIntercept(aThreadIntercept) {
        mThreadIntercept.Block();
      }
      ~AutoBlockIntercepts() {
        MOZ_ASSERT(mThreadIntercept.IsBlocked());
        mThreadIntercept.Unblock();
      }
    };

    //---------------------------------------------------------------------------
    // malloc/free callbacks
    //---------------------------------------------------------------------------

    static void AllocCallback(void* aPtr, size_t aReqSize) {
      if (!aPtr) {
        return;
      }

      // The first part of this function does not allocate.
      size_t actualSize = gMallocTable.malloc_usable_size(aPtr);
      if (actualSize > 0) {
        sCounter->Add(actualSize);
      }

      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;
      }

      // 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());
      AUTO_PROFILER_LABEL("AllocCallback", PROFILER);

      // 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(
              static_cast(actualSize),
              reinterpret_cast(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);
      }

      // 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(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;
      }

      // 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());
      AUTO_PROFILER_LABEL("FreeCallback", PROFILER);

      // 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(signedSize,
                                              reinterpret_cast(aPtr));
      }
    }

    }  // namespace mozilla::profiler

## Minimal test - lines (100, 157)

path: .spaces[0].spaces[2].metrics.nexits.average
old: 2.0
new: 0.9
path: .spaces[0].spaces[2].metrics.nexits.sum
old: 2.0
new: 9.0
path: .spaces[0].spaces[2].metrics.nom.total
old: 1.0
new: 10.0
path: .spaces[0].spaces[2].metrics.nom.functions
old: 1.0
new: 10.0
path: .spaces[0].spaces[2].metrics.cyclomatic.average
old: 3.0
new: 1.2727272727272727
path: .spaces[0].spaces[2].metrics.cyclomatic.sum
old: 3.0
new: 14.0
path: .spaces[0].spaces[2].metrics.loc.sloc
old: 10.0
new: 58.0
path: .spaces[0].spaces[2].metrics.loc.ploc
old: 9.0
new: 50.0
path: .spaces[0].spaces[2].metrics.loc.blank
old: 0.0
new: 8.0
path: .spaces[0].spaces[2].metrics.loc.cloc
old: 1.0
new: 0.0
path: .spaces[0].spaces[2].metrics.loc.lloc
old: 4.0
new: 18.0
path: .spaces[0].spaces[2].metrics.cognitive.average
old: 3.0
new: 0.3
path: .spaces[0].spaces[2].metrics.mi.mi_original
old: 105.87698321080636
new: 64.06148375807365
path: .spaces[0].spaces[2].metrics.mi.mi_visual_studio
old: 61.91636445076395
new: 37.46285599887348
path: .spaces[0].spaces[2].metrics.mi.mi_sei
old: 100.87959832766
new: 18.145810969411443
path: .spaces[0].spaces[2].metrics.nargs.average
old: 1.0
new: 0.3
path: .spaces[0].spaces[2].metrics.nargs.sum
old: 1.0
new: 3.0
path: .spaces[0].spaces[2].metrics.halstead.n1
old: 13.0
new: 17.0
path: .spaces[0].spaces[2].metrics.halstead.bugs
old: 0.05972227172344426
new: 0.395257944624949
path: .spaces[0].spaces[2].metrics.halstead.purity_ratio
old: 1.716802769900814
new: 0.8449505830426094
path: .spaces[0].spaces[2].metrics.halstead.vocabulary
old: 21.0
new: 48.0
path: .spaces[0].spaces[2].metrics.halstead.time
old: 133.23362849095574
new: 2268.455629056354
path: .spaces[0].spaces[2].metrics.halstead.volume
old: 184.4773317567079
new: 1474.4301001903852
path: .spaces[0].spaces[2].metrics.halstead.difficulty
old: 13.0
new: 27.693548387096776
path: .spaces[0].spaces[2].metrics.halstead.effort
old: 2398.205312837203
new: 40832.20132301438
path: .spaces[0].spaces[2].metrics.halstead.n2
old: 8.0
new: 31.0
path: .spaces[0].spaces[2].metrics.halstead.length
old: 42.0
new: 264.0
path: .spaces[0].spaces[2].metrics.halstead.level
old: 0.07692307692307693
new: 0.0361094933022714
path: .spaces[0].spaces[2].metrics.halstead.estimated_program_length
old: 72.10571633583419
new: 223.0669539232489
path: .spaces[0].spaces[2].metrics.halstead.N2
old: 16.0
new: 101.0
path: .spaces[0].spaces[2].metrics.halstead.N1
old: 26.0
new: 163.0

### Code

    class InfallibleAllocWithoutHooksPolicy {
      static void ExitOnFailure(const void* aP) {
        if (!aP) {
          MOZ_CRASH("Profiler memory hooks out of memory; aborting");
        }
      }

     public:
      template
      static T* maybe_pod_malloc(size_t aNumElems) {
        if (aNumElems & mozilla::tl::MulOverflowMask::value) {
          return nullptr;
        }
        return (T*)gMallocTable.malloc(aNumElems * sizeof(T));
      }

      template
      static T* maybe_pod_calloc(size_t aNumElems) {
        return (T*)gMallocTable.calloc(aNumElems, sizeof(T));
      }

      template
      static T* maybe_pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize) {
        if (aNewSize & mozilla::tl::MulOverflowMask::value) {
          return nullptr;
        }
        return (T*)gMallocTable.realloc(aPtr, aNewSize * sizeof(T));
      }

      template
      static T* pod_malloc(size_t aNumElems) {
        T* p = maybe_pod_malloc(aNumElems);
        ExitOnFailure(p);
        return p;
      }

      template
      static T* pod_calloc(size_t aNumElems) {
        T* p = maybe_pod_calloc(aNumElems);
        ExitOnFailure(p);
        return p;
      }

      template
      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
      static void free_(T* aPtr, size_t aSize = 0) {
        gMallocTable.free(aPtr);
      }

      static void reportAllocOverflow() { ExitOnFailure(nullptr); }
      bool checkSimulatedOOM() const { return true; }
    };

## Minimal test - lines (88, 95)

path: .spaces[0].spaces[1].metrics.nexits.average
old: null
new: 0.0
path: .spaces[0].spaces[1].metrics.loc.sloc
old: 1.0
new: 8.0
path: .spaces[0].spaces[1].metrics.loc.ploc
old: 1.0
new: 6.0
path: .spaces[0].spaces[1].metrics.loc.cloc
old: 0.0
new: 2.0
path: .spaces[0].spaces[1].metrics.loc.lloc
old: 0.0
new: 2.0
path: .spaces[0].spaces[1].metrics.nargs.average
old: null
new: 0.0
path: .spaces[0].spaces[1].metrics.nom.total
old: 0.0
new: 1.0
path: .spaces[0].spaces[1].metrics.nom.functions
old: 0.0
new: 1.0
path: .spaces[0].spaces[1].metrics.cognitive.sum
old: 0.0
new: 1.0
path: .spaces[0].spaces[1].metrics.cognitive.average
old: null
new: 1.0
path: .spaces[0].spaces[1].metrics.cyclomatic.sum
old: 1.0
new: 2.0
path: .spaces[0].spaces[1].metrics.cyclomatic.average
old: 1.0
new: 2.0
path: .spaces[0].spaces[1].metrics.mi.mi_visual_studio
old: null
new: 66.77718232276843
path: .spaces[0].spaces[1].metrics.mi.mi_original
old: null
new: 114.188981771934
path: .spaces[0].spaces[1].metrics.mi.mi_sei
old: null
new: 124.21405897649808
path: .spaces[0].spaces[1].metrics.halstead.time
old: 0.0
new: 22.790195141049693
path: .spaces[0].spaces[1].metrics.halstead.N1
old: 0.0
new: 13.0
path: .spaces[0].spaces[1].metrics.halstead.bugs
old: 0.0
new: 0.01840316180582329
path: .spaces[0].spaces[1].metrics.halstead.purity_ratio
old: null
new: 2.201955000865387
path: .spaces[0].spaces[1].metrics.halstead.n2
old: 1.0
new: 6.0
path: .spaces[0].spaces[1].metrics.halstead.n1
old: 0.0
new: 9.0
path: .spaces[0].spaces[1].metrics.halstead.volume
old: 0.0
new: 78.13781191217038
path: .spaces[0].spaces[1].metrics.halstead.effort
old: 0.0
new: 410.2235125388945
path: .spaces[0].spaces[1].metrics.halstead.N2
old: 1.0
new: 7.0
path: .spaces[0].spaces[1].metrics.halstead.length
old: 1.0
new: 20.0
path: .spaces[0].spaces[1].metrics.halstead.level
old: null
new: 0.1904761904761905
path: .spaces[0].spaces[1].metrics.halstead.estimated_program_length
old: null
new: 44.039100017307746
path: .spaces[0].spaces[1].metrics.halstead.difficulty
old: 0.0
new: 5.25
path: .spaces[0].spaces[1].metrics.halstead.vocabulary
old: 1.0
new: 15.0

### Code

    static void EnsureBernoulliIsInstalled() {
      if (!gBernoulli) {
        // This is only installed once. See the gBernoulli definition for more
        // information.
        gBernoulli =
            new FastBernoulliTrial(0.0003, 0x8e26eeee166bc8ca, 0x56820f304a9c9ae0);
      }
    }

## Minimal test - lines (73, 75)

path: .spaces[0].spaces[0].metrics.cognitive.average
old: null
new: 0.0
path: .spaces[0].spaces[0].metrics.loc.lloc
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].metrics.loc.ploc
old: 4.0
new: 3.0
path: .spaces[0].spaces[0].metrics.loc.sloc
old: 4.0
new: 3.0
path: .spaces[0].spaces[0].metrics.nargs.average
old: null
new: 1.0
path: .spaces[0].spaces[0].metrics.nargs.sum
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].metrics.nom.functions
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].metrics.nom.total
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].metrics.nexits.average
old: null
new: 1.0
path: .spaces[0].spaces[0].metrics.nexits.sum
old: 0.0
new: 1.0
path: .spaces[0].spaces[0].metrics.mi.mi_original
old: 132.56043812602817
new: 130.44261265142893
path: .spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 77.52072405030886
new: 76.28222962071868
path: .spaces[0].spaces[0].metrics.mi.mi_sei
old: 115.6452545698808
new: 112.5898782602082
path: .spaces[0].spaces[0].metrics.halstead.bugs
old: 0.003290806962640765
new: 0.018432185171393212
path: .spaces[0].spaces[0].metrics.halstead.level
old: 0.6666666666666666
new: 0.18518518518518515
path: .spaces[0].spaces[0].metrics.halstead.effort
old: 31.019550008653873
new: 411.19433158222125
path: .spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 9.509775004326936
new: 40.13896548741762
path: .spaces[0].spaces[0].metrics.halstead.volume
old: 20.67970000576925
new: 76.14709844115208
path: .spaces[0].spaces[0].metrics.halstead.n1
old: 3.0
new: 9.0
path: .spaces[0].spaces[0].metrics.halstead.N2
old: 3.0
new: 6.0
path: .spaces[0].spaces[0].metrics.halstead.length
old: 8.0
new: 20.0
path: .spaces[0].spaces[0].metrics.halstead.N1
old: 5.0
new: 14.0
path: .spaces[0].spaces[0].metrics.halstead.difficulty
old: 1.5
new: 5.4
path: .spaces[0].spaces[0].metrics.halstead.time
old: 1.723308333814104
new: 22.844129532345622
path: .spaces[0].spaces[0].metrics.halstead.n2
old: 3.0
new: 5.0
path: .spaces[0].spaces[0].metrics.halstead.vocabulary
old: 6.0
new: 14.0
path: .spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.188721875540867
new: 2.006948274370881

### Code

    static size_t MallocSizeOf(const void* aPtr) {
      return gMallocTable.malloc_usable_size(const_cast(aPtr));
    }