LINUX.ORG.RU

Как узнать реальный аптайм?

 


0

1

Без парсинга journalctl (очень медленно, 300-400 мсек сам вызов)? Интересует uptime без учета сна, т.е. реальное время активности. Может есть какая-то утилита?

Поскольку повседневно (daily driver) пользуюсь pwsh, пока этот баг не исправили, встроенный кмдлет Get-Uptime показывает вместо uptime -p аптайм реального времени (без учета сна).

Вот написал такую функцию:


function Show-Uptime
{
    [Alias("up")]

    param
    (
        [Parameter()] [switch] $Since,
        [Parameter()] [switch] $Real
    )


    if ($PSBoundParameters.Count -gt 1)   # Удаляю второй параметер, если он есть (у штатного uptime похожее)
    {
        $key = ([array] $PSBoundParameters.Keys)[1]
        [void] $PSBoundParameters.Remove($key)
    }

    $tspan =
    if ($PSBoundParameters.Real) { Get-Uptime }
    else { [timespan]::FromSeconds((Get-Content /proc/uptime).Split()[0]) }

    if ($PSBoundParameters.Since) { (Get-Date) - $tspan }
    else
    {
        $format = "\u\p"
        switch ($tspan)
        {
            { $_.Days    -gt 0 } { $format += "\ d\d" }
            { $_.Hours   -gt 0 } { $format += "\ h\h" }
            { $_.Minutes -gt 0 } { $format += "\ m\m" }
                         default { $format += "\ m\m" }
        }

        $tspan.ToString($format)
    }
}

Как это выглядит:

$  up  # как uptime -p (с другим форматом)
up 1d 5h 37m
$  up -s  # как uptime -s (с другим форматом)

понедельник, 27 июля 2026 г. 09:41:07

$  up -r  # чистое время без сна (как в хоккее)
up 7h 27m

время выполнения:


$  h -c 3

  Id     Duration CommandLine
  --     -------- -----------
  41        0.006 up
  42        0.003 up -s
  43        0.000 up -r
★★★★★

Последнее исправление: dmitry237 (всего исправлений: 1)
Ответ на: комментарий от gagarin0

Весьма странно всё это выглядит от столь активного и опытного пользователя нашего форума.

unDEFER ★★★★★
()
Ответ на: комментарий от unDEFER

При чем здесь статьи? Меня интересует, как это сделать нативными средствами, которые я смогу адаптировать под свой юзкейс. Можно конечно парсить journalctl, но мне не нравится:

journalctl -b -0 | grep -P "(Starting|Finished)\sSystem\sSuspend"

А потом все это переводить в timespan (время между датами), вычитать и суммировать все парные вхождения. Да еще формат дат без года (хоть бы юникс-эпоха в секундах)

dmitry237 ★★★★★
() автор топика

Эм, причём тут journalctl, какой ещё парсинг? Аптайм это одна единственная переменная в ядре, её clock_gettime(CLOCK_MONOTONIC) возвращает (в Линуксе).

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)
Ответ на: комментарий от gagarin0

самое время осваивать

Да ну нафиг, да и голова уже не варит. Так, какие-то скрипто-удобняшки для себя, это тот максимум, который нажил опытом. С чем сталкивался, то знаю, а остальное очень сложно. У меня же минимальный вопрос, покажите направление для конкретной задачи, вот предложили какую-то ядерную переменную среды, что это, как с ней взаимодействовать…

dmitry237 ★★★★★
() автор топика
Ответ на: комментарий от dmitry237
#include <stdio.h>
#include <time.h>

int main(void) {
  struct timespec ts;
  clock_gettime(CLOCK_MONOTONIC, &ts);
  printf("llu\n", (unsigned long long)ts.tv_sec);
  return 0;
}

Ну и как ее вернуть и что она показывает, какие данные?

Всмысле что показывает? Ты же спрашиваешь как аптайм узнать - вот это он и есть.

Но учти что стандарт не требует от неё аптайм, в других ОС (которые не Linux) может быть другое. В фрибсд например в мане написано, что для аптайма надо CLOCK_UPTIME, а CLOCK_MONOTONIC отсчитывает время от некоторого неуказанного момента времени, хотя по факту в MONOTONIC там тоже аптайм, если посмотреть исходники ядра.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 4)

Поскольку повседневно (daily driver) пользуюсь pwsh

Какой кошмар…

Dimez ★★★★★
()

Но почему нельзя использовать сам $(which uptime)? Потому что pwsh под оффтопиком? Для линукса это нативнее некуда, а pwsh, хоть и под онтопик есть, но…

yars068 ★★★★★
()

Пока решил так:

$  up -Real
up 10h 18m

$  & {     
         $targets = (journalctl -u sleep.target) -replace '(?<=:\d{2}).+'
         $y = [datetime]::Now.Year
         for ($i = 0; $i -lt $targets.Count; $i += 2)
         {
             $sleep += ([datetime] "$y $($targets[$i+1])") - ([datetime] "$y $($targets[$i])")
         }
         [timespan]::FromSeconds((gc /proc/uptime).Split()[0]) - $sleep
     }

Days              : 0
Hours             : 10
Minutes           : 18
Seconds           : 2
Milliseconds      : 300
Ticks             : 370823000000
TotalDays         : 0.429193287037037
TotalHours        : 10.3006388888889
TotalMinutes      : 618.038333333333
TotalSeconds      : 37082.3
TotalMilliseconds : 37082300

С годом могут возникнуть траблы на стыке НГ.

dmitry237 ★★★★★
() автор топика
Ответ на: комментарий от yars068

Но почему нельзя использовать сам $(which uptime)?

Он медленнее функции (хоть и незначительно):

$  uptime -p
up 1 day, 8 hours, 40 minutes

$  up 
up 1d 8h 40m

$  h -c 2

  Id     Duration CommandLine
  --     -------- -----------
 158        0.007 uptime -p
 159        0.003 up

Ну и цель заменить внутренний Get-Uptime, который работает не так, как ожидается. Мало что-ли багов, дохера, и в самом шелле и то, что под капотом, в дотнет, в основном на юникс-платформах.

dmitry237 ★★★★★
() автор топика
Ответ на: комментарий от yars068

Но почему нельзя использовать сам $(which uptime)?

У меня uptime показывает время в сумме со сном, а автор хочет без сна.

Но парсинг логов вместо того чтобы спросить аптайм у ядра это конечно жуткое извращение.

firkax ★★★★★
()
Ответ на: комментарий от dmitry237

который работает не так, как ожидается.

То есть, он должен отдавать такой же вывод, как у uptime -p, верно? Но ведь это просто человекоугодная форма uptime, то есть, только время, без подробностей.

yars068 ★★★★★
()
Последнее исправление: yars068 (всего исправлений: 1)
Ответ на: комментарий от dmitry237

как с ней взаимодействовать…

python3 -c 'import time; print(int(time.clock_gettime(time.CLOCK_MONOTONIC)) // 60, "min")'
  • Ответ сгенерирован ИИ, может содержать бред. Ахтунг.
yars068 ★★★★★
()
Последнее исправление: yars068 (всего исправлений: 1)
Ответ на: комментарий от yars068

То есть, он должен отдавать такой же вывод, как у uptime -p, верно?

Да, но он выводит аптайм с учетом сна. С одной стороны видно сколько реально сидел за ноутом/компом, но если бы это было такой опцией, а не основным поведением. Ну и к тому же показывает время старта, которое исходит из этих же данных. После сна отличается от uptime -s. Это только под юниксами (линукс, макось и фряха (неофициальная сборка))

$  uptime -s; Get-Uptime -s
2026-07-27 09:41:07
вторник, 28 июля 2026 г. 07:50:52
dmitry237 ★★★★★
() автор топика
Ответ на: комментарий от dmitry237

Можно к вопросу подойти философски :)

Что по сути есть uptime компа? И что есть сон у компа. Может все таки правильно что он так кажет? ;)

Комп можно выключить а можно и перегрузить ;)

anonymous
()
Ответ на: комментарий от anonymous

Можно к вопросу подойти философски

Так-то оно правильно. Никогда не фокусировался на этом, и ничего. Просто захотелось навести какой-то порядок. Все это «игрушки», если по правде.

dmitry237 ★★★★★
() автор топика
Ответ на: комментарий от dmitry237

Просто захотелось навести какой-то порядок.

Да я подумал, что по логике правильно, что команда уптайм не вычитает время сна.

anonymous
()
Ответ на: комментарий от dmitry237

Я тебе дал код, не тупи, скомпилируй его, безо всяких питонов.

И это не «переменная среды», а переменная в ядре - 8 байт памяти, в которых оно хранит этот счётчик, всё что тебе надо это эти 8 байт прочитать, а не парсить всякие простыни из journald и прочую ерунду.

firkax ★★★★★
()
Ответ на: комментарий от dmitry237

Так не в секундах:

#include <stdio.h>
#include <time.h>

int main(void) {
  struct timespec ts;
  unsigned long long t;
  unsigned int D, h, m, s;
  clock_gettime(CLOCK_MONOTONIC, &ts);
  printf("%llu\n", (unsigned long long)ts.tv_sec);
  t = ts.tv_sec;
  s = t%60; t/=60;
  m = t%60; t/=60;
  h = t%24; t/=24;
  D = t%365; t/=365;
  printf("%llu years, %u days, %02u:%02u:%02u\n", t, D, h, m, s);
  return 0;
}

firkax ★★★★★
()
Ответ на: комментарий от firkax

В секундах удобно, я ваш код сохранил на всякий случай, может пригодится.

dmitry237 ★★★★★
() автор топика
#!/bin/sh

f=/var/run/active_uptime

[ -f "$f" ] || cut -d. -f1 /proc/uptime > "$f"

while :; do
    sleep 1
    echo $(( $(cat "$f") + 1 )) > "$f"
done

Чтение из файла не дорого, а машине доверия нет и лучше считать самому!

anonymous
()
Ответ на: комментарий от dmitry237

Можно и без питона

       /* clock_times.c

          Licensed under GNU General Public License v2 or later.
       */
       #define _XOPEN_SOURCE 600
       #include <stdbool.h>
       #include <stdint.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <sys/types.h>
       #include <time.h>

       #define SECS_IN_DAY (24 * 60 * 60)

       static void
       displayClock(clockid_t clock, const char *name, bool showRes)
       {
           long             days;
           struct timespec  ts;

           if (clock_gettime(clock, &ts) == -1) {
               perror("clock_gettime");
               exit(EXIT_FAILURE);
           }

           printf("%-15s: %10jd.%03ld (", name,
                  (intmax_t) ts.tv_sec, ts.tv_nsec / 1000000);

           days = ts.tv_sec / SECS_IN_DAY;
           if (days > 0)
               printf("%ld days + ", days);

           printf("%2dh %2dm %2ds",
                  (int) (ts.tv_sec % SECS_IN_DAY) / 3600,
                  (int) (ts.tv_sec % 3600) / 60,
                  (int) ts.tv_sec % 60);
           printf(")\n");

           if (clock_getres(clock, &ts) == -1) {
               perror("clock_getres");
               exit(EXIT_FAILURE);
           }

           if (showRes)
               printf("     resolution: %10jd.%09ld\n",
                      (intmax_t) ts.tv_sec, ts.tv_nsec);
       }

       int
       main(int argc, char *[])
       {
           bool showRes = argc > 1;

           displayClock(CLOCK_REALTIME, "CLOCK_REALTIME", showRes);
       #ifdef CLOCK_TAI
           displayClock(CLOCK_TAI, "CLOCK_TAI", showRes);
       #endif
           displayClock(CLOCK_MONOTONIC, "CLOCK_MONOTONIC", showRes);
       #ifdef CLOCK_BOOTTIME
           displayClock(CLOCK_BOOTTIME, "CLOCK_BOOTTIME", showRes);
       #endif
           exit(EXIT_SUCCESS);
       }
ugoday ★★★★★
()
Ответ на: комментарий от ugoday

А можно и без C

(defn uptime-nonsleep []
    (let [d (java.time.Duration/ofNanos (System/nanoTime))]
      (format "Компьютер непрерывно работал  %s дней %s часов и %s минут." 
              (.toDays d) (mod (.toHours d) 24) (mod (.toMinutes d) 60))))

P.S. На самом деле нельзя, но тут уж ничего не поделаешь. В таком мире живём.

ugoday ★★★★★
()
  • Markdown
Пустая строка (два раза Enter) начинает новый абзац. Знак '>' в начале абзаца выделяет абзац курсивом цитирования.
Внимание: прочитайте описание разметки Markdown.
Используйте Ctrl-Enter для размещения комментария