Bug 1518490 Part 1/3: Measure DLL load timings and pass into UntrustedModulesManager r=aklotz
authorCarl Corcoran <ccorcoran@mozilla.com>
Tue, 15 Jan 2019 10:49:36 +0000
changeset 514079 400434070f20f902659434c8e7d437f800613e35
parent 514078 078e5984f999de05c3987fd04679b8703a042cb3
child 514080 1b8f7dd09d842bf97fa58840d48904a7f38eb4ac
push id1953
push userffxbld-merge
push dateMon, 11 Mar 2019 12:10:20 +0000
treeherdermozilla-release@9c35dcbaa899 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersaklotz
bugs1518490
milestone66.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 1518490 Part 1/3: Measure DLL load timings and pass into UntrustedModulesManager r=aklotz This patch measures the duration of module loads and passes it up to UntrustedModulesManager where, in later patches, it will be consumed by telemetry. Differential Revision: https://phabricator.services.mozilla.com/D16011
mozglue/build/UntrustedDllsHandler.cpp
mozglue/build/UntrustedDllsHandler.h
mozglue/build/WindowsDllBlocklist.cpp
mozglue/build/WindowsDllServices.h
toolkit/xre/ModuleEvaluator_windows.cpp
toolkit/xre/ModuleEvaluator_windows.h
toolkit/xre/WinDllServices.cpp
--- a/mozglue/build/UntrustedDllsHandler.cpp
+++ b/mozglue/build/UntrustedDllsHandler.cpp
@@ -272,17 +272,18 @@ void UntrustedDllsHandler::ExitLoaderCal
   if (!--(sTlsData.get()->mCallDepth)) {
     delete sTlsData.get();
     sTlsData.set(nullptr);
   }
 }
 
 /* static */
 void UntrustedDllsHandler::OnAfterModuleLoad(uintptr_t aBaseAddr,
-                                             PUNICODE_STRING aLdrModuleName) {
+                                             PUNICODE_STRING aLdrModuleName,
+                                             double aLoadDurationMS) {
   RefPtr<UntrustedDllsHandlerImpl> p(UntrustedDllsHandlerImpl::GetInstance());
   if (!p) {
     return;
   }
 
   if (!sTlsData.initialized()) {
     return;
   }
@@ -290,16 +291,17 @@ void UntrustedDllsHandler::OnAfterModule
   if (!tlsData) {
     return;
   }
 
   ModuleLoadEvent::ModuleInfo moduleInfo;
   moduleInfo.mLdrName = CopyString(aLdrModuleName);
   moduleInfo.mBase = aBaseAddr;
   moduleInfo.mFullPath = GetModuleFullPath(aBaseAddr);
+  moduleInfo.mLoadDurationMS = aLoadDurationMS;
 
   Unused << tlsData->mModulesLoaded.emplaceBack(std::move(moduleInfo));
 
   if (tlsData->mCallDepth > 1) {
     // Recursive call; bail and wait until top-level call can proceed.
     return;
   }
 
--- a/mozglue/build/UntrustedDllsHandler.h
+++ b/mozglue/build/UntrustedDllsHandler.h
@@ -47,17 +47,18 @@ class UntrustedDllsHandler {
    * OnAfterModuleLoad should be called between calls to EnterLoaderCall() and
    * ExitLoaderCall(). This handles the successful module load and records it
    * internally if needed. To handle the resulting recorded event, call
    * TakePendingEvents().
    *
    * This method may be called even outside of Init() / Shutdown().
    */
   static void OnAfterModuleLoad(uintptr_t aBaseAddr,
-                                PUNICODE_STRING aLdrModuleName);
+                                PUNICODE_STRING aLdrModuleName,
+                                double aLoadDurationMS);
 
   /**
    * Call TakePendingEvents to get any events that have been recorded since
    * the last call to TakePendingEvents().
    *
    * This method may be called even outside of Init() / Shutdown().
    *
    * @param  aOut [out] Receives a list of events.
--- a/mozglue/build/WindowsDllBlocklist.cpp
+++ b/mozglue/build/WindowsDllBlocklist.cpp
@@ -29,16 +29,17 @@
 #include "MozglueUtils.h"
 #include "UntrustedDllsHandler.h"
 #include "nsAutoPtr.h"
 #include "nsWindowsDllInterceptor.h"
 #include "mozilla/CmdLineAndEnvUtils.h"
 #include "mozilla/ScopeExit.h"
 #include "mozilla/Sprintf.h"
 #include "mozilla/StackWalk_windows.h"
+#include "mozilla/TimeStamp.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Vector.h"
 #include "mozilla/WindowsVersion.h"
 #include "nsWindowsHelpers.h"
 #include "WindowsDllBlocklist.h"
 #include "mozilla/AutoProfilerLabel.h"
 #include "mozilla/glue/WindowsDllServices.h"
 
@@ -647,35 +648,45 @@ continue_loading:
   // the vast majority of DLLs do get labelled here.
   AutoProfilerLabel label("WindowsDllBlocklist::patched_LdrLoadDll", dllName);
 
 #ifdef _M_AMD64
   // Prevent the stack walker from suspending this thread when LdrLoadDll
   // holds the RtlLookupFunctionEntry lock.
   AutoSuppressStackWalking suppress;
 #endif
+
   NTSTATUS ret;
   HANDLE myHandle;
-  ret = stub_LdrLoadDll(filePath, flags, moduleFileName, &myHandle);
-  if (handle) {
-    *handle = myHandle;
+
+  if (IsUntrustedDllsHandlerEnabled()) {
+    TimeStamp loadStart = TimeStamp::Now();
+    ret = stub_LdrLoadDll(filePath, flags, moduleFileName, &myHandle);
+    TimeStamp loadEnd = TimeStamp::Now();
+
+    if (NT_SUCCESS(ret)) {
+      double loadDurationMS = (loadEnd - loadStart).ToMilliseconds();
+      // Win32 HMODULEs use the bottom two bits as flags. Ensure those bits are
+      // cleared so we're left with the base address value.
+      glue::UntrustedDllsHandler::OnAfterModuleLoad(
+          (uintptr_t)myHandle & ~(uintptr_t)3, moduleFileName, loadDurationMS);
+      glue::AutoSharedLock lock(gDllServicesLock);
+      if (gDllServices) {
+        Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy> events;
+        if (glue::UntrustedDllsHandler::TakePendingEvents(events)) {
+          gDllServices->NotifyUntrustedModuleLoads(events);
+        }
+      }
+    }
+  } else {
+    ret = stub_LdrLoadDll(filePath, flags, moduleFileName, &myHandle);
   }
 
-  if (IsUntrustedDllsHandlerEnabled() && NT_SUCCESS(ret)) {
-    // Win32 HMODULEs use the bottom two bits as flags. Ensure those bits are
-    // cleared so we're left with the base address value.
-    glue::UntrustedDllsHandler::OnAfterModuleLoad(
-        (uintptr_t)myHandle & ~(uintptr_t)3, moduleFileName);
-    glue::AutoSharedLock lock(gDllServicesLock);
-    if (gDllServices) {
-      Vector<glue::ModuleLoadEvent, 0, InfallibleAllocPolicy> events;
-      if (glue::UntrustedDllsHandler::TakePendingEvents(events)) {
-        gDllServices->NotifyUntrustedModuleLoads(events);
-      }
-    }
+  if (handle) {
+    *handle = myHandle;
   }
 
   CallDllLoadHook(NT_SUCCESS(ret), ret, handle ? *handle : 0, moduleFileName);
   return ret;
 }
 
 #if defined(NIGHTLY_BUILD)
 // Map of specific thread proc addresses we should block. In particular,
--- a/mozglue/build/WindowsDllServices.h
+++ b/mozglue/build/WindowsDllServices.h
@@ -43,16 +43,17 @@ class ModuleLoadEvent {
     ModuleInfo(ModuleInfo&& aOther) = default;
 
     ModuleInfo operator=(const ModuleInfo& aOther) = delete;
     ModuleInfo operator=(ModuleInfo&& aOther) = delete;
 
     uintptr_t mBase;
     UniquePtr<wchar_t[]> mLdrName;
     UniquePtr<wchar_t[]> mFullPath;
+    double mLoadDurationMS;
   };
 
   ModuleLoadEvent() = default;
   ~ModuleLoadEvent() = default;
   ModuleLoadEvent(const ModuleLoadEvent& aOther) = delete;
   ModuleLoadEvent(ModuleLoadEvent&& aOther) = default;
 
   ModuleLoadEvent& operator=(const ModuleLoadEvent& aOther) = delete;
--- a/toolkit/xre/ModuleEvaluator_windows.cpp
+++ b/toolkit/xre/ModuleEvaluator_windows.cpp
@@ -33,17 +33,17 @@ static bool GetDirectoryName(const nsCOM
   if (NS_FAILED(parentDir->GetPath(aParent))) {
     return false;
   }
   return true;
 }
 
 ModuleLoadEvent::ModuleInfo::ModuleInfo(
     const glue::ModuleLoadEvent::ModuleInfo& aOther)
-    : mBase(aOther.mBase) {
+    : mBase(aOther.mBase), mLoadDurationMS(Some(aOther.mLoadDurationMS)) {
   if (aOther.mLdrName) {
     mLdrName.Assign(aOther.mLdrName.get());
   }
   if (aOther.mFullPath) {
     nsDependentString tempPath(aOther.mFullPath.get());
     Unused << NS_NewLocalFile(tempPath, false, getter_AddRefs(mFile));
   }
 }
--- a/toolkit/xre/ModuleEvaluator_windows.h
+++ b/toolkit/xre/ModuleEvaluator_windows.h
@@ -49,16 +49,17 @@ class ModuleLoadEvent {
 
     // Construct from the mozilla::glue version of this class.
     explicit ModuleInfo(const glue::ModuleLoadEvent::ModuleInfo&);
 
     // The following members should be populated always.
     uintptr_t mBase;
     nsString mLdrName;
     nsCOMPtr<nsIFile> mFile;  // Path as reported by GetModuleFileName()
+    Maybe<double> mLoadDurationMS;
 
     // The following members are populated as we evaluate the module.
     nsString mFilePathClean;  // Path sanitized for telemetry reporting.
     ModuleTrustFlags mTrustFlags;
     nsCString mFileVersion;
   };
 
   ModuleLoadEvent() = default;
--- a/toolkit/xre/WinDllServices.cpp
+++ b/toolkit/xre/WinDllServices.cpp
@@ -297,16 +297,17 @@ class UntrustedModulesManager {
         if (wasFound) {
           continue;
         }
 
         // It's never been seen before so it must be a startup module.
         // One module = one event here.
         ModuleLoadEvent::ModuleInfo mi;
         mi.mBase = base;
+        mi.mLoadDurationMS = Nothing();
         ModuleLoadEvent e;
         e.mIsStartup = true;
         e.mProcessUptimeMS = 0;
         Unused << e.mModules.emplaceBack(std::move(mi));
         Unused << startupEvents.emplaceBack(std::move(e));
       }
 
       // Since we process startup modules only once, this data is no longer