Bug 1341023 - Take module name encoding into account for late writes and hangs. r=Dexter
authorMarco Castelluccio <mcastelluccio@mozilla.com>
Tue, 21 Feb 2017 22:44:42 +0000
changeset 344184 fbd5216f6a4979679dfab4f415fc86777dd88b01
parent 344183 20c8c1cd5a3faec93c9108f7553a6bd6d40b5793
child 344185 1b501700e807b502c4d04e842a881c42c85eb8ef
push id31402
push usercbook@mozilla.com
push dateWed, 22 Feb 2017 13:33:50 +0000
treeherdermozilla-central@f5372cb6c3c7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersDexter
bugs1341023
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1341023 - Take module name encoding into account for late writes and hangs. r=Dexter
toolkit/components/telemetry/ProcessedStack.h
toolkit/components/telemetry/Telemetry.cpp
toolkit/components/telemetry/docs/data/main-ping.rst
toolkit/components/telemetry/tests/unit/test_TelemetryLateWrites.js
xpcom/build/LateWriteChecks.cpp
--- a/toolkit/components/telemetry/ProcessedStack.h
+++ b/toolkit/components/telemetry/ProcessedStack.h
@@ -28,17 +28,18 @@ public:
     uintptr_t mOffset;
     // The index to pass to GetModule to get the module this program counter
     // was in.
     uint16_t mModIndex;
   };
   struct Module
   {
     // The file name, /foo/bar/libxul.so for example.
-    std::string mName;
+    // It can contain unicode characters.
+    nsString mName;
     std::string mBreakpadId;
 
     bool operator==(const Module& other) const;
   };
 
   const Frame &GetFrame(unsigned aIndex) const;
   void AddFrame(const Frame& aFrame);
   const Module &GetModule(unsigned aIndex) const;
--- a/toolkit/components/telemetry/Telemetry.cpp
+++ b/toolkit/components/telemetry/Telemetry.cpp
@@ -1590,30 +1590,24 @@ CreateJSStackObject(JSContext *cx, const
     if (!JS_DefineElement(cx, moduleArray, moduleIndex, moduleInfoArray,
                           JSPROP_ENUMERATE)) {
       return nullptr;
     }
 
     unsigned index = 0;
 
     // Module name
-    JS::Rooted<JSString*> str(cx, JS_NewStringCopyZ(cx, module.mName.c_str()));
-    if (!str) {
-      return nullptr;
-    }
-    if (!JS_DefineElement(cx, moduleInfoArray, index++, str, JSPROP_ENUMERATE)) {
+    JS::Rooted<JSString*> str(cx, JS_NewUCStringCopyZ(cx, module.mName.get()));
+    if (!str || !JS_DefineElement(cx, moduleInfoArray, index++, str, JSPROP_ENUMERATE)) {
       return nullptr;
     }
 
     // Module breakpad identifier
     JS::Rooted<JSString*> id(cx, JS_NewStringCopyZ(cx, module.mBreakpadId.c_str()));
-    if (!id) {
-      return nullptr;
-    }
-    if (!JS_DefineElement(cx, moduleInfoArray, index++, id, JSPROP_ENUMERATE)) {
+    if (!id || !JS_DefineElement(cx, moduleInfoArray, index++, id, JSPROP_ENUMERATE)) {
       return nullptr;
     }
   }
 
   JS::Rooted<JSObject*> reportArray(cx, JS_NewArrayObject(cx, 0));
   if (!reportArray) {
     return nullptr;
   }
@@ -1895,17 +1889,17 @@ ReadStack(const char *aFileName, Telemet
 
     std::string moduleName;
     getline(file, moduleName);
     if (file.fail() || moduleName[0] == ' ') {
       return;
     }
 
     Telemetry::ProcessedStack::Module module = {
-      moduleName,
+      NS_ConvertUTF8toUTF16(moduleName.c_str()),
       breakpadId
     };
     stack.AddModule(module);
   }
 
   size_t numFrames;
   file >> numFrames;
   if (file.fail()) {
@@ -3219,24 +3213,24 @@ GetStackAndModules(const std::vector<uin
   for (auto & rawFrame : rawStack) {
     mozilla::Telemetry::ProcessedStack::Frame frame = { rawFrame.mPC, rawFrame.mModIndex };
     Ret.AddFrame(frame);
   }
 
 #ifdef MOZ_GECKO_PROFILER
   for (unsigned i = 0, n = rawModules.GetSize(); i != n; ++i) {
     const SharedLibrary &info = rawModules.GetEntry(i);
-    std::string basename = info.GetNativeDebugName();
+    nsString basename = info.GetDebugName();
 #if defined(XP_MACOSX) || defined(XP_LINUX)
     // We want to use just the basename as the libname, but the
     // current profiler addon needs the full path name, so we compute the
     // basename in here.
-    size_t pos = basename.rfind('/');
-    if (pos != std::string::npos) {
-      basename = basename.substr(pos + 1);
+    int32_t pos = basename.RFindChar('/');
+    if (pos != kNotFound) {
+      basename.Cut(0, pos + 1);
     }
 #endif
     mozilla::Telemetry::ProcessedStack::Module module = {
       basename,
       info.GetBreakpadId()
     };
     Ret.AddModule(module);
   }
--- a/toolkit/components/telemetry/docs/data/main-ping.rst
+++ b/toolkit/components/telemetry/docs/data/main-ping.rst
@@ -296,16 +296,18 @@ This is similar to :ref:`chromeHangs`, b
 the parent process are reported. This data is only available on Windows, either
 in Firefox Nightly or in builds using ``--enable-profiling`` switch.
 
 Limits for captured stacks are the same as for chromeHangs (see below). Furthermore:
 
 * the key length is limited to 50 characters,
 * keys are restricted to alpha-numeric characters and `-`.
 
+The module names can contain unicode characters.
+
 Structure:
 
 .. code-block:: js
 
     "capturedStacks" : {
       "memoryMap": [
         ["wgdi32.pdb", "08A541B5942242BDB4AEABD8C87E4CFF2"],
         ["igd10iumd32.pdb", "D36DEBF2E78149B5BE1856B772F1C3991"],
@@ -331,16 +333,18 @@ chromeHangs
 -----------
 Contains the statistics about the hangs happening exclusively on the main thread of the parent process. Precise C++ stacks are reported. This is only available on Nightly Release on Windows, when building using "--enable-profiling" switch.
 
 Some limits are applied:
 
 * Reported chrome hang stacks are limited in depth to 50 entries.
 * The maximum number of reported stacks is 50.
 
+The module names can contain unicode characters.
+
 Structure:
 
 .. code-block:: js
 
     "chromeHangs" : {
       "memoryMap" : [
         ["wgdi32.pdb", "08A541B5942242BDB4AEABD8C87E4CFF2"],
         ["igd10iumd32.pdb", "D36DEBF2E78149B5BE1856B772F1C3991"],
@@ -556,17 +560,19 @@ Structure:
         stats, // Number of stat operations
       ],
       "{profile}": [ ... ],
       ...
     }
 
 lateWrites
 ----------
-This sections reports writes to the file system that happen during shutdown. The reported data contains the stack and the loaded libraries at the time the writes happened.
+This sections reports writes to the file system that happen during shutdown. The reported data contains the stack and the file names of the loaded libraries at the time the writes happened.
+
+The file names of the loaded libraries can contain unicode characters.
 
 Structure:
 
 .. code-block:: js
 
     "lateWrites" : {
       "memoryMap" : [
         ["wgdi32.pdb", "08A541B5942242BDB4AEABD8C87E4CFF2"],
--- a/toolkit/components/telemetry/tests/unit/test_TelemetryLateWrites.js
+++ b/toolkit/components/telemetry/tests/unit/test_TelemetryLateWrites.js
@@ -15,40 +15,49 @@ const STACK_SUFFIX1 = "stack1.txt";
 const STACK_SUFFIX2 = "stack2.txt";
 const STACK_BOGUS_SUFFIX = "bogus.txt";
 const LATE_WRITE_PREFIX = "Telemetry.LateWriteFinal-";
 
 // The names and IDs don't matter, but the format of the IDs does.
 const LOADED_MODULES = {
   "4759A7E6993548C89CAF716A67EC242D00": "libtest.so",
   "F77AF15BB8D6419FA875954B4A3506CA00": "libxul.so",
-  "1E2F7FB590424E8F93D60BB88D66B8C500": "libc.so"
+  "1E2F7FB590424E8F93D60BB88D66B8C500": "libc.so",
+  "E4D6D70CC09A63EF8B88D532F867858800": "libmod╬╝les.so",
 };
 const N_MODULES = Object.keys(LOADED_MODULES).length;
 
 // Format of individual items is [index, offset-in-library].
 const STACK1 = [
   [ 0, 0 ],
   [ 1, 1 ],
-  [ 2, 2 ]
+  [ 2, 2 ],
+  [ 3, 3 ],
 ];
 const STACK2 = [
   [ 0, 0 ],
   [ 1, 5 ],
   [ 2, 10 ],
+  [ 3, 15 ],
 ];
 // XXX The only error checking is for a zero-sized stack.
 const STACK_BOGUS = [];
 
 function write_string_to_file(file, contents) {
   let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"]
                 .createInstance(Ci.nsIFileOutputStream);
   ostream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
-	       RW_OWNER, ostream.DEFER_OPEN);
-  ostream.write(contents, contents.length);
+               RW_OWNER, ostream.DEFER_OPEN);
+
+  var bos = Cc["@mozilla.org/binaryoutputstream;1"]
+            .createInstance(Ci.nsIBinaryOutputStream);
+  bos.setOutputStream(ostream);
+
+  let utf8 = new TextEncoder("utf-8").encode(contents);
+  bos.writeByteArray(utf8, utf8.length);
   ostream.QueryInterface(Ci.nsISafeOutputStream).finish();
   ostream.close();
 }
 
 function construct_file(suffix) {
   let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
   let file = profileDirectory.clone();
   file.append(LATE_WRITE_PREFIX + suffix);
--- a/xpcom/build/LateWriteChecks.cpp
+++ b/xpcom/build/LateWriteChecks.cpp
@@ -163,17 +163,17 @@ LateWriteObserver::Observe(IOInterposeOb
 
   SHA1Stream sha1Stream(stream);
 
   size_t numModules = stack.GetNumModules();
   sha1Stream.Printf("%u\n", (unsigned)numModules);
   for (size_t i = 0; i < numModules; ++i) {
     Telemetry::ProcessedStack::Module module = stack.GetModule(i);
     sha1Stream.Printf("%s %s\n", module.mBreakpadId.c_str(),
-                      module.mName.c_str());
+                      NS_ConvertUTF16toUTF8(module.mName).get());
   }
 
   size_t numFrames = stack.GetStackSize();
   sha1Stream.Printf("%u\n", (unsigned)numFrames);
   for (size_t i = 0; i < numFrames; ++i) {
     const Telemetry::ProcessedStack::Frame& frame = stack.GetFrame(i);
     // NOTE: We write the offsets, while the atos tool expects a value with
     // the virtual address added. For example, running otool -l on the the firefox