blob: 0ec6cdfcfce0fdebb6ad74ad48a94b422ff8e3e5 [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.
Daniele Di Proiettoa79094e2022-04-29 11:09:58 +010085void PERFETTO_EXPORT_COMPONENT __attribute__((constructor))
Daniele Di Proiettoadaabb62022-04-26 13:27:24 +010086CheckCpuOptimizations() {
Primiano Tucci2277f062021-11-08 22:24:05 +000087 uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
88 PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0);
89
90 static constexpr uint64_t xcr0_xmm_mask = 0x2;
91 static constexpr uint64_t xcr0_ymm_mask = 0x4;
92 static constexpr uint64_t xcr0_avx_mask = xcr0_xmm_mask | xcr0_ymm_mask;
93
94 const bool have_popcnt = ecx & (1u << 23);
95 const bool have_sse4_2 = ecx & (1u << 20);
96 const bool have_avx =
97 // Does the OS save/restore XMM and YMM state?
Primiano Tucci2277f062021-11-08 22:24:05 +000098 (ecx & (1u << 27)) && // OS support XGETBV.
Primiano Tucci0e7915d2022-02-08 15:25:49 +000099 (ecx & (1u << 28)) && // AVX supported in hardware
100 ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask);
Primiano Tucci2277f062021-11-08 22:24:05 +0000101
Primiano Tucci682a9982022-05-20 17:13:28 +0100102 // Get level 7 features (eax = 7 and ecx= 0), to check for AVX2 support.
103 // (See Intel 64 and IA-32 Architectures Software Developer's Manual
104 // Volume 2A: Instruction Set Reference, A-M CPUID).
105 PERFETTO_GETCPUID(eax, ebx, ecx, edx, 7, 0);
106 const bool have_avx2 = have_avx && ((ebx >> 5) & 0x1);
107
108 if (!have_sse4_2 || !have_popcnt || !have_avx2) {
Primiano Tucci2277f062021-11-08 22:24:05 +0000109 fprintf(
110 stderr,
Primiano Tucci682a9982022-05-20 17:13:28 +0100111 "This executable requires a X86_64 cpu that supports SSE4.2 and AVX2.\n"
Primiano Tuccib37cdb82022-05-20 16:31:44 +0100112#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
113 "On MacOS, this might be caused by running x86_64 binaries on arm64.\n"
114 "See https://github.com/google/perfetto/issues/294 for more.\n"
115#endif
Primiano Tucci682a9982022-05-20 17:13:28 +0100116 "Rebuild with enable_perfetto_x64_cpu_opt=false.\n");
Primiano Tucci2277f062021-11-08 22:24:05 +0000117 _exit(126);
118 }
119}
120#endif
121
122} // namespace
123
Primiano Tuccia81d2772020-10-07 00:12:41 +0200124namespace perfetto {
125namespace base {
126
127void MaybeReleaseAllocatorMemToOS() {
128#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
129 // mallopt() on Android requires SDK level 26. Many targets and embedders
130 // still depend on a lower SDK level. Given mallopt() is a quite simple API,
131 // use reflection to do this rather than bumping the SDK level for all
132 // embedders. This keeps the behavior of standalone builds aligned with
133 // in-tree builds.
134 static MalloptType mallopt_fn =
135 reinterpret_cast<MalloptType>(dlsym(RTLD_DEFAULT, "mallopt"));
136 if (!mallopt_fn)
137 return;
138 mallopt_fn(PERFETTO_M_PURGE, 0);
139#endif
140}
141
Primiano Tucciab293f52020-12-08 11:46:52 +0100142uint32_t GetSysPageSize() {
143 ignore_result(kPageSize); // Just to keep the amalgamated build happy.
144#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
145 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
146 static std::atomic<uint32_t> page_size{0};
147 // This function might be called in hot paths. Avoid calling getpagesize() all
148 // the times, in many implementations getpagesize() calls sysconf() which is
149 // not cheap.
150 uint32_t cached_value = page_size.load(std::memory_order_relaxed);
151 if (PERFETTO_UNLIKELY(cached_value == 0)) {
152 cached_value = static_cast<uint32_t>(getpagesize());
153 page_size.store(cached_value, std::memory_order_relaxed);
154 }
155 return cached_value;
156#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
157 return static_cast<uint32_t>(vm_page_size);
158#else
159 return 4096;
160#endif
161}
162
Primiano Tucci10c9e9e2021-01-08 13:04:40 +0100163uid_t GetCurrentUserId() {
164#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
165 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
166 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
167 return geteuid();
168#else
169 // TODO(primiano): On Windows we could hash the current user SID and derive a
170 // numeric user id [1]. It is not clear whether we need that. Right now that
171 // would not bring any benefit. Returning 0 unil we can prove we need it.
172 // [1]:https://android-review.googlesource.com/c/platform/external/perfetto/+/1513879/25/src/base/utils.cc
173 return 0;
174#endif
175}
176
177void SetEnv(const std::string& key, const std::string& value) {
178#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
179 PERFETTO_CHECK(::_putenv_s(key.c_str(), value.c_str()) == 0);
180#else
181 PERFETTO_CHECK(::setenv(key.c_str(), value.c_str(), /*overwrite=*/true) == 0);
182#endif
183}
184
Daniele Di Proietto240e9a12021-10-26 12:58:16 +0100185void Daemonize(std::function<int()> parent_cb) {
Primiano Tucci003b20e2021-05-21 10:21:43 +0100186#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
187 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
188 PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
189 pid_t pid;
190 switch (pid = fork()) {
191 case -1:
192 PERFETTO_FATAL("fork");
193 case 0: {
194 PERFETTO_CHECK(setsid() != -1);
195 base::ignore_result(chdir("/"));
196 base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
197 PERFETTO_CHECK(null);
198 PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
199 PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
200 PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
201 // Do not accidentally close stdin/stdout/stderr.
202 if (*null <= 2)
203 null.release();
204 break;
205 }
206 default:
207 printf("%d\n", pid);
Daniele Di Proietto240e9a12021-10-26 12:58:16 +0100208 int err = parent_cb();
209 exit(err);
Primiano Tucci003b20e2021-05-21 10:21:43 +0100210 }
211#else
212 // Avoid -Wunreachable warnings.
213 if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
214 PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
Daniele Di Proietto240e9a12021-10-26 12:58:16 +0100215 ignore_result(parent_cb);
Primiano Tucci003b20e2021-05-21 10:21:43 +0100216#endif // OS_WIN
217}
218
219std::string GetCurExecutablePath() {
220 std::string self_path;
221#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
222 PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
223 PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
224 char buf[PATH_MAX];
225 ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
226 PERFETTO_CHECK(size != -1);
227 // readlink does not null terminate.
228 self_path = std::string(buf, static_cast<size_t>(size));
229#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
230 uint32_t size = 0;
231 PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size));
232 self_path.resize(size);
233 PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0);
234#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
235 char buf[MAX_PATH];
236 auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
237 self_path = std::string(buf, len);
238#else
239 PERFETTO_FATAL(
240 "GetCurExecutableDir() not implemented on the current platform");
241#endif
242 return self_path;
243}
244
245std::string GetCurExecutableDir() {
246 auto path = GetCurExecutablePath();
247#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
248 // Paths in Windows can have both kinds of slashes (mingw vs msvc).
Hector Dearman1fe10ce2021-08-23 11:44:26 +0100249 path = path.substr(0, path.find_last_of('\\'));
Primiano Tucci003b20e2021-05-21 10:21:43 +0100250#endif
Hector Dearman1fe10ce2021-08-23 11:44:26 +0100251 path = path.substr(0, path.find_last_of('/'));
Primiano Tucci003b20e2021-05-21 10:21:43 +0100252 return path;
Rahul Ravikumarce6dcb42021-04-19 11:21:40 -0700253}
254
Primiano Tuccic50345c2021-11-09 23:10:06 +0000255void* AlignedAlloc(size_t alignment, size_t size) {
256 void* res = nullptr;
257 alignment = AlignUp<sizeof(void*)>(alignment); // At least pointer size.
Primiano Tuccid99b5d22021-11-10 08:16:02 +0000258#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
Primiano Tuccic50345c2021-11-09 23:10:06 +0000259 // Window's _aligned_malloc() has a nearly identically signature to Unix's
260 // aligned_alloc() but its arguments are obviously swapped.
261 res = _aligned_malloc(size, alignment);
262#else
Primiano Tuccid99b5d22021-11-10 08:16:02 +0000263 // aligned_alloc() has been introduced in Android only in API 28.
264 // Also NaCl and Fuchsia seems to have only posix_memalign().
265 ignore_result(posix_memalign(&res, alignment, size));
Primiano Tuccic50345c2021-11-09 23:10:06 +0000266#endif
267 PERFETTO_CHECK(res);
268 return res;
269}
270
Primiano Tucci97cab972021-11-12 00:17:10 +0000271void AlignedFree(void* ptr) {
272#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
273 _aligned_free(ptr); // MSDN says it is fine to pass nullptr.
274#else
275 free(ptr);
276#endif
277}
278
Daniele Di Proiettobad67fa2021-11-26 14:50:01 +0000279std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
280 const char* data = reinterpret_cast<const char*>(data_void);
281 std::string res;
282 static const size_t kPadding = bytes_per_line * 3 + 12;
283 std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]);
284 for (size_t i = 0; i < len; i += bytes_per_line) {
285 char* wptr = line.get();
286 wptr += sprintf(wptr, "%08zX: ", i);
287 for (size_t j = i; j < i + bytes_per_line && j < len; j++)
288 wptr += sprintf(wptr, "%02X ", static_cast<unsigned>(data[j]) & 0xFF);
289 for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j)
290 *(wptr++) = ' ';
291 for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
292 char c = data[j];
293 *(wptr++) = (c >= 32 && c < 127) ? c : '.';
294 }
295 *(wptr++) = '\n';
296 *(wptr++) = '\0';
297 res.append(line.get());
298 }
299 return res;
300}
301
Primiano Tuccia81d2772020-10-07 00:12:41 +0200302} // namespace base
303} // namespace perfetto