bug 606574 - Win32 event loop instrumentation. r=jimm
authorTed Mielczarek <ted.mielczarek@gmail.com>
Thu, 03 Mar 2011 11:20:02 -0500
changeset 68390 b6726f1fd6ed00a6f9e59f701b758f28988dc9b1
parent 68389 9f474136c458b02bbc2ab7fd3dc03aa21c5195c2
child 68391 855e5cd3c88452721d9e2eb211745e849a3f6e95
push id19619
push usertmielczarek@mozilla.com
push dateThu, 21 Apr 2011 13:04:06 +0000
treeherdermozilla-central@855e5cd3c884 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs606574
milestone6.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 606574 - Win32 event loop instrumentation. r=jimm
configure.in
widget/public/WidgetTraceEvent.h
widget/src/windows/Makefile.in
widget/src/windows/WidgetTraceEvent.cpp
widget/src/windows/nsWindow.cpp
widget/src/windows/nsWindowDefs.h
--- a/configure.in
+++ b/configure.in
@@ -5018,16 +5018,17 @@ photon)
 	MOZ_ENABLE_PHOTON=1
 	AC_DEFINE(MOZ_WIDGET_PHOTON)
     ;;
 
 cairo-windows)
     MOZ_WIDGET_TOOLKIT=windows
     MOZ_WEBGL=1
     MOZ_PDF_PRINTING=1
+    MOZ_INSTRUMENT_EVENT_LOOP=1
     ;;
 
 cairo-gtk2|cairo-gtk2-x11)
     MOZ_WIDGET_TOOLKIT=gtk2
     MOZ_ENABLE_GTK2=1
     MOZ_ENABLE_XREMOTE=1
     MOZ_WEBGL=1
     MOZ_WEBGL_GLX=1
--- a/widget/public/WidgetTraceEvent.h
+++ b/widget/public/WidgetTraceEvent.h
@@ -47,11 +47,14 @@ bool InitWidgetTracing();
 // Perform any required cleanup in the widget backend for event tracing.
 void CleanUpWidgetTracing();
 
 // Fire a tracer event at the UI-thread event loop, and block until
 // the event is processed. This should only be called by
 // a thread that's not the UI thread.
 bool FireAndWaitForTracerEvent();
 
+// Signal that the event has been received by the event loop.
+void SignalTracerThread();
+
 }
 
 #endif  // WIDGET_PUBLIC_WIDGETTRACEEVENT_H_
--- a/widget/src/windows/Makefile.in
+++ b/widget/src/windows/Makefile.in
@@ -42,42 +42,43 @@ VPATH		= @srcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= widget
 LIBRARY_NAME	= widget_windows
 LIBXUL_LIBRARY = 1
 
 
-CPPSRCS		= \
-	nsWindow.cpp \
-	nsWindowGfx.cpp \
-	nsWindowDbg.cpp \
-	nsAppShell.cpp \
-	nsToolkit.cpp \
-	nsFilePicker.cpp \
-	nsScreenWin.cpp	\
-	nsScreenManagerWin.cpp \
-	nsLookAndFeel.cpp \
-	nsUXThemeData.cpp \
-	nsNativeThemeWin.cpp \
-	nsWinGesture.cpp \
-	nsIdleServiceWin.cpp \
-	nsSound.cpp \
-	nsIMM32Handler.cpp \
-	WindowHook.cpp \
-	WinTaskbar.cpp \
-	TaskbarPreview.cpp \
-	TaskbarTabPreview.cpp \
-	TaskbarWindowPreview.cpp \
-	TaskbarPreviewButton.cpp \
- 	JumpListBuilder.cpp \
- 	JumpListItem.cpp \
-	GfxInfo.cpp \
-	$(NULL)
+CPPSRCS = \
+  nsWindow.cpp \
+  nsWindowGfx.cpp \
+  nsWindowDbg.cpp \
+  nsAppShell.cpp \
+  nsToolkit.cpp \
+  nsFilePicker.cpp \
+  nsScreenWin.cpp  \
+  nsScreenManagerWin.cpp \
+  nsLookAndFeel.cpp \
+  nsUXThemeData.cpp \
+  nsNativeThemeWin.cpp \
+  nsWinGesture.cpp \
+  nsIdleServiceWin.cpp \
+  nsSound.cpp \
+  nsIMM32Handler.cpp \
+  WindowHook.cpp \
+  WinTaskbar.cpp \
+  TaskbarPreview.cpp \
+  TaskbarTabPreview.cpp \
+  TaskbarWindowPreview.cpp \
+  TaskbarPreviewButton.cpp \
+  JumpListBuilder.cpp \
+  JumpListItem.cpp \
+  GfxInfo.cpp \
+  WidgetTraceEvent.cpp \
+  $(NULL)
 
 ifdef MOZ_CRASHREPORTER
 CPPSRCS += LSPAnnotator.cpp
 endif
 
 ifdef NS_PRINTING
 CPPSRCS		+= \
 	nsPrintOptionsWin.cpp \
new file mode 100644
--- /dev/null
+++ b/widget/src/windows/WidgetTraceEvent.cpp
@@ -0,0 +1,158 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ted Mielczarek <ted.mielczarek@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Windows widget support for event loop instrumentation.
+ * See toolkit/xre/EventTracer.cpp for more details.
+ */
+
+#include <stdio.h>
+#include <windows.h>
+
+#include "mozilla/WidgetTraceEvent.h"
+#include "nsAppShellCID.h"
+#include "nsComponentManagerUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIAppShellService.h"
+#include "nsIBaseWindow.h"
+#include "nsIDocShell.h"
+#include "nsIWidget.h"
+#include "nsIXULWindow.h"
+#include "nsAutoPtr.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+#include "nsWindowDefs.h"
+
+namespace {
+
+// Used for signaling the background thread from the main thread.
+HANDLE sEventHandle = NULL;
+
+// We need a runnable in order to find the hidden window on the main
+// thread.
+class HWNDGetter : public nsRunnable {
+public:
+  HWNDGetter() : hidden_window_hwnd(NULL) {}
+
+  HWND hidden_window_hwnd;
+
+  NS_IMETHOD Run() {
+    // Jump through some hoops to locate the hidden window.
+    nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
+    nsCOMPtr<nsIXULWindow> hiddenWindow;
+
+    nsresult rv = appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    nsCOMPtr<nsIDocShell> docShell;
+    rv = hiddenWindow->GetDocShell(getter_AddRefs(docShell));
+    if (NS_FAILED(rv) || !docShell) {
+      return rv;
+    }
+
+    nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
+    
+    if (!baseWindow)
+      return NS_ERROR_FAILURE;
+
+    nsCOMPtr<nsIWidget> widget;
+    baseWindow->GetMainWidget(getter_AddRefs(widget));
+
+    if (!widget)
+      return NS_ERROR_FAILURE;
+
+    hidden_window_hwnd = (HWND)widget->GetNativeData(NS_NATIVE_WINDOW);
+
+    return NS_OK;
+  }
+};
+
+HWND GetHiddenWindowHWND()
+{
+  // Need to dispatch this to the main thread because plenty of
+  // the things it wants to access are main-thread-only.
+  nsRefPtr<HWNDGetter> getter = new HWNDGetter();
+  NS_DispatchToMainThread(getter, NS_DISPATCH_SYNC);
+  return getter->hidden_window_hwnd;
+}
+
+} // namespace
+
+namespace mozilla {
+
+bool InitWidgetTracing()
+{
+  sEventHandle = CreateEvent(NULL, FALSE, FALSE, NULL);
+  return sEventHandle != NULL;
+}
+
+void CleanUpWidgetTracing()
+{
+  CloseHandle(sEventHandle);
+}
+
+// This function is called from the main (UI) thread.
+void SignalTracerThread()
+{
+  if (sEventHandle != NULL)
+    SetEvent(sEventHandle);
+}
+
+// This function is called from the background tracer thread.
+bool FireAndWaitForTracerEvent()
+{
+  NS_ABORT_IF_FALSE(sEventHandle, "Tracing not initialized!");
+
+  // First, try to find the hidden window.
+  static HWND hidden_window = NULL;
+  if (hidden_window == NULL) {
+    hidden_window = GetHiddenWindowHWND();
+  }
+
+  if (hidden_window == NULL)
+    return false;
+
+  // Post the tracer message into the hidden window's message queue,
+  // and then block until it's processed.
+  PostMessage(hidden_window, MOZ_WM_TRACE, 0, 0);
+  WaitForSingleObject(sEventHandle, INFINITE);
+  return true;
+}
+
+}  // namespace mozilla
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -113,16 +113,17 @@
 #include <commctrl.h>
 #include <unknwn.h>
 
 #include "prlog.h"
 #include "prtime.h"
 #include "prprf.h"
 #include "prmem.h"
 
+#include "mozilla/WidgetTraceEvent.h"
 #include "nsIAppShell.h"
 #include "nsISupportsPrimitives.h"
 #include "nsIDOMNSUIEvent.h"
 #include "nsITheme.h"
 #include "nsIPrefBranch.h"
 #include "nsIPrefBranch2.h"
 #include "nsIPrefService.h"
 #include "nsIObserverService.h"
@@ -4594,16 +4595,23 @@ LRESULT CALLBACK nsWindow::WindowProcInt
       hWnd = ::GetParent(::GetParent(hWnd));
     } else {
       // Handle all other messages with its original window procedure.
       WNDPROC prevWindowProc = (WNDPROC)::GetWindowLongPtr(hWnd, GWLP_USERDATA);
       return ::CallWindowProcW(prevWindowProc, hWnd, msg, wParam, lParam);
     }
   }
 
+  if (msg == MOZ_WM_TRACE) {
+    // This is a tracer event for measuring event loop latency.
+    // See WidgetTraceEvent.cpp for more details.
+    mozilla::SignalTracerThread();
+    return 0;
+  }
+
   // Get the window which caused the event and ask it to process the message
   nsWindow *someWindow = GetNSWindowPtr(hWnd);
 
   if (someWindow)
     someWindow->IPCWindowProcHandler(msg, wParam, lParam);
 
   // create this here so that we store the last rolled up popup until after
   // the event has been processed.
--- a/widget/src/windows/nsWindowDefs.h
+++ b/widget/src/windows/nsWindowDefs.h
@@ -51,16 +51,18 @@
  *
  * SECTION: defines
  * 
  **************************************************************/
 
 // A magic APP message that can be sent to quit, sort of like a QUERYENDSESSION/ENDSESSION,
 // but without the query.
 #define MOZ_WM_APP_QUIT                   (WM_APP+0x0300)
+// Used as a "tracer" event to probe event loop latency.
+#define MOZ_WM_TRACE                      (WM_APP+0x0301)
 
 // GetWindowsVersion constants
 #define WIN2K_VERSION                     0x500
 #define WINXP_VERSION                     0x501
 #define WIN2K3_VERSION                    0x502
 #define VISTA_VERSION                     0x600
 #define WIN7_VERSION                      0x601