Skip to content

Commit 83e824f

Browse files
author
Emma Malysz
committed
Bug 1640087: Part 2: tuck optimized prefetches behind a preference. r=dthayer,aklotz
PrefetchRegistryInfo is intended to be a temporary file in order to conduct this experiment on startup times vs. retention. Most of the implementation is similar to LauncherRegistryInfo. If we startup and the registry is different than the preference, we will want to use the preference for the purpose of this experiment. Differential Revision: https://phabricator.services.mozilla.com/D76993
1 parent 0bcd6b0 commit 83e824f

5 files changed

+231
-28
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
6+
7+
#include "DllPrefetchExperimentRegistryInfo.h"
8+
9+
#include "mozilla/Assertions.h"
10+
#include "mozilla/NativeNt.h"
11+
#include "mozilla/ResultExtensions.h"
12+
13+
namespace mozilla {
14+
15+
const wchar_t DllPrefetchExperimentRegistryInfo::kExperimentSubKeyPath[] =
16+
L"SOFTWARE"
17+
L"\\" MOZ_APP_VENDOR L"\\" MOZ_APP_BASENAME L"\\DllPrefetchExperiment";
18+
19+
Result<Ok, nsresult> DllPrefetchExperimentRegistryInfo::Open() {
20+
if (!!mRegKey) {
21+
return Ok();
22+
}
23+
24+
DWORD disposition;
25+
HKEY rawKey;
26+
LSTATUS result = ::RegCreateKeyExW(
27+
HKEY_CURRENT_USER, kExperimentSubKeyPath, 0, nullptr,
28+
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr, &rawKey, &disposition);
29+
30+
if (result != ERROR_SUCCESS) {
31+
return Err(NS_ERROR_UNEXPECTED);
32+
}
33+
34+
mRegKey.own(rawKey);
35+
36+
if (disposition == REG_CREATED_NEW_KEY ||
37+
disposition == REG_OPENED_EXISTING_KEY) {
38+
return Ok();
39+
}
40+
41+
MOZ_ASSERT_UNREACHABLE("Invalid disposition from RegCreateKeyExW");
42+
return Err(NS_ERROR_UNEXPECTED);
43+
}
44+
45+
Result<Ok, nsresult> DllPrefetchExperimentRegistryInfo::ReflectPrefToRegistry(
46+
int32_t aVal) {
47+
MOZ_TRY(Open());
48+
49+
mPrefetchMode = aVal;
50+
51+
LSTATUS status =
52+
::RegSetValueExW(mRegKey.get(), mBinPath.get(), 0, REG_DWORD,
53+
reinterpret_cast<PBYTE>(&aVal), sizeof(aVal));
54+
55+
if (status != ERROR_SUCCESS) {
56+
return Err(NS_ERROR_UNEXPECTED);
57+
}
58+
59+
return Ok();
60+
}
61+
62+
Result<Ok, nsresult> DllPrefetchExperimentRegistryInfo::ReadRegistryValueData(
63+
DWORD expectedType) {
64+
MOZ_TRY(Open());
65+
66+
int32_t data;
67+
DWORD dataLen = sizeof((ULONG)data);
68+
DWORD type;
69+
LSTATUS status =
70+
::RegQueryValueExW(mRegKey.get(), mBinPath.get(), nullptr, &type,
71+
reinterpret_cast<PBYTE>(&data), &dataLen);
72+
73+
if (status == ERROR_FILE_NOT_FOUND) {
74+
// The registry key has not been created, set to default 0
75+
mPrefetchMode = 0;
76+
return Ok();
77+
}
78+
79+
if (status != ERROR_SUCCESS) {
80+
return Err(NS_ERROR_UNEXPECTED);
81+
}
82+
83+
if (type != expectedType) {
84+
return Err(NS_ERROR_UNEXPECTED);
85+
}
86+
87+
mPrefetchMode = data;
88+
return Ok();
89+
}
90+
91+
AlteredDllPrefetchMode
92+
DllPrefetchExperimentRegistryInfo::GetAlteredDllPrefetchMode() {
93+
Result<Ok, nsresult> result = ReadRegistryValueData(REG_DWORD);
94+
if (!result.isOk()) {
95+
MOZ_ASSERT(false);
96+
return AlteredDllPrefetchMode::CurrentPrefetch;
97+
}
98+
99+
switch (mPrefetchMode) {
100+
case 0:
101+
return AlteredDllPrefetchMode::CurrentPrefetch;
102+
case 1:
103+
return AlteredDllPrefetchMode::NoPrefetch;
104+
case 2:
105+
return AlteredDllPrefetchMode::OptimizedPrefetch;
106+
default:
107+
MOZ_ASSERT(false);
108+
return AlteredDllPrefetchMode::CurrentPrefetch;
109+
}
110+
}
111+
112+
} // namespace mozilla
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2+
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3+
/* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
6+
7+
#ifndef mozilla_DllPrefetchExperimentRegistryInfo_h
8+
#define mozilla_DllPrefetchExperimentRegistryInfo_h
9+
10+
#include "mozilla/Maybe.h"
11+
#include "mozilla/WinHeaderOnlyUtils.h"
12+
#include "nsWindowsHelpers.h"
13+
14+
/**
15+
* This is a temporary file in order to conduct an experiment on the impact of
16+
* startup time on retention (see Bug 1640087).
17+
* This was generally adapted from LauncherRegistryInfo.h
18+
*/
19+
20+
namespace mozilla {
21+
22+
enum class AlteredDllPrefetchMode {
23+
CurrentPrefetch,
24+
NoPrefetch,
25+
OptimizedPrefetch
26+
};
27+
28+
class DllPrefetchExperimentRegistryInfo final {
29+
public:
30+
DllPrefetchExperimentRegistryInfo() : mBinPath(GetFullBinaryPath().get()) {}
31+
~DllPrefetchExperimentRegistryInfo() {}
32+
33+
Result<Ok, nsresult> ReflectPrefToRegistry(int32_t aVal);
34+
Result<Ok, nsresult> ReadRegistryValueData(DWORD expectedType);
35+
36+
AlteredDllPrefetchMode GetAlteredDllPrefetchMode();
37+
38+
private:
39+
Result<Ok, nsresult> Open();
40+
41+
nsAutoRegKey mRegKey;
42+
nsString mBinPath;
43+
int32_t mPrefetchMode;
44+
45+
static const wchar_t kExperimentSubKeyPath[];
46+
};
47+
48+
} // namespace mozilla
49+
50+
#endif // mozilla_DllPrefetchExperimentRegistryInfo_h

toolkit/xre/moz.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']:
4747
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
4848
EXPORTS.mozilla += [
4949
'AssembleCmdLine.h',
50+
'DllPrefetchExperimentRegistryInfo.h',
5051
'ModuleVersionInfo.h',
5152
'PolicyChecks.h',
5253
'UntrustedModulesProcessor.h',
@@ -55,6 +56,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
5556
]
5657
UNIFIED_SOURCES += [
5758
'/toolkit/mozapps/update/common/updateutils_win.cpp',
59+
'DllPrefetchExperimentRegistryInfo.cpp',
5860
'ModuleEvaluator.cpp',
5961
'ModuleVersionInfo.cpp',
6062
'nsNativeAppSupportWin.cpp',

toolkit/xre/nsAppRunner.cpp

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
# include <intrin.h>
102102
# include <math.h>
103103
# include "cairo/cairo-features.h"
104+
# include "mozilla/DllPrefetchExperimentRegistryInfo.h"
104105
# include "mozilla/WindowsDllBlocklist.h"
105106
# include "mozilla/WindowsProcessMitigations.h"
106107
# include "mozilla/WinHeaderOnlyUtils.h"
@@ -1561,6 +1562,28 @@ static void RegisterApplicationRestartChanged(const char* aPref, void* aData) {
15611562
}
15621563
}
15631564

1565+
static void OnAlteredPrefetchPrefChanged(const char* aPref, void* aData) {
1566+
int32_t prefVal = Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH, 0);
1567+
1568+
mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
1569+
mozilla::DebugOnly<mozilla::Result<Ok, nsresult>> reflectResult =
1570+
prefetchRegInfo.ReflectPrefToRegistry(prefVal);
1571+
1572+
MOZ_ASSERT(reflectResult.value.isOk());
1573+
}
1574+
1575+
static void SetupAlteredPrefetchPref() {
1576+
mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
1577+
1578+
mozilla::DebugOnly<mozilla::Result<Ok, nsresult>> reflectResult =
1579+
prefetchRegInfo.ReflectPrefToRegistry(
1580+
Preferences::GetInt(PREF_WIN_ALTERED_DLL_PREFETCH, 0));
1581+
MOZ_ASSERT(reflectResult.value.isOk());
1582+
1583+
Preferences::RegisterCallback(&OnAlteredPrefetchPrefChanged,
1584+
PREF_WIN_ALTERED_DLL_PREFETCH);
1585+
}
1586+
15641587
# if defined(MOZ_LAUNCHER_PROCESS)
15651588

15661589
static void OnLauncherPrefChanged(const char* aPref, void* aData) {
@@ -3600,14 +3623,12 @@ static void ReadAheadSystemDll(const wchar_t* dllName) {
36003623
}
36013624
}
36023625

3603-
# ifdef NIGHTLY_BUILD
36043626
static void ReadAheadPackagedDll(const wchar_t* dllName,
36053627
const wchar_t* aGREDir) {
36063628
wchar_t dllPath[MAX_PATH];
36073629
swprintf(dllPath, MAX_PATH, L"%s\\%s", aGREDir, dllName);
36083630
ReadAheadLib(dllPath);
36093631
}
3610-
# endif
36113632

36123633
static void PR_CALLBACK ReadAheadDlls_ThreadStart(void* arg) {
36133634
UniquePtr<wchar_t[]> greDir(static_cast<wchar_t*>(arg));
@@ -3618,32 +3639,32 @@ static void PR_CALLBACK ReadAheadDlls_ThreadStart(void* arg) {
36183639
// retention (see Bug 1640087). Before we place this within a pref,
36193640
// we should ensure this feature only ships to the nightly channel
36203641
// and monitor results from that subset.
3621-
# ifdef NIGHTLY_BUILD
3622-
// Prefetch the DLLs shipped with firefox
3623-
ReadAheadPackagedDll(L"libegl.dll", greDir.get());
3624-
ReadAheadPackagedDll(L"libGLESv2.dll", greDir.get());
3625-
ReadAheadPackagedDll(L"nssckbi.dll", greDir.get());
3626-
ReadAheadPackagedDll(L"freebl3.dll", greDir.get());
3627-
ReadAheadPackagedDll(L"softokn3.dll", greDir.get());
3628-
3629-
// Prefetch the system DLLs
3630-
ReadAheadSystemDll(L"DWrite.dll");
3631-
ReadAheadSystemDll(L"D3DCompiler_47.dll");
3632-
# else
3633-
// Load DataExchange.dll and twinapi.appcore.dll for
3634-
// nsWindow::EnableDragDrop
3635-
ReadAheadSystemDll(L"DataExchange.dll");
3636-
ReadAheadSystemDll(L"twinapi.appcore.dll");
3642+
if (greDir) {
3643+
// Prefetch the DLLs shipped with firefox
3644+
ReadAheadPackagedDll(L"libegl.dll", greDir.get());
3645+
ReadAheadPackagedDll(L"libGLESv2.dll", greDir.get());
3646+
ReadAheadPackagedDll(L"nssckbi.dll", greDir.get());
3647+
ReadAheadPackagedDll(L"freebl3.dll", greDir.get());
3648+
ReadAheadPackagedDll(L"softokn3.dll", greDir.get());
3649+
3650+
// Prefetch the system DLLs
3651+
ReadAheadSystemDll(L"DWrite.dll");
3652+
ReadAheadSystemDll(L"D3DCompiler_47.dll");
3653+
} else {
3654+
// Load DataExchange.dll and twinapi.appcore.dll for
3655+
// nsWindow::EnableDragDrop
3656+
ReadAheadSystemDll(L"DataExchange.dll");
3657+
ReadAheadSystemDll(L"twinapi.appcore.dll");
36373658

3638-
// Load twinapi.dll for WindowsUIUtils::UpdateTabletModeState
3639-
ReadAheadSystemDll(L"twinapi.dll");
3659+
// Load twinapi.dll for WindowsUIUtils::UpdateTabletModeState
3660+
ReadAheadSystemDll(L"twinapi.dll");
36403661

3641-
// Load explorerframe.dll for WinTaskbar::Initialize
3642-
ReadAheadSystemDll(L"ExplorerFrame.dll");
3662+
// Load explorerframe.dll for WinTaskbar::Initialize
3663+
ReadAheadSystemDll(L"ExplorerFrame.dll");
36433664

3644-
// Load WinTypes.dll for nsOSHelperAppService::GetApplicationDescription
3645-
ReadAheadSystemDll(L"WinTypes.dll");
3646-
# endif
3665+
// Load WinTypes.dll for nsOSHelperAppService::GetApplicationDescription
3666+
ReadAheadSystemDll(L"WinTypes.dll");
3667+
}
36473668
}
36483669
#endif
36493670

@@ -4335,14 +4356,29 @@ nsresult XREMain::XRE_mainRun() {
43354356
}
43364357

43374358
#ifdef XP_WIN
4338-
if (!PR_GetEnv("XRE_NO_DLL_READAHEAD")) {
4359+
mozilla::DllPrefetchExperimentRegistryInfo prefetchRegInfo;
4360+
mozilla::AlteredDllPrefetchMode dllPrefetchMode =
4361+
prefetchRegInfo.GetAlteredDllPrefetchMode();
4362+
4363+
if (!PR_GetEnv("XRE_NO_DLL_READAHEAD") &&
4364+
dllPrefetchMode != mozilla::AlteredDllPrefetchMode::NoPrefetch) {
43394365
nsCOMPtr<nsIFile> greDir = mDirProvider.GetGREDir();
43404366
nsAutoString path;
43414367
rv = greDir->GetPath(path);
43424368
if (NS_SUCCEEDED(rv)) {
43434369
PRThread* readAheadThread;
4344-
wchar_t* pathRaw = new wchar_t[MAX_PATH];
4345-
wcscpy_s(pathRaw, MAX_PATH, path.get());
4370+
wchar_t* pathRaw;
4371+
4372+
// We use the presence of a path argument inside the thread to determine
4373+
// which list of Dlls to use. The old list does not need access to the
4374+
// GRE dir, so the path argument is set to a null pointer.
4375+
if (dllPrefetchMode ==
4376+
mozilla::AlteredDllPrefetchMode::OptimizedPrefetch) {
4377+
pathRaw = new wchar_t[MAX_PATH];
4378+
wcscpy_s(pathRaw, MAX_PATH, path.get());
4379+
} else {
4380+
pathRaw = nullptr;
4381+
}
43464382
readAheadThread = PR_CreateThread(
43474383
PR_USER_THREAD, ReadAheadDlls_ThreadStart, (void*)pathRaw,
43484384
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, 0);
@@ -4550,6 +4586,7 @@ nsresult XREMain::XRE_mainRun() {
45504586
#ifdef XP_WIN
45514587
Preferences::RegisterCallbackAndCall(RegisterApplicationRestartChanged,
45524588
PREF_WIN_REGISTER_APPLICATION_RESTART);
4589+
SetupAlteredPrefetchPref();
45534590
# if defined(MOZ_LAUNCHER_PROCESS)
45544591
SetupLauncherProcessPref();
45554592
# endif // defined(MOZ_LAUNCHER_PROCESS)

toolkit/xre/nsAppRunner.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ BOOL WinLaunchChild(const wchar_t* exePath, int argc, char** argv,
124124
# define PREF_WIN_REGISTER_APPLICATION_RESTART \
125125
"toolkit.winRegisterApplicationRestart"
126126

127+
# define PREF_WIN_ALTERED_DLL_PREFETCH "startup.experiments.alteredDllPrefetch"
128+
127129
# if defined(MOZ_LAUNCHER_PROCESS)
128130
# define PREF_WIN_LAUNCHER_PROCESS_ENABLED "browser.launcherProcess.enabled"
129131
# endif // defined(MOZ_LAUNCHER_PROCESS)

0 commit comments

Comments
 (0)