LCOV - code coverage report
Current view: top level - xpcom/build - MainThreadIOLogger.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 17 87 19.5 %
Date: 2017-07-14 16:53:18 Functions: 5 12 41.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "MainThreadIOLogger.h"
       8             : 
       9             : #include "GeckoProfiler.h"
      10             : #include "IOInterposerPrivate.h"
      11             : #include "mozilla/IOInterposer.h"
      12             : #include "mozilla/StaticPtr.h"
      13             : #include "mozilla/TimeStamp.h"
      14             : #include "nsAutoPtr.h"
      15             : #include "nsNativeCharsetUtils.h"
      16             : #include "nsThreadUtils.h"
      17             : 
      18             : /**
      19             :  * This code uses NSPR stuff and STL containers because it must be detached
      20             :  * from leak checking code; this observer runs until the process terminates.
      21             :  */
      22             : 
      23             : #include <prenv.h>
      24             : #include <prprf.h>
      25             : #include <prthread.h>
      26             : #include <vector>
      27             : 
      28             : namespace {
      29             : 
      30           0 : struct ObservationWithStack
      31             : {
      32           0 :   ObservationWithStack(mozilla::IOInterposeObserver::Observation& aObs,
      33             :                        ProfilerBacktrace* aStack)
      34           0 :     : mObservation(aObs)
      35           0 :     , mStack(aStack)
      36             :   {
      37           0 :     const char16_t* filename = aObs.Filename();
      38           0 :     if (filename) {
      39           0 :       mFilename = filename;
      40             :     }
      41           0 :   }
      42             : 
      43             :   mozilla::IOInterposeObserver::Observation mObservation;
      44             :   ProfilerBacktrace*                        mStack;
      45             :   nsString                                  mFilename;
      46             : };
      47             : 
      48             : class MainThreadIOLoggerImpl final : public mozilla::IOInterposeObserver
      49             : {
      50             : public:
      51             :   MainThreadIOLoggerImpl();
      52             :   ~MainThreadIOLoggerImpl();
      53             : 
      54             :   bool Init();
      55             : 
      56             :   void Observe(Observation& aObservation);
      57             : 
      58             : private:
      59             :   static void sIOThreadFunc(void* aArg);
      60             :   void IOThreadFunc();
      61             : 
      62             :   TimeStamp             mLogStartTime;
      63             :   const char*           mFileName;
      64             :   PRThread*             mIOThread;
      65             :   IOInterposer::Monitor mMonitor;
      66             :   bool                  mShutdownRequired;
      67             :   std::vector<ObservationWithStack> mObservations;
      68             : };
      69             : 
      70           3 : static StaticAutoPtr<MainThreadIOLoggerImpl> sImpl;
      71             : 
      72           1 : MainThreadIOLoggerImpl::MainThreadIOLoggerImpl()
      73             :   : mFileName(nullptr)
      74             :   , mIOThread(nullptr)
      75           1 :   , mShutdownRequired(false)
      76             : {
      77           1 : }
      78             : 
      79           3 : MainThreadIOLoggerImpl::~MainThreadIOLoggerImpl()
      80             : {
      81           1 :   if (!mIOThread) {
      82           1 :     return;
      83             :   }
      84             :   {
      85             :     // Scope for lock
      86           0 :     IOInterposer::MonitorAutoLock lock(mMonitor);
      87           0 :     mShutdownRequired = true;
      88           0 :     lock.Notify();
      89             :   }
      90           0 :   PR_JoinThread(mIOThread);
      91           0 :   mIOThread = nullptr;
      92           3 : }
      93             : 
      94             : bool
      95           1 : MainThreadIOLoggerImpl::Init()
      96             : {
      97           1 :   if (mFileName) {
      98             :     // Already initialized
      99           0 :     return true;
     100             :   }
     101           1 :   mFileName = PR_GetEnv("MOZ_MAIN_THREAD_IO_LOG");
     102           1 :   if (!mFileName) {
     103             :     // Can't start
     104           1 :     return false;
     105             :   }
     106           0 :   mIOThread = PR_CreateThread(PR_USER_THREAD, &sIOThreadFunc, this,
     107             :                               PR_PRIORITY_LOW, PR_GLOBAL_THREAD,
     108             :                               PR_JOINABLE_THREAD, 0);
     109           0 :   if (!mIOThread) {
     110           0 :     return false;
     111             :   }
     112           0 :   return true;
     113             : }
     114             : 
     115             : /* static */ void
     116           0 : MainThreadIOLoggerImpl::sIOThreadFunc(void* aArg)
     117             : {
     118           0 :   AutoProfilerRegisterThread registerThread("MainThreadIOLogger");
     119           0 :   NS_SetCurrentThreadName("MainThreadIOLogger");
     120           0 :   MainThreadIOLoggerImpl* obj = static_cast<MainThreadIOLoggerImpl*>(aArg);
     121           0 :   obj->IOThreadFunc();
     122           0 : }
     123             : 
     124             : void
     125           0 : MainThreadIOLoggerImpl::IOThreadFunc()
     126             : {
     127           0 :   PRFileDesc* fd = PR_Open(mFileName, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
     128           0 :                            PR_IRUSR | PR_IWUSR | PR_IRGRP);
     129           0 :   if (!fd) {
     130           0 :     IOInterposer::MonitorAutoLock lock(mMonitor);
     131           0 :     mShutdownRequired = true;
     132           0 :     std::vector<ObservationWithStack>().swap(mObservations);
     133           0 :     return;
     134             :   }
     135           0 :   mLogStartTime = TimeStamp::Now();
     136             :   {
     137             :     // Scope for lock
     138           0 :     IOInterposer::MonitorAutoLock lock(mMonitor);
     139             :     while (true) {
     140           0 :       while (!mShutdownRequired && mObservations.empty()) {
     141           0 :         lock.Wait();
     142             :       }
     143           0 :       if (mShutdownRequired) {
     144           0 :         break;
     145             :       }
     146             :       // Pull events off the shared array onto a local one
     147           0 :       std::vector<ObservationWithStack> observationsToWrite;
     148           0 :       observationsToWrite.swap(mObservations);
     149             : 
     150             :       // Release the lock so that we're not holding anybody up during I/O
     151           0 :       IOInterposer::MonitorAutoUnlock unlock(mMonitor);
     152             : 
     153             :       // Now write the events.
     154           0 :       for (auto i = observationsToWrite.begin(), e = observationsToWrite.end();
     155             :            i != e; ++i) {
     156           0 :         if (i->mObservation.ObservedOperation() == OpNextStage) {
     157           0 :           PR_fprintf(fd, "%f,NEXT-STAGE\n",
     158           0 :                      (TimeStamp::Now() - mLogStartTime).ToMilliseconds());
     159           0 :           continue;
     160             :         }
     161           0 :         double durationMs = i->mObservation.Duration().ToMilliseconds();
     162           0 :         nsAutoCString nativeFilename;
     163           0 :         nativeFilename.AssignLiteral("(not available)");
     164           0 :         if (!i->mFilename.IsEmpty()) {
     165           0 :           if (NS_FAILED(NS_CopyUnicodeToNative(i->mFilename, nativeFilename))) {
     166           0 :             nativeFilename.AssignLiteral("(conversion failed)");
     167             :           }
     168             :         }
     169             :         /**
     170             :          * Format:
     171             :          * Start Timestamp (Milliseconds), Operation, Duration (Milliseconds), Event Source, Filename
     172             :          */
     173           0 :         if (PR_fprintf(fd, "%f,%s,%f,%s,%s\n",
     174           0 :                        (i->mObservation.Start() - mLogStartTime).ToMilliseconds(),
     175           0 :                        i->mObservation.ObservedOperationString(), durationMs,
     176           0 :                        i->mObservation.Reference(), nativeFilename.get()) > 0) {
     177             :           // TODO: Write out the callstack
     178           0 :           i->mStack = nullptr;
     179             :         }
     180             :       }
     181           0 :     }
     182             :   }
     183           0 :   PR_Close(fd);
     184             : }
     185             : 
     186             : void
     187           0 : MainThreadIOLoggerImpl::Observe(Observation& aObservation)
     188             : {
     189           0 :   if (!mFileName || !IsMainThread()) {
     190           0 :     return;
     191             :   }
     192           0 :   IOInterposer::MonitorAutoLock lock(mMonitor);
     193           0 :   if (mShutdownRequired) {
     194             :     // The writer thread isn't running. Don't enqueue any more data.
     195           0 :     return;
     196             :   }
     197             :   // Passing nullptr as aStack parameter for now
     198           0 :   mObservations.push_back(ObservationWithStack(aObservation, nullptr));
     199           0 :   lock.Notify();
     200             : }
     201             : 
     202             : } // namespace
     203             : 
     204             : namespace mozilla {
     205             : 
     206             : namespace MainThreadIOLogger {
     207             : 
     208             : bool
     209           1 : Init()
     210             : {
     211           2 :   nsAutoPtr<MainThreadIOLoggerImpl> impl(new MainThreadIOLoggerImpl());
     212           1 :   if (!impl->Init()) {
     213           1 :     return false;
     214             :   }
     215           0 :   sImpl = impl.forget();
     216           0 :   IOInterposer::Register(IOInterposeObserver::OpAllWithStaging, sImpl);
     217           0 :   return true;
     218             : }
     219             : 
     220             : } // namespace MainThreadIOLogger
     221             : 
     222             : } // namespace mozilla
     223             : 

Generated by: LCOV version 1.13