blob: d83362b514d1c06e9d295f03264df064fb4d022c [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/common/variations_util.h"
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/task_scheduler/initialization_util.h"
#include "base/time/time.h"
#include "components/variations/variations_associated_data.h"
namespace task_scheduler_util {
namespace {
#if !defined(OS_IOS)
constexpr char kTaskSchedulerVariationParamsSwitch[] =
"task-scheduler-variation-params";
constexpr char kSeparator[] = "|";
bool ContainsSeparator(const std::string& str) {
return str.find(kSeparator) != std::string::npos;
}
#endif // !defined(OS_IOS)
// Builds a SchedulerWorkerPoolParams from the pool descriptor in
// |variation_params[variation_param_prefix + pool_name]| and
// |backward_compatibility|. Returns an invalid SchedulerWorkerPoolParams on
// failure.
//
// The 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 (int)
// Additional values may appear as necessary and will be ignored.
std::unique_ptr<base::SchedulerWorkerPoolParams> GetWorkerPoolParams(
base::StringPiece variation_param_prefix,
base::StringPiece pool_name,
const std::map<std::string, std::string>& variation_params,
base::SchedulerBackwardCompatibility backward_compatibility =
base::SchedulerBackwardCompatibility::DISABLED) {
auto pool_descriptor_it = variation_params.find(
base::JoinString({variation_param_prefix, pool_name}, ""));
if (pool_descriptor_it == variation_params.end())
return nullptr;
const auto& pool_descriptor = pool_descriptor_it->second;
const std::vector<base::StringPiece> tokens = SplitStringPiece(
pool_descriptor, ";", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
// Normally, we wouldn't initialize the values below because we don't read
// from them before we write to them. However, some compilers (like MSVC)
// complain about uninitialized variables due to the as_string() call below.
int min = 0;
int max = 0;
double cores_multiplier = 0.0;
int offset = 0;
int detach_milliseconds = 0;
// 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].as_string(), &cores_multiplier) ||
!base::StringToInt(tokens[3], &offset) ||
!base::StringToInt(tokens[4], &detach_milliseconds)) {
DLOG(ERROR) << "Invalid Worker Pool Descriptor Format: " << pool_descriptor;
return nullptr;
}
auto params = base::MakeUnique<base::SchedulerWorkerPoolParams>(
base::RecommendedMaxNumberOfThreadsInPool(min, max, cores_multiplier,
offset),
base::TimeDelta::FromMilliseconds(detach_milliseconds),
backward_compatibility);
if (params->max_threads() <= 0) {
DLOG(ERROR) << "Invalid max threads in the Worker Pool Descriptor: "
<< params->max_threads();
return nullptr;
}
if (params->suggested_reclaim_time() < base::TimeDelta()) {
DLOG(ERROR)
<< "Invalid suggested reclaim time in the Worker Pool Descriptor:"
<< params->suggested_reclaim_time();
return nullptr;
}
return params;
}
} // namespace
std::unique_ptr<base::TaskScheduler::InitParams> GetTaskSchedulerInitParams(
base::StringPiece variation_param_prefix,
const std::map<std::string, std::string>& variation_params,
base::SchedulerBackwardCompatibility
foreground_blocking_backward_compatibility) {
const auto background_worker_pool_params = GetWorkerPoolParams(
variation_param_prefix, "Background", variation_params);
const auto background_blocking_worker_pool_params = GetWorkerPoolParams(
variation_param_prefix, "BackgroundBlocking", variation_params);
const auto foreground_worker_pool_params = GetWorkerPoolParams(
variation_param_prefix, "Foreground", variation_params);
const auto foreground_blocking_worker_pool_params = GetWorkerPoolParams(
variation_param_prefix, "ForegroundBlocking", variation_params,
foreground_blocking_backward_compatibility);
if (!background_worker_pool_params ||
!background_blocking_worker_pool_params ||
!foreground_worker_pool_params ||
!foreground_blocking_worker_pool_params) {
return nullptr;
}
return base::MakeUnique<base::TaskScheduler::InitParams>(
*background_worker_pool_params, *background_blocking_worker_pool_params,
*foreground_worker_pool_params, *foreground_blocking_worker_pool_params);
}
#if !defined(OS_IOS)
void AddVariationParamsToCommandLine(base::StringPiece key_prefix,
base::CommandLine* command_line) {
DCHECK(command_line);
std::map<std::string, std::string> variation_params;
if (!variations::GetVariationParams("BrowserScheduler", &variation_params))
return;
std::vector<base::StringPiece> parts;
for (const auto& key_value : variation_params) {
if (base::StartsWith(key_value.first, key_prefix,
base::CompareCase::SENSITIVE)) {
if (ContainsSeparator(key_value.first) ||
ContainsSeparator(key_value.second)) {
DLOG(ERROR)
<< "Unexpected Character in Task Scheduler Variation Params: "
<< key_value.first << " [" << key_value.second << "]";
return;
}
parts.push_back(key_value.first);
parts.push_back(key_value.second);
}
}
if (!parts.empty()) {
command_line->AppendSwitchASCII(kTaskSchedulerVariationParamsSwitch,
base::JoinString(parts, kSeparator));
}
}
std::map<std::string, std::string> GetVariationParamsFromCommandLine(
const base::CommandLine& command_line) {
const auto serialized_variation_params =
command_line.GetSwitchValueASCII(kTaskSchedulerVariationParamsSwitch);
const auto parts =
base::SplitStringPiece(serialized_variation_params, kSeparator,
base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
std::map<std::string, std::string> variation_params;
for (auto it = parts.begin(); it != parts.end(); ++it) {
base::StringPiece key = *it;
++it;
if (it == parts.end()) {
NOTREACHED();
return std::map<std::string, std::string>();
}
base::StringPiece value = *it;
variation_params[key.as_string()] = value.as_string();
}
return variation_params;
}
#endif // !defined(OS_IOS)
} // namespace task_scheduler_util