Bug 1432429 Add FuzzyFox class 2/14 draft
authorTom Ritter <tom@mozilla.com>
Fri, 15 Jun 2018 19:08:32 -0700
changeset 826363 950d2f33c1aa53ab08ae0b4cbcfc34a385ba0207
parent 826362 c0498d48e9523b7aacaf625eacbfdb1dc5eb06ef
child 826364 abe057d6ca2db613e85af69a1eb98ca28b1e8ec1
push id118310
push userbmo:tom@mozilla.com
push dateFri, 03 Aug 2018 18:22:17 +0000
bugs1432429
milestone62.0a1
Bug 1432429 Add FuzzyFox class 2/14 MozReview-Commit-ID: 1luFLRDzZjq
layout/build/nsLayoutStatics.cpp
mozglue/misc/TimeStamp_windows.cpp
mozglue/misc/TimeStamp_windows.h
toolkit/components/fuzzyfox/Fuzzyfox.cpp
toolkit/components/fuzzyfox/Fuzzyfox.h
toolkit/components/fuzzyfox/moz.build
toolkit/components/moz.build
xpcom/threads/Scheduler.cpp
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -107,16 +107,20 @@
 #include "mozilla/StaticPresData.h"
 #include "mozilla/dom/WebIDLGlobalNameHash.h"
 #include "mozilla/dom/ipc/IPCBlobInputStreamStorage.h"
 #include "mozilla/dom/U2FTokenManager.h"
 #include "mozilla/dom/PointerEventHandler.h"
 #include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "nsThreadManager.h"
 
+#ifdef MOZ_FUZZYFOX
+#include "mozilla/Fuzzyfox.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::net;
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
 
 nsrefcnt nsLayoutStatics::sLayoutStaticRefcnt = 0;
 
 nsresult
@@ -280,16 +284,20 @@ nsLayoutStatics::Initialize()
   if (XRE_IsParentProcess()) {
     // On content process we initialize DOMPrefs when PContentChild is fully
     // initialized.
     mozilla::dom::DOMPrefs::Initialize();
   }
 
   nsThreadManager::InitializeShutdownObserver();
 
+#ifdef MOZ_FUZZYFOX
+  mozilla::Fuzzyfox::Start();
+#endif
+
   return NS_OK;
 }
 
 void
 nsLayoutStatics::Shutdown()
 {
   // Don't need to shutdown nsWindowMemoryReporter, that will be done by the
   // memory reporter manager.
--- a/mozglue/misc/TimeStamp_windows.cpp
+++ b/mozglue/misc/TimeStamp_windows.cpp
@@ -58,36 +58,30 @@ static const uint32_t kFailureThreshold 
 // If we are not able to get the value of GTC time increment, use this value
 // which is the most usual increment.
 static const DWORD kDefaultTimeIncrement = 156001;
 
 // ----------------------------------------------------------------------------
 // Global variables, not changing at runtime
 // ----------------------------------------------------------------------------
 
-/**
- * The [mt] unit:
- *
- * Many values are kept in ticks of the Performance Coutner x 1000,
- * further just referred as [mt], meaning milli-ticks.
- *
- * This is needed to preserve maximum precision of the performance frequency
- * representation.  GetTickCount64 values in milliseconds are multiplied with
- * frequency per second.  Therefor we need to multiply QPC value by 1000 to
- * have the same units to allow simple arithmentic with both QPC and GTC.
- */
-
-#define ms2mt(x) ((x) * sFrequencyPerSec)
-#define mt2ms(x) ((x) / sFrequencyPerSec)
-#define mt2ms_f(x) (double(x) / sFrequencyPerSec)
-
 // Result of QueryPerformanceFrequency
 // We use default of 1 for the case we can't use QueryPerformanceCounter
 // to make mt/ms conversions work despite that.
-static LONGLONG sFrequencyPerSec = 1;
+static uint64_t sFrequencyPerSec = 1;
+
+namespace mozilla {
+
+MFBT_API uint64_t
+GetQueryPerformanceFrequencyPerSec()
+{
+  return sFrequencyPerSec;
+}
+
+}
 
 // How much we are tolerant to GTC occasional loose of resoltion.
 // This number says how many multiples of the minimal GTC resolution
 // detected on the system are acceptable.  This number is empirical.
 static const LONGLONG kGTCTickLeapTolerance = 4;
 
 // Base tolerance (more: "inability of detection" range) threshold is calculated
 // dynamically, and kept in sGTCResolutionThreshold.
--- a/mozglue/misc/TimeStamp_windows.h
+++ b/mozglue/misc/TimeStamp_windows.h
@@ -6,16 +6,34 @@
 
 #ifndef mozilla_TimeStamp_windows_h
 #define mozilla_TimeStamp_windows_h
 
 #include "mozilla/Types.h"
 
 namespace mozilla {
 
+/**
+ * The [mt] unit:
+ *
+ * Many values are kept in ticks of the Performance Coutner x 1000,
+ * further just referred as [mt], meaning milli-ticks.
+ *
+ * This is needed to preserve maximum precision of the performance frequency
+ * representation.  GetTickCount64 values in milliseconds are multiplied with
+ * frequency per second.  Therefore we need to multiply QPC value by 1000 to
+ * have the same units to allow simple arithmentic with both QPC and GTC.
+ */
+#define ms2mt(x) ((x) * mozilla::GetQueryPerformanceFrequencyPerSec())
+#define mt2ms(x) ((x) / mozilla::GetQueryPerformanceFrequencyPerSec())
+#define mt2ms_f(x) (double(x) / mozilla::GetQueryPerformanceFrequencyPerSec())
+
+MFBT_API uint64_t
+GetQueryPerformanceFrequencyPerSec();
+
 class TimeStamp;
 
 class TimeStampValue
 {
   friend struct IPC::ParamTraits<mozilla::TimeStampValue>;
   friend class TimeStamp;
 
   // Both QPC and GTC are kept in [mt] units.
new file mode 100644
--- /dev/null
+++ b/toolkit/components/fuzzyfox/Fuzzyfox.cpp
@@ -0,0 +1,207 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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 "Fuzzyfox.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Services.h"
+#include "mozilla/SystemGroup.h"
+#include "mozilla/TimeStamp.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIObserverService.h"
+#include "nsISupportsPrimitives.h"
+#include "prrng.h"
+#include "prtime.h"
+
+// For usleep/Sleep & QueryPerformanceFrequency
+#ifdef XP_WIN
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+using namespace mozilla;
+
+static LazyLogModule sFuzzyfoxLog("Fuzzyfox");
+
+#define PT_STATIC_CLOCK_GRAIN 80
+#define PT_DURATION_CENTER 100000
+
+#define US_TO_NS(x) (x*1000)
+#define NS_TO_US(x) (x/1000)
+
+#ifdef LOG
+#undef LOG
+#endif
+
+#define LOG(args) MOZ_LOG(sFuzzyfoxLog, mozilla::LogLevel::Debug, args)
+
+/* static */ void
+Fuzzyfox::Start()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  RefPtr<Fuzzyfox> r = new Fuzzyfox();
+  SystemGroup::Dispatch(TaskCategory::Other, r.forget());
+}
+
+Fuzzyfox::Fuzzyfox()
+  : Runnable("Fuzzyfox")
+  , mStartTime(ActualTime())
+  , mDuration(PickDuration())
+  , mTickType(eUptick)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+}
+
+Fuzzyfox::~Fuzzyfox() = default;
+
+NS_IMETHODIMP
+Fuzzyfox::Run()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // We need to check how long its been since we ran
+  uint64_t endTime = ActualTime();
+
+  uint64_t remaining = 0;
+  uint64_t durationCount = 1;
+
+  // Pick the amount to sleep
+  if ((endTime - mStartTime) > mDuration) {
+    // We ran over our budget!
+    uint64_t over = (endTime - mStartTime) - mDuration;
+    LOG(("[Fuzzyfox][FuzzyfoxEvent] PT(%p) Overran budget of %" PRIu32 " by %" PRIu64 " \n",
+         this, mDuration, over));
+
+    //TODO: this should probably influence uptick/downtick stuff, and it doesn't
+    uint64_t nextDuration = PickDuration();
+    while (over > nextDuration) {
+      durationCount++;
+      over -= nextDuration;
+      nextDuration = PickDuration();
+    }
+
+    remaining = nextDuration - over;
+  } else {
+    // Didn't go over budget
+    remaining = mDuration - (endTime - mStartTime);
+    LOG(("[Fuzzyfox][FuzzyfoxEvent] PT(%p) Finishing budget of %" PRIu32 " with %" PRIu64 " \n",
+        this, mDuration, remaining));
+
+  }
+
+  // Sleep for now
+#ifdef XP_WIN
+  Sleep(remaining);
+#else
+  usleep(remaining);
+#endif
+
+  //TODO we slept extra long almost certainly, what do we do about that?
+
+  // Update clocks (and fire pending events etc)
+  UpdateClocks();
+
+  // Reset values
+  mTickType = mTickType == eUptick ? eDowntick : eUptick;
+  mStartTime = ActualTime();
+  mDuration = PickDuration();
+
+  // Queue next event
+  nsCOMPtr<nsIRunnable> r = this;
+  SystemGroup::Dispatch(TaskCategory::Other, r.forget());
+  return NS_OK;
+}
+
+uint64_t
+Fuzzyfox::ActualTime()
+{
+  return PR_Now();
+}
+
+uint64_t
+Fuzzyfox::PickDuration()
+{
+  // TODO: Fix to be secure
+  long int rval = rand();
+
+  // We want uniform distribution from 1->PT_DURATION_CENTER*2
+  // so that the mean is PT_DURATION_CENTER
+  return 1 + (rval % (PT_DURATION_CENTER * 2));
+}
+
+void
+Fuzzyfox::UpdateClocks()
+{
+  uint64_t time = ActualTime();
+  TimeStamp timestamp = TimeStamp::NowReally();
+
+  uint64_t newTime = RoundToGrain(time);
+  TimeStamp newTimeStamp = RoundToGrain(timestamp);
+
+  // newTime is the new canonical time for this scope!
+  LOG(("[Fuzzyfox][Fuzzyfox][Time] New time is %" PRIu64 "\n", newTimeStamp));
+
+  // Fire notifications
+  nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+  if (NS_WARN_IF(!os)) {
+    return;
+  }
+
+  // Event firings on occur on downticks and have no data
+  if (mTickType == eDowntick) {
+    os->NotifyObservers(nullptr, "fuzzyfox-fire-outbound", nullptr);
+  }
+
+  nsCOMPtr<nsISupportsPRInt64> wrapper =
+    do_CreateInstance(NS_SUPPORTS_PRINT64_CONTRACTID);
+  if (NS_WARN_IF(!wrapper)) {
+    return;
+  }
+
+  wrapper->SetData(newTime);
+
+  // Clocks get the official 'realtime' time
+  // This happens on all ticks
+  os->NotifyObservers(wrapper, "fuzzyfox-update-clocks", nullptr);
+
+  // Update the timestamp canonicaltime
+  TimeStamp::UpdateFuzzyTimeStamp(newTimeStamp);
+}
+
+uint64_t
+Fuzzyfox::GetClockGrain()
+{
+  // Static for now
+  // Should be reading from some config probably
+  return PT_STATIC_CLOCK_GRAIN;
+}
+
+uint64_t
+Fuzzyfox::RoundToGrain(uint64_t aValue)
+{
+  uint64_t grain = GetClockGrain();
+  return US_TO_NS(aValue - (aValue % grain));
+}
+
+TimeStamp
+Fuzzyfox::RoundToGrain(TimeStamp aValue)
+{
+#ifdef XP_WIN
+  // grain is in us
+  uint64_t grain = GetClockGrain();
+  // GTC and QPS are stored in |mt| and need to be converted
+  uint64_t GTC = mt2ms(aValue.mValue.mGTC);
+  uint64_t QPC = mt2ms(aValue.mValue.mQPC);
+
+  return TimeStamp(TimeStampValue(
+    ms2mt(GTC - (GTC % grain)),
+    ms2mt(GTC - (GTC % grain)),
+    aValue.mValue.mHasQPC), true);
+#else
+  return TimeStamp(RoundToGrain(aValue.mValue));
+#endif
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/toolkit/components/fuzzyfox/Fuzzyfox.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * 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/. */
+
+#ifndef mozilla_Fuzzyfox_h
+#define mozilla_Fuzzyfox_h
+
+#include "nsThreadUtils.h"
+#include "mozilla/TimeStamp.h"
+
+namespace mozilla {
+
+class Fuzzyfox final : public Runnable
+{
+public:
+  static void
+  Start();
+
+  NS_IMETHOD
+  Run() override;
+
+private:
+  Fuzzyfox();
+  ~Fuzzyfox();
+
+  uint64_t
+  ActualTime();
+
+  uint64_t
+  PickDuration();
+
+  void
+  UpdateClocks();
+
+  uint64_t
+  GetClockGrain();
+
+  uint64_t
+  RoundToGrain(uint64_t aValue);
+
+  TimeStamp
+  RoundToGrain(TimeStamp aValue);
+
+  uint64_t mStartTime;
+  uint32_t mDuration;
+
+  enum Tick {
+    eUptick,
+    eDowntick,
+  };
+
+  Tick mTickType;
+};
+
+} // mozilla namespace
+
+#endif /* mozilla_Fuzzyfox_h */
new file mode 100644
--- /dev/null
+++ b/toolkit/components/fuzzyfox/moz.build
@@ -0,0 +1,15 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# 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/.
+
+SOURCES += [
+    'Fuzzyfox.cpp',
+]
+
+EXPORTS.mozilla += [
+    'Fuzzyfox.h'
+]
+
+FINAL_LIBRARY = 'xul'
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -72,16 +72,19 @@ DIRS += [
     'viewconfig',
     'viewsource',
     'windowcreator',
     'windowwatcher',
     'workerloader',
     'xulstore'
 ]
 
+if CONFIG['MOZ_FUZZYFOX']:
+    DIRS += ['fuzzyfox']
+
 if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
     DIRS += ['narrate'];
 
     if CONFIG['NS_PRINTING']:
         DIRS += ['printing']
 
 if CONFIG['BUILD_CTYPES']:
     DIRS += ['ctypes']
--- a/xpcom/threads/Scheduler.cpp
+++ b/xpcom/threads/Scheduler.cpp
@@ -9,24 +9,26 @@
 #include "jsfriendapi.h"
 #include "LabeledEventQueue.h"
 #include "LeakRefPtr.h"
 #include "MainThreadQueue.h"
 #include "mozilla/CooperativeThreadPool.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/SchedulerGroup.h"
+#include "mozilla/ServoBindings.h"
 #include "nsCycleCollector.h"
 #include "nsIThread.h"
 #include "nsPrintfCString.h"
 #include "nsThread.h"
 #include "nsThreadManager.h"
 #include "PrioritizedEventQueue.h"
 #include "xpcpublic.h"
 #include "xpccomponents.h"
+#include "base/message_loop.h"
 
 // Windows silliness. winbase.h defines an empty no-argument Yield macro.
 #undef Yield
 
 using namespace mozilla;
 
 // Using the anonymous namespace here causes GCC to generate:
 // error: 'mozilla::SchedulerImpl' has a field 'mozilla::SchedulerImpl::mQueue' whose type uses the anonymous namespace