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/. */
7 #include "MainThreadIOLogger.h"
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"
17 * This code uses NSPR stuff and STL containers because it must be detached
18 * from leak checking code; this observer runs until the process terminates.
28 struct ObservationWithStack
30 ObservationWithStack(mozilla::IOInterposeObserver::Observation
& aObs
,
31 ProfilerBacktrace
*aStack
)
35 const char16_t
* filename
= aObs
.Filename();
41 mozilla::IOInterposeObserver::Observation mObservation
;
42 ProfilerBacktrace
* mStack
;
46 } // anonymous namespace
50 class MainThreadIOLoggerImpl MOZ_FINAL
: public IOInterposeObserver
53 MainThreadIOLoggerImpl();
54 ~MainThreadIOLoggerImpl();
58 void Observe(Observation
& aObservation
);
61 static void sIOThreadFunc(void* aArg
);
64 TimeStamp mLogStartTime
;
65 const char* mFileName
;
67 IOInterposer::Monitor mMonitor
;
68 bool mShutdownRequired
;
69 std::vector
<ObservationWithStack
> mObservations
;
72 static StaticAutoPtr
<MainThreadIOLoggerImpl
> sImpl
;
74 MainThreadIOLoggerImpl::MainThreadIOLoggerImpl()
77 , mShutdownRequired(false)
81 MainThreadIOLoggerImpl::~MainThreadIOLoggerImpl()
87 IOInterposer::MonitorAutoLock
lock(mMonitor
);
88 mShutdownRequired
= true;
91 PR_JoinThread(mIOThread
);
96 MainThreadIOLoggerImpl::Init()
99 // Already initialized
102 mFileName
= PR_GetEnv("MOZ_MAIN_THREAD_IO_LOG");
107 mIOThread
= PR_CreateThread(PR_USER_THREAD
, &sIOThreadFunc
, this,
108 PR_PRIORITY_LOW
, PR_GLOBAL_THREAD
,
109 PR_JOINABLE_THREAD
, 0);
117 MainThreadIOLoggerImpl::sIOThreadFunc(void* aArg
)
119 PR_SetCurrentThreadName("MainThreadIOLogger");
120 MainThreadIOLoggerImpl
* obj
= static_cast<MainThreadIOLoggerImpl
*>(aArg
);
125 MainThreadIOLoggerImpl::IOThreadFunc()
127 PRFileDesc
* fd
= PR_Open(mFileName
, PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
,
128 PR_IRUSR
| PR_IWUSR
| PR_IRGRP
);
130 IOInterposer::MonitorAutoLock
lock(mMonitor
);
131 mShutdownRequired
= true;
132 std::vector
<ObservationWithStack
>().swap(mObservations
);
135 mLogStartTime
= TimeStamp::Now();
137 IOInterposer::MonitorAutoLock
lock(mMonitor
);
139 while (!mShutdownRequired
&& mObservations
.empty()) {
142 if (mShutdownRequired
) {
145 // Pull events off the shared array onto a local one
146 std::vector
<ObservationWithStack
> observationsToWrite
;
147 observationsToWrite
.swap(mObservations
);
149 // Release the lock so that we're not holding anybody up during I/O
150 IOInterposer::MonitorAutoUnlock
unlock(mMonitor
);
152 // Now write the events.
153 for (std::vector
<ObservationWithStack
>::iterator
154 i
= observationsToWrite
.begin(), e
= observationsToWrite
.end();
156 if (i
->mObservation
.ObservedOperation() == OpNextStage
) {
157 PR_fprintf(fd
, "%f,NEXT-STAGE\n",
158 (TimeStamp::Now() - mLogStartTime
).ToMilliseconds());
161 double durationMs
= i
->mObservation
.Duration().ToMilliseconds();
162 nsAutoCString nativeFilename
;
163 nativeFilename
.AssignLiteral("(not available)");
164 if (!i
->mFilename
.IsEmpty()) {
165 if (NS_FAILED(NS_CopyUnicodeToNative(i
->mFilename
, nativeFilename
))) {
166 nativeFilename
.AssignLiteral("(conversion failed)");
171 * Start Timestamp (Milliseconds), Operation, Duration (Milliseconds), Event Source, Filename
173 if (PR_fprintf(fd
, "%f,%s,%f,%s,%s\n",
174 (i
->mObservation
.Start() - mLogStartTime
).ToMilliseconds(),
175 i
->mObservation
.ObservedOperationString(), durationMs
,
176 i
->mObservation
.Reference(), nativeFilename
.get()) > 0) {
177 ProfilerBacktrace
* stack
= i
->mStack
;
179 // TODO: Write out the callstack
180 // (This will be added in a later bug)
181 profiler_free_backtrace(stack
);
191 MainThreadIOLoggerImpl::Observe(Observation
& aObservation
)
193 if (!mFileName
|| !IsMainThread()) {
196 IOInterposer::MonitorAutoLock
lock(mMonitor
);
197 if (mShutdownRequired
) {
198 // The writer thread isn't running. Don't enqueue any more data.
201 // Passing nullptr as aStack parameter for now
202 mObservations
.push_back(ObservationWithStack(aObservation
, nullptr));
206 namespace MainThreadIOLogger
{
211 nsAutoPtr
<MainThreadIOLoggerImpl
> impl(new MainThreadIOLoggerImpl());
215 sImpl
= impl
.forget();
216 IOInterposer::Register(IOInterposeObserver::OpAllWithStaging
, sImpl
);
220 } // namespace MainThreadIOLogger
222 } // namespace mozilla