xpcom/build/MainThreadIOLogger.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial