0

This question been asked several times before in different variations, but I still don't quite get it.

I need to find a way to trigger a while loop at exactly (or very very closely) to when a millisecond changes.

The idea is that the first while loop will wait for that period of time - the time between milliseconds, and once a millisecond changes (or very very close to such change), start doing whatever needed (at the moment count the amount of iterations it can do in 1 MS).

My question is, is my time calculation correct about the MS change and loop timings?

If so, why does the output is not consistent? or at least outputs close numbers? (because in theory, the loop should run for approx. The same amount of time therefore the approx. same amount of iterations should occur), and if so maybe the reason it outputs such numbers is because the process "looses CPU" in runtime?

I don't mind doing this in c or c++ if needed

This is my current code (using c#):

{
    int incerments_per_ms = 0;
    const long ticks_per_ms = 10000; //10000 ticks per ms 

    var start = DateTime.Now.Ticks;//get current time in ticks since jan 1st 2000 00:00

    while ((DateTime.Now.Ticks - start) <= nano_seconds_in_ms) { }
    start += ticks_per_ms;//raise 1 ms 
    while ((DateTime.Now.Ticks - start) <= nano_seconds_in_ms)
    {
        incerments_per_ms++;
    }

    Console.WriteLine(incerments_per_ms.ToString());

    if (min == 0)
        min = incerments_per_ms;

    if (min > incerments_per_ms)
        min = incerments_per_ms;

    if (max < incerments_per_ms)
        max = incerments_per_ms;

    sum += incerments_per_ms;
}

int avg = sum / iterations;

Console.WriteLine("minimum is: " + min.ToString());
Console.WriteLine("maximum is: " + max.ToString());
Console.WriteLine("average is: " + avg.ToString() + "\n\n\n");

Output for 50 iterations:

0
6582
6601
6509
5248
6423
6710
4901
6499
6187
6426
6573
6545
6450
6567
4786
6582
6919
7018
6393
5990
6432
6084
5589
5396
6357
6578
6577
6557
7182
5137
6472
6543
6321
6533
6956
6811
2846
6269
5739
6307
5740
3673
5609
5440
5857
6561
4379
6026
6162
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
alws34
  • 45
  • 1
  • 6
  • 2
    Yes, your code will be interrupted by other processes or even other threads in your process so the speed it runs at will vary. Your cpu probably also doesn't run at a constant speed – Alan Birtles Nov 05 '21 at 07:59
  • 3
    To get this kind of precision you'll usually also need some sort of RT patch. Other processes running in the background will likely also require a good chunk of CPU time. The thing about sleeping is, that you're generally not guaranteed anything. At most, you'll be guaranteed **at least** X time. – SimonC Nov 05 '21 at 08:10
  • 1. should i use a mutex? 2. is there a way to "force" the cpu to work in a certain clock speed? - for at least x amount of time? – alws34 Nov 05 '21 at 08:15
  • 2
    Why do you need to have your code run at a specific speed? Without a real time operating system there isn't much more than you are already doing that you can do. You can run your process at a higher priority. You can disable turbo boost in your computer's BIOS but that'll just make your computer slower – Alan Birtles Nov 05 '21 at 08:20
  • 4
    Windows is not a realtime OS, so no. – Jeroen van Langen Nov 05 '21 at 08:21
  • 1
    so these is the best i can do on windows? – alws34 Nov 05 '21 at 08:30
  • 2
    See also [High resolution timers](https://stackoverflow.com/questions/24839105/high-resolution-timer-in-c-sharp) – JonasH Nov 05 '21 at 08:38
  • 3
    also note that the resolution of `DateTime.Now` varies, and may be as low as 16ms, so it should not be relied upon for anything that needs high precision. – JonasH Nov 05 '21 at 08:40
  • If your question is about C# then don't add a lot of other irrelevant language tags to the post. "...the time between milliseconds and once a millisecond changes" Then don't use any of the following tools: C#, Windows, a PC. – Lundin Nov 05 '21 at 08:45
  • @Lundin, I would appreciate a higher precision - if such can be achieved with c or c++, as mentioned I don't mind doing this measurement in these languages. – alws34 Nov 05 '21 at 08:53
  • 1
    @ALWS34 The language is somewhat irrelevant. Your operating system (and in the end your bare metal) must be able to make such guarantees. You can think about your language choice when you have hardware that is real-time capable and installed a real time OS on it. – Fildor Nov 05 '21 at 08:55
  • @ALWS34 Yes well this isn't a place where you can go and tell others to write code for you in any language. As I already told you, you are not likely to get finer real-time accuracy when using the tools C#, Windows and PC. Replacing C# with something else still leaves you with the Windows and PC problems left to solve. – Lundin Nov 05 '21 at 08:57
  • 1
    Take a look at: [How can I get the Windows system time with millisecond resolution?](https://stackoverflow.com/questions/3729169/how-can-i-get-the-windows-system-time-with-millisecond-resolution), [High-Resolution Timers (Windows Drivers)](https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/high-resolution-timers), [SysInternals Tool to lookup the lock resolution](https://learn.microsoft.com/en-us/sysinternals/downloads/clockres) – kapsiR Nov 05 '21 at 09:23
  • @Lundin, I never "told" anyone to write code for me. I asked for a pure professional opinion and help, and wrote a code myself to try out and ask about (the code I posted is one of many different things I tried prior of asking here). I merely asked if there might be a solution in c or CPP because these are lower level languages and might have more control of what's going on behind the curtain. This argument is unnecessary and I'm ending it right now. about the OS/machine/language, I do appreciate the help and professional opinion and understood my conceptual error in this matted – alws34 Nov 05 '21 at 09:53
  • Thanks everyone for your help and consult, I will try doing it on a real time OS with supported hardware with the mentioned factors and referrals in mind. I will post a solution once I get it to work. – alws34 Nov 05 '21 at 09:55
  • @ALWS34 Your code is in C# so you shouldn't be poking C or C++ programmers to read your post, because they might be completely uninterested in it and/or unable to answer it. So adding multiple unrelated language tags is a certain method to get your question heavily down-voted around here. Which in turn can lead to a question ban for new users. I removed those extra tags for you before that happened. – Lundin Nov 05 '21 at 10:02

1 Answers1

0

This is a totally nonsensical solution, and it's not going to be perfectly accurate for obvious reasons.

The premise is, just time a bunch of SpinWait(10), then set the resolution. Obviously there are many other ways to do this with varying degrees of success.

You can expand on the following of course and adjust to taste, it's able to resolve millisecond timing in the most part (in C#), with drift on my pc of 0.01 ms:

const int cycles = 10000000;

var s = Stopwatch.StartNew();
for (int i = 0; i < cycles; i++)
   Thread.SpinWait(10);

s.Stop();

var spinRate = cycles / s.ElapsedMilliseconds;

Console.WriteLine($"Time Taken {s.ElapsedMilliseconds}ms");
Console.WriteLine($"spinRate {spinRate}");

var ticks = DateTime.Now.Ticks;

var array = new string[100];

for (var i = 0; i < 100; i++)
{
   for (var j = 0; j < (int)spinRate; j++)
      Thread.SpinWait(10);

   array[i] = $"Ticks at : {((DateTime.Now.Ticks - ticks) / (double)10000)}ms";
}

Console.WriteLine(string.Join(Environment.NewLine, array));

Output

Time Taken 3375ms
spinRate 2962
Ticks at : 1.6557ms
Ticks at : 3.5533ms
Ticks at : 4.5521ms
Ticks at : 5.5597ms
Ticks at : 6.5644ms
Ticks at : 7.5631ms
Ticks at : 8.5544ms
Ticks at : 9.554ms
Ticks at : 10.5443ms
Ticks at : 11.5346ms
Ticks at : 12.5354ms
Ticks at : 13.6026ms
Ticks at : 14.7118ms
Ticks at : 15.7672ms
Ticks at : 16.758ms
Ticks at : 17.7482ms
Ticks at : 18.813ms
Ticks at : 19.8041ms
Ticks at : 20.795ms
Ticks at : 21.7858ms
Ticks at : 22.7817ms
Ticks at : 23.7728ms
Ticks at : 24.7637ms
Ticks at : 25.7543ms
Ticks at : 26.7448ms
Ticks at : 27.7735ms
Ticks at : 28.8142ms
Ticks at : 29.8768ms
Ticks at : 30.868ms
Ticks at : 31.8593ms
Ticks at : 32.9084ms
Ticks at : 33.8998ms
Ticks at : 34.8902ms
Ticks at : 35.9574ms
Ticks at : 36.9484ms
Ticks at : 37.9449ms
Ticks at : 38.936ms
Ticks at : 39.9268ms
Ticks at : 40.9171ms
Ticks at : 41.9079ms
Ticks at : 42.9165ms
Ticks at : 43.9077ms
Ticks at : 44.898ms
Ticks at : 45.8881ms
Ticks at : 46.9491ms
Ticks at : 47.9401ms
Ticks at : 48.9311ms
Ticks at : 49.9219ms
Ticks at : 50.9127ms
Ticks at : 51.9754ms
Ticks at : 53.004ms
Ticks at : 53.9949ms
Ticks at : 54.9851ms
Ticks at : 55.9759ms
Ticks at : 56.9666ms
Ticks at : 57.9568ms
Ticks at : 58.9778ms
Ticks at : 59.9696ms
Ticks at : 60.9644ms
Ticks at : 62.0114ms
Ticks at : 63.0707ms
Ticks at : 64.0622ms
Ticks at : 65.1154ms
Ticks at : 66.1062ms
Ticks at : 67.0963ms
Ticks at : 68.111ms
Ticks at : 69.1789ms
Ticks at : 70.1699ms
Ticks at : 71.1601ms
Ticks at : 72.1502ms
Ticks at : 73.1409ms
Ticks at : 74.1311ms
Ticks at : 75.1287ms
Ticks at : 76.1199ms
Ticks at : 77.1101ms
Ticks at : 78.1003ms
Ticks at : 79.0907ms
Ticks at : 80.1556ms
Ticks at : 81.1466ms
Ticks at : 82.1373ms
Ticks at : 83.1736ms
Ticks at : 84.1645ms
Ticks at : 85.2285ms
Ticks at : 86.2196ms
Ticks at : 87.2104ms
Ticks at : 88.2008ms
Ticks at : 89.1911ms
Ticks at : 90.2238ms
Ticks at : 91.2148ms
Ticks at : 92.2055ms
Ticks at : 93.1964ms
Ticks at : 94.1871ms
Ticks at : 95.1774ms
Ticks at : 96.1681ms
Ticks at : 97.2371ms
Ticks at : 98.308ms
Ticks at : 99.2993ms
Ticks at : 100.2903ms
Ticks at : 101.2808ms
Ticks at : 102.3488ms
halfer
  • 19,824
  • 17
  • 99
  • 186
TheGeneral
  • 79,002
  • 9
  • 103
  • 141