process_uptime.cpp 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. #include "process_uptime.h"
  2. #include "systime.h"
  3. #include "uptime.h"
  4. #if defined(_linux_)
  5. #include <util/string/builder.h>
  6. #include <util/string/cast.h>
  7. #include <util/stream/file.h>
  8. #include <util/string/split.h>
  9. #include <unistd.h>
  10. #elif defined(_win_)
  11. #include <processthreadsapi.h>
  12. #endif
  13. TDuration ProcessUptime() {
  14. #if defined(_win_)
  15. FILETIME createProcessTime;
  16. FILETIME dummy1;
  17. FILETIME dummy2;
  18. FILETIME dummy3;
  19. if (GetProcessTimes(GetCurrentProcess(), &createProcessTime, &dummy1, &dummy2, &dummy3)) {
  20. timeval processCreationTimeval{.tv_sec = 0, .tv_usec = 0};
  21. FileTimeToTimeval(&createProcessTime, &processCreationTimeval);
  22. const TInstant processCreationInstant = TInstant::Seconds(processCreationTimeval.tv_sec) + TDuration::MicroSeconds(processCreationTimeval.tv_usec);
  23. return TInstant::Now() - processCreationInstant;
  24. }
  25. ythrow TSystemError() << "Failed to obtain process starttime";
  26. #elif defined(_linux_)
  27. static const auto statPath = "/proc/self/stat";
  28. // /proc/<pid>/stat format: #21 (0-based) item - starttime %llu - The time the process started after system boot
  29. TUnbufferedFileInput statFile(statPath);
  30. auto statStr = statFile.ReadAll();
  31. const auto completeStatsSize = 20; // First two fields skipped to ignore variations of parentheses
  32. const TVector<TStringBuf> stats = StringSplitter(TStringBuf{statStr}.RAfter(')').After(' ')).Split(' ').Take(completeStatsSize);
  33. ui64 startTimeTicks = 0;
  34. Y_THROW_UNLESS(stats.size() == completeStatsSize, "Broken format of " << statPath);
  35. if (!TryFromString<ui64>(stats.back(), startTimeTicks)) {
  36. ythrow yexception() << "Failed to extract process starttime value from " << statPath;
  37. }
  38. long ticksPerSecond = sysconf(_SC_CLK_TCK);
  39. Y_THROW_UNLESS_EX(ticksPerSecond != -1, TSystemError() << "Failed to get _SC_CLK_TCK");
  40. Y_THROW_UNLESS(ticksPerSecond > 0, "Invalid value of the _SC_CLK_TCK variable: " << ticksPerSecond);
  41. const ui64 startTimeSeconds = startTimeTicks / ticksPerSecond;
  42. const ui64 fractionTicks = startTimeTicks % ticksPerSecond;
  43. const TDuration startTimeFractionSeconds = TDuration::MicroSeconds(1'000'000u * fractionTicks / ticksPerSecond);
  44. const TDuration startTime = TDuration::Seconds(startTimeSeconds) + startTimeFractionSeconds;
  45. return Uptime() - startTime;
  46. #else
  47. ythrow yexception() << "unimplemented";
  48. #endif
  49. }