blob: fb1ec4b169979613a4254211ada3fc0055ff21fb [file] [log] [blame]
Sajjad Mirza94c68bc2019-08-15 01:02:351// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Sebastien Marchand836d04b32020-04-28 18:10:035#include "content/public/common/profiling_utils.h"
Sajjad Mirza94c68bc2019-08-15 01:02:356
Sebastien Marchand836d04b32020-04-28 18:10:037#include <limits>
Sajjad Mirza94c68bc2019-08-15 01:02:358#include <memory>
Jan Wilken Dörriead587c32021-03-11 14:09:279#include <string>
Sajjad Mirza94c68bc2019-08-15 01:02:3510
11#include "base/base_paths.h"
Sebastien Marchand836d04b32020-04-28 18:10:0312#include "base/bind.h"
Sebastien Marchand836d04b32020-04-28 18:10:0313#include "base/clang_profiling_buildflags.h"
Sajjad Mirza94c68bc2019-08-15 01:02:3514#include "base/environment.h"
15#include "base/files/file.h"
16#include "base/files/file_path.h"
17#include "base/files/file_util.h"
Sebastien Marchand836d04b32020-04-28 18:10:0318#include "base/guid.h"
Sajjad Mirza94c68bc2019-08-15 01:02:3519#include "base/logging.h"
20#include "base/path_service.h"
21#include "base/rand_util.h"
Sebastien Marchand836d04b32020-04-28 18:10:0322#include "base/run_loop.h"
Sajjad Mirza94c68bc2019-08-15 01:02:3523#include "base/strings/strcat.h"
Sajjad Mirza94c68bc2019-08-15 01:02:3524#include "base/strings/string_number_conversions.h"
Sajjad Mirza68de71d2019-09-12 00:21:1025#include "base/strings/utf_string_conversions.h"
Sebastien Marchand836d04b32020-04-28 18:10:0326#include "base/synchronization/waitable_event.h"
27#include "base/task/task_traits.h"
28#include "base/task/thread_pool.h"
Sajjad Mirza94c68bc2019-08-15 01:02:3529#include "base/threading/thread_restrictions.h"
Sajjad Mirza68de71d2019-09-12 00:21:1030#include "build/build_config.h"
Sajjad Mirza94c68bc2019-08-15 01:02:3531
32namespace content {
33
Sebastien Marchand388062c2021-08-20 21:39:1134namespace {
35
36// Returns the path where the PGO profiles should be saved.
37// On Android this is always a static path, on other platforms it's either
38// the path specified by the LLVM_PROFILE_FILE environment variable or the
39// current path if it's not set.
40base::FilePath GetProfileFileDirectory() {
Sajjad Mirza94c68bc2019-08-15 01:02:3541 base::FilePath path;
Sebastien Marchand388062c2021-08-20 21:39:1142
43 // Android differs from the other platforms because it's not possible to
44 // write in base::DIR_CURRENT and environment variables aren't well supported.
45#if defined(OS_ANDROID)
46 base::PathService::Get(base::DIR_TEMP, &path);
47 path = path.Append("pgo_profiles/");
48#else // !defined(OS_ANDROID)
49 std::string prof_template;
50 std::unique_ptr<base::Environment> env(base::Environment::Create());
Sajjad Mirza94c68bc2019-08-15 01:02:3551 if (env->GetVar("LLVM_PROFILE_FILE", &prof_template)) {
Sajjad Mirza68de71d2019-09-12 00:21:1052#if defined(OS_WIN)
Jan Wilken Dörrie86069892021-02-23 17:09:1353 path = base::FilePath(base::UTF8ToWide(prof_template)).DirName();
Sajjad Mirza68de71d2019-09-12 00:21:1054#else
Sajjad Mirza94c68bc2019-08-15 01:02:3555 path = base::FilePath(prof_template).DirName();
Sajjad Mirza68de71d2019-09-12 00:21:1056#endif
Sebastien Marchand388062c2021-08-20 21:39:1157 }
58#endif
59
60 if (!path.empty()) {
Sajjad Mirza94c68bc2019-08-15 01:02:3561 base::CreateDirectory(path);
62 } else {
63 base::PathService::Get(base::DIR_CURRENT, &path);
64 }
65
Sebastien Marchand388062c2021-08-20 21:39:1166 return path;
67}
68
69} // namespace
70
71base::File OpenProfilingFile() {
72 base::ScopedAllowBlockingForTesting allows_blocking;
73 base::FilePath path = GetProfileFileDirectory();
74
Sajjad Mirza94c68bc2019-08-15 01:02:3575 // sajjadm@ and liaoyuke@ experimentally determined that a size 4 pool works
Sebastien Marchand24bb6772020-05-01 18:25:0876 // well for the coverage builder.
77 // TODO(https://crbug.com/1059335): Check if this is an appropriate value for
78 // the PGO builds.
79 int pool_index = base::RandInt(0, 3);
80 std::string filename = base::StrCat(
81 {"child_pool-", base::NumberToString(pool_index), ".profraw"});
Sajjad Mirza68de71d2019-09-12 00:21:1082#if defined(OS_WIN)
Jan Wilken Dörrie86069892021-02-23 17:09:1383 path = path.Append(base::UTF8ToWide(filename));
Sajjad Mirza68de71d2019-09-12 00:21:1084#else
Sajjad Mirza94c68bc2019-08-15 01:02:3585 path = path.Append(filename);
Sajjad Mirza68de71d2019-09-12 00:21:1086#endif
Sajjad Mirza94c68bc2019-08-15 01:02:3587 uint32_t flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
88 base::File::FLAG_WRITE;
89
90 base::File file(path, flags);
91 if (!file.IsValid()) {
92 LOG(ERROR) << "Opening file: " << path << " failed with "
93 << file.error_details();
94 }
95
96 return file;
97}
Sebastien Marchand836d04b32020-04-28 18:10:0398WaitForProcessesToDumpProfilingInfo::WaitForProcessesToDumpProfilingInfo() =
99 default;
100WaitForProcessesToDumpProfilingInfo::~WaitForProcessesToDumpProfilingInfo() =
101 default;
102
103void WaitForProcessesToDumpProfilingInfo::WaitForAll() {
104 base::RunLoop nested_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
105
106 // Some of the waitable events will be signaled on the main thread, use a
107 // nested run loop to ensure we're not preventing them from signaling.
108 base::ThreadPool::PostTask(
109 FROM_HERE, {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
110 base::BindOnce(
111 &WaitForProcessesToDumpProfilingInfo::WaitForAllOnThreadPool,
112 base::Unretained(this), nested_run_loop.QuitClosure()));
113 nested_run_loop.Run();
114}
115
116void WaitForProcessesToDumpProfilingInfo::WaitForAllOnThreadPool(
117 base::OnceClosure quit_closure) {
118 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_blocking;
119
120 std::vector<base::WaitableEvent*> events_raw;
121 events_raw.reserve(events_.size());
122 for (const auto& iter : events_)
123 events_raw.push_back(iter.get());
124
125 // Wait for all the events to be signaled.
126 while (events_raw.size()) {
127 size_t index =
128 base::WaitableEvent::WaitMany(events_raw.data(), events_raw.size());
129 events_raw.erase(events_raw.begin() + index);
130 }
131
132 std::move(quit_closure).Run();
133}
134
135base::WaitableEvent*
136WaitForProcessesToDumpProfilingInfo::GetNewWaitableEvent() {
137 events_.push_back(std::make_unique<base::WaitableEvent>());
138 return events_.back().get();
139}
Sajjad Mirza94c68bc2019-08-15 01:02:35140
141} // namespace content