I've been using time with high precision to log the events of my program in console. But soon I noticed that the program sometimes displays time rounded to milliseconds and sometimes not! It occurs completely sporadically, it's the SAME CODE, NOT RECOMPILED, NOT EDITED BETWEEN RUNS:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace DateTimePrecisionTest
{
class Program
{
static DateTime ProgramStartTimeGlobal;
static void PrintConsoleLogGlobal()
{
string TimeStampText = ((DateTime.Now - ProgramStartTimeGlobal).TotalMilliseconds / 1000).ToString("0.000000");
Console.WriteLine(String.Format("Global var: [ {0,10} ] ", TimeStampText));
}
static void PrintConsoleLogLocal(DateTime StartTime)
{
string TimeStampText = ((DateTime.Now - StartTime).TotalMilliseconds / 1000).ToString("0.000000");
Console.WriteLine(String.Format("Local var: [ {0,10} ] ", TimeStampText));
}
static void Main(string[] args)
{
ProgramStartTimeGlobal = DateTime.Now;
for (int i = 0; i < 20; i++)
{
PrintConsoleLogGlobal();
PrintConsoleLogLocal(ProgramStartTimeGlobal);
Thread.Sleep(512);
}
Console.ReadLine();
}
}
}
First I thought it depends whether I'm printing global or local variable. But it doesn't seem to be the case.
The output is (values braces are in seconds):
This chaotic precision changes occur in other programs employing this logging. This program, for instance, executes tasks at remote server (with unpredictable delays between them):
Why??
Internally, DateTime.Now (via UtcNow) depends on the Windows API GetSystemTimeAsFileTime. Unfortunately, it would appear (see community comments at bottom of that page) that the resolution of this clock can vary based on the activity of other programs on your system.
The timeBeginPeriod function is documented as:
This function affects a global Windows setting. Windows uses the lowest value (that is, highest resolution) requested by any process.
Related
Background
My colleague thinks reads in multithreaded C# are reliable and will always give you the current, fresh value of a field, but I've always used locks because I was sure I'd experienced problems otherwise.
I spent some time googling and reading articles, but I mustn't be able to provide google with correct search input, because I didn't find exactly what I was after.
So I wrote the below program without locks in an attempt to prove why that's bad.
Question
I'm assuming the below is a valid test, then the results show that the reads aren't reliable/fresh.
Can someone explain what this is caused by? (reordering, staleness or something else)?
And link me to official Microsoft documentation/section explaining why this happens and what is the recommended solution?
If the below isn't a valid test, what would be?
Program
If there are two threads, one calls SetA and the other calls SetB, if the reads are unreliable without locks, then intermittently Foo's field "c" will be false.
using System;
using System.Threading.Tasks;
namespace SetASetBTestAB
{
class Program
{
class Foo
{
public bool a;
public bool b;
public bool c;
public void SetA()
{
a = true;
TestAB();
}
public void SetB()
{
b = true;
TestAB();
}
public void TestAB()
{
if (a && b)
{
c = true;
}
}
}
static void Main(string[] args)
{
int timesCWasFalse = 0;
for (int i = 0; i < 100000; i++)
{
var f = new Foo();
var t1 = Task.Run(() => f.SetA());
var t2 = Task.Run(() => f.SetB());
Task.WaitAll(t1, t2);
if (!f.c)
{
timesCWasFalse++;
}
}
Console.WriteLine($"timesCWasFalse: {timesCWasFalse}");
Console.WriteLine("Finished. Press Enter to exit");
Console.ReadLine();
}
}
}
Output
Release mode. Intel Core i7 6700HQ:
Run 1: timesCWasFalse: 8
Run 2: timesCWasFalse: 10
Of course it is not fresh. The average CPU nowadays has 3 layers of Caches between each cores Registers and the RAM. And it can take quite some time for a write to one cache to be propagate to all of them.
And then there is the JiT Compiler. Part of it's job is dead code dection. And one of the first things it will do is cut out "useless" variables. For example this code tried to force a OOM excpetion by running into the 2 GiB Limit on x32 Systems:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OOM_32_forced
{
class Program
{
static void Main(string[] args)
{
//each short is 2 byte big, Int32.MaxValue is 2^31.
//So this will require a bit above 2^32 byte, or 2 GiB
short[] Array = new short[Int32.MaxValue];
/*need to actually access that array
Otherwise JIT compiler and optimisations will just skip
the array definition and creation */
foreach (short value in Array)
Console.WriteLine(value);
}
}
}
The thing is that if you cut out the output stuff, there is a decent chance that the JiT will remove the variable Array inlcuding the instantionation order. The JiT has a decent chance to reduce this programming to doing nothing at all at runtime.
volatile is first preventing the JiT from doing any optimisations on that value. And it might even have some effect on how the CPU processes stuff.
In my "LuaTest" namespace I have a class called "Planet". The C# code reads like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LuaInterface;
namespace LuaTest
{
public class Planet
{
public Planet(string name)
{
this.Name = name;
}
public Planet() : this("NoName") { }
public string Name
{
get;
private set;
}
public void printName()
{
Console.WriteLine("This planet's name is {0}", Name);
}
}
}
Then I built LuaTest.dll and copied this file to the same folder where my Lua script is saved. In the Lua script I wrote:
--define Path for required dlls
package.cpath = package.cpath .. ";" .. "/?.dll"
package.path = package.path .. ";" .. "/?.dll/"
require 'luanet'
luanet.load_assembly("LuaTest")
local Planet = luanet.import_type("LuaTest.Planet")
local planet = Planet("Earth")
planet.printName()
However, this piece of code does not work. Lua interpreter throws this error:
lua: dllTest.lua:7: attempt to call local 'Planet' (a nil value)
I suspect that my LuaTest assembly is not loaded at all. Could anyone point out where I did wrong? I would very much appreciate it, since I've been stuck by this problem for days.
Also it might be helpful to add that my LuaInterface.dll is the rebuilt version in .NET4.0 environment.
So I spent a LOT of time similarly. What really drove me bonkers was trying to get Enums working. Eventually I ditched my project for a very simplified console application, very similar (ironically also named 'LuaTest').
Edit: I've noted that the initial "luanet.load_assembly("LuaTest")" appears superfluous. Works with it, or surprisingly without it.
Another Edit: As in my badly edited comment below, when I removed:
print(luanet.LuaTest.Pointless)
It all stopped working (LuaTest.Pointless became nil). But adding the luanet.load_assembly("LuaTest") then makes it work. It may be that there is some sort of odd implicit load in the print or in just expressing they type. Very Strange(tm).
In any case, it seems to work for me (note: after a lot of experimentation). I don't know why yours is failing, I don't note any real difference, but here's all my code in case someone else can spot the critical difference:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LuaInterface;
namespace LuaTest
{
public class Program
{
static void Main(string[] args)
{
Lua lua = new Lua();
lua.DoFile("test.lua");
}
public int some_member = 3;
}
public class Pointless
{
public enum AnEnum
{
One,
Two,
Three
};
public static string aStaticInt = "This is static.";
public double i;
public string n = "Nice";
public AnEnum oneEnumVal = AnEnum.One;
private AnEnum twoEnumVal = AnEnum.Two;
private string very;
public Pointless(string HowPointLess)
{
i = 3.13;
very = HowPointLess;
}
public class MoreInnerClass
{
public string message = "More, please!";
}
public void Compare(AnEnum inputEnum)
{
if (inputEnum == AnEnum.Three)
Console.WriteLine("Match.");
else
Console.WriteLine("Fail match.");
}
}
}
and test.lua:
luanet.load_assembly("LuaTest")
--Pointless is a class in LuaTest assembly
local Pointless = luanet.import_type("LuaTest.Pointless")
print(Pointless)
--Gives 'ProxyType(LuaTest.Pointless): 46104728
print(Pointless.aStaticInt)
--'This is static.'
--Fails if not static, as we expect
--Instantiate a 'Pointless'.
local p = Pointless("Very")
print(p)
--Gives 'LuaTest.Pointless: 12289376'
--Now we can get at the items inside the Pointless
--class (well, this instance, anyway).
local e = p.AnEnum;
print(e)
--ProxyType(LuaTest.Pointless+AnEnum): 23452342
--I guess the + must designate that it is a type?
print(p.i)
--3.14
print(p.oneEnumVal)
--Gives 'One: 0'
print(p.twoEnumVal)
--Gives 'twoEnumVal'... private
--behaves very differently.
print(e.Two:ToString())
--Gives 'Two'
local more = p.MoreInnerClass()
print(more.message)
--'More, Please!'
--create an enum value here in the script,
--pass it back for a comparison to
--the enum.
local anotherEnumVal = p.AnEnum.Three
p:Compare(anotherEnumVal)
--outputs 'Match'
Having spent the last several days working on a project that required this exact functionality from LuaInterface, I stumbled across a piece of Lua code that turned out to be the perfect solution (see Reference 1). Whilst searching for this solution, I noticed this question and figured I'd drop my two cents in.
To apply this solution, I merely run the CLRPackage code while initializing my LuaInterface Lua object. However, the require statement works just as well.
The code provided in reference 1 allows the use of import statements, similar to C# using statements. Once an assembly is imported, its members are accessible in the global namespace. The import statement eliminates the need to use load_assembly or import_type (except in situations in which you need to use members of the same name from different assemblies. In this scenario, import_type would be used similar to C# using NewTypeName = Assembly.OldTypeName).
import "LuaTest"
planet = Planet("Earth")
planet:printName()
This package also works great with enums!
Further information regarding the use of this package may be found at Reference 2.
Hope this helps!
Reference 1: https://github.com/stevedonovan/MonoLuaInterface/blob/master/bin/lua/CLRPackage.lua
Reference 2: http://penlight.luaforge.net/project-pages/penlight/packages/LuaInterface/
I spent some time in binding C# dll to lua. Your posts were helpful but something was missing. The following solution should work:
(Make sure to change your compiler to .NET Framework 3.5 or lower!)
Planet.dll:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Planets
{
public class Planet
{
private string name;
public string Name
{
get { return name; }
set { this.name = value; }
}
private float diameter;
public float Diameter
{
get { return diameter; }
set { this.diameter = value; }
}
private int cntContinents;
public int CntContinents
{
get { return cntContinents; }
set { this.cntContinents = value; }
}
public Planet()
{
Console.WriteLine("Constructor 1");
this.name = "nameless";
this.diameter = 0;
this.cntContinents = 0;
}
public Planet(string n, float d, int k)
{
Console.WriteLine("Constructor 2");
this.name = n;
this.diameter = d;
this.cntContinents = k;
}
public void testMethod()
{
Console.WriteLine("This is a Test!");
}
}
}
Use the code above, paste it into your class library project and compile it with .NET smaller or equal 3.5.
The location of the generated DLL needs to be known by the lua enviroment. Paste it e.g at "clibs"-folder or another well known lua system path. Then try to use the following lua example. It should work.
Test1.lua: (Option 1 with "import" from CLRPackage)
require "luanet"
require "CLRPackage"
import "Planet"
local PlanetClass = luanet.import_type("Planets.Planet")
print(PlanetClass)
local PlanetObject1 = PlanetClass()
print(PlanetObject1)
local PlanetObject2 = PlanetClass("Earth",6371.00*2,7)
print(PlanetObject1.Name)
PlanetObject1.Name = 'Mars'
print(PlanetObject1.Name)
print( "Planet " ..
PlanetObject2.Name ..
" is my home planet. Its diameter is round about " ..
PlanetObject2.Diameter .. "km." ..
" Our neighour is " ..
PlanetObject1.Name)
Test2.lua: (Option 2 with "load_assembly")
require "luanet"
require "CLRPackage"
luanet.load_assembly("Planet")
local PlanetClass = luanet.import_type("Planets.Planet")
print(PlanetClass)
local PlanetObject1 = PlanetClass()
print(PlanetObject1)
local PlanetObject2 = PlanetClass("Earth",6371.00*2,7)
print(PlanetObject1.Name)
PlanetObject1.Name = 'Mars'
print(PlanetObject1.Name)
print( "Planet " ..
PlanetObject2.Name ..
" is my home planet. Its diameter is round about " ..
PlanetObject2.Diameter .. "km." ..
" Our neighour is " ..
PlanetObject1.Name)
In both cases the console output will look like this:
ProxyType(Planets.Planet): 18643596
Constructor 1
Planets.Planet: 33574638
Constructor 2
nameless
Mars
Planet Earth is my home planet. Its diameter is round about 12742km. Our neighbour is Mars
I hope its helps some of you.
Edit 1:
by the way, a method call from lua looks like this:
PlanetObject1:testMethod()
PlanetObject2:testMethod()
Edit 2:
I found different dll's whitch needed to be handled differently. One needed the "import"-function and another needed the "load_assembly"-function. Keep that maybe in mind!
I need a robust way of getting system uptime, and ended up using something as follows.
Added some comments to help people read it. I cannot use Task's as this has to run on a .NET 3.5 application.
// This is a structure, can't be marked as volatile
// need to implement MemoryBarrier manually as appropriate
private static TimeSpan _uptime;
private static TimeSpan GetUptime()
{
// Try and set the Uptime using per counters
var uptimeThread = new Thread(GetPerformanceCounterUptime);
uptimeThread.Start();
// If our thread hasn't finished in 5 seconds, perf counters are broken
if (!uptimeThread.Join(5 * 1000))
{
// Kill the thread and use Environment.TickCount
uptimeThread.Abort();
_uptime = TimeSpan.FromMilliseconds(
Environment.TickCount & Int32.MaxValue);
}
Thread.MemoryBarrier();
return _uptime;
}
// This sets the System uptime using the perf counters
// this gives the best result but on a system with corrupt perf counters
// it can freeze
private static void GetPerformanceCounterUptime()
{
using (var uptime = new PerformanceCounter("System", "System Up Time"))
{
uptime.NextValue();
_uptime = TimeSpan.FromSeconds(uptime.NextValue());
}
}
The part I am struggling with is where should Thread.MemoryBarrier() be placed?
I am placing it before reading the value, but either the current thread or a different thread could have written to it. Does the above look correct?
Edit, Answer based on Daniel
This is what I eneded up implementing, thank you both for the insight.
private static TimeSpan _uptime;
private static TimeSpan GetUptime()
{
var uptimeThread = new Thread(GetPerformanceCounterUptime);
uptimeThread.Start();
if (uptimeThread.Join(5*1000))
{
return _uptime;
}
else
{
uptimeThread.Abort();
return TimeSpan.FromMilliseconds(
Environment.TickCount & Int32.MaxValue);
}
}
private static void GetPerformanceCounterUptime()
{
using (var uptime = new PerformanceCounter("System", "System Up Time"))
{
uptime.NextValue();
_uptime = TimeSpan.FromSeconds(uptime.NextValue());
}
}
Edit 2
Updated based on Bob's comments.
private static DateTimeOffset _uptime;
private static DateTimeOffset GetUptime()
{
var uptimeThread = new Thread(GetPerformanceCounterUptime);
uptimeThread.Start();
if (uptimeThread.Join(5*1000))
{
return _uptime;
}
else
{
uptimeThread.Abort();
return DateTimeOffset.Now.Subtract(TimeSpan.FromMilliseconds(
Environment.TickCount & Int32.MaxValue));
}
}
private static void GetPerformanceCounterUptime()
{
if (_uptime != default(DateTimeOffset))
{
return;
}
using (var uptime = new PerformanceCounter("System", "System Up Time"))
{
uptime.NextValue();
_uptime = DateTimeOffset.Now.Subtract(
TimeSpan.FromSeconds(uptime.NextValue()));
}
}
Thread.Join already ensures that writes performed by the uptimeThread are visible on the main thread. You don't need any explicit memory barrier. (without the synchronization performed by Join, you'd need barriers on both threads - after the write and before the read)
However, there's a potential problem with your code: writing to a TimeSpan struct isn't atomic, and the main thread and the uptimeThread may write to it at the same time (Thread.Abort just signals abortion, but doesn't wait for the thread to finish aborting), causing a torn write.
My solution would be to not use the field at all when aborting. Also, multiple concurrent calls to GetUptime() may cause the same problem, so you should use an instance field instead.
private static TimeSpan GetUptime()
{
// Try and set the Uptime using per counters
var helper = new Helper();
var uptimeThread = new Thread(helper.GetPerformanceCounterUptime);
uptimeThread.Start();
// If our thread hasn't finished in 5 seconds, perf counters are broken
if (uptimeThread.Join(5 * 1000))
{
return helper._uptime;
} else {
// Kill the thread and use Environment.TickCount
uptimeThread.Abort();
return TimeSpan.FromMilliseconds(
Environment.TickCount & Int32.MaxValue);
}
}
class Helper
{
internal TimeSpan _uptime;
// This sets the System uptime using the perf counters
// this gives the best result but on a system with corrupt perf counters
// it can freeze
internal void GetPerformanceCounterUptime()
{
using (var uptime = new PerformanceCounter("System", "System Up Time"))
{
uptime.NextValue();
_uptime = TimeSpan.FromSeconds(uptime.NextValue());
}
}
}
However, I'm not sure if aborting the performance counter thread will work correctly at all - Thread.Abort() only aborts managed code execution. If the code is hanging within a Windows API call, the thread will keep running.
AFAIK writes in .NET are volatile, so the only place where you would need a memory fence would be before each read, since they are subject to reordering and/or caching. To quote from a post by Joe Duffy:
For reference, here are the rules as I have come to understand them
stated as simply as I can:
Rule 1: Data dependence among loads and stores is never violated.
Rule 2: All stores have release semantics, i.e. no load or store may move after one.
Rule 3: All volatile loads are acquire, i.e. no load or store may move before one.
Rule 4: No loads and stores may ever cross a full-barrier.
Rule 5: Loads and stores to the heap may never be introduced.
Rule 6: Loads and stores may only be deleted when coalescing adjacent loads and
stores from/to the same location.
Note that by this definition, non-volatile loads are not required to
have any sort of barrier associated with them. So loads may be freely
reordered, and writes may move after them (though not before, due to
Rule 2). With this model, the only true case where you’d truly need
the strength of a full-barrier provided by Rule 4 is to prevent
reordering in the case where a store is followed by a volatile load.
Without the barrier, the instructions may reorder.
I copied this example from here
I have seen many similar examples. Most of them say they're using the Async CTP. I'm using Visual Studio 11 on Windows 8 though so that does not apply. As shown, the error says TaskEx doesn't exist. I assume I'm missing a reference but don't know which one.
This page is http://users.zoominternet.net/~charleswatson/pic.png.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static Random rnd = new Random();
static void Main(string[] args)
{
//Do some other heavy duty background task in this thread
StartHotel();
Console.WriteLine("StartHotel called..");
Console.ReadLine();
}
static void StartHotel()
{
Console.WriteLine("Starting Hotel..");
for (int i = 0; i < 10; i++)
{
string name = "Chef" + i;
CookDish(name, "Dish" + i);
Console.WriteLine("Asked {0} to start cooking at {1}", name, DateTime.Now.ToString());
}
}
static async void CookDish(string chefName, string dish)
{
//Induce a random delay
int delay = rnd.Next(1000, 4000);
//Cook is cooking - Task
await TaskEx.Delay(delay);
//Write the result - StuffAfterAwait
Console.WriteLine("Chef {0} Finished at {1}", chefName, DateTime.Now.ToString());
}
}
}
In the CTP we were unable to add new features to the Task type so we did the pragmatic thing and just made a new TaskEx type. In the final release there will be no such type; those methods will just be on Task like you'd expect.
Replace TaskEx with Task. At the top of the .cs file, you'll need:
using System.Threading.Tasks;
Much of the sample code I've seen refers to TaskEx, and the estimable Mr. Lippert seems to be indicating that's an artifact of their development process. If you're using the Developer Preview, calls like Run, WhenAll, and Delay are already methods of the class Task rather than of TaskEx. The release tools should be the same.
Is there a simple way to get a system's uptime using C#?
public TimeSpan UpTime {
get {
using (var uptime = new PerformanceCounter("System", "System Up Time")) {
uptime.NextValue(); //Call this an extra time before reading its value
return TimeSpan.FromSeconds(uptime.NextValue());
}
}
}
I'm a bit late, but another simple way is to use the GetTickCount64 function, which is available starting with Windows Vista and does not overflow as GetTickCount does:
public static TimeSpan GetUpTime()
{
return TimeSpan.FromMilliseconds(GetTickCount64());
}
[DllImport("kernel32")]
extern static UInt64 GetTickCount64();
System.Environment.TickCount gets the number of milliseconds since the system was restarted.
Beware though that it is an Int32 and will overflow after 24.9 days and will become negative. See the remarks on the MDSN docs.
My machine has an uptime of 58 days 17 hours according to Task Manager. I went through and tried each answer here and the fast ones are off by a little bit (~1-3 minutes roughly, but over 58 days of uptime):
Stopwatch.GetTimeStamp(): 58days 17hours 11minutes 25seconds
~Time to calculate (ms): 6.8413
DllImport GetTickCount64(): 58days 17hours 13minutes 34seconds
~Time to calculate (ms): 0.2192
PerformanceCounter(System, System Up Time): 58days 17hours 14minutes 02seconds
~Time to calculate (ms): 1233.2854
ManagementObject LastBootUpTime: 58days 17hours 14minutes 02seconds
~Time to calculate (ms): 30.0283
The last two, using PerformanceCounter or using ManagementObject, are always within the same second as Windows Task Manager (just have to take my word for it, or try it yourself with the code below). Based on the results I am going to use the ManagementObject LastBootUpTime method because it's drastically faster than the PerformanceCounter but is still perfectly accurate when compared to Task Manager.
Note that I did subtract the current elapsed time from each method before printing the times, but the whole thing takes less than 2 seconds to run so the time shift can't be explained by improperly accounting for execution time anyway. Here's the code I used:
[System.Runtime.InteropServices.DllImport("kernel32")]
extern static UInt64 GetTickCount64();
public static void Main()
{
var start = Stopwatch.StartNew();
var eachStart = Stopwatch.StartNew();
var ticks = Stopwatch.GetTimestamp();
var uptime = ((double)ticks) / Stopwatch.Frequency;
var uptimeTimeSpan = TimeSpan.FromSeconds(uptime);
Console.WriteLine("Stopwatch.GetTimeStamp(): " + uptimeTimeSpan.Subtract(start.Elapsed).ToString(#"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
eachStart.Restart();
Console.WriteLine("DllImport GetTickCount64(): " + TimeSpan.FromMilliseconds(GetTickCount64()).Subtract(start.Elapsed).ToString(#"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
eachStart.Restart();
var upTime = new PerformanceCounter("System", "System Up Time");
upTime.NextValue(); //Call this an extra time before reading its value
Console.WriteLine("PerformanceCounter(System, System Up Time): " + TimeSpan.FromSeconds(upTime.NextValue()).Subtract(start.Elapsed).ToString(#"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
eachStart.Restart();
ManagementObject mo = new ManagementObject(#"\\.\root\cimv2:Win32_OperatingSystem=#");
DateTime lastBootUp = ManagementDateTimeConverter.ToDateTime(mo["LastBootUpTime"].ToString());
Console.WriteLine("ManagementObject LastBootUpTime: " + (DateTime.Now.ToUniversalTime() - lastBootUp.ToUniversalTime()).Subtract(start.Elapsed).ToString(#"dd\d\a\y\s\ hh\h\o\u\r\s\ mm\m\i\n\u\t\e\s\ ss\s\e\c\o\n\d\s"));
Console.WriteLine($"~Time to calculate (ms): {eachStart.Elapsed.TotalMilliseconds}");
}
Precise and bigger than System.Environment.TickCount, not involving OS horrific perf counters, WMI or native calls:
var ticks = Stopwatch.GetTimestamp();
var uptime = ((double)ticks) / Stopwatch.Frequency;
var uptimeSpan = TimeSpan.FromSeconds(uptime);
If you are using a later .NET version (Core 3.0/.NET 5.0 or above), then the Environment class now has a TickCount64 property.
This doesn't suffer from the wrap-around issues of the TickCount property, nor do you have to resort to P/Invoke to get the value.
long tickCountMs = Environment.TickCount64;
var uptime = TimeSpan.FromMilliseconds(tickCountMs);
The simplest and proper way to do this is
public static TimeSpan GetUptime()
{
ManagementObject mo = new ManagementObject(#"\\.\root\cimv2:Win32_OperatingSystem=#");
DateTime lastBootUp = ManagementDateTimeConverter.ToDateTime(mo["LastBootUpTime"].ToString());
return DateTime.Now.ToUniversalTime() - lastBootUp.ToUniversalTime();
}
Simple, no but it can be done:
static DateTime getLastBootTime(ManagementObject mObject)
{
PropertyData pd = mObject.Properties["LastBootUpTime"];
string name = pd.Name.ToString();
DateTime lastBoot = parseCmiDateTime(pd.Value.ToString());
return lastBoot;
}
static ManagementObject getServerOSObject(string serverName)
{
ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("Select * From Win32_OperatingSystem");
mSearcher.Scope = new ManagementScope(String.Format(#"\\{0}\root\cimv2", serverName));
ManagementObjectCollection mObjects = mSearcher.Get();
if (mObjects.Count != 1) throw new Exception(String.Format("Expected 1 object, returned {0}.", mObjects.Count));
foreach (ManagementObject m in mObjects)
{
//No indexing on collection
return m;
}
throw new Exception("Something went wrong!");
}
I know question is both old and solved, but the esiest solution I can tink of is just using the Enviroment.TickCount property, which returns the number of millisecounds since the system started:
System.DateTime SystemStartTime = DateAndTime.Now.AddMilliseconds(-Environment.TickCount);
System.DateTime Uptime = DateAndTime.Now - SystemStartTime;
This solition is a lot faster than the accepted answare.
The (one and only) correct answer so far:
Using the 32-bit timer is incredibly dangerous, and prone to error for all but limited use.
I'm not sure when the NativeMethods class stuff was added to .net, but it was. You definitely want to avoid P/Invoke overhead. Do this:
using System;
using System.Runtime.InteropServices;
namespace Mu
{
// prevents PInvoke (not in NativeMethods class) or Stack walk (NativeMethods class) performance penalties.
internal static partial class SafeNativeMethods
{
[DllImport("kernel32")]
internal extern static UInt64 GetTickCount64();
}
public static class MuTime
{
public static UInt64 UpTimeMillis { get { return SafeNativeMethods.GetTickCount64(); } }
}
}
/*
Dual License (use either, not both). To avoid CC-BY-SA, access a copy of this
code at (https://pastebin.com/6EKTWsSf) to use under BSD 0-clause license,
Copyright (c) 2020 Robin Davies
CC-BY-SA 3.0 (due to StackExchange terms of use). Not my fault, blame StackExchange. Fix this
please, StackExchange!
BSD 0-Clause
Copyright 2020 Robin Davies.
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/