chromium/components/app_launch_prefetch/app_launch_prefetch.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/app_launch_prefetch/app_launch_prefetch.h"

#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/notreached.h"
#include "base/win/windows_version.h"

namespace {

BASE_FEATURE(kExpandedPrefetchRange,
             "ExpandedPrefetchRange",
             base::FEATURE_ENABLED_BY_DEFAULT);

// /prefetch:# arguments to use when launching various process types. It has
// been observed that when file reads are consistent for 3 process launches with
// the same /prefetch:# argument, the Windows prefetcher starts issuing reads in
// batch at process launch. Because reads depend on the process type, the
// prefetcher wouldn't be able to observe consistent reads if no /prefetch:#
// arguments were used. Note that the browser process has no /prefetch:#
// argument; as such all other processes must have one in order to avoid
// polluting its profile.

// On Windows versions before Win11 21H2 the value must always be in [1, 8];
// otherwise it is treated as 0 by the Windows prefetcher and will interfere
// with the main process launch.

constexpr base::CommandLine::StringViewType kPrefetchArgument1 = L"/prefetch:1";
constexpr base::CommandLine::StringViewType kPrefetchArgument2 = L"/prefetch:2";
constexpr base::CommandLine::StringViewType kPrefetchArgument3 = L"/prefetch:3";
constexpr base::CommandLine::StringViewType kPrefetchArgument4 = L"/prefetch:4";

// /prefetch:5, /prefetch:6 and /prefetch:7 are reserved for content embedders
// and are not to be used by content itself, with caveats: we violate this
// rule with kBrowserBackground using bucket 5, while the 7th bucket is used by
// the crashpad fallback handler.
constexpr base::CommandLine::StringViewType kPrefetchArgument5 = L"/prefetch:5";
// constexpr base::CommandLine::StringViewType kPrefetchArgument6 =
// "/prefetch:6";
constexpr base::CommandLine::StringViewType kPrefetchArgument7 = L"/prefetch:7";

// Catch all for Windows versions before Win 11 21H2.
constexpr base::CommandLine::StringViewType kPrefetchArgument8 = L"/prefetch:8";

// On Windows 11 21H2 and later the prefetch range was expanded to be [1,16]

constexpr base::CommandLine::StringViewType kPrefetchArgument9 = L"/prefetch:9";
constexpr base::CommandLine::StringViewType kPrefetchArgument10 =
    L"/prefetch:10";
constexpr base::CommandLine::StringViewType kPrefetchArgument11 =
    L"/prefetch:11";
constexpr base::CommandLine::StringViewType kPrefetchArgument12 =
    L"/prefetch:12";
constexpr base::CommandLine::StringViewType kPrefetchArgument13 =
    L"/prefetch:13";
constexpr base::CommandLine::StringViewType kPrefetchArgument14 =
    L"/prefetch:14";
// constexpr base::CommandLine::StringViewType kPrefetchArgument15 =
// "/prefetch:15";

// Catch all for Windows versions  Win 11 21H2 and later.
constexpr base::CommandLine::StringViewType kPrefetchArgument16 =
    L"/prefetch:16";

}  // namespace

namespace app_launch_prefetch {

base::CommandLine::StringViewType GetPrefetchSwitch(SubprocessType type) {
  using enum SubprocessType;
  if (base::win::GetVersion() >= base::win::Version::WIN11 &&
      base::FeatureList::GetInstance() &&
      base::FeatureList::IsEnabled(kExpandedPrefetchRange)) {
    // These are the prefetch arguments used on Windows versions
    // for Win11 and later. There are fewer processes using the same
    // values and this should lead to better App Launch PreFetch (ALPF)
    // behavior.

    // kPrefetchArgument8 and kPrefetchArgument15 are currently unused.
    switch (type) {
      case kBrowser:
        NOTREACHED();
      case kRenderer:
        return kPrefetchArgument1;
      case kGPU:
        return kPrefetchArgument2;
      case kPpapi:
        return kPrefetchArgument3;
      case kCrashpad:
        return kPrefetchArgument4;
      case kBrowserBackground:
        return kPrefetchArgument5;
      case kCrashpadFallback:
        return kPrefetchArgument7;
      case kExtension:
        return kPrefetchArgument9;
      case kGPUInfo:
        return kPrefetchArgument10;
      case kUtilityNetworkService:
        return kPrefetchArgument11;
      case kUtilityAudio:
        return kPrefetchArgument12;
      case kUtilityStorage:
        return kPrefetchArgument13;
      case kUtilityOther:
        return kPrefetchArgument14;
      case kCatchAll:
        return kPrefetchArgument16;
    }
  } else {
    // These are the prefetch arguments used on Windows versions
    // before Win11 21H2. There are multiple processes using the same values
    // and this leads to less than optimal App Launch PreFetch (ALPF) behavior.

    // /prefetch:5, /prefetch:6 and /prefetch:7 are reserved for content
    // embedders and are not to be used by content itself, with caveats: we
    // violate this rule with kBrowserBackground using bucket 5, while the 7th
    // bucket is used by the crashpad fallback handler.
    switch (type) {
      case kBrowser:
        NOTREACHED();
      case kRenderer:
        return kPrefetchArgument1;
      case kGPU:
        return kPrefetchArgument2;
      case kExtension:
        return kPrefetchArgument2;
      case kPpapi:
        return kPrefetchArgument3;
      case kUtilityNetworkService:
        return kPrefetchArgument3;
      case kCrashpad:
        return kPrefetchArgument4;
      case kBrowserBackground:
        return kPrefetchArgument5;
      case kCrashpadFallback:
        return kPrefetchArgument7;
      case kCatchAll:
        return kPrefetchArgument8;
      case kGPUInfo:
        return kPrefetchArgument8;
      case kUtilityAudio:
        return kPrefetchArgument8;
      case kUtilityStorage:
        return kPrefetchArgument8;
      case kUtilityOther:
        return kPrefetchArgument8;
    }
  }
}

}  // namespace app_launch_prefetch