blob: c080388cc75bce47c3064d2ac041d4f082eec828 [file] [log] [blame]
Primiano Tuccia81d2772020-10-07 00:12:41 +02001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "perfetto/ext/base/utils.h"
18
Primiano Tucci003b20e2021-05-21 10:21:43 +010019#include <string>
20
Primiano Tuccia81d2772020-10-07 00:12:41 +020021#include "perfetto/base/build_config.h"
Primiano Tucci10c9e9e2021-01-08 13:04:40 +010022#include "perfetto/base/logging.h"
Primiano Tucci003b20e2021-05-21 10:21:43 +010023#include "perfetto/ext/base/file_utils.h"
Primiano Tuccia81d2772020-10-07 00:12:41 +020024
Primiano Tucci10c9e9e2021-01-08 13:04:40 +010025#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
26 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
Primiano Tucci003b20e2021-05-21 10:21:43 +010027 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
28 PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
29#include <limits.h>
Primiano Tucci2277f062021-11-08 22:24:05 +000030#include <stdlib.h> // For _exit()
Rahul Ravikumarce6dcb42021-04-19 11:21:40 -070031#include <unistd.h> // For getpagesize() and geteuid() & fork()
Primiano Tucci10c9e9e2021-01-08 13:04:40 +010032#endif
33
34#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
Primiano Tucci003b20e2021-05-21 10:21:43 +010035#include <mach-o/dyld.h>
Primiano Tucciab293f52020-12-08 11:46:52 +010036#include <mach/vm_page_size.h>
37#endif
38
Primiano Tucci003b20e2021-05-21 10:21:43 +010039#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
40#include <Windows.h>
41#include <io.h>
Primiano Tuccic50345c2021-11-09 23:10:06 +000042#include <malloc.h> // For _aligned_malloc().
Primiano Tucci003b20e2021-05-21 10:21:43 +010043#endif
44
Primiano Tuccia81d2772020-10-07 00:12:41 +020045#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
46#include <dlfcn.h>
47#include <malloc.h>
48
49#ifdef M_PURGE
50#define PERFETTO_M_PURGE M_PURGE
51#else
52// Only available in in-tree builds and on newer SDKs.
53#define PERFETTO_M_PURGE -101
Primiano Tucci003b20e2021-05-21 10:21:43 +010054#endif // M_PURGE
Primiano Tuccia81d2772020-10-07 00:12:41 +020055
56namespace {
57extern "C" {
58using MalloptType = void (*)(int, int);
59}
60} // namespace
61#endif // OS_ANDROID
62
Primiano Tucci2277f062021-11-08 22:24:05 +000063namespace {
64
65#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
66
67// Preserve the %rbx register via %rdi to work around a clang bug
68// https://bugs.llvm.org/show_bug.cgi?id=17907 (%rbx in an output constraint
69// is not considered a clobbered register).
70#define PERFETTO_GETCPUID(a, b, c, d, a_inp, c_inp) \
71 asm("mov %%rbx, %%rdi\n" \
72 "cpuid\n" \
73 "xchg %%rdi, %%rbx\n" \
74 : "=a"(a), "=D"(b), "=c"(c), "=d"(d) \
75 : "a"(a_inp), "2"(c_inp))
76
77uint32_t GetXCR0EAX() {
78 uint32_t eax = 0, edx = 0;
79 asm("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
80 return eax;
81}
82
83// If we are building with -msse4 check that the CPU actually supports it.
84// This file must be kept in sync with gn/standalone/BUILD.gn.
85void PERFETTO_EXPORT __attribute__((constructor)) CheckCpuOptimizations() {
86 uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
87 PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0);
88
89 static constexpr uint64_t xcr0_xmm_mask = 0x2;
90 static constexpr uint64_t xcr0_ymm_mask = 0x4;
91 static constexpr uint64_t xcr0_avx_mask = xcr0_xmm_mask | xcr0_ymm_mask;
92
93 const bool have_popcnt = ecx & (1u << 23);
94 const bool have_sse4_2 = ecx & (1u << 20);
95 const bool have_avx =
96 // Does the OS save/restore XMM and YMM state?
97 ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask) &&
98 (ecx & (1u << 27)) && // OS support XGETBV.
99 (ecx & (1u << 28)); // AVX supported in hardware
100
101 if (!have_sse4_2 || !have_popcnt || !have_avx) {
102 fprintf(
103 stderr,
104 "This executable requires a cpu that supports SSE4.2 and AVX2.\n"
105 "Rebuild with enable_perfetto_x64_cpu_opt=false (ebx=%x, ecx=%x).\n",
106 ebx, ecx);
107 _exit(126);
108 }
109}
110#endif
111
112} // namespace
113
Primiano Tuccia81d2772020-10-07 00:12:41 +0200114namespace perfetto {
115namespace base {
116
117void MaybeReleaseAllocatorMemToOS() {
118#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
119 // mallopt() on Android requires SDK level 26. Many targets and embedders
120 // still depend on a lower SDK level. Given mallopt() is a quite simple API,
121 // use reflection to do this rather than bumping the SDK level for all
122 // embedders. This keeps the behavior of standalone builds aligned with
123 // in-tree builds.
124 static MalloptType mallopt_fn =
125 reinterpret_cast<MalloptType>(dlsym(RTLD_DEFAULT, "mallopt"));
126 if (!mallopt_fn)
127 return;
128 mallopt_fn(PERFETTO_M_PURGE, 0);
129#endif
130}
131
Primiano Tucciab293f52020-12-08 11:46:52 +0100132uint32_t GetSysPageSize() {
133 ignore_result(kPageSize); // Just to keep the amalgamated build happy.
134#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
135 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
136 static std::atomic<uint32_t> page_size{0};
137 // This function might be called in hot paths. Avoid calling getpagesize() all
138 // the times, in many implementations getpagesize() calls sysconf() which is
139 // not cheap.
140 uint32_t cached_value = page_size.load(std::memory_order_relaxed);
141 if (PERFETTO_UNLIKELY(cached_value == 0)) {
142 cached_value = static_cast<uint32_t>(getpagesize());
143 page_size.store(cached_value, std::memory_order_relaxed);
144 }
145 return cached_value;
146#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
147 return static_cast<uint32_t>(vm_page_size);
148#else
149 return 4096;
150#endif
151}
152
Primiano Tucci10c9e9e2021-01-08 13:04:40 +0100153uid_t GetCurrentUserId() {
154#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
155 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
156 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
157 return geteuid();
158#else
159 // TODO(primiano): On Windows we could hash the current user SID and derive a
160 // numeric user id [1]. It is not clear whether we need that. Right now that
161 // would not bring any benefit. Returning 0 unil we can prove we need it.
162 // [1]:https://android-review.googlesource.com/c/platform/external/perfetto/+/1513879/25/src/base/utils.cc
163 return 0;
164#endif
165}
166
167void SetEnv(const std::string& key, const std::string& value) {
168#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
169 PERFETTO_CHECK(::_putenv_s(key.c_str(), value.c_str()) == 0);
170#else
171 PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0);
172#endif
173}
174
Daniele Di Proietto240e9a12021-10-26 12:58:16 +0100175void Daemonize(std::function<int()> parent_cb) {
Primiano Tucci003b20e2021-05-21 10:21:43 +0100176#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
177 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
178 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
179 pid_t pid;
180 switch (pid = fork()) {
181 case -1:
182 PERFETTO_FATAL("fork");
183 case 0: {
184 PERFETTO_CHECK(setsid() != -1);
185 base::ignore_result(chdir("/"));
186 base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
187 PERFETTO_CHECK(null);
188 PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
189 PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
190 PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
191 // Do not accidentally close stdin/stdout/stderr.
192 if (*null <= 2)
193 null.release();
194 break;
195 }
196 default:
197 printf("%d\n", pid);
Daniele Di Proietto240e9a12021-10-26 12:58:16 +0100198 int err = parent_cb();
199 exit(err);
Primiano Tucci003b20e2021-05-21 10:21:43 +0100200 }
201#else
202 // Avoid -Wunreachable warnings.
203 if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
204 PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
Daniele Di Proietto240e9a12021-10-26 12:58:16 +0100205 ignore_result(parent_cb);
Primiano Tucci003b20e2021-05-21 10:21:43 +0100206#endif // OS_WIN
207}
208
209std::string GetCurExecutablePath() {
210 std::string self_path;
211#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
212 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
213 PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
214 char buf[PATH_MAX];
215 ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
216 PERFETTO_CHECK(size != -1);
217 // readlink does not null terminate.
218 self_path = std::string(buf, static_cast<size_t>(size));
219#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
220 uint32_t size = 0;
221 PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size));
222 self_path.resize(size);
223 PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0);
224#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
225 char buf[MAX_PATH];
226 auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
227 self_path = std::string(buf, len);
228#else
229 PERFETTO_FATAL(
230 "GetCurExecutableDir() not implemented on the current platform");
231#endif
232 return self_path;
233}
234
235std::string GetCurExecutableDir() {
236 auto path = GetCurExecutablePath();
237#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
238 // Paths in Windows can have both kinds of slashes (mingw vs msvc).
Hector Dearman1fe10ce2021-08-23 11:44:26 +0100239 path = path.substr(0, path.find_last_of('\\'));
Primiano Tucci003b20e2021-05-21 10:21:43 +0100240#endif
Hector Dearman1fe10ce2021-08-23 11:44:26 +0100241 path = path.substr(0, path.find_last_of('/'));
Primiano Tucci003b20e2021-05-21 10:21:43 +0100242 return path;
Rahul Ravikumarce6dcb42021-04-19 11:21:40 -0700243}
244
Primiano Tuccic50345c2021-11-09 23:10:06 +0000245void* AlignedAlloc(size_t alignment, size_t size) {
246 void* res = nullptr;
247 alignment = AlignUp<sizeof(void*)>(alignment); // At least pointer size.
Primiano Tuccid99b5d22021-11-10 08:16:02 +0000248#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
Primiano Tuccic50345c2021-11-09 23:10:06 +0000249 // Window's _aligned_malloc() has a nearly identically signature to Unix's
250 // aligned_alloc() but its arguments are obviously swapped.
251 res = _aligned_malloc(size, alignment);
252#else
Primiano Tuccid99b5d22021-11-10 08:16:02 +0000253 // aligned_alloc() has been introduced in Android only in API 28.
254 // Also NaCl and Fuchsia seems to have only posix_memalign().
255 ignore_result(posix_memalign(&res, alignment, size));
Primiano Tuccic50345c2021-11-09 23:10:06 +0000256#endif
257 PERFETTO_CHECK(res);
258 return res;
259}
260
Primiano Tuccia81d2772020-10-07 00:12:41 +0200261} // namespace base
262} // namespace perfetto