Bug 1498637 - Use __gcov_flush to implement dumping and resetting instead of __gcov_dump and __gcov_reset. r=froydnj
authorMarco Castelluccio <mcastelluccio@mozilla.com>
Mon, 15 Oct 2018 10:36:45 +0200
changeset 489816 5687061cc8320ab2f339766cb1cf0c0877deee72
parent 489815 399335d39d4c49eec8396aef9c77789bee33e3c2
child 489817 bc4d8d0bf57555a39cf825c91c82fea0843072bc
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersfroydnj
bugs1498637
milestone64.0a1
Bug 1498637 - Use __gcov_flush to implement dumping and resetting instead of __gcov_dump and __gcov_reset. r=froydnj
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/PContent.ipdl
testing/talos/talos/talos-powers/api.js
tools/code-coverage/CodeCoverageHandler.cpp
tools/code-coverage/CodeCoverageHandler.h
tools/code-coverage/PerTestCoverageUtils.jsm
tools/code-coverage/nsCodeCoverage.cpp
tools/code-coverage/nsICodeCoverage.idl
tools/code-coverage/tests/xpcshell/test_basic.js
tools/code-coverage/tests/xpcshell/test_basic_child_and_parent.js
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -3800,32 +3800,20 @@ ContentChild::RecvShareCodeCoverageMutex
   CodeCoverageHandler::Init(aHandle);
   return IPC_OK();
 #else
   MOZ_CRASH("Shouldn't receive this message in non-code coverage builds!");
 #endif
 }
 
 mozilla::ipc::IPCResult
-ContentChild::RecvDumpCodeCoverageCounters(DumpCodeCoverageCountersResolver&& aResolver)
+ContentChild::RecvFlushCodeCoverageCounters(FlushCodeCoverageCountersResolver&& aResolver)
 {
 #ifdef MOZ_CODE_COVERAGE
-  CodeCoverageHandler::DumpCounters();
-  aResolver(/* unused */ true);
-  return IPC_OK();
-#else
-  MOZ_CRASH("Shouldn't receive this message in non-code coverage builds!");
-#endif
-}
-
-mozilla::ipc::IPCResult
-ContentChild::RecvResetCodeCoverageCounters(ResetCodeCoverageCountersResolver&& aResolver)
-{
-#ifdef MOZ_CODE_COVERAGE
-  CodeCoverageHandler::ResetCounters();
+  CodeCoverageHandler::FlushCounters();
   aResolver(/* unused */ true);
   return IPC_OK();
 #else
   MOZ_CRASH("Shouldn't receive this message in non-code coverage builds!");
 #endif
 }
 
 mozilla::ipc::IPCResult
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -634,20 +634,17 @@ public:
   mozilla::ipc::IPCResult
   RecvSetPermissionsWithKey(const nsCString& aPermissionKey,
                             nsTArray<IPC::Permission>&& aPerms) override;
 
   virtual mozilla::ipc::IPCResult
   RecvShareCodeCoverageMutex(const CrossProcessMutexHandle& aHandle) override;
 
   virtual mozilla::ipc::IPCResult
-  RecvDumpCodeCoverageCounters(DumpCodeCoverageCountersResolver&& aResolver) override;
-
-  virtual mozilla::ipc::IPCResult
-  RecvResetCodeCoverageCounters(ResetCodeCoverageCountersResolver&& aResolver) override;
+  RecvFlushCodeCoverageCounters(FlushCodeCoverageCountersResolver&& aResolver) override;
 
   virtual mozilla::ipc::IPCResult
   RecvSetInputEventQueueEnabled() override;
 
   virtual mozilla::ipc::IPCResult
   RecvFlushInputEventQueue() override;
 
   virtual mozilla::ipc::IPCResult
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -643,18 +643,17 @@ child:
      * plugins changes. The chrome process sends up the last epoch it observed.
      * If the epoch last seen by the content process is the same, the content
      * process ignores the update. Otherwise the content process updates its
      * list and reloads its plugins.
      **/
     async SetPluginList(uint32_t pluginEpoch, PluginTag[] plugins, FakePluginTag[] fakePlugins);
 
     async ShareCodeCoverageMutex(CrossProcessMutexHandle handle);
-    async DumpCodeCoverageCounters() returns (bool unused);
-    async ResetCodeCoverageCounters() returns (bool unused);
+    async FlushCodeCoverageCounters() returns (bool unused);
 
     /*
      * IPC message to enable the input event queue on the main thread of the
      * content process.
      */
     async SetInputEventQueueEnabled();
 
     /*
--- a/testing/talos/talos/talos-powers/api.js
+++ b/testing/talos/talos/talos-powers/api.js
@@ -4,16 +4,17 @@
 
 /* globals ExtensionAPI */
 
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetters(this, {
   BrowserWindowTracker: "resource:///modules/BrowserWindowTracker.jsm",
   OS: "resource://gre/modules/osfile.jsm",
   Services: "resource://gre/modules/Services.jsm",
+  PerTestCoverageUtils: "resource://testing-common/PerTestCoverageUtils.jsm",
 });
 
 XPCOMUtils.defineLazyServiceGetter(this, "resProto",
                                    "@mozilla.org/network/protocol;1?name=resource",
                                    "nsISubstitutingProtocolHandler");
 
 Cu.importGlobalProperties(["TextEncoder"]);
 
@@ -315,27 +316,21 @@ TalosPowersService.prototype = {
 
     // arg: handle from startFrameTimeRecording. return: array with composition intervals
     stopFrameTimeRecording(arg, callback, win) {
       var rv = win.windowUtils.stopFrameTimeRecording(arg);
       callback(rv);
     },
 
     requestDumpCoverageCounters(arg, callback, win) {
-      let codeCoverage = Cc["@mozilla.org/tools/code-coverage;1"].
-                         getService(Ci.nsICodeCoverage);
-      codeCoverage.dumpCounters();
-      callback();
+      PerTestCoverageUtils.afterTest().then(callback);
     },
 
     requestResetCoverageCounters(arg, callback, win) {
-      let codeCoverage = Cc["@mozilla.org/tools/code-coverage;1"].
-                         getService(Ci.nsICodeCoverage);
-      codeCoverage.resetCounters();
-      callback();
+      PerTestCoverageUtils.beforeTest().then(callback);
     },
 
     dumpAboutSupport(arg, callback, win) {
       ChromeUtils.import("resource://gre/modules/Troubleshoot.jsm");
       Troubleshoot.snapshot(function(snapshot) {
         dump("about:support\t" + JSON.stringify(snapshot));
       });
       callback();
--- a/tools/code-coverage/CodeCoverageHandler.cpp
+++ b/tools/code-coverage/CodeCoverageHandler.cpp
@@ -13,93 +13,50 @@
 #endif
 #include "mozilla/CodeCoverageHandler.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/DebugOnly.h"
 #include "nsAppRunner.h"
 
 using namespace mozilla;
 
-// The __gcov_dump function writes the coverage counters to gcda files.
-// The __gcov_reset function resets the coverage counters to zero.
-// They are defined at https://github.com/gcc-mirror/gcc/blob/aad93da1a579b9ae23ede6b9cf8523360f0a08b4/libgcc/libgcov-interface.c.
-// __gcov_flush is protected by a mutex, __gcov_dump and __gcov_reset aren't.
-// So we are using a CrossProcessMutex to protect them.
-
-#if defined(__GNUC__) && !defined(__clang__)
-extern "C" void __gcov_dump();
-extern "C" void __gcov_reset();
+// The __gcov_flush function writes the coverage counters to gcda files and then resets them to zero.
+// It is defined at https://github.com/gcc-mirror/gcc/blob/aad93da1a579b9ae23ede6b9cf8523360f0a08b4/libgcc/libgcov-interface.c.
+// __gcov_flush is protected by a mutex in GCC, but not in LLVM, so we are using a CrossProcessMutex to protect it.
 
-void counters_dump() {
-  __gcov_dump();
-}
-
-void counters_reset() {
-  __gcov_reset();
-}
-#else
-void counters_dump() {
-  /* Do nothing */
-}
-
-void counters_reset() {
-  /* Do nothing */
-}
-#endif
+extern "C" void __gcov_flush();
 
 StaticAutoPtr<CodeCoverageHandler> CodeCoverageHandler::instance;
 
-void CodeCoverageHandler::DumpCounters()
+void CodeCoverageHandler::FlushCounters()
 {
-  printf_stderr("[CodeCoverage] Requested dump for %d.\n", getpid());
+  printf_stderr("[CodeCoverage] Requested flush for %d.\n", getpid());
 
   CrossProcessMutexAutoLock lock(*CodeCoverageHandler::Get()->GetMutex());
 
-  counters_dump();
-  printf_stderr("[CodeCoverage] Dump completed.\n");
-}
-
-void CodeCoverageHandler::DumpCountersSignalHandler(int)
-{
-  DumpCounters();
+  __gcov_flush();
+  printf_stderr("[CodeCoverage] flush completed.\n");
 }
 
-void CodeCoverageHandler::ResetCounters()
+void CodeCoverageHandler::FlushCountersSignalHandler(int)
 {
-  printf_stderr("[CodeCoverage] Requested reset for %d.\n", getpid());
-
-  CrossProcessMutexAutoLock lock(*CodeCoverageHandler::Get()->GetMutex());
-
-  counters_reset();
-  printf_stderr("[CodeCoverage] Reset completed.\n");
-}
-
-void CodeCoverageHandler::ResetCountersSignalHandler(int)
-{
-  ResetCounters();
+  FlushCounters();
 }
 
 void CodeCoverageHandler::SetSignalHandlers()
 {
 #ifndef XP_WIN
   printf_stderr("[CodeCoverage] Setting handlers for process %d.\n", getpid());
 
   struct sigaction dump_sa;
-  dump_sa.sa_handler = CodeCoverageHandler::DumpCountersSignalHandler;
+  dump_sa.sa_handler = CodeCoverageHandler::FlushCountersSignalHandler;
   dump_sa.sa_flags = SA_RESTART;
   sigemptyset(&dump_sa.sa_mask);
   DebugOnly<int> r1 = sigaction(SIGUSR1, &dump_sa, nullptr);
   MOZ_ASSERT(r1 == 0, "Failed to install GCOV SIGUSR1 handler");
-
-  struct sigaction reset_sa;
-  reset_sa.sa_handler = CodeCoverageHandler::ResetCountersSignalHandler;
-  reset_sa.sa_flags = SA_RESTART;
-  sigemptyset(&reset_sa.sa_mask);
-  DebugOnly<int> r2 = sigaction(SIGUSR2, &reset_sa, nullptr);
-  MOZ_ASSERT(r2 == 0, "Failed to install GCOV SIGUSR2 handler");
 #endif
 }
 
 CodeCoverageHandler::CodeCoverageHandler()
   : mGcovLock("GcovLock")
 {
   SetSignalHandlers();
 }
--- a/tools/code-coverage/CodeCoverageHandler.h
+++ b/tools/code-coverage/CodeCoverageHandler.h
@@ -13,20 +13,18 @@ namespace mozilla {
 
 class CodeCoverageHandler {
 public:
   static void Init();
   static void Init(const CrossProcessMutexHandle& aHandle);
   static CodeCoverageHandler* Get();
   CrossProcessMutex* GetMutex();
   CrossProcessMutexHandle GetMutexHandle(int aProcId);
-  static void DumpCounters();
-  static void DumpCountersSignalHandler(int);
-  static void ResetCounters();
-  static void ResetCountersSignalHandler(int);
+  static void FlushCounters();
+  static void FlushCountersSignalHandler(int);
 
 private:
   CodeCoverageHandler();
   explicit CodeCoverageHandler(const CrossProcessMutexHandle& aHandle);
 
   static StaticAutoPtr<CodeCoverageHandler> instance;
   CrossProcessMutex mGcovLock;
 
--- a/tools/code-coverage/PerTestCoverageUtils.jsm
+++ b/tools/code-coverage/PerTestCoverageUtils.jsm
@@ -57,40 +57,40 @@ function moveDirectoryContents(src, dst)
 
 var PerTestCoverageUtils = class PerTestCoverageUtilsClass {
   // Resets the counters to 0.
   static async beforeTest() {
     if (!PerTestCoverageUtils.enabled) {
       return;
     }
 
-    // Reset the counters.
+    // Flush the counters.
     let codeCoverageService = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
-    await codeCoverageService.resetCounters();
+    await codeCoverageService.flushCounters();
 
-    // Remove any gcda file that might have been created between the end of a previous test and the beginning of the next one (e.g. some tests can create a new content process for every sub-test).
+    // Remove gcda files created by the flush, and those that might have been created between the end of a previous test and the beginning of the next one (e.g. some tests can create a new content process for every sub-test).
     removeDirectoryContents(gcovPrefixDir);
 
     // Move gcda files from the GCOV_RESULTS_DIR directory, so we can accumulate the counters.
     moveDirectoryContents(gcovResultsDir, gcovPrefixDir);
   }
 
   static beforeTestSync() {
     awaitPromise(this.beforeTest());
   }
 
   // Dumps counters and moves the gcda files in the directory expected by codecoverage.py.
   static async afterTest() {
     if (!PerTestCoverageUtils.enabled) {
       return;
     }
 
-    // Dump the counters.
+    // Flush the counters.
     let codeCoverageService = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
-    await codeCoverageService.dumpCounters();
+    await codeCoverageService.flushCounters();
 
     // Move the gcda files in the GCOV_RESULTS_DIR, so that the execution from now to shutdown (or next test) is not counted.
     moveDirectoryContents(gcovPrefixDir, gcovResultsDir);
   }
 
   static afterTestSync() {
     awaitPromise(this.afterTest());
   }
--- a/tools/code-coverage/nsCodeCoverage.cpp
+++ b/tools/code-coverage/nsCodeCoverage.cpp
@@ -19,17 +19,17 @@ NS_IMPL_ISUPPORTS(nsCodeCoverage,
 nsCodeCoverage::nsCodeCoverage()
 {
 }
 
 nsCodeCoverage::~nsCodeCoverage()
 {
 }
 
-enum RequestType { Dump, Reset };
+enum RequestType { Flush };
 
 class ProcessCount final {
   NS_INLINE_DECL_REFCOUNTING(ProcessCount);
 
 public:
   explicit ProcessCount(uint32_t c) : mCount(c) {}
   operator uint32_t() const { return mCount; }
   ProcessCount& operator--() { mCount--; return *this; }
@@ -56,20 +56,18 @@ nsresult Request(JSContext* cx, Promise*
   }
 
   uint32_t processCount = 0;
   for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
     Unused << cp;
     ++processCount;
   }
 
-  if (requestType == RequestType::Dump) {
-    CodeCoverageHandler::DumpCounters();
-  } else if (requestType == RequestType::Reset) {
-    CodeCoverageHandler::ResetCounters();
+  if (requestType == RequestType::Flush) {
+    CodeCoverageHandler::FlushCounters();
   }
 
   if (processCount == 0) {
     promise->MaybeResolveWithUndefined();
   } else {
     RefPtr<ProcessCount> processCountHolder(new ProcessCount(processCount));
 
     auto resolve = [processCountHolder, promise](bool unused) {
@@ -78,29 +76,22 @@ nsresult Request(JSContext* cx, Promise*
       }
     };
 
     auto reject = [promise](ResponseRejectReason aReason) {
       promise->MaybeReject(NS_ERROR_FAILURE);
     };
 
     for (auto* cp : ContentParent::AllProcesses(ContentParent::eLive)) {
-      if (requestType == RequestType::Dump) {
-        cp->SendDumpCodeCoverageCounters(resolve, reject);
-      } else if (requestType == RequestType::Reset) {
-        cp->SendResetCodeCoverageCounters(resolve, reject);
+      if (requestType == RequestType::Flush) {
+        cp->SendFlushCodeCoverageCounters(resolve, reject);
       }
     }
   }
 
   promise.forget(aPromise);
   return NS_OK;
 }
 
-NS_IMETHODIMP nsCodeCoverage::DumpCounters(JSContext *cx, Promise** aPromise)
+NS_IMETHODIMP nsCodeCoverage::FlushCounters(JSContext *cx, Promise** aPromise)
 {
-  return Request(cx, aPromise, RequestType::Dump);
+  return Request(cx, aPromise, RequestType::Flush);
 }
-
-NS_IMETHODIMP nsCodeCoverage::ResetCounters(JSContext *cx, Promise** aPromise)
-{
-  return Request(cx, aPromise, RequestType::Reset);
-}
--- a/tools/code-coverage/nsICodeCoverage.idl
+++ b/tools/code-coverage/nsICodeCoverage.idl
@@ -3,28 +3,22 @@
  * 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 "nsISupports.idl"
 
 /**
  * The nsICodeCoverage component allows controlling the code coverage counters
  * collected by Firefox during execution.
- * By resetting and dumping the counters, one can analyze the coverage information
+ * By flushing the counters, one can analyze the coverage information
  * for a subset of the program execution (e.g. startup code coverage).
  *
  */
 
 [scriptable, uuid(57d92056-37b4-4d0a-a52f-deb8f6dac8bc)]
 interface nsICodeCoverage : nsISupports
 {
   /**
-   * Write the coverage counters to disk.
+   * Write the coverage counters to disk, and reset them in memory to 0.
    */
   [implicit_jscontext]
-  Promise dumpCounters();
-
-  /**
-   * Reset the coverage counters to 0 (as if nothing was executed).
-   */
-  [implicit_jscontext]
-  Promise resetCounters();
+  Promise flushCounters();
 };
--- a/tools/code-coverage/tests/xpcshell/test_basic.js
+++ b/tools/code-coverage/tests/xpcshell/test_basic.js
@@ -8,14 +8,12 @@ async function run_test() {
   Assert.ok("@mozilla.org/tools/code-coverage;1" in Cc);
 
   let codeCoverageCc = Cc["@mozilla.org/tools/code-coverage;1"];
   Assert.ok(!!codeCoverageCc);
 
   let codeCoverage = codeCoverageCc.getService(Ci.nsICodeCoverage);
   Assert.ok(!!codeCoverage);
 
-  await codeCoverage.dumpCounters();
-
-  await codeCoverage.resetCounters();
+  await codeCoverage.flushCounters();
 
   do_test_finished();
 }
--- a/tools/code-coverage/tests/xpcshell/test_basic_child_and_parent.js
+++ b/tools/code-coverage/tests/xpcshell/test_basic_child_and_parent.js
@@ -4,14 +4,13 @@
 
 function run_test() {
   do_load_child_test_harness();
   do_test_pending();
 
   sendCommand("let v = 'test';", async function() {
       let codeCoverage = Cc["@mozilla.org/tools/code-coverage;1"].getService(Ci.nsICodeCoverage);
 
-      await codeCoverage.dumpCounters();
-      await codeCoverage.resetCounters();
+      await codeCoverage.flushCounters();
 
       do_test_finished();
   });
 }