• 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 
25 #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) ||   \
26     PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
27     PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) ||   \
28     PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
29 #include <limits.h>
30 #include <stdlib.h>  // For _exit()
31 #include <unistd.h>  // For getpagesize() and geteuid() & fork()
32 #endif
33 
34 #if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
35 #include <mach-o/dyld.h>
36 #include <mach/vm_page_size.h>
37 #endif
38 
39 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
40 #include <Windows.h>
41 #include <io.h>
42 #include <malloc.h>  // For _aligned_malloc().
43 #endif
44 
45 #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
54 #endif  // M_PURGE
55 
56 namespace {
57 extern "C" {
58 using MalloptType = void (*)(int, int);
59 }
60 }  // namespace
61 #endif  // OS_ANDROID
62 
63 namespace {
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 
GetXCR0EAX()77 uint32_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.
CheckCpuOptimizations()85 void 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       (ecx & (1u << 27)) &&  // OS support XGETBV.
98       (ecx & (1u << 28)) &&  // AVX supported in hardware
99       ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask);
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 
114 namespace perfetto {
115 namespace base {
116 
MaybeReleaseAllocatorMemToOS()117 void 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 
GetSysPageSize()132 uint32_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 
GetCurrentUserId()153 uid_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 
SetEnv(const std::string & key,const std::string & value)167 void 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 
Daemonize(std::function<int ()> parent_cb)175 void Daemonize(std::function<int()> parent_cb) {
176 #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);
198       int err = parent_cb();
199       exit(err);
200   }
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");
205   ignore_result(parent_cb);
206 #endif  // OS_WIN
207 }
208 
GetCurExecutablePath()209 std::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 
GetCurExecutableDir()235 std::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).
239   path = path.substr(0, path.find_last_of('\\'));
240 #endif
241   path = path.substr(0, path.find_last_of('/'));
242   return path;
243 }
244 
AlignedAlloc(size_t alignment,size_t size)245 void* AlignedAlloc(size_t alignment, size_t size) {
246   void* res = nullptr;
247   alignment = AlignUp<sizeof(void*)>(alignment);  // At least pointer size.
248 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
249   // 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
253   // 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));
256 #endif
257   PERFETTO_CHECK(res);
258   return res;
259 }
260 
AlignedFree(void * ptr)261 void AlignedFree(void* ptr) {
262 #if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
263   _aligned_free(ptr);  // MSDN says it is fine to pass nullptr.
264 #else
265   free(ptr);
266 #endif
267 }
268 
HexDump(const void * data_void,size_t len,size_t bytes_per_line)269 std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
270   const char* data = reinterpret_cast<const char*>(data_void);
271   std::string res;
272   static const size_t kPadding = bytes_per_line * 3 + 12;
273   std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]);
274   for (size_t i = 0; i < len; i += bytes_per_line) {
275     char* wptr = line.get();
276     wptr += sprintf(wptr, "%08zX: ", i);
277     for (size_t j = i; j < i + bytes_per_line && j < len; j++)
278       wptr += sprintf(wptr, "%02X ", static_cast<unsigned>(data[j]) & 0xFF);
279     for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j)
280       *(wptr++) = ' ';
281     for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
282       char c = data[j];
283       *(wptr++) = (c >= 32 && c < 127) ? c : '.';
284     }
285     *(wptr++) = '\n';
286     *(wptr++) = '\0';
287     res.append(line.get());
288   }
289   return res;
290 }
291 
292 }  // namespace base
293 }  // namespace perfetto
294