OSX:以编程方式获得正常运行时间?

问题描述 投票:0回答:9

类似于linux的东西

cat /proc/uptime

返回以秒为单位的正常运行时间,并且最好不解析正常运行时间(1)。

macos uptime
9个回答
19
投票

老问题,我知道,但我需要做同样的事情,所以我想我应该发布我正在使用的代码,这是我从 http://cocoadev.com/wiki/FindingUptime

获得的
#include <time.h>
#include <errno.h>
#include <sys/sysctl.h>

double uptime()
{
    struct timeval boottime;
    size_t len = sizeof(boottime);
    int mib[2] = { CTL_KERN, KERN_BOOTTIME };
    if( sysctl(mib, 2, &boottime, &len, NULL, 0) < 0 )
    {
        return -1.0;
    }
    time_t bsec = boottime.tv_sec, csec = time(NULL);

    return difftime(csec, bsec);
}

17
投票

维基百科上的正常运行时间文章有一个有趣的线索:

使用sysctl

还有一种使用sysctl的方法 调用系统最后一次启动 时间: $ sysctl kern.boottime kern.boottime: { 秒 = 1271934886, usec = 667779 } 四月 22 日星期四 12:14:46 2010

哪个引用sysctl(8),哪个引用sysctl(3)


2
投票

如果有人尝试使用

sysctl.h
以编程方式执行此操作,并且期望返回一个像命令行中所看到的字符串,那么我得到的返回值是一个 16 字节数组,而不是字符串:

sysctlbyname("kern.boottime", value, &size, NULL, 0);

从 [0] 索引开始以十六进制形式放入

value
的示例:

a9 af c6 4e 0 0 0 0 0 0 0 0 28 为 92 55

前 4 个字节(可能是前 8 个,直到 2012 年 1 月才知道)是小端字节顺序的纪元时间。


1
投票

正确做法:

CFTimeInterval getSystemUptime(void)
{
    enum { NANOSECONDS_IN_SEC = 1000 * 1000 * 1000 };
    static double multiply = 0;
    if (multiply == 0)
    {
        mach_timebase_info_data_t s_timebase_info;
        kern_return_t result = mach_timebase_info(&s_timebase_info);
        assert(result == noErr);
        // multiply to get value in the nano seconds
        multiply = (double)s_timebase_info.numer / (double)s_timebase_info.denom;
        // multiply to get value in the seconds
        multiply /= NANOSECONDS_IN_SEC;
    }
    return mach_absolute_time() * multiply;
}

您也可以使用 QuartzCore.framework 中的

CACurrentMediaTime()
(可能具有相同的代码) - 自 OS X v10.5 和 iOS 2.0 起可用


1
投票

添加@Bleyddyn的答案(因为已经11年了并且还在继续)...

我需要一个小实用程序来在几秒钟内打印正常运行时间,因此我对该代码进行了稍微修改以在现代 macOS 上进行编译。

您可以克隆

luckman212/uptime_s
存储库并运行
./build.sh
来生成您自己的通用二进制文件,该二进制文件将简单地以秒为单位打印正常运行时间。


0
投票

DriverServices.h 中声明了一个函数

UpTime
。 我相信这相当于另一个函数
mach_absolute_time
。 两者似乎都没有记录。


0
投票

不幸的是,“sysctl kern.boottime”返回时间戳的秒数,而不是经过的秒数。多次调用不会增加秒计数,但必须是从启动日期本身的 epoc 算起的秒数。


0
投票

一个简单的 Lua 脚本可以完全满足您的要求:

local now=tonumber(io.popen("date +%s"):read())
local boottime=tonumber(io.popen("sysctl -n kern.boottime"):read():match("sec = (%d+)"))
local uptime=now-boottime

0
投票

为了Delphi开发者的利益:

首先我们声明一个函数 ExecuteCommand,它可以运行“sysctl kern.boottime”等命令并获取其输出。

我们将使用 libC 函数 popen、fgets 和 pclose

const libc = '/usr/lib/libc.dylib';

/// Man Page: http://man7.org/linux/man-pages/man3/popen.3.html
function popen(const command: MarshaledAString; const _type: MarshaledAString): TStreamHandle; cdecl; external libc name _PU + 'popen';

/// Man Page: http://man7.org/linux/man-pages/man3/pclose.3p.html
function pclose(filehandle: TStreamHandle): Int32; cdecl; external libc name _PU + 'pclose';

/// Man Page: http://man7.org/linux/man-pages/man3/fgets.3p.html
function fgets(Buffer: Pointer; Size: Int32; Stream: TStreamHAndle): Pointer; cdecl; external libc name _PU + 'fgets';

/// Utility function to return a buffer of ASCII-Z data as a string.
function BufferToString(Buffer: Pointer; MaxSize: UInt32): string;
var
  Cursor: ^UInt8;
  EndOfBuffer: NativeUInt;
begin
  Result := EmptyStr;
  if not Assigned(Buffer) then
    Exit;
  Cursor := Buffer;
  EndOfBuffer := NativeUint(Cursor) + MaxSize;
  while (NativeUint(Cursor) < EndOfBuffer) and (Cursor^ <> 0) do
  begin
    Result := Result + Chr(Cursor^);
    Cursor := Pointer(Succ(NativeUInt(Cursor)));
  end;
end;

{$if defined(POSIX)}
// URL https://chapmanworld.com/calling-linux-commands-from-delphi/
function ExecuteCommand(const CommandLine: AnsiString): string;
var
  Handle: TStreamHandle;
  Data: array[0..511] of UInt8;
begin
  Handle := popen(PAnsiChar(CommandLine), 'r');
  try
    Result := EmptyStr;
    while fgets(@data[0], Sizeof(Data), Handle) <> nil do
      Result := Result + BufferToString(@Data[0], SizeOf(Data));
  finally
    pclose(Handle);
  end;
end;
{$endif}

这将返回一个值,例如:

{ sec = 1730143666, usec = 758303 } Mon Oct 28 21:27:46 2024

现在让我们声明一个可以提取命名正则表达式组的函数:

function GetFirstValue(const Text, Mask, GroupName: string): string;
begin
  Result := EmptyStr;
  var MC := TRegex.Matches(Text, Mask, [TRegexOption.roIgnoreCase, TRegexOption.roMultiLine, TRegexOption.roCompiled, TRegexOption.roExplicitCapture]);
  var M := Default(TMatch);
  for M in MC do
  begin
    Result := M.Groups[GroupName].Value;
    Break;
  end;
end;

并且还声明一个从 Unix 纪元返回 Delphi TDateTime 的函数(自 1970 年 1 月 1 日以来的秒数):

function FromUnix(const Value: Int64): TDateTime;
// Sets UnixStartDate to TDateTime of 01/01/1970
const UnixStartDate: TDateTime = 25569.0; // EncodeDate(1970, 1, 1)
begin
  Result := (Value / 86400) + UnixStartDate;
end;

你这样称呼它:

var Output := ExecuteCommand(AnsiString('sysctl -n kern.boottime'));
var Seconds := TRegexInternal.GetFirstValue(Output, 'sec\s=\s(?<sec>\d+),', 'sec');
var BootTime := TTimestamps.FromUnix(StrToInt64(Seconds));

BootTime 保存操作系统启动时的 TDateTime 值。

© www.soinside.com 2019 - 2024. All rights reserved.