Browse Source

UTIL: ProcUptime - process uptime

Добавляем uptime  для процесса
7dc898ce5f81666a4cd5f912f49a3035dc2c599c
leasid 9 months ago
parent
commit
bbb72f5da0

+ 46 - 0
util/datetime/process_uptime.cpp

@@ -0,0 +1,46 @@
+#include "process_uptime.h"
+#include "systime.h"
+#include "uptime.h"
+
+#if defined(_linux_)
+    #include <util/string/builder.h>
+    #include <util/string/cast.h>
+    #include <util/stream/file.h>
+    #include <util/string/split.h>
+
+    #include <unistd.h>
+#elif defined(_win_)
+    #include <processthreadsapi.h>
+#endif
+
+TDuration ProcessUptime() {
+#if defined(_win_)
+    FILETIME createProcessTime;
+    FILETIME dummy1;
+    FILETIME dummy2;
+    FILETIME dummy3;
+    if (GetProcessTimes(GetCurrentProcess(), &createProcessTime, &dummy1, &dummy2, &dummy3)) {
+        timeval processCreationTimeval{.tv_sec = 0, .tv_usec = 0};
+        FileTimeToTimeval(&createProcessTime, &processCreationTimeval);
+        const TInstant processCreationInstant = TInstant::Seconds(processCreationTimeval.tv_sec) + TDuration::MicroSeconds(processCreationTimeval.tv_usec);
+        return TInstant::Now() - processCreationInstant;
+    }
+    ythrow TSystemError() << "Failed to obtain process starttime";
+#elif defined(_linux_)
+    static const auto statPath = "/proc/self/stat";
+    // /proc/<pid>/stat format: #21 (0-based) item - starttime %llu - The time the process started after system boot
+    TUnbufferedFileInput statFile(statPath);
+    auto statStr = statFile.ReadAll();
+    const auto completeStatsSize = 20; // First two fields skipped to ignore variations of parentheses
+    TVector<TString> stats = StringSplitter(TStringBuf{statStr}.RAfter(')').After(' ')).Split(' ').Take(completeStatsSize);
+    ui64 startTimeTicks = 0;
+    Y_THROW_UNLESS(stats.size() == completeStatsSize, "Broken format of " << statPath);
+    if (!TryFromString<ui64>(stats.back(), startTimeTicks)) {
+        ythrow yexception() << "Failed to extract process starttime value from " << statPath;
+    }
+    auto startTimeSeconds = startTimeTicks / sysconf(_SC_CLK_TCK);
+    return Uptime() - TDuration::Seconds(startTimeSeconds);
+#else
+    ythrow yexception() << "unimplemented";
+#endif
+}

+ 8 - 0
util/datetime/process_uptime.h

@@ -0,0 +1,8 @@
+#pragma once
+
+#include "base.h"
+
+/**
+ * Returns process uptime
+ */
+TDuration ProcessUptime();

+ 17 - 0
util/datetime/process_uptime_ut.cpp

@@ -0,0 +1,17 @@
+#include <library/cpp/testing/unittest/registar.h>
+
+#include "base.h"
+#include "process_uptime.h"
+#include "uptime.h"
+
+Y_UNIT_TEST_SUITE(TestProcessUptimeSuite) {
+    Y_UNIT_TEST(TestProcessUptime) {
+        auto t0 = Uptime();
+        auto t1 = ProcessUptime();
+        UNIT_ASSERT(t1 < TDuration::Minutes(30));
+        UNIT_ASSERT(t0 > t1);
+        Sleep(TDuration::MilliSeconds(50)); // typical uptime resolution is 10-16 ms
+        auto t2 = ProcessUptime();
+        UNIT_ASSERT(t2 >= t1);
+    }
+}

+ 1 - 0
util/datetime/ut/ya.make

@@ -5,6 +5,7 @@ SRCS(
     datetime/cputimer_ut.cpp
     datetime/parser_deprecated_ut.cpp
     datetime/parser_ut.cpp
+    datetime/process_uptime_ut.cpp
     datetime/uptime_ut.cpp
 )
 

+ 1 - 0
util/ya.make

@@ -22,6 +22,7 @@ JOIN_SRCS(
     datetime/base.cpp
     datetime/constants.cpp
     datetime/cputimer.cpp
+    datetime/process_uptime.cpp
     datetime/systime.cpp
     datetime/uptime.cpp
 )