| #include "base/StringFormat.h" |
| #include "base/System.h" |
| |
| #ifdef _WIN32 |
| #include <windows.h> |
| #endif |
| |
| #ifdef _MSC_VER |
| #include "msvc-posix.h" |
| #include "dirent.h" |
| #else |
| #include <sys/time.h> |
| #include <sys/resource.h> |
| #include <unistd.h> |
| #endif |
| |
| #include <string.h> |
| |
| namespace { |
| |
| struct TickCountImpl { |
| private: |
| uint64_t mStartTimeUs; |
| #ifdef _WIN32 |
| long long mFreqPerSec = 0; // 0 means 'high perf counter isn't available' |
| #elif defined(__APPLE__) |
| clock_serv_t mClockServ; |
| #endif |
| |
| public: |
| TickCountImpl() { |
| #ifdef _WIN32 |
| LARGE_INTEGER freq; |
| if (::QueryPerformanceFrequency(&freq)) { |
| mFreqPerSec = freq.QuadPart; |
| } |
| #elif defined(__APPLE__) |
| host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &mClockServ); |
| #endif |
| mStartTimeUs = getUs(); |
| } |
| |
| #ifdef __APPLE__ |
| ~TickCountImpl() { |
| mach_port_deallocate(mach_task_self(), mClockServ); |
| } |
| #endif |
| |
| uint64_t getStartTimeUs() const { |
| return mStartTimeUs; |
| } |
| |
| uint64_t getUs() const { |
| #ifdef _WIN32 |
| if (!mFreqPerSec) { |
| return ::GetTickCount() * 1000; |
| } |
| LARGE_INTEGER now; |
| ::QueryPerformanceCounter(&now); |
| return (now.QuadPart * 1000000ull) / mFreqPerSec; |
| #elif defined __linux__ |
| timespec ts; |
| clock_gettime(CLOCK_MONOTONIC, &ts); |
| return ts.tv_sec * 1000000ll + ts.tv_nsec / 1000; |
| #else // APPLE |
| mach_timespec_t mts; |
| clock_get_time(mClockServ, &mts); |
| return mts.tv_sec * 1000000ll + mts.tv_nsec / 1000; |
| #endif |
| } |
| }; |
| |
| // This is, maybe, the only static variable that may not be a LazyInstance: |
| // it holds the actual timestamp at startup, and has to be initialized as |
| // soon as possible after the application launch. |
| static const TickCountImpl kTickCount; |
| |
| } // namespace |
| |
| namespace android { |
| namespace base { |
| |
| std::string getEnvironmentVariable(const std::string& key) { |
| return {}; |
| } |
| |
| void setEnvironmentVariable(const std::string& key, const std::string& value) { |
| #ifdef _WIN32 |
| std::string envStr = |
| StringFormat("%s=%s", key, value); |
| // Note: this leaks the result of release(). |
| _wputenv(Win32UnicodeString(envStr).release()); |
| #else |
| if (value.empty()) { |
| unsetenv(key.c_str()); |
| } else { |
| setenv(key.c_str(), value.c_str(), 1); |
| } |
| #endif |
| } |
| |
| bool isVerboseLogging() { |
| return false; |
| } |
| |
| void sleepMs(uint64_t n) { |
| #ifdef _WIN32 |
| ::Sleep(n); |
| #else |
| usleep(n * 1000); |
| #endif |
| } |
| |
| void sleepUs(uint64_t n) { |
| #ifdef _WIN32 |
| ::Sleep(n / 1000); |
| #else |
| usleep(n); |
| #endif |
| } |
| |
| uint64_t getUnixTimeUs() { |
| timeval tv; |
| gettimeofday(&tv, nullptr); |
| return tv.tv_sec * 1000000LL + tv.tv_usec; |
| } |
| |
| uint64_t getHighResTimeUs() { |
| return kTickCount.getUs(); |
| } |
| |
| uint64_t getUptimeMs() { |
| return (kTickCount.getUs() - kTickCount.getStartTimeUs()) / 1000; |
| } |
| |
| std::string getProgramDirectoryFromPlatform() { |
| std::string res; |
| #if defined(__linux__) |
| char path[1024]; |
| memset(path, 0, sizeof(path)); // happy valgrind! |
| int len = readlink("/proc/self/exe", path, sizeof(path)); |
| if (len > 0 && len < (int)sizeof(path)) { |
| char* x = ::strrchr(path, '/'); |
| if (x) { |
| *x = '\0'; |
| res.assign(path); |
| } |
| } |
| #elif defined(__APPLE__) |
| char s[PATH_MAX]; |
| auto pid = getpid(); |
| proc_pidpath(pid, s, sizeof(s)); |
| char* x = ::strrchr(s, '/'); |
| if (x) { |
| // skip all slashes - there might be more than one |
| while (x > s && x[-1] == '/') { |
| --x; |
| } |
| *x = '\0'; |
| res.assign(s); |
| } else { |
| res.assign("<unknown-application-dir>"); |
| } |
| #elif defined(_WIN32) |
| Win32UnicodeString appDir(PATH_MAX); |
| int len = GetModuleFileNameW(0, appDir.data(), appDir.size()); |
| res.assign("<unknown-application-dir>"); |
| if (len > 0) { |
| if (len > (int)appDir.size()) { |
| appDir.resize(static_cast<size_t>(len)); |
| GetModuleFileNameW(0, appDir.data(), appDir.size()); |
| } |
| std::string dir = appDir.toString(); |
| char* sep = ::strrchr(&dir[0], '\\'); |
| if (sep) { |
| *sep = '\0'; |
| res.assign(dir.c_str()); |
| } |
| } |
| #else |
| #error "Unsupported platform!" |
| #endif |
| return res; |
| } |
| std::string getProgramDirectory() { |
| static std::string progDir; |
| if (progDir.empty()) { |
| progDir.assign(getProgramDirectoryFromPlatform()); |
| } |
| return progDir; |
| } |
| |
| std::string getLauncherDirectory() { |
| return getProgramDirectory(); |
| } |
| |
| CpuTime cpuTime() { |
| CpuTime res; |
| |
| res.wall_time_us = kTickCount.getUs(); |
| |
| #ifdef __APPLE__ |
| cpuUsageCurrentThread_macImpl( |
| &res.user_time_us, |
| &res.system_time_us); |
| #else |
| |
| #ifdef __linux__ |
| struct rusage usage; |
| getrusage(RUSAGE_THREAD, &usage); |
| res.user_time_us = |
| usage.ru_utime.tv_sec * 1000000ULL + |
| usage.ru_utime.tv_usec; |
| res.system_time_us = |
| usage.ru_stime.tv_sec * 1000000ULL + |
| usage.ru_stime.tv_usec; |
| #else // Windows |
| FILETIME creation_time_struct; |
| FILETIME exit_time_struct; |
| FILETIME kernel_time_struct; |
| FILETIME user_time_struct; |
| GetThreadTimes( |
| GetCurrentThread(), |
| &creation_time_struct, |
| &exit_time_struct, |
| &kernel_time_struct, |
| &user_time_struct); |
| (void)creation_time_struct; |
| (void)exit_time_struct; |
| uint64_t user_time_100ns = |
| user_time_struct.dwLowDateTime | |
| ((uint64_t)user_time_struct.dwHighDateTime << 32); |
| uint64_t system_time_100ns = |
| kernel_time_struct.dwLowDateTime | |
| ((uint64_t)kernel_time_struct.dwHighDateTime << 32); |
| res.user_time_us = user_time_100ns / 10; |
| res.system_time_us = system_time_100ns / 10; |
| #endif |
| |
| #endif |
| return res; |
| } |
| |
| } // namespace base |
| } // namespace android |