Bug 799640 - Part 2: Save profiles on shutdown using custom JSON encoder. r=ehsan

This commit is contained in:
Benoit Girard 2012-11-30 12:49:20 -05:00
parent e9dec350e6
commit 5137011d7b
9 changed files with 540 additions and 71 deletions

View File

@ -3937,6 +3937,7 @@ XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
MOZ_gdk_display_close(mGdkDisplay);
#endif
SAMPLER_SHUTDOWN();
rv = LaunchChild(mNativeApp, true);
#ifdef MOZ_CRASHREPORTER
@ -3959,6 +3960,8 @@ XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
XRE_DeinitCommandLine();
SAMPLER_SHUTDOWN();
return NS_FAILED(rv) ? 1 : 0;
}
@ -4070,6 +4073,7 @@ XRE_mainMetro(int argc, char* argv[], const nsXREAppData* aAppData)
// thread that called XRE_metroStartup.
NS_ASSERTION(!xreMainPtr->mScopedXPCom,
"XPCOM Shutdown hasn't occured, and we are exiting.");
SAMPLER_SHUTDOWN();
return 0;
}

View File

@ -0,0 +1,30 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
#ifndef JSAOBJECTBUILDER_H
#define JSAOBJECTBUILDER_H
class JSCustomObject;
class JSCustomArray;
class nsAString;
class JSAObjectBuilder
{
public:
virtual ~JSAObjectBuilder() = 0;
virtual void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue) = 0;
virtual void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue) = 0;
virtual void DefineProperty(JSCustomObject *aObject, const char *name, int value) = 0;
virtual void DefineProperty(JSCustomObject *aObject, const char *name, double value) = 0;
virtual void DefineProperty(JSCustomObject *aObject, const char *name, const char *value) = 0;
virtual void ArrayPush(JSCustomArray *aArray, int value) = 0;
virtual void ArrayPush(JSCustomArray *aArray, const char *value) = 0;
virtual void ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject) = 0;
virtual JSCustomArray *CreateArray() = 0;
virtual JSCustomObject *CreateObject() = 0;
};
#endif

View File

@ -0,0 +1,311 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
#include "JSCustomObjectBuilder.h"
#include "nsStringGlue.h"
#include "nsDataHashtable.h"
#include "nsUTF8Utils.h"
#if _MSC_VER
#define snprintf _snprintf
#endif
// These are owned and deleted by JSCustomObject
struct PropertyValue {
virtual ~PropertyValue() {}
virtual void SendToStream(std::ostream& stream) = 0;
};
template <typename T>
struct finalizer_impl
{
static void run(T) {}
};
template <typename T>
struct finalizer_impl<T*>
{
static void run(T* p) {
delete p;
}
};
template <>
struct finalizer_impl<char *>
{
static void run(char* p) {
free(p);
}
};
template <class T>
class TemplatePropertyValue : public PropertyValue {
public:
TemplatePropertyValue(T aValue)
: mValue(aValue)
{}
~TemplatePropertyValue() {
finalizer_impl<T>::run(mValue);
}
virtual void SendToStream(std::ostream& stream);
private:
T mValue;
};
// Escape a UTF8 string to a stream. When an illegal encoding
// is found it will insert "INVALID" and the function will return.
void EscapeToStream(std::ostream& stream, const char* str) {
stream << "\"";
size_t len = strlen(str);
const char* end = &str[len];
while (str < end) {
bool err;
const char* utf8CharStart = str;
uint32_t ucs4Char = UTF8CharEnumerator::NextChar(&str, end, &err);
if (err) {
// Encoding error
stream << "INVALID\"";
return;
}
// See http://www.ietf.org/rfc/rfc4627.txt?number=4627
// characters that must be escaped: quotation mark,
// reverse solidus, and the control characters
// (U+0000 through U+001F).
if (ucs4Char == '\"') {
stream << "\\\"";
} else if (ucs4Char == '\\') {
stream << "\\\\";
} else if (ucs4Char > 0xFF) {
PRUnichar chr[2];
ConvertUTF8toUTF16 encoder(chr);
encoder.write(utf8CharStart, str-utf8CharStart);
char escChar[13];
snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X\\u%04X", chr[0], chr[1]);
stream << escChar;
} else if (ucs4Char < 0x1F || ucs4Char > 0xFF) {
char escChar[7];
snprintf(escChar, mozilla::ArrayLength(escChar), "\\u%04X", ucs4Char);
stream << escChar;
} else {
stream << char(ucs4Char);
}
}
stream << "\"";
}
class JSCustomObject {
public:
JSCustomObject() {
mProperties.Init();
}
~JSCustomObject();
friend std::ostream& operator<<(std::ostream& stream, JSCustomObject* entry);
template<class T>
void AddProperty(const char* aName, T aValue) {
mProperties.Put(nsDependentCString(aName), new TemplatePropertyValue<T>(aValue));
}
nsDataHashtable<nsCStringHashKey, PropertyValue*> mProperties;
};
class JSCustomArray {
public:
nsTArray<PropertyValue*> mValues;
friend std::ostream& operator<<(std::ostream& stream, JSCustomArray* entry);
template<class T>
void AppendElement(T aValue) {
mValues.AppendElement(new TemplatePropertyValue<T>(aValue));
}
};
template <typename T>
struct SendToStreamImpl
{
static void run(std::ostream& stream, const T& t) {
stream << t;
}
};
template<typename T>
struct SendToStreamImpl<T*>
{
static void run(std::ostream& stream, T* t) {
stream << *t;
}
};
template <>
struct SendToStreamImpl<char *>
{
static void run(std::ostream& stream, char* p) {
EscapeToStream(stream, p);
}
};
template <>
struct SendToStreamImpl<JSCustomObject*>
{
static void run(std::ostream& stream, JSCustomObject* p) {
stream << p;
}
};
template <>
struct SendToStreamImpl<JSCustomArray*>
{
static void run(std::ostream& stream, JSCustomArray* p) {
stream << p;
}
};
template <class T> void
TemplatePropertyValue<T>::SendToStream(std::ostream& stream)
{
SendToStreamImpl<T>::run(stream, mValue);
}
struct JSONStreamClosure {
std::ostream& mStream;
bool mNeedsComma;
};
PLDHashOperator HashTableOutput(const nsACString& aKey, PropertyValue* aValue, void* stream)
{
JSONStreamClosure& streamClosure = *(JSONStreamClosure*)stream;
if (streamClosure.mNeedsComma) {
streamClosure.mStream << ",";
}
streamClosure.mNeedsComma = true;
EscapeToStream(streamClosure.mStream, (const char*)aKey.BeginReading());
streamClosure.mStream << ":";
aValue->SendToStream(streamClosure.mStream);
return PLDHashOperator::PL_DHASH_NEXT;
}
std::ostream&
operator<<(std::ostream& stream, JSCustomObject* entry)
{
JSONStreamClosure streamClosure = {stream, false};
stream << "{";
entry->mProperties.EnumerateRead(HashTableOutput, &streamClosure);
stream << "}";
return stream;
}
std::ostream&
operator<<(std::ostream& stream, JSCustomArray* entry)
{
bool needsComma = false;
stream << "[";
for (int i = 0; i < entry->mValues.Length(); i++) {
if (needsComma) {
stream << ",";
}
entry->mValues[i]->SendToStream(stream);
needsComma = true;
}
stream << "]";
return stream;
}
PLDHashOperator HashTableFree(const nsACString& aKey, PropertyValue* aValue, void* stream)
{
delete aValue;
return PLDHashOperator::PL_DHASH_NEXT;
}
JSCustomObject::~JSCustomObject()
{
mProperties.EnumerateRead(HashTableFree, nullptr);
}
JSAObjectBuilder::~JSAObjectBuilder()
{
}
JSCustomObjectBuilder::JSCustomObjectBuilder()
{}
void
JSCustomObjectBuilder::DeleteObject(JSCustomObject* aObject)
{
delete aObject;
}
void
JSCustomObjectBuilder::Serialize(JSCustomObject* aObject, std::ostream& stream)
{
stream << aObject;
}
void
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue)
{
aObject->AddProperty(name, aValue);
}
void
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue)
{
aObject->AddProperty(name, aValue);
}
void
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, int aValue)
{
aObject->AddProperty(name, aValue);
}
void
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, double aValue)
{
aObject->AddProperty(name, aValue);
}
void
JSCustomObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, const char *aValue)
{
// aValue copy will be freed by the property desctructor (template specialization)
aObject->AddProperty(name, strdup(aValue));
}
void
JSCustomObjectBuilder::ArrayPush(JSCustomArray *aArray, int aValue)
{
aArray->AppendElement(aValue);
}
void
JSCustomObjectBuilder::ArrayPush(JSCustomArray *aArray, const char *aValue)
{
// aValue copy will be freed by the property desctructor (template specialization)
aArray->AppendElement(strdup(aValue));
}
void
JSCustomObjectBuilder::ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject)
{
aArray->AppendElement(aObject);
}
JSCustomArray*
JSCustomObjectBuilder::CreateArray() {
return new JSCustomArray();
}
JSCustomObject*
JSCustomObjectBuilder::CreateObject() {
return new JSCustomObject();
}

View File

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
#ifndef JSCUSTOMOBJECTBUILDER_H
#define JSCUSTOMOBJECTBUILDER_H
#include <ostream>
#include "JSAObjectBuilder.h"
class JSCustomObject;
class JSCustomArray;
class JSCustomObjectBuilder;
class JSCustomObjectBuilder : public JSAObjectBuilder
{
public:
// We need to ensure that this object lives on the stack so that GC sees it properly
JSCustomObjectBuilder();
void Serialize(JSCustomObject* aObject, std::ostream& stream);
void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue);
void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue);
void DefineProperty(JSCustomObject *aObject, const char *name, int value);
void DefineProperty(JSCustomObject *aObject, const char *name, double value);
void DefineProperty(JSCustomObject *aObject, const char *name, const char *value, size_t valueLength);
void DefineProperty(JSCustomObject *aObject, const char *name, const char *value);
void ArrayPush(JSCustomArray *aArray, int value);
void ArrayPush(JSCustomArray *aArray, const char *value);
void ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject);
JSCustomArray *CreateArray();
JSCustomObject *CreateObject();
// Delete this object and all of its descendant
void DeleteObject(JSCustomObject* aObject);
private:
// This class can't be copied
JSCustomObjectBuilder(const JSCustomObjectBuilder&);
JSCustomObjectBuilder& operator=(const JSCustomObjectBuilder&);
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*) {
// Since JSCustomObjectBuilder has a virtual destructor the compiler
// has to provide a destructor in the object file that will call
// operate delete in case there is a derived class since its
// destructor wont know how to free this instance.
abort();
}
void operator delete[](void*);
};
#endif

View File

@ -11,34 +11,40 @@ JSObjectBuilder::JSObjectBuilder(JSContext *aCx) : mCx(aCx), mOk(JS_TRUE)
{}
void
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, JSObject *aValue)
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue)
{
DefineProperty(aObject, name, (JSCustomObject*)aValue);
}
void
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue)
{
if (!mOk)
return;
mOk = JS_DefineProperty(mCx, aObject, name, OBJECT_TO_JSVAL(aValue), NULL, NULL, JSPROP_ENUMERATE);
mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, OBJECT_TO_JSVAL((JSObject*)aValue), nullptr, nullptr, JSPROP_ENUMERATE);
}
void
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, int value)
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, int value)
{
if (!mOk)
return;
mOk = JS_DefineProperty(mCx, aObject, name, INT_TO_JSVAL(value), NULL, NULL, JSPROP_ENUMERATE);
mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, INT_TO_JSVAL(value), nullptr, nullptr, JSPROP_ENUMERATE);
}
void
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, double value)
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, double value)
{
if (!mOk)
return;
mOk = JS_DefineProperty(mCx, aObject, name, DOUBLE_TO_JSVAL(value), NULL, NULL, JSPROP_ENUMERATE);
mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, DOUBLE_TO_JSVAL(value), nullptr, nullptr, JSPROP_ENUMERATE);
}
void
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, nsAString &value)
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, nsAString &value)
{
if (!mOk)
return;
@ -51,11 +57,11 @@ JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, nsAString &
if (!mOk)
return;
mOk = JS_DefineProperty(mCx, aObject, name, STRING_TO_JSVAL(string), NULL, NULL, JSPROP_ENUMERATE);
mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, STRING_TO_JSVAL(string), nullptr, nullptr, JSPROP_ENUMERATE);
}
void
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, const char *value, size_t valueLength)
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, const char *value, size_t valueLength)
{
if (!mOk)
return;
@ -66,33 +72,32 @@ JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, const char
return;
}
mOk = JS_DefineProperty(mCx, aObject, name, STRING_TO_JSVAL(string), NULL, NULL, JSPROP_ENUMERATE);
}
mOk = JS_DefineProperty(mCx, (JSObject*)aObject, name, STRING_TO_JSVAL(string), nullptr, nullptr, JSPROP_ENUMERATE); }
void
JSObjectBuilder::DefineProperty(JSObject *aObject, const char *name, const char *value)
JSObjectBuilder::DefineProperty(JSCustomObject *aObject, const char *name, const char *value)
{
DefineProperty(aObject, name, value, strlen(value));
}
void
JSObjectBuilder::ArrayPush(JSObject *aArray, int value)
JSObjectBuilder::ArrayPush(JSCustomArray *aArray, int value)
{
if (!mOk)
return;
jsval objval = INT_TO_JSVAL(value);
uint32_t length;
mOk = JS_GetArrayLength(mCx, aArray, &length);
mOk = JS_GetArrayLength(mCx, (JSObject*)aArray, &length);
if (!mOk)
return;
mOk = JS_SetElement(mCx, aArray, length, &objval);
mOk = JS_SetElement(mCx, (JSObject*)aArray, length, &objval);
}
void
JSObjectBuilder::ArrayPush(JSObject *aArray, const char *value)
JSObjectBuilder::ArrayPush(JSCustomArray *aArray, const char *value)
{
if (!mOk)
return;
@ -105,42 +110,41 @@ JSObjectBuilder::ArrayPush(JSObject *aArray, const char *value)
jsval objval = STRING_TO_JSVAL(string);
uint32_t length;
mOk = JS_GetArrayLength(mCx, aArray, &length);
mOk = JS_GetArrayLength(mCx, (JSObject*)aArray, &length);
if (!mOk)
return;
mOk = JS_SetElement(mCx, aArray, length, &objval);
mOk = JS_SetElement(mCx, (JSObject*)aArray, length, &objval);
}
void
JSObjectBuilder::ArrayPush(JSObject *aArray, JSObject *aObject)
JSObjectBuilder::ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject)
{
if (!mOk)
return;
jsval objval = OBJECT_TO_JSVAL(aObject);
uint32_t length;
mOk = JS_GetArrayLength(mCx, aArray, &length);
jsval objval = OBJECT_TO_JSVAL((JSObject*)aObject); uint32_t length;
mOk = JS_GetArrayLength(mCx, (JSObject*)aArray, &length);
if (!mOk)
return;
mOk = JS_SetElement(mCx, aArray, length, &objval);
mOk = JS_SetElement(mCx, (JSObject*)aArray, length, &objval);
}
JSObject*
JSCustomArray*
JSObjectBuilder::CreateArray() {
JSObject *array = JS_NewArrayObject(mCx, 0, NULL);
JSCustomArray *array = (JSCustomArray*)JS_NewArrayObject(mCx, 0, nullptr);
if (!array)
mOk = JS_FALSE;
return array;
}
JSObject*
JSCustomObject*
JSObjectBuilder::CreateObject() {
JSObject *obj = JS_NewObject(mCx, NULL, NULL, NULL);
JSCustomObject *obj = (JSCustomObject*)JS_NewObject(mCx, nullptr, nullptr, nullptr);
if (!obj)
mOk = JS_FALSE;

View File

@ -3,37 +3,60 @@
* 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/. */
class JSObject;
class JSObjectBuilder;
#ifndef JSOBJECTBUILDER_H
#define JSOBJECTBUILDER_H
#include "JSAObjectBuilder.h"
class JSCustomObject;
class JSCustomObjectBuilder;
class JSContext;
class nsAString;
/* this is handy wrapper around JSAPI to make it more pleasant to use.
* We collect the JSAPI errors and so that callers don't need to */
class JSObjectBuilder
class JSObjectBuilder : public JSAObjectBuilder
{
public:
// We need to ensure that this object lives on the stack so that GC sees it properly
JSObjectBuilder(JSContext *aCx);
explicit JSObjectBuilder(JSContext *aCx);
~JSObjectBuilder() {}
void DefineProperty(JSObject *aObject, const char *name, JSObject *aValue);
void DefineProperty(JSObject *aObject, const char *name, int value);
void DefineProperty(JSObject *aObject, const char *name, double value);
void DefineProperty(JSObject *aObject, const char *name, nsAString &value);
void DefineProperty(JSObject *aObject, const char *name, const char *value, size_t valueLength);
void DefineProperty(JSObject *aObject, const char *name, const char *value);
void ArrayPush(JSObject *aArray, int value);
void ArrayPush(JSObject *aArray, const char *value);
void ArrayPush(JSObject *aArray, JSObject *aObject);
JSObject *CreateArray();
JSObject *CreateObject();
void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomObject *aValue);
void DefineProperty(JSCustomObject *aObject, const char *name, JSCustomArray *aValue);
void DefineProperty(JSCustomObject *aObject, const char *name, int value);
void DefineProperty(JSCustomObject *aObject, const char *name, double value);
void DefineProperty(JSCustomObject *aObject, const char *name, nsAString &value);
void DefineProperty(JSCustomObject *aObject, const char *name, const char *value, size_t valueLength);
void DefineProperty(JSCustomObject *aObject, const char *name, const char *value);
void ArrayPush(JSCustomArray *aArray, int value);
void ArrayPush(JSCustomArray *aArray, const char *value);
void ArrayPush(JSCustomArray *aArray, JSCustomArray *aObject);
void ArrayPush(JSCustomArray *aArray, JSCustomObject *aObject);
JSCustomArray *CreateArray();
JSCustomObject *CreateObject();
JSObject* GetJSObject(JSCustomObject* aObject) { return (JSObject*)aObject; }
private:
JSObjectBuilder(JSObjectBuilder&);
JSObjectBuilder(const JSObjectBuilder&);
JSObjectBuilder& operator=(const JSObjectBuilder&);
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*) {
// Since JSObjectBuilder has a virtual destructor the compiler
// has to provide a destructor in the object file that will call
// operate delete in case there is a derived class since its
// destructor wont know how to free this instance.
abort();
}
void operator delete[](void*);
JSContext *mCx;
JSObject *mObj;
int mOk;
};
#endif

View File

@ -64,6 +64,7 @@ CPPSRCS = \
nsProfiler.cpp \
TableTicker.cpp \
JSObjectBuilder.cpp \
JSCustomObjectBuilder.cpp \
$(NULL)
XPIDLSRCS = \

View File

@ -5,7 +5,6 @@
#include <string>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include "sps_sampler.h"
@ -18,6 +17,7 @@
// JSON
#include "JSObjectBuilder.h"
#include "JSCustomObjectBuilder.h"
#include "nsIJSRuntimeService.h"
// Meta
@ -307,17 +307,31 @@ public:
}
}
JSObject *ToJSObject(JSContext *aCx)
void ToStreamAsJSON(std::ostream& stream)
{
JSCustomObjectBuilder b;
JSCustomObject *profile = b.CreateObject();
BuildJSObject(b, profile);
b.Serialize(profile, stream);
b.DeleteObject(profile);
}
JSCustomObject *ToJSObject(JSContext *aCx)
{
JSObjectBuilder b(aCx);
JSCustomObject *profile = b.CreateObject();
BuildJSObject(b, profile);
JSObject *profile = b.CreateObject();
JSObject *samples = b.CreateArray();
return profile;
}
void BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile) {
JSCustomArray *samples = b.CreateArray();
b.DefineProperty(profile, "samples", samples);
JSObject *sample = NULL;
JSObject *frames = NULL;
JSObject *marker = NULL;
JSCustomObject *sample = nullptr;
JSCustomArray *frames = nullptr;
JSCustomArray *marker = nullptr;
int readPos = mReadPos;
while (readPos != mLastFlushPos) {
@ -382,7 +396,7 @@ public:
case 'l':
{
if (sample) {
JSObject *frame = b.CreateObject();
JSCustomObject *frame = b.CreateObject();
if (entry.mTagName == 'l') {
// Bug 753041
// We need a double cast here to tell GCC that we don't want to sign
@ -406,8 +420,6 @@ public:
}
readPos = (readPos + incBy) % mEntrySize;
}
return profile;
}
ProfileStack* GetStack()
@ -473,8 +485,9 @@ class TableTicker: public Sampler {
return &mPrimaryThreadProfile;
}
void ToStreamAsJSON(std::ostream& stream);
JSObject *ToJSObject(JSContext *aCx);
JSObject *GetMetaJSObject(JSObjectBuilder& b);
JSCustomObject *GetMetaJSCustomObject(JSAObjectBuilder& b);
const bool ProfileJS() { return mProfileJS; }
@ -482,6 +495,7 @@ private:
// Not implemented on platforms which do not support backtracing
void doBacktrace(ThreadProfile &aProfile, TickSample* aSample);
void BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile);
private:
// This represent the application's main thread (SAMPLER_INIT)
ThreadProfile mPrimaryThreadProfile;
@ -513,7 +527,6 @@ public:
NS_IMETHOD Run() {
TableTicker *t = tlsTicker.get();
// Pause the profiler during saving.
// This will prevent us from recording sampling
// regarding profile saving. This will also
@ -543,7 +556,7 @@ public:
return rv;
#endif
// Create a JSContext to run a JSObjectBuilder :(
// Create a JSContext to run a JSCustomObjectBuilder :(
// Based on XPCShellEnvironment
JSRuntime *rt;
JSContext *cx;
@ -575,7 +588,6 @@ public:
// regarding profile saving. This will also
// prevent bugs caused by the circular buffer not
// being thread safe. Bug 750989.
t->SetPaused(true);
if (stream.is_open()) {
JSAutoCompartment autoComp(cx, obj);
JSObject* profileObj = mozilla_sampler_get_profile_data(cx);
@ -590,8 +602,6 @@ public:
JS_EndRequest(cx);
JS_DestroyContext(cx);
t->SetPaused(false);
return NS_OK;
}
};
@ -608,9 +618,9 @@ void TableTicker::HandleSaveRequest()
NS_DispatchToMainThread(runnable);
}
JSObject* TableTicker::GetMetaJSObject(JSObjectBuilder& b)
JSCustomObject* TableTicker::GetMetaJSCustomObject(JSAObjectBuilder& b)
{
JSObject *meta = b.CreateObject();
JSCustomObject *meta = b.CreateObject();
b.DefineProperty(meta, "version", 2);
b.DefineProperty(meta, "interval", interval());
@ -661,30 +671,44 @@ JSObject* TableTicker::GetMetaJSObject(JSObjectBuilder& b)
return meta;
}
void TableTicker::ToStreamAsJSON(std::ostream& stream)
{
JSCustomObjectBuilder b;
JSCustomObject* profile = b.CreateObject();
BuildJSObject(b, profile);
b.Serialize(profile, stream);
b.DeleteObject(profile);
}
JSObject* TableTicker::ToJSObject(JSContext *aCx)
{
JSObjectBuilder b(aCx);
JSCustomObject* profile = b.CreateObject();
BuildJSObject(b, profile);
JSObject* jsProfile = b.GetJSObject(profile);
JSObject *profile = b.CreateObject();
return jsProfile;
}
void TableTicker::BuildJSObject(JSAObjectBuilder& b, JSCustomObject* profile)
{
// Put shared library info
b.DefineProperty(profile, "libs", GetSharedLibraryInfoString().c_str());
// Put meta data
JSObject *meta = GetMetaJSObject(b);
JSCustomObject *meta = GetMetaJSCustomObject(b);
b.DefineProperty(profile, "meta", meta);
// Lists the samples for each ThreadProfile
JSObject *threads = b.CreateArray();
JSCustomArray *threads = b.CreateArray();
b.DefineProperty(profile, "threads", threads);
// For now we only have one thread
SetPaused(true);
JSObject* threadSamples = GetPrimaryThreadProfile()->ToJSObject(aCx);
JSCustomObject* threadSamples = b.CreateObject();
GetPrimaryThreadProfile()->BuildJSObject(b, threadSamples);
b.ArrayPush(threads, threadSamples);
SetPaused(false);
return profile;
}
static
@ -1062,8 +1086,21 @@ void mozilla_sampler_init()
features, sizeof(features)/sizeof(const char*));
}
void mozilla_sampler_deinit()
void mozilla_sampler_shutdown()
{
TableTicker *t = tlsTicker.get();
if (t) {
const char *val = PR_GetEnv("MOZ_PROFILER_SHUTDOWN");
if (val) {
std::ofstream stream;
stream.open(val);
if (stream.is_open()) {
t->ToStreamAsJSON(stream);
stream.close();
}
}
}
mozilla_sampler_stop();
// We can't delete the Stack because we can be between a
// sampler call_enter/call_exit point.

View File

@ -8,11 +8,11 @@
#include <stdarg.h>
#include "mozilla/ThreadLocal.h"
#include "nscore.h"
#include "jsapi.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Util.h"
#include "nsAlgorithm.h"
/* QT has a #define for the word "slots" and jsfriendapi.h has a struct with
* this variable name, causing compilation problems. Alleviate this for now by
* removing this #define */
@ -26,6 +26,7 @@ using mozilla::TimeDuration;
struct ProfileStack;
class TableTicker;
class JSCustomObject;
extern mozilla::ThreadLocal<ProfileStack *> tlsStack;
extern mozilla::ThreadLocal<TableTicker *> tlsTicker;
@ -42,7 +43,7 @@ extern bool stack_key_initialized;
#endif
#define SAMPLER_INIT() mozilla_sampler_init()
#define SAMPLER_DEINIT() mozilla_sampler_deinit()
#define SAMPLER_SHUTDOWN() mozilla_sampler_shutdown()
#define SAMPLER_START(entries, interval, features, featureCount) mozilla_sampler_start(entries, interval, features, featureCount)
#define SAMPLER_STOP() mozilla_sampler_stop()
#define SAMPLER_IS_ACTIVE() mozilla_sampler_is_active()
@ -172,6 +173,7 @@ char* mozilla_sampler_get_profile();
JSObject *mozilla_sampler_get_profile_data(JSContext *aCx);
const char** mozilla_sampler_get_features();
void mozilla_sampler_init();
void mozilla_sampler_shutdown();
void mozilla_sampler_print_location();