Bug 1329111 - Change the nsIProfiler shared library information API. r=njn

API before this change:
 - nsIProfiler::getSharedLibraryInformation() returns a string containing a
   JSON array of libraries.
 - The profile format is at version 3.
 - Every profile has a "libs" field that contains the same JSON string as the
   return value of nsIProfiler::getSharedLibraryInformation.
 - The array of libraries is not sorted.
 - Each library has a "name" field that contains:
    - The module's debug name on Windows
    - The full path to the binary on Mac + Linux

API after this change:
 - nsIProfiler::getSharedLibraryInformation() is removed.
 - nsIProfiler has a readonly property called sharedLibraries.
 - The profile format is at version 4.
 - Every profile has a "libs" field that contains the same array as
   nsIProfiler.sharedLibraries, no longer as a JSON string but as a regular
   array.
 - The array of libraries is sorted by start address.
 - Each library has a "name" field that contains the binary file's basename,
   on all platforms.
 - Each library has a "path" field that contains the full path to the binary,
   on all platforms.
 - Each library has a "debugName" field that contains the library's debug
   name, on all platforms. On Windows, the debug name is the filename
   (basename) of the pdb file for that binary. On other platforms, debugName
   is the same as |name|.
 - Each library has a "debugPath" field that contains the absolute path
   library's pdb file on Windows; on non-Windows, debugPath and path are the
   same.
 - Each library has an "arch" field that is either an empty string (Linux +
   Windows) or the library's architecture; it'll differentiate between the
   architectures "x86_64" and "x86_64h". (x86_64h is used for binaries that
   contain instructions that are specific to the Intel Haswell
   microarchitecture.)

MozReview-Commit-ID: 8Nrs4dyHhDS

--HG--
extra : rebase_source : 4039926ae4d776bf53ea71df5fe3f8200d3e2784
extra : source : 4e282aa03422de5b8d51e1aaeb3e53ee547293dd
This commit is contained in:
Markus Stange 2017-03-14 18:59:20 -04:00
parent e552737d0a
commit 5c5945bfa0
5 changed files with 80 additions and 34 deletions

View File

@ -1048,23 +1048,23 @@ AddSharedLibraryInfoToStream(JSONWriter& aWriter, const SharedLibrary& aLib)
aWriter.IntProperty("start", SafeJSInteger(aLib.GetStart()));
aWriter.IntProperty("end", SafeJSInteger(aLib.GetEnd()));
aWriter.IntProperty("offset", SafeJSInteger(aLib.GetOffset()));
aWriter.StringProperty("name", aLib.GetNativeDebugPath().c_str());
aWriter.StringProperty("name", NS_ConvertUTF16toUTF8(aLib.GetModuleName()).get());
aWriter.StringProperty("path", NS_ConvertUTF16toUTF8(aLib.GetModulePath()).get());
aWriter.StringProperty("debugName", NS_ConvertUTF16toUTF8(aLib.GetDebugName()).get());
aWriter.StringProperty("debugPath", NS_ConvertUTF16toUTF8(aLib.GetDebugPath()).get());
aWriter.StringProperty("breakpadId", aLib.GetBreakpadId().c_str());
aWriter.StringProperty("arch", aLib.GetArch().c_str());
aWriter.EndObject();
}
static std::string
GetSharedLibraryInfoStringInternal()
void
AppendSharedLibraries(JSONWriter& aWriter)
{
SharedLibraryInfo info = SharedLibraryInfo::GetInfoForSelf();
std::ostringstream os;
JSONWriter w(MakeUnique<OStreamJSONWriteFunc>(os));
w.StartArrayElement();
info.SortByAddress();
for (size_t i = 0; i < info.GetSize(); i++) {
AddSharedLibraryInfoToStream(w, info.GetEntry(i));
AddSharedLibraryInfoToStream(aWriter, info.GetEntry(i));
}
w.EndArray();
return os.str();
}
static void
@ -1112,7 +1112,7 @@ StreamMetaJSCustomObject(PS::LockRef aLock, SpliceableJSONWriter& aWriter)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
aWriter.IntProperty("version", 3);
aWriter.IntProperty("version", 4);
aWriter.DoubleProperty("interval", gPS->Interval(aLock));
aWriter.IntProperty("stackwalk", gPS->FeatureStackWalk(aLock));
@ -1267,8 +1267,9 @@ StreamJSON(PS::LockRef aLock, SpliceableJSONWriter& aWriter, double aSinceTime)
aWriter.Start(SpliceableJSONWriter::SingleLineStyle);
{
// Put shared library info
aWriter.StringProperty("libs",
GetSharedLibraryInfoStringInternal().c_str());
aWriter.StartArrayProperty("libs");
AppendSharedLibraries(aWriter);
aWriter.EndArray();
// Put meta data
aWriter.StartObjectProperty("meta");

View File

@ -167,4 +167,9 @@ UniquePlatformData AllocPlatformData(int aThreadId);
mozilla::UniquePtr<char[]>
ToJSON(PSLockRef aLock, double aSinceTime);
namespace mozilla {
class JSONWriter;
}
void AppendSharedLibraries(mozilla::JSONWriter& aWriter);
#endif /* ndef TOOLS_PLATFORM_H_ */

View File

@ -77,16 +77,28 @@ interface nsIProfiler : nsISupports
double getElapsedTime();
/**
* Returns a JSON string of an array of shared library objects.
* Every object has three properties: start, end, and name.
* start and end are integers describing the address range that the library
* occupies in memory. name is the path of the library as a string.
*
* On Windows profiling builds, the shared library objects will have
* additional pdbSignature and pdbAge properties for uniquely identifying
* shared library versions for stack symbolication.
* Contains an array of shared library objects.
* Every object has the properties:
* - start: The start address of the memory region occupied by this library.
* - end: The end address of the memory region occupied by this library.
* - offset: Usually zero, except on Android if the region was mapped from
* a file (using mmap), then this is the offset in the file where
* the mapping begins.
* - name: The name (file basename) of the binary.
* - path: The full absolute path to the binary.
* - debugName: On Windows, the name of the pdb file for the binary. On other
* platforms, the same as |name|.
* - debugPath: On Windows, the full absolute path of the pdb file for the
* binary. On other platforms, the same as |path|.
* - arch: On Mac, the name of the architecture that identifies the right
* binary image of a fat binary. Example values are "i386", "x86_64",
* and "x86_64h". (x86_64h is used for binaries that contain
* instructions that are specific to the Intel Haswell microarchitecture.)
* On non-Mac platforms, arch is "".
* - breakpadId: A unique identifier string for this library, as used by breakpad.
*/
AString getSharedLibraryInformation();
[implicit_jscontext]
readonly attribute jsval sharedLibraries;
/**
* Dump the collected profile to a file.

View File

@ -144,18 +144,38 @@ nsProfiler::GetProfile(double aSinceTime, char** aProfile)
return NS_OK;
}
std::string GetSharedLibraryInfoStringInternal();
namespace {
struct StringWriteFunc : public JSONWriteFunc
{
nsAString& mBuffer; // This struct must not outlive this buffer
explicit StringWriteFunc(nsAString& buffer) : mBuffer(buffer) {}
std::string
GetSharedLibraryInfoString()
{
return GetSharedLibraryInfoStringInternal();
void Write(const char* aStr)
{
mBuffer.Append(NS_ConvertUTF8toUTF16(aStr));
}
};
}
NS_IMETHODIMP
nsProfiler::GetSharedLibraryInformation(nsAString& aOutString)
nsProfiler::GetSharedLibraries(JSContext* aCx,
JS::MutableHandle<JS::Value> aResult)
{
aOutString.Assign(NS_ConvertUTF8toUTF16(GetSharedLibraryInfoString().c_str()));
JS::RootedValue val(aCx);
{
nsString buffer;
JSONWriter w(MakeUnique<StringWriteFunc>(buffer));
w.StartArrayElement();
AppendSharedLibraries(w);
w.EndArray();
MOZ_ALWAYS_TRUE(JS_ParseJSON(aCx, static_cast<const char16_t*>(buffer.get()),
buffer.Length(), &val));
}
JS::RootedObject obj(aCx, &val.toObject());
if (!obj) {
return NS_ERROR_FAILURE;
}
aResult.setObject(*obj);
return NS_OK;
}

View File

@ -13,11 +13,19 @@ function run_test() {
if (!profiler)
return;
var sharedStr = profiler.getSharedLibraryInformation();
sharedStr = sharedStr.toLowerCase();
var libs = profiler.sharedLibraries;
// Let's not hardcode anything too specific
// just some sanity checks.
do_check_neq(sharedStr, null);
do_check_neq(sharedStr, "");
do_check_eq(typeof libs, "object");
do_check_true(Array.isArray(libs));
do_check_eq(typeof libs, "object");
do_check_true(libs.length >= 1);
do_check_eq(typeof libs[0], "object");
do_check_eq(typeof libs[0].name, "string");
do_check_eq(typeof libs[0].path, "string");
do_check_eq(typeof libs[0].debugName, "string");
do_check_eq(typeof libs[0].debugPath, "string");
do_check_eq(typeof libs[0].arch, "string");
do_check_eq(typeof libs[0].start, "number");
do_check_eq(typeof libs[0].end, "number");
do_check_true(libs[0].start <= libs[0].end);
}