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