aboutsummaryrefslogtreecommitdiff
path: root/src/base/utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/base/utils.cc')
-rw-r--r--src/base/utils.cc214
1 files changed, 181 insertions, 33 deletions
diff --git a/src/base/utils.cc b/src/base/utils.cc
index d5bd5a0d7..b4da80cb1 100644
--- a/src/base/utils.cc
+++ b/src/base/utils.cc
@@ -14,22 +14,34 @@
* limitations under the License.
*/
-#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/utils.h"
+#include <string>
+
#include "perfetto/base/build_config.h"
#include "perfetto/base/logging.h"
+#include "perfetto/ext/base/file_utils.h"
#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
+#include <limits.h>
+#include <stdlib.h> // For _exit()
#include <unistd.h> // For getpagesize() and geteuid() & fork()
#endif
#if PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+#include <mach-o/dyld.h>
#include <mach/vm_page_size.h>
#endif
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+#include <Windows.h>
+#include <io.h>
+#include <malloc.h> // For _aligned_malloc().
+#endif
+
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
#include <dlfcn.h>
#include <malloc.h>
@@ -39,7 +51,7 @@
#else
// Only available in in-tree builds and on newer SDKs.
#define PERFETTO_M_PURGE -101
-#endif
+#endif // M_PURGE
namespace {
extern "C" {
@@ -48,6 +60,57 @@ using MalloptType = void (*)(int, int);
} // namespace
#endif // OS_ANDROID
+namespace {
+
+#if PERFETTO_BUILDFLAG(PERFETTO_X64_CPU_OPT)
+
+// Preserve the %rbx register via %rdi to work around a clang bug
+// https://bugs.llvm.org/show_bug.cgi?id=17907 (%rbx in an output constraint
+// is not considered a clobbered register).
+#define PERFETTO_GETCPUID(a, b, c, d, a_inp, c_inp) \
+ asm("mov %%rbx, %%rdi\n" \
+ "cpuid\n" \
+ "xchg %%rdi, %%rbx\n" \
+ : "=a"(a), "=D"(b), "=c"(c), "=d"(d) \
+ : "a"(a_inp), "2"(c_inp))
+
+uint32_t GetXCR0EAX() {
+ uint32_t eax = 0, edx = 0;
+ asm("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0));
+ return eax;
+}
+
+// If we are building with -msse4 check that the CPU actually supports it.
+// This file must be kept in sync with gn/standalone/BUILD.gn.
+void PERFETTO_EXPORT __attribute__((constructor)) CheckCpuOptimizations() {
+ uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
+ PERFETTO_GETCPUID(eax, ebx, ecx, edx, 1, 0);
+
+ static constexpr uint64_t xcr0_xmm_mask = 0x2;
+ static constexpr uint64_t xcr0_ymm_mask = 0x4;
+ static constexpr uint64_t xcr0_avx_mask = xcr0_xmm_mask | xcr0_ymm_mask;
+
+ const bool have_popcnt = ecx & (1u << 23);
+ const bool have_sse4_2 = ecx & (1u << 20);
+ const bool have_avx =
+ // Does the OS save/restore XMM and YMM state?
+ (ecx & (1u << 27)) && // OS support XGETBV.
+ (ecx & (1u << 28)) && // AVX supported in hardware
+ ((GetXCR0EAX() & xcr0_avx_mask) == xcr0_avx_mask);
+
+ if (!have_sse4_2 || !have_popcnt || !have_avx) {
+ fprintf(
+ stderr,
+ "This executable requires a cpu that supports SSE4.2 and AVX2.\n"
+ "Rebuild with enable_perfetto_x64_cpu_opt=false (ebx=%x, ecx=%x).\n",
+ ebx, ecx);
+ _exit(126);
+ }
+}
+#endif
+
+} // namespace
+
namespace perfetto {
namespace base {
@@ -109,36 +172,121 @@ void SetEnv(const std::string& key, const std::string& value) {
#endif
}
-void Daemonize() {
- #if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
- PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
- pid_t pid;
- switch (pid = fork()) {
- case -1:
- PERFETTO_FATAL("fork");
- case 0: {
- PERFETTO_CHECK(setsid() != -1);
- base::ignore_result(chdir("/"));
- base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
- PERFETTO_CHECK(null);
- PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
- PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
- PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
- // Do not accidentally close stdin/stdout/stderr.
- if (*null <= 2)
- null.release();
- break;
- }
- default:
- printf("%d\n", pid);
- exit(0);
- }
- #else
- // Avoid -Wunreachable warnings.
- if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
- PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
- #endif // OS_WIN
+void Daemonize(std::function<int()> parent_cb) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ pid_t pid;
+ switch (pid = fork()) {
+ case -1:
+ PERFETTO_FATAL("fork");
+ case 0: {
+ PERFETTO_CHECK(setsid() != -1);
+ base::ignore_result(chdir("/"));
+ base::ScopedFile null = base::OpenFile("/dev/null", O_RDONLY);
+ PERFETTO_CHECK(null);
+ PERFETTO_CHECK(dup2(*null, STDIN_FILENO) != -1);
+ PERFETTO_CHECK(dup2(*null, STDOUT_FILENO) != -1);
+ PERFETTO_CHECK(dup2(*null, STDERR_FILENO) != -1);
+ // Do not accidentally close stdin/stdout/stderr.
+ if (*null <= 2)
+ null.release();
+ break;
+ }
+ default:
+ printf("%d\n", pid);
+ int err = parent_cb();
+ exit(err);
+ }
+#else
+ // Avoid -Wunreachable warnings.
+ if (reinterpret_cast<intptr_t>(&Daemonize) != 16)
+ PERFETTO_FATAL("--background is only supported on Linux/Android/Mac");
+ ignore_result(parent_cb);
+#endif // OS_WIN
+}
+
+std::string GetCurExecutablePath() {
+ std::string self_path;
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_LINUX) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) || \
+ PERFETTO_BUILDFLAG(PERFETTO_OS_FUCHSIA)
+ char buf[PATH_MAX];
+ ssize_t size = readlink("/proc/self/exe", buf, sizeof(buf));
+ PERFETTO_CHECK(size != -1);
+ // readlink does not null terminate.
+ self_path = std::string(buf, static_cast<size_t>(size));
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_APPLE)
+ uint32_t size = 0;
+ PERFETTO_CHECK(_NSGetExecutablePath(nullptr, &size));
+ self_path.resize(size);
+ PERFETTO_CHECK(_NSGetExecutablePath(&self_path[0], &size) == 0);
+#elif PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ char buf[MAX_PATH];
+ auto len = ::GetModuleFileNameA(nullptr /*current*/, buf, sizeof(buf));
+ self_path = std::string(buf, len);
+#else
+ PERFETTO_FATAL(
+ "GetCurExecutableDir() not implemented on the current platform");
+#endif
+ return self_path;
+}
+
+std::string GetCurExecutableDir() {
+ auto path = GetCurExecutablePath();
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // Paths in Windows can have both kinds of slashes (mingw vs msvc).
+ path = path.substr(0, path.find_last_of('\\'));
+#endif
+ path = path.substr(0, path.find_last_of('/'));
+ return path;
+}
+
+void* AlignedAlloc(size_t alignment, size_t size) {
+ void* res = nullptr;
+ alignment = AlignUp<sizeof(void*)>(alignment); // At least pointer size.
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ // Window's _aligned_malloc() has a nearly identically signature to Unix's
+ // aligned_alloc() but its arguments are obviously swapped.
+ res = _aligned_malloc(size, alignment);
+#else
+ // aligned_alloc() has been introduced in Android only in API 28.
+ // Also NaCl and Fuchsia seems to have only posix_memalign().
+ ignore_result(posix_memalign(&res, alignment, size));
+#endif
+ PERFETTO_CHECK(res);
+ return res;
+}
+
+void AlignedFree(void* ptr) {
+#if PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
+ _aligned_free(ptr); // MSDN says it is fine to pass nullptr.
+#else
+ free(ptr);
+#endif
+}
+
+std::string HexDump(const void* data_void, size_t len, size_t bytes_per_line) {
+ const char* data = reinterpret_cast<const char*>(data_void);
+ std::string res;
+ static const size_t kPadding = bytes_per_line * 3 + 12;
+ std::unique_ptr<char[]> line(new char[bytes_per_line * 4 + 128]);
+ for (size_t i = 0; i < len; i += bytes_per_line) {
+ char* wptr = line.get();
+ wptr += sprintf(wptr, "%08zX: ", i);
+ for (size_t j = i; j < i + bytes_per_line && j < len; j++)
+ wptr += sprintf(wptr, "%02X ", static_cast<unsigned>(data[j]) & 0xFF);
+ for (size_t j = static_cast<size_t>(wptr - line.get()); j < kPadding; ++j)
+ *(wptr++) = ' ';
+ for (size_t j = i; j < i + bytes_per_line && j < len; j++) {
+ char c = data[j];
+ *(wptr++) = (c >= 32 && c < 127) ? c : '.';
+ }
+ *(wptr++) = '\n';
+ *(wptr++) = '\0';
+ res.append(line.get());
+ }
+ return res;
}
} // namespace base