blob: 967acef935f784591bcebcbbd17b1c2e6693c5ea [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/task_scheduler_util/initialization_util.h"
#include <map>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/task_scheduler/initialization_util.h"
#include "base/task_scheduler/scheduler_worker_pool_params.h"
#include "base/task_scheduler/switches.h"
#include "base/task_scheduler/task_scheduler.h"
#include "base/task_scheduler/task_traits.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "components/variations/variations_associated_data.h"
namespace task_scheduler_util {
namespace {
using StandbyThreadPolicy =
base::SchedulerWorkerPoolParams::StandbyThreadPolicy;
enum WorkerPoolType : size_t {
BACKGROUND_WORKER_POOL = 0,
BACKGROUND_FILE_IO_WORKER_POOL,
FOREGROUND_WORKER_POOL,
FOREGROUND_FILE_IO_WORKER_POOL,
WORKER_POOL_COUNT // Always last.
};
struct WorkerPoolVariationValues {
StandbyThreadPolicy standby_thread_policy;
int threads = 0;
base::TimeDelta detach_period;
};
// Converts |pool_descriptor| to a WorkerPoolVariationValues. Returns a default
// WorkerPoolVariationValues on failure.
//
// |pool_descriptor| is a semi-colon separated value string with the following
// items:
// 0. Minimum Thread Count (int)
// 1. Maximum Thread Count (int)
// 2. Thread Count Multiplier (double)
// 3. Thread Count Offset (int)
// 4. Detach Time in Milliseconds (milliseconds)
// 5. Standby Thread Policy (string)
// Additional values may appear as necessary and will be ignored.
WorkerPoolVariationValues StringToWorkerPoolVariationValues(
const base::StringPiece pool_descriptor) {
const std::vector<std::string> tokens =
SplitString(pool_descriptor, ";",
base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
int min;
int max;
double cores_multiplier;
int offset;
int detach_milliseconds;
// Checking for a size greater than the expected amount allows us to be
// forward compatible if we add more variation values.
if (tokens.size() >= 5 && base::StringToInt(tokens[0], &min) &&
base::StringToInt(tokens[1], &max) &&
base::StringToDouble(tokens[2], &cores_multiplier) &&
base::StringToInt(tokens[3], &offset) &&
base::StringToInt(tokens[4], &detach_milliseconds)) {
WorkerPoolVariationValues values;
values.threads = base::RecommendedMaxNumberOfThreadsInPool(
min, max, cores_multiplier, offset);
values.detach_period =
base::TimeDelta::FromMilliseconds(detach_milliseconds);
values.standby_thread_policy =
(tokens.size() >= 6 && tokens[5] == "lazy")
? StandbyThreadPolicy::LAZY
: StandbyThreadPolicy::ONE;
return values;
}
DLOG(ERROR) << "Invalid Worker Pool Descriptor: " << pool_descriptor;
return WorkerPoolVariationValues();
}
// Returns the worker pool index for |traits| defaulting to
// FOREGROUND_WORKER_POOL or FOREGROUND_FILE_IO_WORKER_POOL on unknown
// priorities.
size_t WorkerPoolIndexForTraits(const base::TaskTraits& traits) {
const bool is_background =
traits.priority() == base::TaskPriority::BACKGROUND;
if (traits.with_file_io()) {
return is_background ? BACKGROUND_FILE_IO_WORKER_POOL
: FOREGROUND_FILE_IO_WORKER_POOL;
}
return is_background ? BACKGROUND_WORKER_POOL : FOREGROUND_WORKER_POOL;
}
std::map<std::string, std::string> GetDefaultBrowserVariationParams() {
std::map<std::string, std::string> variation_params;
#if defined(OS_ANDROID) || defined(OS_IOS)
variation_params["Background"] = "2;8;0.1;0;30000";
variation_params["BackgroundFileIO"] = "2;8;0.1;0;30000";
variation_params["Foreground"] = "3;8;0.3;0;30000";
variation_params["ForegroundFileIO"] = "3;8;0.3;0;30000";
#else
variation_params["Background"] = "3;8;0.1;0;30000";
variation_params["BackgroundFileIO"] = "3;8;0.1;0;30000";
variation_params["Foreground"] = "8;32;0.3;0;30000";
variation_params["ForegroundFileIO"] = "8;32;0.3;0;30000";
#endif // defined(OS_ANDROID) || defined(OS_IOS)
return variation_params;
}
// Converts a browser-based |variation_params| to
// std::vector<base::SchedulerWorkerPoolParams>. Returns an empty vector on
// failure.
std::vector<base::SchedulerWorkerPoolParams>
VariationsParamsToBrowserSchedulerWorkerPoolParams(
const std::map<std::string, std::string>& variation_params) {
using ThreadPriority = base::ThreadPriority;
using IORestriction = base::SchedulerWorkerPoolParams::IORestriction;
struct SchedulerWorkerPoolPredefinedParams {
const char* name;
ThreadPriority priority_hint;
IORestriction io_restriction;
};
static const SchedulerWorkerPoolPredefinedParams kAllPredefinedParams[] = {
{"Background", ThreadPriority::BACKGROUND, IORestriction::DISALLOWED},
{"BackgroundFileIO", ThreadPriority::BACKGROUND, IORestriction::ALLOWED},
{"Foreground", ThreadPriority::NORMAL, IORestriction::DISALLOWED},
{"ForegroundFileIO", ThreadPriority::NORMAL, IORestriction::ALLOWED},
};
static_assert(arraysize(kAllPredefinedParams) == WORKER_POOL_COUNT,
"Mismatched Worker Pool Types and Predefined Parameters");
std::vector<base::SchedulerWorkerPoolParams> params_vector;
for (const auto& predefined_params : kAllPredefinedParams) {
const auto pair = variation_params.find(predefined_params.name);
if (pair == variation_params.end()) {
DLOG(ERROR) << "Missing Worker Pool Configuration: "
<< predefined_params.name;
return std::vector<base::SchedulerWorkerPoolParams>();
}
const WorkerPoolVariationValues variation_values =
StringToWorkerPoolVariationValues(pair->second);
if (variation_values.threads <= 0 ||
variation_values.detach_period.is_zero()) {
DLOG(ERROR) << "Invalid Worker Pool Configuration: " <<
predefined_params.name << " [" << pair->second << "]";
return std::vector<base::SchedulerWorkerPoolParams>();
}
params_vector.emplace_back(predefined_params.name,
predefined_params.priority_hint,
predefined_params.io_restriction,
variation_values.standby_thread_policy,
variation_values.threads,
variation_values.detach_period);
}
DCHECK_EQ(WORKER_POOL_COUNT, params_vector.size());
return params_vector;
}
} // namespace
void InitializeDefaultBrowserTaskScheduler() {
static constexpr char kFieldTrialName[] = "BrowserScheduler";
std::map<std::string, std::string> variation_params;
if (!variations::GetVariationParams(kFieldTrialName, &variation_params))
variation_params = GetDefaultBrowserVariationParams();
auto params_vector =
VariationsParamsToBrowserSchedulerWorkerPoolParams(variation_params);
if (params_vector.empty()) {
variation_params = GetDefaultBrowserVariationParams();
params_vector =
VariationsParamsToBrowserSchedulerWorkerPoolParams(variation_params);
DCHECK(!params_vector.empty());
}
base::TaskScheduler::CreateAndSetDefaultTaskScheduler(
params_vector, base::Bind(WorkerPoolIndexForTraits));
// TODO(gab): Remove this when http://crbug.com/622400 concludes.
const auto sequenced_worker_pool_param =
variation_params.find("RedirectSequencedWorkerPools");
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableBrowserTaskScheduler) &&
sequenced_worker_pool_param != variation_params.end() &&
sequenced_worker_pool_param->second == "true") {
base::SequencedWorkerPool::EnableWithRedirectionToTaskSchedulerForProcess();
} else {
base::SequencedWorkerPool::EnableForProcess();
}
}
} // namespace task_scheduler_util