8000 Get-Uptime is very slightly but increasingly inaccurate relative to Task Manager's up time · Issue #24432 · PowerShell/PowerShell · GitHub
[go: up one dir, main page]

Skip to content

Get-Uptime is very slightly but increasingly inaccurate relative to Task Manager's up time #24432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
5 tasks done
evelyn-bi opened this issue Oct 14, 2024 · 13 comments
Open
5 tasks done
Labels
In-PR Indicates that a PR is out for the issue Up-for-Grabs Up-for-grabs issues are not high priorities, and may be opportunities for external contributors WG-Cmdlets general cmdlet issues WG-Reviewed A Working Group has reviewed this and made a recommendation

Comments

@evelyn-bi
Copy link

Prerequisites

Steps to reproduce

Open Task Manager to the Performance tab and click on the CPU item on the left, and open a PowerShell command window simultaneously next to it. In the PowerShell window run Get-Uptime, note how the time doesn't match that given by Task Manager (listed at the bottom of the CPU page), it can be off by seconds to minutes or more depending on the uptime of the system. You can see in this StackOverflow answer how various methods of getting uptime have a drift relative to the "real" uptime as given by Task Manager (let's all assume Microsoft got it correct in Task Manager and it's the other methods that are wrong): https://stackoverflow.com/a/34010110/15743074, some methods have no drift while others do.

More info: The C# code behind Get-Uptime uses StopWatch.GetTimeStamp() which uses QueryPerformanceCounter, hidden behind a shim but the fact it uses QPC is also indicated on this Microsoft Learn page about high-resolution timestamps:

The primary API for native code is QueryPerformanceCounter (QPC). For managed code, the System.Diagnostics.Stopwatch class uses QPC as its precise time basis.

Which also states,

QPC is typically the best method to use to time-stamp events and measure small time intervals that occur on the same system or virtual machine.

And the page goes into examples of typical crystal oscillators used in computers and how they will drift relative to the real world by seconds per week. I suspect that when Windows synchronizes its time to a timeserver, any corrections to the time are applied to other time sources which is one of the ones Task Manager uses, so if the clock was fast by a second when it gets updated then some kernel counter has 1 second subtracted which causes Task Manager to show an accurate uptime, but the "number of ticks" does not get adjusted to remove a second--which is all the QPC timers use, an unsynchronized number of ticks.

High-resolution timestamps are accurate to microseconds, but microsecond accuracy doesn't hold over days and weeks, these high-resolution timestamps are intended for short profiling events. Get-Uptime is expected to return long times, sometimes even years if you have a server up forever, therefore it should not be using a high resolution timestamp under the hood because it has known issues with drift against real world clocks when used over days or longer.

Expected behavior

Task Manager "up time" and PowerShell `Get-Uptime` should match each other to a second or better.

Actual behavior

Task Manager "up time" and PowerShell `Get-Uptime` are different from each other by seconds or more depending on the uptime of the system. My system has 13 day uptime and the difference is 8 seconds right now, which is admittedly very small at only 0.0007% off after 13 days. The accumulated error will be system dependent and represents an unsynchronized time.

Error details

No response

Environment data

> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      7.4.5
PSEdition                      Core
GitCommitId                    7.4.5
OS                             Microsoft Windows 10.0.19044
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

Visuals

No response

@evelyn-bi evelyn-bi added the Needs-Triage The issue is new and needs to be triaged by a work group. label Oct 14, 2024
Copy link

We've found some similar issues:

If any of the above are duplicates, please consider closing this issue out and adding additional context in the original issue.

Note: You can give me feedback by 👍 or 👎 this comment.

@evelyn-bi
Copy link
Author

We've found some similar issues:

If any of the above are duplicates, please consider closing this issue out and adding additional context in the original issue.

Note: You can give me feedback by 👍 or 👎 this comment.

I disagree that this is a duplicate:

  1. That issue is for Linux whereas this one is for Windows.
  2. That issue was closed due to inactivity, so it was never really solved (the linked issue to fix Linux accounting of sleep time is still open also).
  3. In that issue they suspected it was a bug in Linux only and not shown in Windows because, "We use Stopwatch.GetTimestamp() and if it takes into account suspend time on Windows but not on Unix this looks like a bug. It makes sense to open new issue in .Net Runtime repository", however I have shown that there is a time drift in Windows which is unrelated to sleep time--as they say GetTimestamp() handles sleep correctly, which is also pointed out in the Microsoft Learn page I linked, "QueryPerformanceCounter reads the performance counter and returns the total number of ticks that have occurred since the Windows operating system was started, including the time when the machine was in a sleep state such as standby, hibernate, or connected standby".

This issue is about high performance counters being unsuitable (inaccurate) for timing long running things, such as the uptime of a system. The linked StackOverflow page gives some ideas for alternatives.

@SteveL-MSFT SteveL-MSFT added WG-Cmdlets general cmdlet issues WG-NeedsReview Needs a review by the labeled Working Group labels Oct 21, 2024
@SteveL-MSFT
Copy link
Member

The @PowerShell/wg-powershell-cmdlets discussed this. In our ad hoc testing, we also observed on some systems a drift as compared to using WMI. We would approve of a change to the cmdlet specific to Windows to use WMI to get the LastBootUpTime and subtracting from curren time as (Get-Date).Subtract((get-ciminstance win32_operatingsystem).LastBootUpTime). The existing code would still be needed for Linux and macOS which doesn't have WMI.

@SteveL-MSFT SteveL-MSFT added WG-Reviewed A Working Group has reviewed this and made a recommendation Up-for-Grabs Up-for-grabs issues are not high priorities, and may be opportunities for external contributors and removed Needs-Triage The issue is new and needs to be triaged by a work group. WG-NeedsReview Needs a review by the labeled Working Group labels Dec 4, 2024
@TobiasPSP
Copy link
Collaborator

I did a quick research on where WMI gets this information (as I assumed it might be just a registry key). However it turns out the boot time information is coming from some un(der)documented APIs. The well documented WMI route seems to be the best approach.

@microsoft-github-policy-service microsoft-github-policy-service bot added the In-PR Indicates that a PR is out for the issue label Dec 5, 2024
@iSazonov
Copy link
Collaborator
iSazonov commented Dec 25, 2024

I think it's worth leaving this cmdlet as it is until OS-s or .Net will not offer a standard API.
Now there are several uptime sources (counters) with different behavior. Any of them may be suitable in some scenarios and unsuitable in others. https://stackoverflow.com/questions/972105/retrieve-system-uptime-using-c-sharp/34010110#34010110
For example, WMI requires elevated permissions for remote use.
In addition, there is no clear definition of uptime. What is the zero point? Are we talking about the start time or the time that has passed since the start of the system? Does this time include downtime or sleep time?

The best we can do is describe the drift problem in the documentation.


I found a deviation of GetUptime from WMI of several minutes on one system and no deviation on the other. I do not know what this is due to. But this is not important for support scenarios like "Has the user rebooted the system now?" or "Has the CU (requires a reboot) been installed on the system in the last month?"

Stack Overflow
Is there a simple way to get a system's uptime using C#?

@rhubarb-geek-nz
Copy link

I have put together a proof of concept module getting the boot time from Windows, Linux, MacOS and hopefully FreeBSD

For Windows it uses

(Get-CimInstance -ClassName 'Win32_OperatingSystem').LastBootupTime

For Linux it uses either

uptime -s

or

(Get-Item -LiteralPath '/proc/1').CreationTime

For MacOS and the *BSD it uses

sysctl kern.boottime

Linux Docker images typically don't have uptime so if it is not present it gets the creation date of process 1.

@iSazonov
Copy link
Collaborator

I'd prefer binary examples for supported OS-s.

@rhubarb-geek-nz
Copy link

I'd prefer binary examples for supported OS-s.

I also, but as a proof of concept it is about is it getting the information from the correct place and consistent.

@rhubarb-geek-nz
Copy link
rhubarb-geek-nz commented Feb 1, 2025

I'd prefer binary examples for supported OS-s.

Rewritten in C# SinceYouAsk.cs using the example OSX DllImport

var time = new timeval { tv_sec = 0, tv_usec = 0 };
var size = Marshal.SizeOf<timeval>();
sysctlbyname("kern.boottime", ref time, ref size, IntPtr.Zero, 0);
bootTime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(time.tv_sec).AddMilliseconds(time.tv_usec / 1000);

Running 7.4.5 on FreeBSD 13.3

Name                           Value
----                           -----
PSVersion                      7.4.5
PSEdition                      Core
GitCommitId                    7.4.5
OS                             FreeBSD 13.3-RELEASE FreeBSD 13.3-RELEASE releng/13.3-n257428-80d2b634ddf0 GENERIC
Platform                       Unix
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
$ pwsh -c Get-UptimeSince

Sunday, 02 February 2025 07:15:13

@iSazonov
Copy link
Collaborator
iSazonov commented Feb 2, 2025

@rhubarb-geek-nz Thanks! Some notices for your code.

  1. We don't support FreeBSD, we haven't CIs for FreeBSD so we can not add a code for FreeBSD
  2. I like the idea to cache boot time.
  3. You can see GetCIMInstanceCommand.cs how use CIM on more low level. (Or WMI alternative Use WMI in Get-Uptime on Windows #24644)
  4. On Linux I'd expect we read and parse /proc/uptime

@rhubarb-geek-nz
Copy link
  1. We don't support FreeBSD,

True, it is very much work in progress at the moment! ReadLine does not work well at all. But the core SDK does give it an entry in OSPlatform, but not in netstandard2.0 Historically much of OSX/Darwin derives from FreeBSD.

  1. On Linux I'd expect we read and parse /proc/uptime

Does it take into account hibernate/suspend times? If it counts clock tick interrupts then it will drift from true boot time.
I found that /proc/1 creation time was a reasonable proxy for boot time, except in the case of devices like Raspberry Pi with no real-time clock so they appear to boot at start of epoch until they read the time from disk or update from NTP.

@iSazonov
Copy link
Collaborator
iSazonov commented Feb 3, 2025

Does it take into account hibernate/suspend times?

No.
From https://man7.org/linux/man-pages/man5/proc_uptime.5.html

This file contains two numbers (values in seconds): the
uptime of the system (including time spent in suspend) and
the amount of time spent in the idle process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
In-PR Indicates that a PR is out for the issue Up-for-Grabs Up-for-grabs issues are not high priorities, and may be opportunities for external contributors WG-Cmdlets general cmdlet issues WG-Reviewed A Working Group has reviewed this and made a recommendation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants
0