blob: 27a22fe8e73edb913ba376231665cd46bb26e4b5 [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>
9
10#include "base/base_paths.h"
Sebastien Marchand836d04b32020-04-28 18:10:0311#include "base/bind.h"
12#include "base/callback_forward.h"
13#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 Mirza68de71d2019-09-12 00:21:1024#include "base/strings/string16.h"
Sajjad Mirza94c68bc2019-08-15 01:02:3525#include "base/strings/string_number_conversions.h"
Sajjad Mirza68de71d2019-09-12 00:21:1026#include "base/strings/utf_string_conversions.h"
Sebastien Marchand836d04b32020-04-28 18:10:0327#include "base/synchronization/waitable_event.h"
28#include "base/task/task_traits.h"
29#include "base/task/thread_pool.h"
Sajjad Mirza94c68bc2019-08-15 01:02:3530#include "base/threading/thread_restrictions.h"
Sajjad Mirza68de71d2019-09-12 00:21:1031#include "build/build_config.h"
Sajjad Mirza94c68bc2019-08-15 01:02:3532
33namespace content {
34
Sebastien Marchandbd02bc29e2020-03-11 15:53:3635base::File OpenProfilingFile() {
Sajjad Mirza94c68bc2019-08-15 01:02:3536 base::ScopedAllowBlockingForTesting allows_blocking;
37 std::unique_ptr<base::Environment> env(base::Environment::Create());
38 std::string prof_template;
39 base::FilePath path;
40 if (env->GetVar("LLVM_PROFILE_FILE", &prof_template)) {
Sajjad Mirza68de71d2019-09-12 00:21:1041#if defined(OS_WIN)
42 path = base::FilePath(base::UTF8ToUTF16(prof_template)).DirName();
43#else
Sajjad Mirza94c68bc2019-08-15 01:02:3544 path = base::FilePath(prof_template).DirName();
Sajjad Mirza68de71d2019-09-12 00:21:1045#endif
Sajjad Mirza94c68bc2019-08-15 01:02:3546 base::CreateDirectory(path);
47 } else {
48 base::PathService::Get(base::DIR_CURRENT, &path);
49 }
50
51 // sajjadm@ and liaoyuke@ experimentally determined that a size 4 pool works
Sebastien Marchand24bb6772020-05-01 18:25:0852 // well for the coverage builder.
53 // TODO(https://crbug.com/1059335): Check if this is an appropriate value for
54 // the PGO builds.
55 int pool_index = base::RandInt(0, 3);
56 std::string filename = base::StrCat(
57 {"child_pool-", base::NumberToString(pool_index), ".profraw"});
Sajjad Mirza68de71d2019-09-12 00:21:1058#if defined(OS_WIN)
59 path = path.Append(base::UTF8ToUTF16(filename));
60#else
Sajjad Mirza94c68bc2019-08-15 01:02:3561 path = path.Append(filename);
Sajjad Mirza68de71d2019-09-12 00:21:1062#endif
Sajjad Mirza94c68bc2019-08-15 01:02:3563 uint32_t flags = base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_READ |
64 base::File::FLAG_WRITE;
65
66 base::File file(path, flags);
67 if (!file.IsValid()) {
68 LOG(ERROR) << "Opening file: " << path << " failed with "
69 << file.error_details();
70 }
71
72 return file;
73}
Sebastien Marchand836d04b32020-04-28 18:10:0374WaitForProcessesToDumpProfilingInfo::WaitForProcessesToDumpProfilingInfo() =
75 default;
76WaitForProcessesToDumpProfilingInfo::~WaitForProcessesToDumpProfilingInfo() =
77 default;
78
79void WaitForProcessesToDumpProfilingInfo::WaitForAll() {
80 base::RunLoop nested_run_loop(base::RunLoop::Type::kNestableTasksAllowed);
81
82 // Some of the waitable events will be signaled on the main thread, use a
83 // nested run loop to ensure we're not preventing them from signaling.
84 base::ThreadPool::PostTask(
85 FROM_HERE, {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
86 base::BindOnce(
87 &WaitForProcessesToDumpProfilingInfo::WaitForAllOnThreadPool,
88 base::Unretained(this), nested_run_loop.QuitClosure()));
89 nested_run_loop.Run();
90}
91
92void WaitForProcessesToDumpProfilingInfo::WaitForAllOnThreadPool(
93 base::OnceClosure quit_closure) {
94 base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_blocking;
95
96 std::vector<base::WaitableEvent*> events_raw;
97 events_raw.reserve(events_.size());
98 for (const auto& iter : events_)
99 events_raw.push_back(iter.get());
100
101 // Wait for all the events to be signaled.
102 while (events_raw.size()) {
103 size_t index =
104 base::WaitableEvent::WaitMany(events_raw.data(), events_raw.size());
105 events_raw.erase(events_raw.begin() + index);
106 }
107
108 std::move(quit_closure).Run();
109}
110
111base::WaitableEvent*
112WaitForProcessesToDumpProfilingInfo::GetNewWaitableEvent() {
113 events_.push_back(std::make_unique<base::WaitableEvent>());
114 return events_.back().get();
115}
Sajjad Mirza94c68bc2019-08-15 01:02:35116
117} // namespace content