about summary refs log tree commit diff
path: root/pkgs/applications/networking/browsers/firefox/common.nix
diff options
context:
space:
mode:
authorMartin Weinelt <hexa@darmstadt.ccc.de>2022-03-22 03:35:51 +0100
committerYuka <yuka@yuka.dev>2022-03-28 21:42:49 +0200
commit0d3772f6455c0185c9dee3f8c31130e7ad6edff9 (patch)
tree1a1e9525380295d9161448f48fe7e520c45191f7 /pkgs/applications/networking/browsers/firefox/common.nix
parentf37810ba4ddb9fe77022bb868429a273f6a1d0e2 (diff)
firefox: add profile-guided optimization
Lo and behold, we're finally catching up with Mozillas very own firefox
build in terms of speed.

PGO is an optimization technique in which in a first step we create a
build that supports instrumentation, meaning we can use it to create a
profile of how the browser behaved during usage. Then in a second pass
we create the final build that uses the acquired profiling data to
optimize the browser for the workload it actually received during
profiling.

The downside is that with PGO we now need to build Firefox twice, which
increases the build time from around 20 minutes to roughly 50 minutes.

In the Speedometer 2.0 benchmark multiple tests could see a
responsiveness improvemeant around 20-25%, which makes the increased
build time well worth it.

Sadly this benefit seems limited to x86_64-linux, builds on
aarch64-linux get stuck during profiling and I haven't found out why.

Finally, after a long time, we can say:

Closes: #76484
Supersedes: #129503
Diffstat (limited to 'pkgs/applications/networking/browsers/firefox/common.nix')
-rw-r--r--pkgs/applications/networking/browsers/firefox/common.nix60
1 files changed, 60 insertions, 0 deletions
diff --git a/pkgs/applications/networking/browsers/firefox/common.nix b/pkgs/applications/networking/browsers/firefox/common.nix
index 64cba1b52a60e..8d445ac44eb2c 100644
--- a/pkgs/applications/networking/browsers/firefox/common.nix
+++ b/pkgs/applications/networking/browsers/firefox/common.nix
@@ -83,6 +83,7 @@
 , gssSupport ? true, libkrb5
 , jemallocSupport ? true, jemalloc
 , ltoSupport ? (stdenv.isLinux && stdenv.is64bit), overrideCC, buildPackages
+, pgoSupport ? (stdenv.isLinux && stdenv.isx86_64 && stdenv.hostPlatform == stdenv.buildPlatform), xvfb-run
 , pipewireSupport ? waylandSupport && webrtcSupport
 , pulseaudioSupport ? stdenv.isLinux, libpulseaudio
 , waylandSupport ? true, libxkbcommon, libdrm
@@ -164,6 +165,13 @@ buildStdenv.mkDerivation ({
 
   inherit src unpackPhase meta;
 
+  # Add another configure-build-profiling run before the final configure phase if we build with pgo
+  preConfigurePhases = lib.optionals pgoSupport [
+    "configurePhase"
+    "buildPhase"
+    "profilingPhase"
+  ];
+
   patches = [
   ]
   ++ lib.optional (lib.versionAtLeast version "86") ./env_var_for_system_dir-ff86.patch
@@ -199,6 +207,7 @@ buildStdenv.mkDerivation ({
     which
     wrapGAppsHook
   ]
+  ++ lib.optionals pgoSupport [ xvfb-run ]
   ++ extraNativeBuildInputs;
 
   setOutputFlags = false; # `./mach configure` doesn't understand `--*dir=` flags.
@@ -214,6 +223,9 @@ buildStdenv.mkDerivation ({
     export MOZ_OBJDIR=$(pwd)/mozobj
     export MOZBUILD_STATE_PATH=$(pwd)/mozbuild
 
+    # Don't try to send libnotify notifications during build
+    export MOZ_NOSPAM=1
+
     # Set consistent remoting name to ensure wmclass matches with desktop file
     export MOZ_APP_REMOTINGNAME="${binaryName}"
 
@@ -228,6 +240,25 @@ buildStdenv.mkDerivation ({
     # RBox WASM Sandboxing
     export WASM_CC=${pkgsCross.wasi32.stdenv.cc}/bin/${pkgsCross.wasi32.stdenv.cc.targetPrefix}cc
     export WASM_CXX=${pkgsCross.wasi32.stdenv.cc}/bin/${pkgsCross.wasi32.stdenv.cc.targetPrefix}c++
+ '' + lib.optionalString pgoSupport ''
+   if [ -e "$TMPDIR/merged.profdata" ]; then
+     echo "Configuring with profiling data"
+     for i in "''${!configureFlagsArray[@]}"; do
+       if [[ ''${configureFlagsArray[i]} = "--enable-profile-generate=cross" ]]; then
+         unset 'configureFlagsArray[i]'
+       fi
+     done
+     configureFlagsArray+=(
+       "--enable-profile-use=cross"
+       "--with-pgo-profile-path="$TMPDIR/merged.profdata""
+       "--with-pgo-jarlog="$TMPDIR/jarlog""
+     )
+   else
+     echo "Configuring to generate profiling data"
+     configureFlagsArray+=(
+       "--enable-profile-generate=cross"
+     )
+   fi
   '' + lib.optionalString googleAPISupport ''
     # Google API key used by Chromium and Firefox.
     # Note: These are for NixOS/nixpkgs use ONLY. For your own distribution,
@@ -336,10 +367,35 @@ buildStdenv.mkDerivation ({
   ++ lib.optional  jemallocSupport jemalloc
   ++ extraBuildInputs;
 
+  profilingPhase = lib.optionalString pgoSupport ''
+    # Package up Firefox for profiling
+    ./mach package
+
+    # Run profiling
+    (
+      export HOME=$TMPDIR
+      export LLVM_PROFDATA=llvm-profdata
+      export JARLOG_FILE="$TMPDIR/jarlog"
+
+      xvfb-run -w 10 -s "-screen 0 1920x1080x24" \
+        ./mach python ./build/pgo/profileserver.py
+    )
+
+    # Copy profiling data to a place we can easily reference
+    cp ./merged.profdata $TMPDIR/merged.profdata
+
+    # Clean build dir
+    ./mach clobber
+  '';
+
   preBuild = ''
     cd mozobj
   '';
 
+  postBuild = ''
+    cd ..
+  '';
+
   makeFlags = extraMakeFlags;
   separateDebugInfo = enableDebugSymbols;
   enableParallelBuilding = true;
@@ -347,6 +403,10 @@ buildStdenv.mkDerivation ({
   # tests were disabled in configureFlags
   doCheck = false;
 
+  preInstall = ''
+    cd mozobj
+  '';
+
   postInstall = lib.optionalString buildStdenv.isLinux ''
     # Remove SDK cruft. FIXME: move to a separate output?
     rm -rf $out/share/idl $out/include $out/lib/${binaryName}-devel-*