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