Deshim VirtualExecutor in folly
[hiphop-php.git] / hphp / util / process.h
blob4f6bb1cdcfbf4c2924ec4a5f22e9d77bd4430be4
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #pragma once
19 #include <atomic>
20 #include <cassert>
21 #include <chrono>
22 #include <filesystem>
23 #include <map>
24 #include <string>
25 #include <vector>
27 #include <folly/portability/SysResource.h>
28 #include <folly/portability/Unistd.h>
30 #include <sys/syscall.h>
32 #include <pthread.h>
33 #include <signal.h>
35 #include "hphp/util/process-cpu.h"
36 #include "hphp/util/process-host.h"
37 #include "hphp/util/optional.h"
39 namespace HPHP {
40 ///////////////////////////////////////////////////////////////////////////////
43 * System-wide memory information from /proc/meminfo
45 struct MemInfo {
46 int64_t totalMb{-1};
47 int64_t freeMb{-1};
48 int64_t cachedMb{-1};
49 int64_t buffersMb{-1};
50 int64_t availableMb{-1};
51 bool valid() const {
52 return (totalMb | freeMb | cachedMb | buffersMb | availableMb) >= 0;
57 * Information from /proc/self/status, along with other HHVM-specific memory
58 * usage data.
60 * Kernel documentation: http://man7.org/linux/man-pages/man5/proc.5.html
62 struct ProcStatus {
63 static std::atomic_int64_t VmSizeKb; // virtual memory size
64 static std::atomic_int64_t VmRSSKb; // RSS, not including hugetlb pages
65 static std::atomic_int64_t VmHWMKb; // peak RSS
66 static std::atomic_int64_t VmSwapKb; // swap usage
67 static std::atomic_int64_t HugetlbPagesKb; // Hugetlb
69 // Mapped but unused size, updated periodically when updating jemalloc stats.
70 static std::atomic_int64_t UnusedKb;
72 // Number of threads running in the current process.
73 static std::atomic_int threads;
74 static std::atomic_uint lastUpdate; // seconds in std::chrono::steady_clock
76 public:
77 static auto totalRssKb() { // include hugetlb pages
78 return VmRSSKb.load(std::memory_order_relaxed) +
79 HugetlbPagesKb.load(std::memory_order_relaxed);
81 static auto adjustedRssKb() {
82 assert(valid());
83 return VmRSSKb.load(std::memory_order_relaxed)
84 + VmSwapKb.load(std::memory_order_relaxed)
85 + HugetlbPagesKb.load(std::memory_order_relaxed)
86 - UnusedKb.load(std::memory_order_relaxed);
88 static auto nThreads() {
89 return threads.load(std::memory_order_relaxed);
91 static void updateUnused(int64_t unusedKb) {
92 UnusedKb.store(unusedKb, std::memory_order_relaxed);
94 static bool valid() {
95 return static_cast<bool>(lastUpdate.load(std::memory_order_acquire));
97 static unsigned time() {
98 auto const d = std::chrono::steady_clock::now().time_since_epoch();
99 return std::chrono::duration_cast<std::chrono::seconds>(d).count();
101 static void checkUpdate(int updateInterval) {
102 if (time() >= lastUpdate.load(std::memory_order_acquire) + updateInterval) {
103 update();
106 static void update();
110 * Information about system pressure (cpu, io, memory) read from
111 * /proc/pressure/{cpu,io,memory}
113 * PSI docs: https://facebookmicrosites.github.io/psi/docs/overview
115 struct Pressure {
116 // Pressure over the last 10, 60, and 300 seconds respectively
117 double avg10;
118 double avg60;
119 double avg300;
120 // Total number of accumulated microseconds
121 uint64_t total;
124 struct ProcPressure {
125 Optional<Pressure> some;
126 Optional<Pressure> full;
129 ///////////////////////////////////////////////////////////////////////////////
131 namespace Process {
132 // The maximum supported signal number is kNSig - 1.
133 constexpr unsigned kNSig =
134 #if defined(NSIG)
135 NSIG
136 #elif defined(_NSIG)
137 _NSIG
138 #else
140 #endif
143 // Cached process statics
144 extern std::string HostName;
145 extern std::string CurrentWorkingDirectory;
146 extern char** Argv;
148 void InitProcessStatics();
149 inline void RecordArgv(char** argv) { // only call this in main()
150 Argv = argv;
154 * Current executable's name.
156 std::string GetAppName();
159 * Get command line with a process ID.
161 std::string GetCommandLine(pid_t pid);
164 * Check if the current process is being run under GDB. Will return false if
165 * we're unable to read /proc/{getpid()}/status.
167 bool IsUnderGDB();
170 * Get memory usage in MB by a process.
172 int64_t GetMemUsageMb();
175 * Get the total systems cpu delay in milliseconds.
177 * The cpu delay measure the total amount of time that a processes were
178 * runnable, but not running because the CPUs were busy.
180 int64_t GetSystemCPUDelayMS();
182 ProcPressure GetCPUPressure(const std::filesystem::path& path = "/proc/pressure/cpu");
183 ProcPressure GetIOPressure(const std::filesystem::path& path = "/proc/pressure/io");
184 ProcPressure GetMemoryPressure(const std::filesystem::path& path = "/proc/pressure/memory");
187 * Get the number of threads running in the current process.
189 int GetNumThreads();
192 * Get system-wide memory usage information. If `checkCgroup2' is true and
193 * HHVM is running inside a cgroup2, this function checks cgroup2's limits to
194 * potentially reduce the amount of total and available memory. Returns false
195 * upon failure. Note that previous value of `info` is reset, even upon
196 * failure.
198 bool GetMemoryInfo(MemInfo& info, bool checkCgroup2);
201 * Current thread's identifier.
203 inline pthread_t GetThreadId() {
204 return pthread_self();
208 * Current thread's identifier.
210 inline uint64_t GetThreadIdForTrace() {
211 return (uint64_t)pthread_self();
215 * Thread's process identifier.
217 inline pid_t GetThreadPid() {
218 return syscall(SYS_gettid);
222 * Are we in the main thread still?
224 inline bool IsInMainThread() {
225 return Process::GetThreadPid() == getpid();
229 * Get current working directory.
231 std::string GetCurrentDirectory();
234 * Get current user's name.
236 std::string GetCurrentUser();
239 * Get current user's home directory.
241 std::string GetHomeDirectory();
244 * Set core dump filters to make sure hugetlb pages are included in coredumps.
246 void SetCoreDumpHugePages();
249 * Write to /proc/self/oom_score_adj (for Linux only). This affects the OOM
250 * killer when it decides which process to kill. Valid values are between
251 * -1000 and 1000. Lower values makes it less likely for the process to be
252 * killed. In particular, -1000 disables the OOM killer completely for the
253 * current process. Returns whether adjustment was successful.
255 bool OOMScoreAdj(int adj = 1000);
257 * Sometimes we want to relaunch under modified environment. It won't return
258 * upon success, and returns -1 when an error occurs (similar to exec()).
260 int Relaunch();
262 /** Replace the FDs, ensuring a clean STDIO, and avoiding conflicts.
264 * `fds` is a map where:
265 * - keys are the target FD in the new process
266 * - values are the FD in the current process
268 * Any FDs not specified (including STDIO) will be closed.
270 * If the TARGET is negative, it will be given any FD that does not conflict
271 * with the other input.
273 * createDelegate() closes stdin/stdout/stderr, so some of our
274 * received handles may be FD 0/1/2 - that doesn't mean they're
275 * stdin/out/err though, but we need to make sure we don't accidentally
276 * close them. Copy everything out of the 'unsafe' space, close everything
277 * else, then move back.
279 * Returns a map of negative targets (if any) to their new actual FD.
281 std::map<int, int> RemapFDsPreExec(const std::map<int, int>& fds);
283 const int FORK_AND_EXECVE_FLAG_NONE = 0;
284 const int FORK_AND_EXECVE_FLAG_SETPGID = 1 << 0;
285 const int FORK_AND_EXECVE_FLAG_SETSID = 1 << 1;
286 const int FORK_AND_EXECVE_FLAG_EXECVPE = 1 << 2;
288 /** Opens a process with the given arguments, environment, working directory,
289 * and file descriptors.
291 * This *does not* use the shell; to use the shell, consider executing
292 * `/bin/sh` with args `['-c', 'command'].
294 * `pgid` is ignored unless `FORK_AND_EXECVE_FLAG_SETPGID` is in `flags`.
296 * `FORK_AND_EXECVE_FLAG_SETPGID` and `FORK_AND_EXECVE_FLAG_SETSID` are
297 * mutually exclusive.
299 * `fds` is a map where:
300 * - keys are the target FD in the new process
301 * - values are the FD in the current process
303 * Any FDs not specified (including STDIO) will be closed.
305 * On error, `errno` will be set.
306 * - if fork() fails, -1 will be returned
307 * - if chdir() fails, -2 will be returned
308 * - if setsid() fails, -3 will be returned
309 * - if setpgid() fails, -4 will be returned
310 * - if execve() fails, -5 will be returned
312 pid_t ForkAndExecve(
313 const std::string& path,
314 const std::vector<std::string>& argv,
315 const std::vector<std::string>& envp,
316 const std::string& cwd,
317 const std::map<int, int>& fds,
318 int flags = FORK_AND_EXECVE_FLAG_NONE,
319 pid_t pgid = 0);
321 } // namespace Process
323 ///////////////////////////////////////////////////////////////////////////////