/src/perfetto/src/base/utils.cc
Line | Count | Source |
1 | | /* |
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 | | |
19 | | #include <string> |
20 | | |
21 | | #include "perfetto/base/build_config.h" |
22 | | #include "perfetto/base/logging.h" |
23 | | #include "perfetto/ext/base/file_utils.h" |
24 | | #include "perfetto/ext/base/pipe.h" |
25 | | #include "perfetto/ext/base/string_utils.h" |
26 | | |
27 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ |
28 | | PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ |
29 | | PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \ |
30 | | PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) |
31 | | #include <limits.h> |
32 | | #include <stdlib.h> // For _exit() |
33 | | #include <unistd.h> // For getpagesize() and geteuid() & fork() |
34 | | #endif |
35 | | |
36 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) |
37 | | #include <mach-o/dyld.h> |
38 | | #include <mach/vm_page_size.h> |
39 | | #endif |
40 | | |
41 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \ |
42 | | PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) |
43 | | #include <sys/prctl.h> |
44 | | |
45 | | #ifndef PR_GET_TAGGED_ADDR_CTRL |
46 | | #define PR_GET_TAGGED_ADDR_CTRL 56 |
47 | | #endif |
48 | | |
49 | | #ifndef PR_TAGGED_ADDR_ENABLE |
50 | | #define PR_TAGGED_ADDR_ENABLE (1UL << 0) |
51 | | #endif |
52 | | |
53 | | #ifndef PR_MTE_TCF_SYNC |
54 | 0 | #define PR_MTE_TCF_SYNC (1UL << 1) |
55 | | #endif |
56 | | |
57 | | #endif // OS_LINUX | OS_ANDROID |
58 | | |
59 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
60 | | #include <Windows.h> |
61 | | #include <io.h> |
62 | | #include <malloc.h> // For _aligned_malloc(). |
63 | | #endif |
64 | | |
65 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) |
66 | | #include <dlfcn.h> |
67 | | #include <malloc.h> |
68 | | |
69 | | #ifdef M_PURGE |
70 | | #define PERFETTO_M_PURGE M_PURGE |
71 | | #else |
72 | | // Only available in in-tree builds and on newer SDKs. |
73 | | #define PERFETTO_M_PURGE -101 |
74 | | #endif // M_PURGE |
75 | | |
76 | | #ifdef M_PURGE_ALL |
77 | | #define PERFETTO_M_PURGE_ALL M_PURGE_ALL |
78 | | #else |
79 | | // Only available in in-tree builds and on newer SDKs. |
80 | | #define PERFETTO_M_PURGE_ALL -104 |
81 | | #endif // M_PURGE |
82 | | |
83 | | namespace { |
84 | | extern "C" { |
85 | | using MalloptType = int (*)(int, int); |
86 | | } |
87 | | } // namespace |
88 | | #endif // OS_ANDROID |
89 | | |
90 | | namespace { |
91 | | |
92 | | #if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT) |
93 | | |
94 | | // Preserve the %rbx register via %rdi to work around a clang bug |
95 | | // https://bugs.llvm.org/show_bug.cgi?id=17907 (%rbx in an output constraint |
96 | | // is not considered a clobbered register). |
97 | | #define PERFETTO_GETCPUID(a, b, c, d, a_inp, c_inp) \ |
98 | 48 | asm("mov %%rbx, %%rdi\n" \ |
99 | 48 | "cpuid\n" \ |
100 | 48 | "xchg %%rdi, %%rbx\n" \ |
101 | 48 | : "=a"(a), "=D"(b), "=c"(c), "=d"(d) \ |
102 | 48 | : "a"(a_inp), "2"(c_inp)) |
103 | | |
104 | 24 | uint32_t GetXCR0EAX() { |
105 | 24 | uint32_t eax = 0, edx = 0; |
106 | 24 | asm("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0)); |
107 | 24 | return eax; |
108 | 24 | } |
109 | | |
110 | | // If we are building with -msse4 check that the CPU actually supports it. |
111 | | // This file must be kept in sync with gn/standalone/BUILD.gn. |
112 | | void PERFETTO_EXPORT_COMPONENT __attribute__((constructor)) |
113 | 24 | CheckCpuOptimizations() { |
114 | 24 | uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; |
115 | 24 | PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0); |
116 | | |
117 | 24 | static constexpr uint64_t xcr0_xmm_mask = 0x2; |
118 | 24 | static constexpr uint64_t xcr0_ymm_mask = 0x4; |
119 | 24 | static constexpr uint64_t xcr0_avx_mask = xcr0_xmm_mask | xcr0_ymm_mask; |
120 | | |
121 | 24 | const bool have_popcnt = ecx & (1u << 23); |
122 | 24 | const bool have_sse4_2 = ecx & (1u << 20); |
123 | 24 | const bool have_avx = |
124 | | // Does the OS save/restore XMM and YMM state? |
125 | 24 | (ecx & (1u << 27)) && // OS support XGETBV. |
126 | 24 | (ecx & (1u << 28)) && // AVX supported in hardware |
127 | 24 | ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask); |
128 | | |
129 | | // Get level 7 features (eax = 7 and ecx= 0), to check for AVX2 support. |
130 | | // (See Intel 64 and IA-32 Architectures Software Developer's Manual |
131 | | // Volume 2A: Instruction Set Reference, A-M CPUID). |
132 | 24 | PERFETTO_GETCPUID(eax, ebx, ecx, edx, 7, 0); |
133 | 24 | const bool have_avx2 = have_avx && ((ebx >> 5) & 0x1); |
134 | 24 | const bool have_bmi = (ebx >> 3) & 0x1; |
135 | 24 | const bool have_bmi2 = (ebx >> 8) & 0x1; |
136 | | |
137 | 24 | if (!have_sse4_2 || !have_popcnt || !have_avx2 || !have_bmi || !have_bmi2) { |
138 | 0 | fprintf( |
139 | 0 | stderr, |
140 | 0 | "This executable requires a x86_64 cpu that supports SSE4.2, BMI2 and " |
141 | 0 | "AVX2.\n" |
142 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) |
143 | | "On MacOS, this might be caused by running x86_64 binaries on arm64.\n" |
144 | | "See https://github.com/google/perfetto/issues/294 for more.\n" |
145 | | #endif |
146 | 0 | "Rebuild with enable_perfetto_x64_cpu_opt=false.\n"); |
147 | 0 | _exit(126); |
148 | 0 | } |
149 | 24 | } |
150 | | #endif |
151 | | |
152 | | } // namespace |
153 | | |
154 | | namespace perfetto { |
155 | | namespace base { |
156 | | |
157 | | namespace internal { |
158 | | |
159 | | std::atomic<uint32_t> g_cached_page_size{0}; |
160 | | |
161 | 7 | uint32_t GetSysPageSizeSlowpath() { |
162 | 7 | uint32_t page_size = 0; |
163 | 7 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ |
164 | 7 | PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) |
165 | 7 | const int page_size_int = getpagesize(); |
166 | | // If sysconf() fails for obscure reasons (e.g. SELinux denial) assume the |
167 | | // page size is 4KB. This is to avoid regressing subtle SDK usages, as old |
168 | | // versions of this code had a static constant baked in. |
169 | 7 | page_size = static_cast<uint32_t>(page_size_int > 0 ? page_size_int : 4096); |
170 | | #elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) |
171 | | page_size = static_cast<uint32_t>(vm_page_size); |
172 | | #else |
173 | | page_size = 4096; |
174 | | #endif |
175 | | |
176 | 7 | PERFETTO_CHECK(page_size > 0 && page_size % 4096 == 0); |
177 | | |
178 | | // Races here are fine because any thread will write the same value. |
179 | 7 | g_cached_page_size.store(page_size, std::memory_order_relaxed); |
180 | 7 | return page_size; |
181 | 7 | } |
182 | | |
183 | | } // namespace internal |
184 | | |
185 | 348 | void MaybeReleaseAllocatorMemToOS() { |
186 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) |
187 | | // mallopt() on Android requires SDK level 26. Many targets and embedders |
188 | | // still depend on a lower SDK level. Given mallopt() is a quite simple API, |
189 | | // use reflection to do this rather than bumping the SDK level for all |
190 | | // embedders. This keeps the behavior of standalone builds aligned with |
191 | | // in-tree builds. |
192 | | static MalloptType mallopt_fn = |
193 | | reinterpret_cast<MalloptType>(dlsym(RTLD_DEFAULT, "mallopt")); |
194 | | if (!mallopt_fn) |
195 | | return; |
196 | | if (mallopt_fn(PERFETTO_M_PURGE_ALL, 0) == 0) { |
197 | | mallopt_fn(PERFETTO_M_PURGE, 0); |
198 | | } |
199 | | #endif |
200 | 348 | } |
201 | | |
202 | 350 | uid_t GetCurrentUserId() { |
203 | 350 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ |
204 | 350 | PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ |
205 | 350 | PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) |
206 | 350 | return geteuid(); |
207 | | #else |
208 | | // TODO(primiano): On Windows we could hash the current user SID and derive a |
209 | | // numeric user id [1]. It is not clear whether we need that. Right now that |
210 | | // would not bring any benefit. Returning 0 unil we can prove we need it. |
211 | | // [1]:https://android-review.googlesource.com/c/platform/external/perfetto/+/1513879/25/src/base/utils.cc |
212 | | return 0; |
213 | | #endif |
214 | 350 | } |
215 | | |
216 | 700 | void SetEnv(const std::string& key, const std::string& value) { |
217 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
218 | | PERFETTO_CHECK(::_putenv_s(key.c_str(), value.c_str()) == 0); |
219 | | #else |
220 | 700 | PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0); |
221 | 700 | #endif |
222 | 700 | } |
223 | | |
224 | 700 | void UnsetEnv(const std::string& key) { |
225 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
226 | | PERFETTO_CHECK(::_putenv_s(key.c_str(), "") == 0); |
227 | | #else |
228 | 700 | PERFETTO_CHECK(::unsetenv(key.c_str()) == 0); |
229 | 700 | #endif |
230 | 700 | } |
231 | | |
232 | 0 | void Daemonize(std::function<int()> parent_cb) { |
233 | 0 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ |
234 | 0 | PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ |
235 | 0 | (PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) && \ |
236 | 0 | !PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE_TVOS)) |
237 | 0 | Pipe pipe = Pipe::Create(Pipe::kBothBlock); |
238 | 0 | pid_t pid; |
239 | 0 | switch (pid = fork()) { |
240 | 0 | case -1: |
241 | 0 | PERFETTO_FATAL("fork"); |
242 | 0 | case 0: { |
243 | 0 | PERFETTO_CHECK(setsid() != -1); |
244 | 0 | base::ignore_result(chdir("/")); |
245 | 0 | base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY); |
246 | 0 | PERFETTO_CHECK(null); |
247 | 0 | PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1); |
248 | 0 | PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1); |
249 | 0 | PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1); |
250 | | // Do not accidentally close stdin/stdout/stderr. |
251 | 0 | if (*null <= 2) |
252 | 0 | null.release(); |
253 | 0 | WriteAll(*pipe.wr, "1", 1); |
254 | 0 | break; |
255 | 0 | } |
256 | 0 | default: { |
257 | | // Wait for the child process to have reached the setsid() call. This is |
258 | | // to avoid that 'adb shell perfetto -D' destroys the terminal (hence |
259 | | // sending a SIGHUP to the child) before the child has detached from the |
260 | | // terminal (see b/238644870). |
261 | | |
262 | | // This is to unblock the read() below (with EOF, which will fail the |
263 | | // CHECK) in the unlikely case of the child crashing before WriteAll("1"). |
264 | 0 | pipe.wr.reset(); |
265 | 0 | char one = '\0'; |
266 | 0 | PERFETTO_CHECK(Read(*pipe.rd, &one, sizeof(one)) == 1 && one == '1'); |
267 | 0 | printf("%d\n", pid); |
268 | 0 | int err = parent_cb(); |
269 | 0 | exit(err); |
270 | 0 | } |
271 | 0 | } |
272 | | #else |
273 | | // Avoid -Wunreachable warnings. |
274 | | if (reinterpret_cast<intptr_t>(&Daemonize) != 16) |
275 | | PERFETTO_FATAL("--background is only supported on Linux/Android/Mac"); |
276 | | ignore_result(parent_cb); |
277 | | #endif // OS_WIN |
278 | 0 | } |
279 | | |
280 | 0 | std::string GetCurExecutablePath() { |
281 | 0 | std::string self_path; |
282 | 0 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \ |
283 | 0 | PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \ |
284 | 0 | PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA) |
285 | 0 | char buf[PATH_MAX]; |
286 | 0 | ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf)); |
287 | 0 | PERFETTO_CHECK(size != -1); |
288 | | // readlink does not null terminate. |
289 | 0 | self_path = std::string(buf, static_cast<size_t>(size)); |
290 | | #elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) |
291 | | uint32_t size = 0; |
292 | | PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size)); |
293 | | self_path.resize(size); |
294 | | PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0); |
295 | | #elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
296 | | char buf[MAX_PATH]; |
297 | | auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf)); |
298 | | self_path = std::string(buf, len); |
299 | | #else |
300 | | PERFETTO_FATAL( |
301 | | "GetCurExecutableDir() not implemented on the current platform"); |
302 | | #endif |
303 | 0 | return self_path; |
304 | 0 | } |
305 | | |
306 | 0 | std::string GetCurExecutableDir() { |
307 | 0 | auto path = GetCurExecutablePath(); |
308 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
309 | | // Paths in Windows can have both kinds of slashes (mingw vs msvc). |
310 | | path = path.substr(0, path.find_last_of('\\')); |
311 | | #endif |
312 | 0 | path = path.substr(0, path.find_last_of('/')); |
313 | 0 | return path; |
314 | 0 | } |
315 | | |
316 | 1.14M | void* AlignedAlloc(size_t alignment, size_t size) { |
317 | 1.14M | void* res = nullptr; |
318 | 1.14M | alignment = AlignUp<sizeof(void*)>(alignment); // At least pointer size. |
319 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
320 | | // Window's _aligned_malloc() has a nearly identically signature to Unix's |
321 | | // aligned_alloc() but its arguments are obviously swapped. |
322 | | res = _aligned_malloc(size, alignment); |
323 | | #else |
324 | | // aligned_alloc() has been introduced in Android only in API 28. |
325 | | // Also NaCl and Fuchsia seems to have only posix_memalign(). |
326 | 1.14M | ignore_result(posix_memalign(&res, alignment, size)); |
327 | 1.14M | #endif |
328 | 1.14M | PERFETTO_CHECK(res); |
329 | 1.14M | return res; |
330 | 1.14M | } |
331 | | |
332 | 1.14M | void AlignedFree(void* ptr) { |
333 | | #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN) |
334 | | _aligned_free(ptr); // MSDN says it is fine to pass nullptr. |
335 | | #else |
336 | 1.14M | free(ptr); |
337 | 1.14M | #endif |
338 | 1.14M | } |
339 | | |
340 | 0 | bool IsSyncMemoryTaggingEnabled() { |
341 | 0 | #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX_BUT_NOT_QNX) || \ |
342 | 0 | PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) |
343 | | // Compute only once per lifetime of the process. |
344 | 0 | static bool cached_value = [] { |
345 | 0 | const int res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0); |
346 | 0 | if (res < 0) |
347 | 0 | return false; |
348 | 0 | const uint32_t actl = static_cast<uint32_t>(res); |
349 | 0 | return (actl & PR_TAGGED_ADDR_ENABLE) && (actl & PR_MTE_TCF_SYNC); |
350 | 0 | }(); |
351 | 0 | return cached_value; |
352 | | #else |
353 | | return false; |
354 | | #endif |
355 | 0 | } |
356 | | |
357 | 0 | std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) { |
358 | 0 | const char* data = reinterpret_cast<const char*>(data_void); |
359 | 0 | std::string res; |
360 | 0 | static const size_t kPadding = bytes_per_line * 3 + 12; |
361 | 0 | std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]); |
362 | 0 | for (size_t i = 0; i < len; i += bytes_per_line) { |
363 | 0 | char* wptr = line.get(); |
364 | 0 | wptr += base::SprintfTrunc(wptr, 19, "%08zX: ", i); |
365 | 0 | for (size_t j = i; j < i + bytes_per_line && j < len; j++) { |
366 | 0 | wptr += base::SprintfTrunc(wptr, 4, "%02X ", |
367 | 0 | static_cast<unsigned>(data[j]) & 0xFF); |
368 | 0 | } |
369 | 0 | for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j) |
370 | 0 | *(wptr++) = ' '; |
371 | 0 | for (size_t j = i; j < i + bytes_per_line && j < len; j++) { |
372 | 0 | char c = data[j]; |
373 | 0 | *(wptr++) = (c >= 32 && c < 127) ? c : '.'; |
374 | 0 | } |
375 | 0 | *(wptr++) = '\n'; |
376 | 0 | *(wptr++) = '\0'; |
377 | 0 | res.append(line.get()); |
378 | 0 | } |
379 | 0 | return res; |
380 | 0 | } |
381 | | |
382 | | } // namespace base |
383 | | } // namespace perfetto |