mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-14 03:07:31 +09:00
Issue #21 - Remove Telemetry plumbing and fix build.
Note this won't give working applications. Requires FE changes and additional js module changes (next part).
This commit is contained in:
parent
92a1cc3139
commit
8d800b1cb0
205 changed files with 45 additions and 40519 deletions
|
|
@ -8,7 +8,6 @@ EXPORTS += ['nsTerminator.h']
|
|||
SOURCES += ['nsTerminator.cpp']
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'nsTerminatorTelemetry.js',
|
||||
'terminator.manifest',
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
|
@ -44,7 +43,6 @@
|
|||
#include "mozilla/Services.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
// Normally, the number of milliseconds that AsyncShutdown waits until
|
||||
// it decides to crash is specified as a preference. We use the
|
||||
|
|
@ -156,143 +154,6 @@ RunWatchdog(void* arg)
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////
|
||||
//
|
||||
// Writer thread
|
||||
//
|
||||
// This nspr thread is in charge of writing to disk statistics produced by the
|
||||
// watchdog thread and collected by the main thread. Note that we use a nspr
|
||||
// thread rather than usual XPCOM I/O simply because we outlive XPCOM and its
|
||||
// threads.
|
||||
//
|
||||
|
||||
// Utility class, used by UniquePtr<> to close nspr files.
|
||||
class PR_CloseDelete
|
||||
{
|
||||
public:
|
||||
constexpr PR_CloseDelete() {}
|
||||
|
||||
PR_CloseDelete(const PR_CloseDelete& aOther)
|
||||
{}
|
||||
|
||||
void operator()(PRFileDesc* aPtr) const
|
||||
{
|
||||
PR_Close(aPtr);
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Communication between the main thread and the writer thread.
|
||||
//
|
||||
// Main thread:
|
||||
//
|
||||
// * Whenever a shutdown step has been completed, the main thread
|
||||
// obtains the number of ticks from the watchdog threads, builds
|
||||
// a string representing all the data gathered so far, places
|
||||
// this string in `gWriteData`, and wakes up the writer thread
|
||||
// using `gWriteReady`. If `gWriteData` already contained a non-null
|
||||
// pointer, this means that the writer thread is lagging behind the
|
||||
// main thread, and the main thread cleans up the memory.
|
||||
//
|
||||
// Writer thread:
|
||||
//
|
||||
// * When awake, the writer thread swaps `gWriteData` to nullptr. If
|
||||
// `gWriteData` contained data to write, the . If so, the writer
|
||||
// thread writes the data to a file named "ShutdownDuration.json.tmp",
|
||||
// then moves that file to "ShutdownDuration.json" and cleans up the
|
||||
// data. If `gWriteData` contains a nullptr, the writer goes to sleep
|
||||
// until it is awkened using `gWriteReady`.
|
||||
//
|
||||
//
|
||||
// The data written by the writer thread will be read by another
|
||||
// module upon the next restart and fed to Telemetry.
|
||||
//
|
||||
Atomic<nsCString*> gWriteData(nullptr);
|
||||
PRMonitor* gWriteReady = nullptr;
|
||||
|
||||
void RunWriter(void* arg)
|
||||
{
|
||||
PR_SetCurrentThreadName("Shutdown Statistics Writer");
|
||||
|
||||
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(arg);
|
||||
// Shutdown will generally complete before we have a chance to
|
||||
// deallocate. This is not a leak.
|
||||
|
||||
// Setup destinationPath and tmpFilePath
|
||||
|
||||
nsCString destinationPath(static_cast<char*>(arg));
|
||||
nsAutoCString tmpFilePath;
|
||||
tmpFilePath.Append(destinationPath);
|
||||
tmpFilePath.AppendLiteral(".tmp");
|
||||
|
||||
// Cleanup any file leftover from a previous run
|
||||
Unused << PR_Delete(tmpFilePath.get());
|
||||
Unused << PR_Delete(destinationPath.get());
|
||||
|
||||
while (true) {
|
||||
//
|
||||
// Check whether we have received data from the main thread.
|
||||
//
|
||||
// We perform the check before waiting on `gWriteReady` as we may
|
||||
// have received data while we were busy writing.
|
||||
//
|
||||
// Also note that gWriteData may have been modified several times
|
||||
// since we last checked. That's ok, we are not losing any important
|
||||
// data (since we keep adding data), and we are not leaking memory
|
||||
// (since the main thread deallocates any data that hasn't been
|
||||
// consumed by the writer thread).
|
||||
//
|
||||
UniquePtr<nsCString> data(gWriteData.exchange(nullptr));
|
||||
if (!data) {
|
||||
// Data is not available yet.
|
||||
// Wait until the main thread provides it.
|
||||
PR_EnterMonitor(gWriteReady);
|
||||
PR_Wait(gWriteReady, PR_INTERVAL_NO_TIMEOUT);
|
||||
PR_ExitMonitor(gWriteReady);
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(data.get());
|
||||
// Shutdown may complete before we have a chance to deallocate.
|
||||
// This is not a leak.
|
||||
|
||||
//
|
||||
// Write to a temporary file
|
||||
//
|
||||
// In case of any error, we simply give up. Since the data is
|
||||
// hardly critical, we don't want to spend too much effort
|
||||
// salvaging it.
|
||||
//
|
||||
UniquePtr<PRFileDesc, PR_CloseDelete>
|
||||
tmpFileDesc(PR_Open(tmpFilePath.get(),
|
||||
PR_WRONLY | PR_TRUNCATE | PR_CREATE_FILE,
|
||||
00600));
|
||||
|
||||
// Shutdown may complete before we have a chance to close the file.
|
||||
// This is not a leak.
|
||||
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(tmpFileDesc.get());
|
||||
|
||||
if (tmpFileDesc == nullptr) {
|
||||
break;
|
||||
}
|
||||
if (PR_Write(tmpFileDesc.get(), data->get(), data->Length()) == -1) {
|
||||
break;
|
||||
}
|
||||
tmpFileDesc.reset();
|
||||
|
||||
//
|
||||
// Rename on top of destination file.
|
||||
//
|
||||
// This is not sufficient to guarantee that the destination file
|
||||
// will be written correctly, but, again, we don't care enough
|
||||
// about the data to make more efforts.
|
||||
//
|
||||
if (PR_Rename(tmpFilePath.get(), destinationPath.get()) != PR_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A step during shutdown.
|
||||
*
|
||||
|
|
@ -347,18 +208,12 @@ nsTerminator::SelfInit()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Actually launch these threads. This takes place at the first sign of shutdown.
|
||||
// Actually launch the thread. This takes place at the first sign of shutdown.
|
||||
void
|
||||
nsTerminator::Start()
|
||||
{
|
||||
MOZ_ASSERT(!mInitialized);
|
||||
StartWatchdog();
|
||||
#if !defined(DEBUG)
|
||||
// Only allow nsTerminator to write on non-debug builds so we don't get leak warnings on
|
||||
// shutdown for intentional leaks (see bug 1242084). This will be enabled again by bug
|
||||
// 1255484 when 1255478 lands.
|
||||
StartWriter();
|
||||
#endif // !defined(DEBUG)
|
||||
mInitialized = true;
|
||||
}
|
||||
|
||||
|
|
@ -397,43 +252,6 @@ nsTerminator::StartWatchdog()
|
|||
MOZ_ASSERT(watchdogThread);
|
||||
}
|
||||
|
||||
// Prepare, allocate and start the writer thread. By design, it will never
|
||||
// finish, nor be deallocated. In case of error, we degrade
|
||||
// gracefully to not writing Telemetry data.
|
||||
void
|
||||
nsTerminator::StartWriter()
|
||||
{
|
||||
if (!Telemetry::CanRecordExtended()) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIFile> profLD;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_LOCAL_50_DIR,
|
||||
getter_AddRefs(profLD));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rv = profLD->Append(NS_LITERAL_STRING("ShutdownDuration.json"));
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString path;
|
||||
rv = profLD->GetPath(path);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
gWriteReady = PR_NewMonitor();
|
||||
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(gWriteReady); // We will never deallocate this object
|
||||
PRThread* writerThread = CreateSystemThread(RunWriter,
|
||||
ToNewUTF8String(path));
|
||||
|
||||
if (!writerThread) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsTerminator::Observe(nsISupports *, const char *aTopic, const char16_t *)
|
||||
{
|
||||
|
|
@ -451,13 +269,6 @@ nsTerminator::Observe(nsISupports *, const char *aTopic, const char16_t *)
|
|||
}
|
||||
|
||||
UpdateHeartbeat(aTopic);
|
||||
#if !defined(DEBUG)
|
||||
// Only allow nsTerminator to write on non-debug builds so we don't get leak warnings on
|
||||
// shutdown for intentional leaks (see bug 1242084). This will be enabled again by bug
|
||||
// 1255484 when 1255478 lands.
|
||||
UpdateTelemetry();
|
||||
#endif // !defined(DEBUG)
|
||||
UpdateCrashReport(aTopic);
|
||||
|
||||
// Perform a little cleanup
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
|
|
@ -489,61 +300,4 @@ nsTerminator::UpdateHeartbeat(const char* aTopic)
|
|||
mCurrentStep = nextStep;
|
||||
}
|
||||
|
||||
void
|
||||
nsTerminator::UpdateTelemetry()
|
||||
{
|
||||
if (!Telemetry::CanRecordExtended() || !gWriteReady) {
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// We need Telemetry data on the effective duration of each step,
|
||||
// to be able to tune the time-to-crash of each of both the
|
||||
// Terminator and AsyncShutdown. However, at this stage, it is too
|
||||
// late to record such data into Telemetry, so we write it to disk
|
||||
// and read it upon the next startup.
|
||||
//
|
||||
|
||||
// Build JSON.
|
||||
UniquePtr<nsCString> telemetryData(new nsCString());
|
||||
telemetryData->AppendLiteral("{");
|
||||
size_t fields = 0;
|
||||
for (size_t i = 0; i < ArrayLength(sShutdownSteps); ++i) {
|
||||
if (sShutdownSteps[i].mTicks < 0) {
|
||||
// Ignore this field.
|
||||
continue;
|
||||
}
|
||||
if (fields++ > 0) {
|
||||
telemetryData->Append(", ");
|
||||
}
|
||||
telemetryData->AppendLiteral("\"");
|
||||
telemetryData->Append(sShutdownSteps[i].mTopic);
|
||||
telemetryData->AppendLiteral("\": ");
|
||||
telemetryData->AppendInt(sShutdownSteps[i].mTicks);
|
||||
}
|
||||
telemetryData->AppendLiteral("}");
|
||||
|
||||
if (fields == 0) {
|
||||
// Nothing to write
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Send data to the worker thread.
|
||||
//
|
||||
delete gWriteData.exchange(telemetryData.release()); // Clear any data that hasn't been written yet
|
||||
|
||||
// In case the worker thread was sleeping, wake it up.
|
||||
PR_EnterMonitor(gWriteReady);
|
||||
PR_Notify(gWriteReady);
|
||||
PR_ExitMonitor(gWriteReady);
|
||||
}
|
||||
|
||||
void
|
||||
nsTerminator::UpdateCrashReport(const char* aTopic)
|
||||
{
|
||||
/*** STUB ***/
|
||||
}
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
|
@ -23,11 +22,8 @@ private:
|
|||
nsresult SelfInit();
|
||||
void Start();
|
||||
void StartWatchdog();
|
||||
void StartWriter();
|
||||
|
||||
void UpdateHeartbeat(const char* aTopic);
|
||||
void UpdateTelemetry();
|
||||
void UpdateCrashReport(const char* aTopic);
|
||||
|
||||
~nsTerminator() {}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,104 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Read the data saved by nsTerminator during shutdown and feed it to the
|
||||
* relevant telemetry histograms.
|
||||
*/
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS",
|
||||
"resource://gre/modules/osfile.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "setTimeout",
|
||||
"resource://gre/modules/Timer.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
||||
"resource://gre/modules/Services.jsm");
|
||||
|
||||
function nsTerminatorTelemetry() {}
|
||||
|
||||
var HISTOGRAMS = {
|
||||
"quit-application": "SHUTDOWN_PHASE_DURATION_TICKS_QUIT_APPLICATION",
|
||||
"profile-change-teardown": "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_CHANGE_TEARDOWN",
|
||||
"profile-before-change": "SHUTDOWN_PHASE_DURATION_TICKS_PROFILE_BEFORE_CHANGE",
|
||||
"xpcom-will-shutdown": "SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_WILL_SHUTDOWN",
|
||||
};
|
||||
|
||||
nsTerminatorTelemetry.prototype = {
|
||||
classID: Components.ID("{3f78ada1-cba2-442a-82dd-d5fb300ddea7}"),
|
||||
|
||||
_xpcom_factory: XPCOMUtils.generateSingletonFactory(nsTerminatorTelemetry),
|
||||
|
||||
// nsISupports
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
|
||||
|
||||
// nsIObserver
|
||||
|
||||
observe: function DS_observe(aSubject, aTopic, aData)
|
||||
{
|
||||
Task.spawn(function*() {
|
||||
//
|
||||
// This data is hardly critical, reading it can wait for a few seconds.
|
||||
//
|
||||
yield new Promise(resolve => setTimeout(resolve, 3000));
|
||||
|
||||
let PATH = OS.Path.join(OS.Constants.Path.localProfileDir,
|
||||
"ShutdownDuration.json");
|
||||
let raw;
|
||||
try {
|
||||
raw = yield OS.File.read(PATH, { encoding: "utf-8" });
|
||||
} catch (ex) {
|
||||
if (!ex.becauseNoSuchFile) {
|
||||
throw ex;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// Let other errors be reported by Promise's error-reporting.
|
||||
|
||||
// Clean up
|
||||
OS.File.remove(PATH);
|
||||
OS.File.remove(PATH + ".tmp");
|
||||
|
||||
let data = JSON.parse(raw);
|
||||
for (let k of Object.keys(data)) {
|
||||
let id = HISTOGRAMS[k];
|
||||
try {
|
||||
let histogram = Services.telemetry.getHistogramById(id);
|
||||
if (!histogram) {
|
||||
throw new Error("Unknown histogram " + id);
|
||||
}
|
||||
|
||||
histogram.add(Number.parseInt(data[k]));
|
||||
} catch (ex) {
|
||||
// Make sure that the error is reported and causes test failures,
|
||||
// but otherwise, ignore it.
|
||||
Promise.reject(ex);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Inform observers that we are done.
|
||||
Services.obs.notifyObservers(null,
|
||||
"shutdown-terminator-telemetry-updated",
|
||||
"");
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// Module
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([nsTerminatorTelemetry]);
|
||||
Loading…
Add table
Add a link
Reference in a new issue