# Global Metrics

path: .metrics.nexits.average
old: 1.75
new: 0.6111111111111112
path: .metrics.nexits.sum
old: 49.0
new: 11.0
path: .metrics.halstead.vocabulary
old: 214.0
new: 129.0
path: .metrics.halstead.volume
old: 12618.591187833868
new: 5384.622532165059
path: .metrics.halstead.bugs
old: 3.0026464307431935
new: 1.2694197569665069
path: .metrics.halstead.effort
old: 854944.9984566093
new: 235011.850416344
path: .metrics.halstead.purity_ratio
old: 0.930550828689535
new: 1.048524827911682
path: .metrics.halstead.N2
old: 670.0
new: 301.0
path: .metrics.halstead.difficulty
old: 67.75280898876404
new: 43.645
path: .metrics.halstead.n1
old: 36.0
new: 29.0
path: .metrics.halstead.n2
old: 178.0
new: 100.0
path: .metrics.halstead.N1
old: 960.0
new: 467.0
path: .metrics.halstead.length
old: 1630.0
new: 768.0
path: .metrics.halstead.time
old: 47496.944358700515
new: 13056.213912019111
path: .metrics.halstead.estimated_program_length
old: 1516.797850763942
new: 805.2670678361719
path: .metrics.halstead.level
old: 0.014759535655058043
new: 0.02291213197388017
path: .metrics.cognitive.sum
old: 63.0
new: 12.0
path: .metrics.cognitive.average
old: 2.25
new: 0.6666666666666666
path: .metrics.nom.functions
old: 28.0
new: 18.0
path: .metrics.nom.total
old: 28.0
new: 18.0
path: .metrics.mi.mi_original
old: 3.191983010934578
new: 28.56313599357672
path: .metrics.mi.mi_sei
old: -42.31526119622495
new: 2.407163592796863
path: .metrics.mi.mi_visual_studio
old: 1.866656731540689
new: 16.703588300337262
path: .metrics.nargs.average
old: 0.7857142857142857
new: 0.6666666666666666
path: .metrics.nargs.sum
old: 22.0
new: 12.0
path: .metrics.loc.lloc
old: 144.0
new: 51.0
path: .metrics.loc.blank
old: 45.0
new: 34.0
path: .metrics.loc.sloc
old: 418.0
new: 247.0
path: .metrics.loc.ploc
old: 345.0
new: 159.0
path: .metrics.loc.cloc
old: 28.0
new: 54.0
path: .metrics.cyclomatic.average
old: 3.033333333333333
new: 1.48
path: .metrics.cyclomatic.sum
old: 91.0
new: 37.0

# Spaces Data

## Minimal test - lines (20, 245)

path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 12.0
path: .spaces[0].metrics.cognitive.average
old: 0.0
new: 0.6666666666666666
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 47.0
path: .spaces[0].metrics.loc.ploc
old: 11.0
new: 147.0
path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 51.0
path: .spaces[0].metrics.loc.blank
old: 3.0
new: 32.0
path: .spaces[0].metrics.loc.sloc
old: 14.0
new: 226.0
path: .spaces[0].metrics.mi.mi_sei
old: 65.88158499817104
new: 4.204249248104773
path: .spaces[0].metrics.mi.mi_original
old: 97.9963147196096
new: 30.34705289034588
path: .spaces[0].metrics.mi.mi_visual_studio
old: 57.3077863857366
new: 17.746814555757823
path: .spaces[0].metrics.halstead.volume
old: 307.67071501168664
new: 5267.360376547794
path: .spaces[0].metrics.halstead.difficulty
old: 5.921052631578948
new: 45.68279569892473
path: .spaces[0].metrics.halstead.vocabulary
old: 28.0
new: 122.0
path: .spaces[0].metrics.halstead.effort
old: 1821.7344967797237
new: 240627.7479544441
path: .spaces[0].metrics.halstead.length
old: 64.0
new: 760.0
path: .spaces[0].metrics.halstead.n2
old: 19.0
new: 93.0
path: .spaces[0].metrics.halstead.time
old: 101.20747204331798
new: 13368.208219691338
path: .spaces[0].metrics.halstead.N2
old: 25.0
new: 293.0
path: .spaces[0].metrics.halstead.N1
old: 39.0
new: 467.0
path: .spaces[0].metrics.halstead.bugs
old: 0.04972049764924493
new: 1.2895629575446417
path: .spaces[0].metrics.halstead.estimated_program_length
old: 109.23994776840892
new: 749.0232182917464
path: .spaces[0].metrics.halstead.n1
old: 9.0
new: 29.0
path: .spaces[0].metrics.halstead.level
old: 0.16888888888888887
new: 0.021890078851359303
path: .spaces[0].metrics.halstead.purity_ratio
old: 1.7068741838813897
new: 0.9855568661733504
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 1.5
path: .spaces[0].metrics.cyclomatic.sum
old: 2.0
new: 36.0
path: .spaces[0].metrics.nexits.average
old: 0.0
new: 0.6111111111111112
path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 11.0
path: .spaces[0].metrics.nargs.average
old: 0.0
new: 0.6666666666666666
path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 12.0
path: .spaces[0].metrics.nom.total
old: 1.0
new: 18.0
path: .spaces[0].metrics.nom.functions
old: 1.0
new: 18.0

### Code

    namespace mozilla {

    namespace detail {

    template
    class CodeAddressServiceAllocPolicy : public AllocPolicy {
     public:
      char* strdup_(const char* aStr) {
        char* s = AllocPolicy::template pod_malloc(strlen(aStr) + 1);
        if (!s) {
          MOZ_CRASH("CodeAddressService OOM");
        }
        strcpy(s, aStr);
        return s;
      }
    };

    // Default implementation of DescribeCodeAddressLock.
    struct DefaultDescribeCodeAddressLock {
      static void Unlock() {}
      static void Lock() {}
      // Because CodeAddressService asserts that IsLocked() is true, returning true
      // here is a sensible default when there is no relevant lock.
      static bool IsLocked() { return true; }
    };

    }  // namespace detail

    // This class is used to print details about code locations.
    //
    // |AllocPolicy_| must adhere to the description in mfbt/AllocPolicy.h.
    //
    // |DescribeCodeAddressLock| is needed when the callers may be holding a lock
    // used by MozDescribeCodeAddress.  |DescribeCodeAddressLock| must implement
    // static methods IsLocked(), Unlock() and Lock().
    template
    class CodeAddressService
        : private detail::CodeAddressServiceAllocPolicy {
     protected:
      // GetLocation() is the key function in this class.  It's basically a wrapper
      // around MozDescribeCodeAddress.
      //
      // However, MozDescribeCodeAddress is very slow on some platforms, and we
      // have lots of repeated (i.e. same PC) calls to it.  So we do some caching
      // of results.  Each cached result includes two strings (|mFunction| and
      // |mLibrary|), so we also optimize them for space in the following ways.
      //
      // - The number of distinct library names is small, e.g. a few dozen.  There
      //   is lots of repetition, especially of libxul.  So we intern them in their
      //   own table, which saves space over duplicating them for each cache entry.
      //
      // - The number of distinct function names is much higher, so we duplicate
      //   them in each cache entry.  That's more space-efficient than interning
      //   because entries containing single-occurrence function names are quickly
      //   overwritten, and their copies released.  In addition, empty function
      //   names are common, so we use nullptr to represent them compactly.

      using AllocPolicy = detail::CodeAddressServiceAllocPolicy;
      using StringHashSet = HashSet;

      StringHashSet mLibraryStrings;

      struct Entry : private AllocPolicy {
        const void* mPc;
        char* mFunction;       // owned by the Entry;  may be null
        const char* mLibrary;  // owned by mLibraryStrings;  never null
                               //   in a non-empty entry is in use
        ptrdiff_t mLOffset;
        char* mFileName;  // owned by the Entry; may be null
        uint32_t mLineNo : 31;
        uint32_t mInUse : 1;  // is the entry used?

        Entry()
            : mPc(0),
              mFunction(nullptr),
              mLibrary(nullptr),
              mLOffset(0),
              mFileName(nullptr),
              mLineNo(0),
              mInUse(0) {}

        ~Entry() {
          // We don't free mLibrary because it's externally owned.
          AllocPolicy::free_(mFunction);
          AllocPolicy::free_(mFileName);
        }

        void Replace(const void* aPc, const char* aFunction, const char* aLibrary,
                     ptrdiff_t aLOffset, const char* aFileName,
                     unsigned long aLineNo) {
          mPc = aPc;

          // Convert "" to nullptr.  Otherwise, make a copy of the name.
          AllocPolicy::free_(mFunction);
          mFunction = !aFunction[0] ? nullptr : AllocPolicy::strdup_(aFunction);
          AllocPolicy::free_(mFileName);
          mFileName = !aFileName[0] ? nullptr : AllocPolicy::strdup_(aFileName);

          mLibrary = aLibrary;
          mLOffset = aLOffset;
          mLineNo = aLineNo;

          mInUse = 1;
        }

        size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
          // Don't measure mLibrary because it's externally owned.
          size_t n = 0;
          n += aMallocSizeOf(mFunction);
          n += aMallocSizeOf(mFileName);
          return n;
        }
      };

      const char* InternLibraryString(const char* aString) {
        auto p = mLibraryStrings.lookupForAdd(aString);
        if (p) {
          return *p;
        }

        const char* newString = AllocPolicy::strdup_(aString);
        if (!mLibraryStrings.add(p, newString)) {
          MOZ_CRASH("CodeAddressService OOM");
        }
        return newString;
      }

      Entry& GetEntry(const void* aPc) {
        MOZ_ASSERT(DescribeCodeAddressLock::IsLocked());

        uint32_t index = HashGeneric(aPc) & kMask;
        MOZ_ASSERT(index < kNumEntries);
        Entry& entry = mEntries[index];

        if (!entry.mInUse || entry.mPc != aPc) {
          mNumCacheMisses++;

          // MozDescribeCodeAddress can (on Linux) acquire a lock inside
          // the shared library loader.  Another thread might call malloc
          // while holding that lock (when loading a shared library).  So
          // we have to exit the lock around this call.  For details, see
          // https://bugzilla.mozilla.org/show_bug.cgi?id=363334#c3
          MozCodeAddressDetails details;
          {
            DescribeCodeAddressLock::Unlock();
            (void)MozDescribeCodeAddress(const_cast(aPc), &details);
            DescribeCodeAddressLock::Lock();
          }

          const char* library = InternLibraryString(details.library);
          entry.Replace(aPc, details.function, library, details.loffset,
                        details.filename, details.lineno);

        } else {
          mNumCacheHits++;
        }

        MOZ_ASSERT(entry.mPc == aPc);

        return entry;
      }

      // A direct-mapped cache.  When doing dmd::Analyze() just after starting
      // desktop Firefox (which is similar to analyzing after a longer-running
      // session, thanks to the limit on how many records we print), a cache with
      // 2^24 entries (which approximates an infinite-entry cache) has a ~91% hit
      // rate.  A cache with 2^12 entries has a ~83% hit rate, and takes up ~85 KiB
      // (on 32-bit platforms) or ~150 KiB (on 64-bit platforms).
      static const size_t kNumEntries = 1 << 12;
      static const size_t kMask = kNumEntries - 1;
      Entry mEntries[kNumEntries];

      size_t mNumCacheHits;
      size_t mNumCacheMisses;

     public:
      CodeAddressService()
          : mLibraryStrings(64), mEntries(), mNumCacheHits(0), mNumCacheMisses(0) {}

      ~CodeAddressService() {
        for (auto iter = mLibraryStrings.iter(); !iter.done(); iter.next()) {
          AllocPolicy::free_(const_cast(iter.get()));
        }
      }

      void GetLocation(uint32_t aFrameNumber, const void* aPc, char* aBuf,
                       size_t aBufLen) {
        Entry& entry = GetEntry(aPc);
        MozFormatCodeAddress(aBuf, aBufLen, aFrameNumber, entry.mPc,
                             entry.mFunction, entry.mLibrary, entry.mLOffset,
                             entry.mFileName, entry.mLineNo);
      }

      size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
        size_t n = aMallocSizeOf(this);
        for (uint32_t i = 0; i < kNumEntries; i++) {
          n += mEntries[i].SizeOfExcludingThis(aMallocSizeOf);
        }

        n += mLibraryStrings.shallowSizeOfExcludingThis(aMallocSizeOf);
        for (auto iter = mLibraryStrings.iter(); !iter.done(); iter.next()) {
          n += aMallocSizeOf(iter.get());
        }

        return n;
      }

      size_t CacheCapacity() const { return kNumEntries; }

      size_t CacheCount() const {
        size_t n = 0;
        for (size_t i = 0; i < kNumEntries; i++) {
          if (mEntries[i].mInUse) {
            n++;
          }
        }
        return n;
      }

      size_t NumCacheHits() const { return mNumCacheHits; }
      size_t NumCacheMisses() const { return mNumCacheMisses; }
    };

    }  // namespace mozilla

## Minimal test - lines (22, 46)

path: .spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 89.23284250314286
new: 50.50321903589104
path: .spaces[0].spaces[0].metrics.mi.mi_sei
old: 144.53915057933605
new: 75.2688392743859
path: .spaces[0].spaces[0].metrics.mi.mi_original
old: 152.5881606803743
new: 86.3605045513737
path: .spaces[0].spaces[0].metrics.loc.blank
old: 0.0
new: 3.0
path: .spaces[0].spaces[0].metrics.loc.cloc
old: 0.0
new: 3.0
path: .spaces[0].spaces[0].metrics.loc.sloc
old: 1.0
new: 25.0
path: .spaces[0].spaces[0].metrics.loc.lloc
old: 0.0
new: 5.0
path: .spaces[0].spaces[0].metrics.loc.ploc
old: 1.0
new: 19.0
path: .spaces[0].spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 8.0
path: .spaces[0].spaces[0].metrics.cyclomatic.average
old: 1.0
new: 1.1428571428571428
path: .spaces[0].spaces[0].metrics.nexits.average
old: 0.0
new: 0.5
path: .spaces[0].spaces[0].metrics.nexits.sum
old: 0.0
new: 2.0
path: .spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 16.0
new: 133.6620089600894
path: .spaces[0].spaces[0].metrics.halstead.n1
old: 4.0
new: 15.0
path: .spaces[0].spaces[0].metrics.halstead.effort
old: 82.5
new: 3631.963765938086
path: .spaces[0].spaces[0].metrics.halstead.N1
old: 6.0
new: 48.0
path: .spaces[0].spaces[0].metrics.halstead.difficulty
old: 2.5
new: 10.0
path: .spaces[0].spaces[0].metrics.halstead.N2
old: 5.0
new: 24.0
path: .spaces[0].spaces[0].metrics.halstead.length
old: 11.0
new: 72.0
path: .spaces[0].spaces[0].metrics.halstead.n2
old: 4.0
new: 18.0
path: .spaces[0].spaces[0].metrics.halstead.vocabulary
old: 8.0
new: 33.0
path: .spaces[0].spaces[0].metrics.halstead.bugs
old: 0.006317055768674653
new: 0.07876012862433353
path: .spaces[0].spaces[0].metrics.halstead.level
old: 0.4
new: 0.1
path: .spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.4545454545454546
new: 1.8564167911123528
path: .spaces[0].spaces[0].metrics.halstead.time
old: 4.583333333333333
new: 201.7757647743381
path: .spaces[0].spaces[0].metrics.halstead.volume
old: 33.0
new: 363.1963765938086
path: .spaces[0].spaces[0].metrics.nom.functions
old: 1.0
new: 4.0
path: .spaces[0].spaces[0].metrics.nom.total
old: 1.0
new: 4.0
path: .spaces[0].spaces[0].metrics.cognitive.average
old: 0.0
new: 0.25
path: .spaces[0].spaces[0].metrics.cognitive.sum
old: 0.0
new: 1.0

### Code

    namespace detail {

    template
    class CodeAddressServiceAllocPolicy : public AllocPolicy {
     public:
      char* strdup_(const char* aStr) {
        char* s = AllocPolicy::template pod_malloc(strlen(aStr) + 1);
        if (!s) {
          MOZ_CRASH("CodeAddressService OOM");
        }
        strcpy(s, aStr);
        return s;
      }
    };

    // Default implementation of DescribeCodeAddressLock.
    struct DefaultDescribeCodeAddressLock {
      static void Unlock() {}
      static void Lock() {}
      // Because CodeAddressService asserts that IsLocked() is true, returning true
      // here is a sensible default when there is no relevant lock.
      static bool IsLocked() { return true; }
    };

    }  // namespace detail