Global Metrics

path: .metrics.loc.lloc
old: 230.0
new: 52.0

path: .metrics.loc.sloc
old: 515.0
new: 224.0

path: .metrics.loc.ploc
old: 388.0
new: 170.0

path: .metrics.loc.blank
old: 72.0
new: 25.0

path: .metrics.loc.cloc
old: 55.0
new: 29.0

path: .metrics.nargs.sum
old: 34.0
new: 6.0

path: .metrics.nargs.average
old: 1.4782608695652173
new: 0.75

path: .metrics.cognitive.sum
old: 196.0
new: 30.0

path: .metrics.cognitive.average
old: 8.521739130434783
new: 3.75

path: .metrics.halstead.estimated_program_length
old: 1644.403252118508
new: 886.8310173464122

path: .metrics.halstead.bugs
old: 4.417962851769083
new: 0.9253160538109342

path: .metrics.halstead.purity_ratio
old: 0.7508690648942958
new: 1.4054374284412237

path: .metrics.halstead.level
old: 0.011251258364422336
new: 0.030713388245148677

path: .metrics.halstead.N1
old: 1324.0
new: 384.0

path: .metrics.halstead.N2
old: 866.0
new: 247.0

path: .metrics.halstead.difficulty
old: 88.87894736842105
new: 32.55909090909091

path: .metrics.halstead.effort
old: 1525860.9961547835
new: 146257.12347442078

path: .metrics.halstead.length
old: 2190.0
new: 631.0

path: .metrics.halstead.n1
old: 39.0
new: 29.0

path: .metrics.halstead.time
old: 84770.05534193241
new: 8125.395748578932

path: .metrics.halstead.n2
old: 190.0
new: 110.0

path: .metrics.halstead.vocabulary
old: 229.0
new: 139.0

path: .metrics.halstead.volume
old: 17167.856295932306
new: 4492.051816888534

path: .metrics.nom.functions
old: 23.0
new: 8.0

path: .metrics.nom.total
old: 23.0
new: 8.0

path: .metrics.nexits.average
old: 3.0869565217391304
new: 1.25

path: .metrics.nexits.sum
old: 71.0
new: 10.0

path: .metrics.mi.mi_visual_studio
old: 0.0
new: 18.853214464268703

path: .metrics.mi.mi_sei
old: -56.0411544625703
new: 0.5182444800644106

path: .metrics.mi.mi_original
old: -13.0596330815017
new: 32.238996733899484

path: .metrics.cyclomatic.average
old: 4.827586206896552
new: 2.2857142857142856

path: .metrics.cyclomatic.sum
old: 140.0
new: 32.0

Spaces Data

Minimal test - lines (30, 51)

path: .spaces[0].spaces[0].metrics.loc.lloc
old: 0.0
new: 1.0

path: .spaces[0].spaces[0].metrics.loc.sloc
old: 7.0
new: 22.0

path: .spaces[0].spaces[0].metrics.loc.ploc
old: 6.0
new: 21.0

path: .spaces[0].spaces[0].metrics.halstead.vocabulary
old: 16.0
new: 20.0

path: .spaces[0].spaces[0].metrics.halstead.difficulty
old: 5.444444444444445
new: 9.0

path: .spaces[0].spaces[0].metrics.halstead.bugs
old: 0.025097778938159565
new: 0.046968253716542153

path: .spaces[0].spaces[0].metrics.halstead.effort
old: 653.3333333333334
new: 1672.5861727214094

path: .spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.6060269822461346
new: 1.5484435539067694

path: .spaces[0].spaces[0].metrics.halstead.level
old: 0.18367346938775508
new: 0.1111111111111111

path: .spaces[0].spaces[0].metrics.halstead.volume
old: 120.0
new: 185.8429080801566

path: .spaces[0].spaces[0].metrics.halstead.n1
old: 7.0
new: 9.0

path: .spaces[0].spaces[0].metrics.halstead.n2
old: 9.0
new: 11.0

path: .spaces[0].spaces[0].metrics.halstead.N1
old: 16.0
new: 21.0

path: .spaces[0].spaces[0].metrics.halstead.length
old: 30.0
new: 43.0

path: .spaces[0].spaces[0].metrics.halstead.N2
old: 14.0
new: 22.0

path: .spaces[0].spaces[0].metrics.halstead.time
old: 36.2962962962963
new: 92.9214540400783

path: .spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 48.18080946738404
new: 66.58307281799108

path: .spaces[0].spaces[0].metrics.mi.mi_sei
old: 89.1450191655025
new: 59.09992069024463

path: .spaces[0].spaces[0].metrics.mi.mi_original
old: 114.1212985228373
new: 93.29562322506636

path: .spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 66.73760147534345
new: 54.55884399126688

path: .spaces[0].spaces[0].metrics.nargs.sum
old: 0.0
new: 4.0

path: .spaces[0].spaces[0].metrics.nargs.average
old: 0.0
new: 4.0

Code

struct ObservationWithStack {
  explicit ObservationWithStack(mozilla::IOInterposeObserver::Observation& aObs
#ifdef MOZ_GECKO_PROFILER
                                ,
                                ProfilerBacktrace* aStack
#endif
                                )
      : mObservation(aObs)
#ifdef MOZ_GECKO_PROFILER
        ,
        mStack(aStack)
#endif
  {
    aObs.Filename(mFilename);
  }

  mozilla::IOInterposeObserver::Observation mObservation;
#ifdef MOZ_GECKO_PROFILER
  ProfilerBacktrace* mStack;
#endif
  nsString mFilename;
};

Minimal test - lines (31, 44)

path: .spaces[0].spaces[0].spaces[0].metrics.mi.mi_visual_studio
old: 87.97970938710789
new: 60.332377463615366

path: .spaces[0].spaces[0].spaces[0].metrics.mi.mi_sei
old: 141.4476605054837
new: 73.24145709716794

path: .spaces[0].spaces[0].spaces[0].metrics.mi.mi_original
old: 150.44530305195448
new: 103.16836546278228

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.length
old: 15.0
new: 28.0

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.n2
old: 6.0
new: 10.0

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.volume
old: 49.82892142331043
new: 118.9419703764204

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.difficulty
old: 2.3333333333333335
new: 6.3

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.level
old: 0.42857142857142855
new: 0.15873015873015872

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.vocabulary
old: 10.0
new: 19.0

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.N1
old: 8.0
new: 14.0

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.N2
old: 7.0
new: 14.0

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.purity_ratio
old: 1.5673183336217955
new: 2.2053073557805156

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.bugs
old: 0.007940556250510787
new: 0.027499778601425103

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.effort
old: 116.26748332105768
new: 749.3344133714484

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.time
old: 6.459304628947649
new: 41.629689631747134

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.n1
old: 4.0
new: 9.0

path: .spaces[0].spaces[0].spaces[0].metrics.halstead.estimated_program_length
old: 23.509775004326936
new: 61.74860596185444

path: .spaces[0].spaces[0].spaces[0].metrics.loc.sloc
old: 1.0
new: 14.0

path: .spaces[0].spaces[0].spaces[0].metrics.loc.ploc
old: 1.0
new: 14.0

path: .spaces[0].spaces[0].spaces[0].metrics.loc.lloc
old: 0.0
new: 1.0

path: .spaces[0].spaces[0].spaces[0].metrics.nargs.average
old: 0.0
new: 4.0

path: .spaces[0].spaces[0].spaces[0].metrics.nargs.sum
old: 0.0
new: 4.0

Code

  explicit ObservationWithStack(mozilla::IOInterposeObserver::Observation& aObs
#ifdef MOZ_GECKO_PROFILER
                                ,
                                ProfilerBacktrace* aStack
#endif
                                )
      : mObservation(aObs)
#ifdef MOZ_GECKO_PROFILER
        ,
        mStack(aStack)
#endif
  {
    aObs.Filename(mFilename);
  }

Minimal test - lines (28, 206)

path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 29.0

path: .spaces[0].metrics.cognitive.average
old: 0.0
new: 4.142857142857143

path: .spaces[0].metrics.cyclomatic.sum
old: 3.0
new: 27.0

path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 2.7

path: .spaces[0].metrics.mi.mi_visual_studio
old: 55.13610199277192
new: 21.99866503267546

path: .spaces[0].metrics.mi.mi_original
old: 94.28273440763998
new: 37.61771720587504

path: .spaces[0].metrics.mi.mi_sei
old: 78.02454794791635
new: 4.293782376696974

path: .spaces[0].metrics.nom.total
old: 1.0
new: 7.0

path: .spaces[0].metrics.nom.functions
old: 1.0
new: 7.0

path: .spaces[0].metrics.loc.ploc
old: 15.0
new: 144.0

path: .spaces[0].metrics.loc.lloc
old: 0.0
new: 47.0

path: .spaces[0].metrics.loc.blank
old: 3.0
new: 18.0

path: .spaces[0].metrics.loc.cloc
old: 1.0
new: 17.0

path: .spaces[0].metrics.loc.sloc
old: 19.0
new: 179.0

path: .spaces[0].metrics.nexits.sum
old: 0.0
new: 8.0

path: .spaces[0].metrics.nexits.average
old: 0.0
new: 1.1428571428571428

path: .spaces[0].metrics.nargs.sum
old: 0.0
new: 6.0

path: .spaces[0].metrics.nargs.average
old: 0.0
new: 0.8571428571428571

path: .spaces[0].metrics.halstead.purity_ratio
old: 1.8697373660251153
new: 1.3119805908429767

path: .spaces[0].metrics.halstead.N1
old: 27.0
new: 355.0

path: .spaces[0].metrics.halstead.n2
old: 17.0
new: 94.0

path: .spaces[0].metrics.halstead.difficulty
old: 5.411764705882353
new: 34.244680851063826

path: .spaces[0].metrics.halstead.effort
old: 1256.572851350808
new: 137178.39967213196

path: .spaces[0].metrics.halstead.length
old: 50.0
new: 577.0

path: .spaces[0].metrics.halstead.N2
old: 23.0
new: 222.0

path: .spaces[0].metrics.halstead.bugs
old: 0.0388153816076943
new: 0.8866166851526256

path: .spaces[0].metrics.halstead.level
old: 0.18478260869565216
new: 0.029201615408511964

path: .spaces[0].metrics.halstead.estimated_program_length
old: 93.48686830125575
new: 757.0128009163975

path: .spaces[0].metrics.halstead.vocabulary
old: 25.0
new: 123.0

path: .spaces[0].metrics.halstead.n1
old: 8.0
new: 29.0

path: .spaces[0].metrics.halstead.volume
old: 232.19280948873623
new: 4005.830869580742

path: .spaces[0].metrics.halstead.time
old: 69.80960285282266
new: 7621.022204007331

Code

namespace {

struct ObservationWithStack {
  explicit ObservationWithStack(mozilla::IOInterposeObserver::Observation& aObs
#ifdef MOZ_GECKO_PROFILER
                                ,
                                ProfilerBacktrace* aStack
#endif
                                )
      : mObservation(aObs)
#ifdef MOZ_GECKO_PROFILER
        ,
        mStack(aStack)
#endif
  {
    aObs.Filename(mFilename);
  }

  mozilla::IOInterposeObserver::Observation mObservation;
#ifdef MOZ_GECKO_PROFILER
  ProfilerBacktrace* mStack;
#endif
  nsString mFilename;
};

class MainThreadIOLoggerImpl final : public mozilla::IOInterposeObserver {
 public:
  MainThreadIOLoggerImpl();
  ~MainThreadIOLoggerImpl();

  bool Init();

  void Observe(Observation& aObservation) override;

 private:
  static void sIOThreadFunc(void* aArg);
  void IOThreadFunc();

  mozilla::TimeStamp mLogStartTime;
  const char* mFileName;
  PRThread* mIOThread;
  mozilla::IOInterposer::Monitor mMonitor;
  bool mShutdownRequired;
  std::vector mObservations;
};

static mozilla::StaticAutoPtr sImpl;

MainThreadIOLoggerImpl::MainThreadIOLoggerImpl()
    : mFileName(nullptr), mIOThread(nullptr), mShutdownRequired(false) {}

MainThreadIOLoggerImpl::~MainThreadIOLoggerImpl() {
  if (!mIOThread) {
    return;
  }
  {
    // Scope for lock
    mozilla::IOInterposer::MonitorAutoLock lock(mMonitor);
    mShutdownRequired = true;
    lock.Notify();
  }
  PR_JoinThread(mIOThread);
  mIOThread = nullptr;
}

bool MainThreadIOLoggerImpl::Init() {
  if (mFileName) {
    // Already initialized
    return true;
  }
  mFileName = PR_GetEnv("MOZ_MAIN_THREAD_IO_LOG");
  if (!mFileName) {
    // Can't start
    return false;
  }
  mIOThread =
      PR_CreateThread(PR_USER_THREAD, &sIOThreadFunc, this, PR_PRIORITY_LOW,
                      PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
  if (!mIOThread) {
    return false;
  }
  return true;
}

/* static */
void MainThreadIOLoggerImpl::sIOThreadFunc(void* aArg) {
  AUTO_PROFILER_REGISTER_THREAD("MainThreadIOLogger");

  NS_SetCurrentThreadName("MainThreadIOLogger");
  MainThreadIOLoggerImpl* obj = static_cast(aArg);
  obj->IOThreadFunc();
}

void MainThreadIOLoggerImpl::IOThreadFunc() {
  PRFileDesc* fd = PR_Open(mFileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
                           PR_IRUSR | PR_IWUSR | PR_IRGRP);
  if (!fd) {
    mozilla::IOInterposer::MonitorAutoLock lock(mMonitor);
    mShutdownRequired = true;
    std::vector().swap(mObservations);
    return;
  }
  mLogStartTime = mozilla::TimeStamp::Now();
  {
    // Scope for lock
    mozilla::IOInterposer::MonitorAutoLock lock(mMonitor);
    while (true) {
      while (!mShutdownRequired && mObservations.empty()) {
        lock.Wait();
      }
      if (mShutdownRequired) {
        break;
      }
      // Pull events off the shared array onto a local one
      std::vector observationsToWrite;
      observationsToWrite.swap(mObservations);

      // Release the lock so that we're not holding anybody up during I/O
      mozilla::IOInterposer::MonitorAutoUnlock unlock(mMonitor);

      // Now write the events.
      for (auto i = observationsToWrite.begin(), e = observationsToWrite.end();
           i != e; ++i) {
        if (i->mObservation.ObservedOperation() == OpNextStage) {
          PR_fprintf(
              fd, "%f,NEXT-STAGE\n",
              (mozilla::TimeStamp::Now() - mLogStartTime).ToMilliseconds());
          continue;
        }
        double durationMs = i->mObservation.Duration().ToMilliseconds();
        nsAutoCString nativeFilename;
        nativeFilename.AssignLiteral("(not available)");
        if (!i->mFilename.IsEmpty()) {
          if (NS_FAILED(NS_CopyUnicodeToNative(i->mFilename, nativeFilename))) {
            nativeFilename.AssignLiteral("(conversion failed)");
          }
        }
        // clang-format off
        /**
         * Format:
         * Start Timestamp (Milliseconds), Operation, Duration (Milliseconds), Event Source, Filename
         */
        // clang-format on
        if (PR_fprintf(
                fd, "%f,%s,%f,%s,%s\n",
                (i->mObservation.Start() - mLogStartTime).ToMilliseconds(),
                i->mObservation.ObservedOperationString(), durationMs,
                i->mObservation.Reference(), nativeFilename.get()) > 0) {
#ifdef MOZ_GECKO_PROFILER
          // TODO: Write out the callstack
          i->mStack = nullptr;
#endif
        }
      }
    }
  }
  PR_Close(fd);
}

void MainThreadIOLoggerImpl::Observe(Observation& aObservation) {
  if (!mFileName || !IsMainThread()) {
    return;
  }
  mozilla::IOInterposer::MonitorAutoLock lock(mMonitor);
  if (mShutdownRequired) {
    // The writer thread isn't running. Don't enqueue any more data.
    return;
  }
  // Passing nullptr as aStack parameter for now
  mObservations.push_back(ObservationWithStack(aObservation
#ifdef MOZ_GECKO_PROFILER
                                               ,
                                               nullptr
#endif
                                               ));
  lock.Notify();
}

}  // namespace

Minimal test - lines (208, 224)

path: .spaces[1].metrics.cognitive.sum
old: 119.0
new: 1.0

path: .spaces[1].metrics.cognitive.average
old: 13.22222222222222
new: 1.0

path: .spaces[1].metrics.mi.mi_original
old: 19.72034018044529
new: 96.33948736024982

path: .spaces[1].metrics.mi.mi_sei
old: -18.2437887787733
new: 82.04272597782098

path: .spaces[1].metrics.mi.mi_visual_studio
old: 11.532362678622976
new: 56.33888149722212

path: .spaces[1].metrics.nargs.sum
old: 19.0
new: 0.0

path: .spaces[1].metrics.nargs.average
old: 2.111111111111111
new: 0.0

path: .spaces[1].metrics.cyclomatic.average
old: 7.0
new: 1.3333333333333333

path: .spaces[1].metrics.cyclomatic.sum
old: 70.0
new: 4.0

path: .spaces[1].metrics.halstead.n2
old: 105.0
new: 12.0

path: .spaces[1].metrics.halstead.length
old: 1139.0
new: 45.0

path: .spaces[1].metrics.halstead.purity_ratio
old: 0.7708248603665095
new: 2.1405004203880074

path: .spaces[1].metrics.halstead.N1
old: 683.0
new: 29.0

path: .spaces[1].metrics.halstead.difficulty
old: 73.82857142857142
new: 9.333333333333334

path: .spaces[1].metrics.halstead.estimated_program_length
old: 877.9695159574544
new: 96.32251891746031

path: .spaces[1].metrics.halstead.n1
old: 34.0
new: 14.0

path: .spaces[1].metrics.halstead.time
old: 33257.61350897473
new: 109.67692675662548

path: .spaces[1].metrics.halstead.effort
old: 598637.0431615452
new: 1974.1846816192583

path: .spaces[1].metrics.halstead.level
old: 0.013544891640866877
new: 0.10714285714285714

path: .spaces[1].metrics.halstead.volume
old: 8108.473881832075
new: 211.51978731634912

path: .spaces[1].metrics.halstead.bugs
old: 2.367669810907326
new: 0.0524570580560377

path: .spaces[1].metrics.halstead.N2
old: 456.0
new: 16.0

path: .spaces[1].metrics.halstead.vocabulary
old: 139.0
new: 26.0

path: .spaces[1].metrics.nexits.average
old: 3.7777777777777777
new: 2.0

path: .spaces[1].metrics.nexits.sum
old: 34.0
new: 2.0

path: .spaces[1].metrics.nom.functions
old: 9.0
new: 1.0

path: .spaces[1].metrics.nom.total
old: 9.0
new: 1.0

path: .spaces[1].metrics.loc.sloc
old: 234.0
new: 17.0

path: .spaces[1].metrics.loc.blank
old: 26.0
new: 3.0

path: .spaces[1].metrics.loc.cloc
old: 20.0
new: 1.0

path: .spaces[1].metrics.loc.lloc
old: 119.0
new: 5.0

path: .spaces[1].metrics.loc.ploc
old: 188.0
new: 13.0

Code

namespace mozilla {

namespace MainThreadIOLogger {

bool Init() {
  auto impl = MakeUnique();
  if (!impl->Init()) {
    return false;
  }
  sImpl = impl.release();
  IOInterposer::Register(IOInterposeObserver::OpAllWithStaging, sImpl);
  return true;
}

}  // namespace MainThreadIOLogger

}  // namespace mozilla

Minimal test - lines (210, 222)

path: .spaces[1].spaces[0].metrics.cyclomatic.sum
old: 2.0
new: 3.0

path: .spaces[1].spaces[0].metrics.cyclomatic.average
old: 2.0
new: 1.5

path: .spaces[1].spaces[0].metrics.loc.sloc
old: 3.0
new: 13.0

path: .spaces[1].spaces[0].metrics.loc.lloc
old: 2.0
new: 5.0

path: .spaces[1].spaces[0].metrics.loc.blank
old: 0.0
new: 2.0

path: .spaces[1].spaces[0].metrics.loc.ploc
old: 3.0
new: 11.0

path: .spaces[1].spaces[0].metrics.halstead.level
old: 0.1111111111111111
new: 0.10476190476190476

path: .spaces[1].spaces[0].metrics.halstead.length
old: 25.0
new: 43.0

path: .spaces[1].spaces[0].metrics.halstead.purity_ratio
old: 1.6055586194967049
new: 2.1245748072980635

path: .spaces[1].spaces[0].metrics.halstead.N2
old: 10.0
new: 15.0

path: .spaces[1].spaces[0].metrics.halstead.vocabulary
old: 14.0
new: 25.0

path: .spaces[1].spaces[0].metrics.halstead.difficulty
old: 9.0
new: 9.545454545454543

path: .spaces[1].spaces[0].metrics.halstead.time
old: 47.59193652572005
new: 105.89399341834788

path: .spaces[1].spaces[0].metrics.halstead.volume
old: 95.1838730514401
new: 199.68581616031315

path: .spaces[1].spaces[0].metrics.halstead.N1
old: 15.0
new: 28.0

path: .spaces[1].spaces[0].metrics.halstead.effort
old: 856.6548574629609
new: 1906.0918815302616

path: .spaces[1].spaces[0].metrics.halstead.estimated_program_length
old: 40.13896548741762
new: 91.35671671381672

path: .spaces[1].spaces[0].metrics.halstead.n1
old: 9.0
new: 14.0

path: .spaces[1].spaces[0].metrics.halstead.bugs
old: 0.030066485534799937
new: 0.05124379671641141

path: .spaces[1].spaces[0].metrics.halstead.n2
old: 5.0
new: 11.0

path: .spaces[1].spaces[0].metrics.mi.mi_sei
old: 110.6858521667939
new: 70.62661870383211

path: .spaces[1].spaces[0].metrics.mi.mi_visual_studio
old: 75.46916151145908
new: 59.1899095356019

path: .spaces[1].spaces[0].metrics.mi.mi_original
old: 129.05226618459503
new: 101.21474530587923

path: .spaces[1].spaces[0].metrics.nexits.sum
old: 0.0
new: 2.0

path: .spaces[1].spaces[0].metrics.nexits.average
old: 0.0
new: 2.0

Code

namespace MainThreadIOLogger {

bool Init() {
  auto impl = MakeUnique();
  if (!impl->Init()) {
    return false;
  }
  sImpl = impl.release();
  IOInterposer::Register(IOInterposeObserver::OpAllWithStaging, sImpl);
  return true;
}

}  // namespace MainThreadIOLogger