Chromium Code Reviews| Index: chrome/browser/chrome_browser_main.cc |
| diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc |
| index d1a7a6e3866a7442a68adb0d2c8ef6b4d0b92f2d..4de86a918c75a02b7648b8f96a92fdcc0ca35e4b 100644 |
| --- a/chrome/browser/chrome_browser_main.cc |
| +++ b/chrome/browser/chrome_browser_main.cc |
| @@ -7,6 +7,8 @@ |
| #include <stddef.h> |
| #include <stdint.h> |
| +#include <algorithm> |
| +#include <map> |
| #include <set> |
| #include <string> |
| #include <utility> |
| @@ -21,6 +23,7 @@ |
| #include "base/feature_list.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| +#include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/metrics/field_trial.h" |
| #include "base/metrics/histogram_macros.h" |
| @@ -33,6 +36,9 @@ |
| #include "base/strings/sys_string_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/sys_info.h" |
| +#include "base/task_scheduler/scheduler_worker_pool_params.h" |
| +#include "base/task_scheduler/task_scheduler.h" |
| +#include "base/task_scheduler/task_traits.h" |
| #include "base/threading/platform_thread.h" |
| #include "base/time/default_tick_clock.h" |
| #include "base/time/time.h" |
| @@ -317,6 +323,156 @@ void AddFirstRunNewTabs(StartupBrowserCreator* browser_creator, |
| } |
| #endif // !defined(OS_ANDROID) && !defined(OS_CHROMEOS) |
| +enum WorkerPoolType : size_t { |
| + BACKGROUND_WORKER_POOL = 0, |
| + BACKGROUND_FILE_IO_WORKER_POOL, |
| + FOREGROUND_WORKER_POOL, |
| + FOREGROUND_FILE_IO_WORKER_POOL, |
| + WORKER_POOL_COUNT, |
| +}; |
| + |
| +struct WorkerPoolVariationValues { |
| + int threads = 0; |
| + base::TimeDelta detach_period; |
| +}; |
| + |
| +// Converts |pool_descriptor| to a WorkerPoolVariationValues. Returns a default |
| +// WorkerPoolVariationValues on failure. |
| +// |
| +// |pool_descriptor| is a comma separated value string with the following items: |
| +// 1. Minimum Thread Count (int) |
| +// 2. Maximum Thread Count (int) |
| +// 3. Thread Count Multiplier (double) |
| +// 4. Thread Count Offset (int) |
| +// 5. Detach Time in Milliseconds (milliseconds) |
| +// 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 minimum; |
| + int maximum; |
| + double 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], &minimum) && |
| + base::StringToInt(tokens[1], &maximum) && |
| + base::StringToDouble(tokens[2], &multiplier) && |
| + base::StringToInt(tokens[3], &offset) && |
| + base::StringToInt(tokens[4], &detach_milliseconds)) { |
| + const int num_of_cores = base::SysInfo::NumberOfProcessors(); |
| + const int threads = std::round<int>(num_of_cores * multiplier) + offset; |
| + WorkerPoolVariationValues values; |
| + values.threads = std::min(maximum, std::max(minimum, threads)); |
| + values.detach_period = |
| + base::TimeDelta::FromMilliseconds(detach_milliseconds); |
| + return values; |
| + } |
| + LOG(WARNING) << "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) { |
| + if (traits.with_file_io()) { |
| + return traits.priority() == base::TaskPriority::BACKGROUND |
| + ? BACKGROUND_FILE_IO_WORKER_POOL |
| + : FOREGROUND_FILE_IO_WORKER_POOL; |
| + } |
| + return traits.priority() == base::TaskPriority::BACKGROUND |
| + ? BACKGROUND_WORKER_POOL |
| + : FOREGROUND_WORKER_POOL; |
| +} |
| + |
| +// Initializes the Default Browser Task Scheduler if there is a valid variation |
| +// parameter for the field trial. |
| +void MaybeInitializeTaskScheduler() { |
| + static constexpr char kFieldTrialName[] = "BrowserScheduler"; |
| + std::map<std::string, std::string> variation_params; |
| + if (!variations::GetVariationParams(kFieldTrialName, &variation_params)) |
| + return; |
| + |
| + // Order matches WorkerPoolType above. |
| + static const char* kWorkerPoolNames[] = { |
| + "Background", |
| + "BackgroundFileIO", |
| + "Foreground", |
| + "ForegroundFileIO", |
| + }; |
| + static_assert(arraysize(kWorkerPoolNames) == WORKER_POOL_COUNT, |
|
fdoray
2016/08/05 22:59:12
What do you think of this?
struct SchedulerWorker
robliao
2016/08/05 23:45:38
Went one further and just used a static const stru
|
| + "Mismatched Worker Pool Types and Names"); |
| + |
| + std::vector<WorkerPoolVariationValues> values; |
| + for (size_t i = 0; i < arraysize(kWorkerPoolNames); i++) { |
|
fdoray
2016/08/05 22:59:12
for (const char* worker_pool_name : kWorkerPoolNam
robliao
2016/08/05 23:45:38
Done.
|
| + const char* current = kWorkerPoolNames[i]; |
| + const auto pair = variation_params.find(current); |
| + if (pair == variation_params.end()) { |
| + LOG(WARNING) << "Missing Worker Pool Configuration: " << current; |
| + return; |
| + } |
| + |
| + const WorkerPoolVariationValues variation_value = |
| + StringToWorkerPoolVariationValues(pair->second); |
| + |
| + if (variation_value.threads == 0 || |
| + variation_value.detach_period.is_zero()) { |
| + LOG(WARNING) << "Invalid Worker Pool Configuration: " << current << |
| + " [" << pair->second << "]"; |
| + return; |
| + } |
| + |
| + values.push_back(variation_value); |
| + } |
| + |
| + DCHECK_EQ(values.size(), WORKER_POOL_COUNT); |
| + |
| + using ThreadPriority = base::ThreadPriority; |
| + using IORestriction = base::SchedulerWorkerPoolParams::IORestriction; |
| + std::vector<base::SchedulerWorkerPoolParams> params_vector; |
| + DCHECK_EQ(params_vector.size(), BACKGROUND_WORKER_POOL); |
| + params_vector.emplace_back( |
| + kWorkerPoolNames[BACKGROUND_WORKER_POOL], |
| + ThreadPriority::BACKGROUND, |
| + IORestriction::DISALLOWED, |
| + values[BACKGROUND_WORKER_POOL].threads, |
| + values[BACKGROUND_WORKER_POOL].detach_period); |
| + |
| + DCHECK_EQ(params_vector.size(), BACKGROUND_FILE_IO_WORKER_POOL); |
| + params_vector.emplace_back( |
| + kWorkerPoolNames[BACKGROUND_FILE_IO_WORKER_POOL], |
| + ThreadPriority::BACKGROUND, |
| + IORestriction::ALLOWED, |
| + values[BACKGROUND_FILE_IO_WORKER_POOL].threads, |
| + values[BACKGROUND_FILE_IO_WORKER_POOL].detach_period); |
| + |
| + DCHECK_EQ(params_vector.size(), FOREGROUND_WORKER_POOL); |
| + params_vector.emplace_back( |
| + kWorkerPoolNames[FOREGROUND_WORKER_POOL], |
| + ThreadPriority::NORMAL, |
| + IORestriction::DISALLOWED, |
| + values[FOREGROUND_WORKER_POOL].threads, |
| + values[FOREGROUND_WORKER_POOL].detach_period); |
| + |
| + DCHECK_EQ(params_vector.size(), FOREGROUND_FILE_IO_WORKER_POOL); |
| + params_vector.emplace_back( |
| + kWorkerPoolNames[FOREGROUND_FILE_IO_WORKER_POOL], |
| + ThreadPriority::NORMAL, |
| + IORestriction::ALLOWED, |
| + values[FOREGROUND_FILE_IO_WORKER_POOL].threads, |
| + values[FOREGROUND_FILE_IO_WORKER_POOL].detach_period); |
| + |
| + DCHECK_EQ(params_vector.size(), WORKER_POOL_COUNT); |
| + |
| + base::TaskScheduler::CreateAndSetDefaultTaskScheduler( |
| + params_vector, base::Bind(WorkerPoolIndexForTraits)); |
| +} |
| + |
| // Returns the new local state object, guaranteed non-NULL. |
| // |local_state_task_runner| must be a shutdown-blocking task runner. |
| PrefService* InitializeLocalState( |
| @@ -1214,6 +1370,8 @@ int ChromeBrowserMainParts::PreCreateThreadsImpl() { |
| // IOThread's initialization which happens in BrowserProcess:PreCreateThreads. |
| SetupMetricsAndFieldTrials(); |
| + MaybeInitializeTaskScheduler(); |
| + |
| // ChromeOS needs ResourceBundle::InitSharedInstance to be called before this. |
| browser_process_->PreCreateThreads(); |