Lazarus

Programming => LCL => Topic started by: kinlion on May 17, 2019, 09:31:22 am

Title: Sleep(1) in thread's loop can reduce CPU usage much
Post by: kinlion on May 17, 2019, 09:31:22 am
I create a thread to listen to a pipe.
I found that if I put "sleep(1);" in thread.Execute's while-loop, the CPU usage of the application is nearly 0%, but when I put "yield;" instead, the CPU usage if about 25%.
It looks that let the thread sleep a minest while, say 1ms, is better than yield it.
BTW, I have tested that sleep(0) is similar to yield.

So, I think if a thread is NOT very time-critical, one should use sleep(1) to reduce the CPU usage.

Code: Pascal  [Select][+][-]
  1. procedure TMyThread.Execute;
  2. begin
  3.   while not Terminated do
  4.   begin
  5.     // do something
  6.     ...
  7.  
  8.     sleep(1); // To sleep 1ms will reduce CPU usage much.
  9.   end;
  10. end;
  11.  
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: marcov on May 17, 2019, 09:37:30 am
If it is for user interface, sleep(50) or even sleep (150) are good enough.

Rule of thumb is that humans notice interface delays only starting from about 250ms.   
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: devEric69 on May 17, 2019, 10:33:03 am
Quote
Rule of thumb is that humans notice interface delays only starting from about 250ms.

250ms is indeed for the most awake.
To get an overview of your reflexes (reaction time), you can test it here ^^: https://www.humanbenchmark.com/tests/reactiontime/index.php (https://www.humanbenchmark.com/tests/reactiontime/index.php)
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: Martin_fr on May 17, 2019, 02:04:27 pm
It depends exactly what you do.
I assume you do a none-blocking check on the pipe? You keep calling that, until you get some data. Then yes that will drive CPU usage up.

If you wait for a single piece of data, then sleep(150) will not hurt.

If you do back and forward communication (i.e. each time you receive something, you send the next bit, which will trigger the next response....) then even Sleep(10) can accumulate. It depends how fast the other side responds.

Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: marcov on May 17, 2019, 02:20:44 pm
Yeah. And if you are just polling for a signal, see if you can use a TEvent.

I use industrial cameras on windows, and many of their SDK have a grabmethod that you can give a custom TEvent.handle to signal abort. So you can blok on the grab forever, but still interrupt if you need to stop acquisition or do something else.

WaitforMultiple() are some of the nicest win32 api calls :-)
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: devEric69 on May 17, 2019, 04:44:51 pm
For  information, the equivalent of the Windows TEvent's methods are (if we need to read or write a string, or bitwise mask of [0, 1] - forming various communication tokens, or something else, on a comm. port, for example):
Code: Pascal  [Select][+][-]
  1. cthreads.pp . IntBasicEventCreate
  2. cthreads.pp . IntBasicEventDestroy
  3. cthreads.pp . IntBasicEventWaitFor
  4. .../...

(knowing that today, we can *name* a USB port "comm1" :) )
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: marcov on May 17, 2019, 04:56:52 pm
Afaik tevent is perfectly supported on Linux. Just not multiple waits  (waitmultiple), though there is sem_timedwait now.

The procedures that you name are simply the OS dependent interface (and starting with INT as in INTERNAL) for a reason.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: devEric69 on May 17, 2019, 05:08:41 pm
For what I know, I just saw TEvent for Windows targeted cross-compilation.

As for the search for CreateEvent, ResetEvent, etc., methods encapsulated in a Windows TEvent component, I didn't see it for a Linux target: I only found equivalent APIs in cthreads.pp.

Is there a TEvent for Linux in Lazarus?
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: furious programming on May 17, 2019, 06:36:31 pm
I found that if I put "sleep(1);" in thread.Execute's while-loop, the CPU usage of the application is nearly 0%, but when I put "yield;" instead, the CPU usage if about 25%.

Yep, but your Sleep(1) does not freeze the program for 1ms, and for much longer. It probably stops the program for about 16ms. The clock's resolution is not so high, so if you need to increase it, use the TimeBeginPeriod and TimeEndPeriod functions from the MMSystem unit.

But even if you call TimeBeginPeriod(1), the Sleep(1) will pause the program for 2ms — this procedure is not very precise for such small values.

If you want to know what is the possible timer lowest period, use TimeGetDevCaps and use the value from the wPeriodMin field in the TimeBeginPeriod call. Example below:

Code: Pascal  [Select][+][-]
  1. uses
  2.   MMSystem;
  3.  
  4.   // field to store the period
  5.   FTimerPeriod: Integer;
  6.  
  7. // somewhere at the beginning of the program code
  8. var
  9.   Periods: TTimeCaps;
  10. begin
  11.   if TimeGetDevCaps(@Periods, SizeOf(Periods)) = TIMERR_NOERROR then
  12.   begin
  13.     FTimerPeriod := Periods.wPeriodMin;
  14.     TimeBeginPeriod(FTimerPeriod);
  15.   end
  16.   else
  17.     FTimerPeriod := -1;
  18. end;
  19.  
  20. // somewhere at the end of the program code
  21. begin
  22.   if FTimerPeriod <> -1 then
  23.     TimeEndPeriod(FTimerPeriod);
  24. end;

I'm using such code in my platformer — changing system timer period is mandatory, works excellent.

Quote
BTW, I have tested that sleep(0) is similar to yield.

Sleep(0) does nothing, does not stop the program, so the processor's power consumption will still be full. The smallest actually working value for Sleep procedure is 1, and the real shortest break is that lasting 2ms.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: 440bx on May 17, 2019, 06:47:06 pm
@kinlion

I found that if I put "sleep(1);" in thread.Execute's while-loop, the CPU usage of the application is nearly 0%, but when I put "yield;" instead, the CPU usage if about 25%.
There is a lot of fun to be had with Sleep(0).  From what you typed, you have a computer with a quad-core.  If your computer had 8 cores, the CPU usage would have been slightly above 12.5%. (presuming the machine is not very busy with other processes.)  Keep digging into Sleep(0) and you'll learn a lot about how Windows works, particularly about how it schedules CPU time to processes.

So, I think if a thread is NOT very time-critical, one should use sleep(1) to reduce the CPU usage.
You got that right :)

Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: marcov on May 17, 2019, 08:03:56 pm
I found that if I put "sleep(1);" in thread.Execute's while-loop, the CPU usage of the application is nearly 0%, but when I put "yield;" instead, the CPU usage if about 25%.

Yep, but your Sleep(1) does not freeze the program for 1ms, and for much longer. It probably stops the program for about 16ms. The clock's resolution is not so high, so if you need to increase it, use the TimeBeginPeriod and TimeEndPeriod functions from the MMSystem unit.

But sleep works using the scheduler timer, probably some HPET thing, and not the RTC.

Quote
Sleep(0) does nothing, does not stop the program, so the processor's power consumption will still be full. The smallest actually working value for Sleep procedure is 1, and the real shortest break is that lasting 2ms.

Please inform Microsoft https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-sleep
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: Cyrax on May 18, 2019, 12:48:50 am
For what I know, I just saw TEvent for Windows targeted cross-compilation.

As for the search for CreateEvent, ResetEvent, etc., methods encapsulated in a Windows TEvent component, I didn't see it for a Linux target: I only found equivalent APIs in cthreads.pp.

Is there a TEvent for Linux in Lazarus?

Yes, Use SyncObjs unit.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: furious programming on May 18, 2019, 01:18:58 am
But sleep works using the scheduler timer, probably some HPET thing, and not the RTC.

Explain one thing to me. My platformer uses Sleep between frames to make delays (few ms). I checked how it works on Win10. Without using the TimeBeginPeriod function, the game maintains 41fps, and if I call it with a minimum period, it maintains 60fps.

Results of some quick research on timing in Win32 (http://www.geisswerks.com/ryan/FAQS/timing.html) — see the penultimate section. Old article, but helped me a lot.

I know it's not like Sleep(0) actually does anything. My point was that it does not freeze the program/thread, so 25% of the power consumption (100% of the core) is the expected value.

Quote
Please inform Microsoft https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-sleep

You don't have to believe me, just check it:

Code: Pascal  [Select][+][-]
  1. uses
  2.   Crt, Windows, MMSystem;
  3. var
  4.   TicksBegin: Int64 = 0;
  5.   TicksEnd: Int64 = 0;
  6.   TicksPerSecond: Int64 = 0;
  7. var
  8.   Time: Double;
  9. begin
  10.   QueryPerformanceFrequency(TicksPerSecond);
  11.  
  12.   repeat
  13.     QueryPerformanceCounter(TicksBegin);
  14.     Sleep(1);
  15.     QueryPerformanceCounter(TicksEnd);
  16.  
  17.     Time := (TicksEnd - TicksBegin) / (TicksPerSecond / 1000);
  18.     WriteLn(Time:2:2, 'ms');
  19.   until ReadKey() = 'e';
  20. end.
Code: Pascal  [Select][+][-]
  1. 1.39ms
  2. 1.90ms
  3. 1.73ms
  4. 1.88ms
  5. 1.96ms
  6. 1.85ms
  7. 1.88ms
  8. 1.88ms
  9. 1.87ms
  10. 1.92ms
  11. 1.90ms
  12. 1.88ms
  13. {..}

Tomorrow I will check it on Win10.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: marcov on May 18, 2019, 11:36:18 am
But sleep works using the scheduler timer, probably some HPET thing, and not the RTC.

Explain one thing to me. My platformer uses Sleep between frames to make delays (few ms). I checked how it works on Win10. Without using the TimeBeginPeriod function, the game maintains 41fps, and if I call it with a minimum period, it maintains 60fps.

The scheduler's timer is accurate, the preemptive scheduler is not :-)

I reacted to your

Quote
It probably stops the program for about 16ms.

Based on old 18.2 clock timer resolutions, which is simply not true.  Since Nehalem, hpet timers are in uncore and constant in frequency and quite precise. Windows will use whatever resources it have to try to keep it short.

Of course, reaction to the timer (polling, interrupt latency, or simply fair scheduling) does not.

If you have some precise timing requirements you can use realtime extensions, at the expense of the efficiency of scheduling.

Quote
Results of some quick research on timing in Win32 (http://www.geisswerks.com/ryan/FAQS/timing.html) — see the penultimate section. Old article, but helped me a lot.

Too old, one of the two test systems is win98 for christ sake!

Quote
I know it's not like Sleep(0) actually does anything. My point was that it does not freeze the program/thread, so 25% of the power consumption (100% of the core) is the expected value.

Quote
Please inform Microsoft https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-sleep

And with that I meant not the deviation, but the sleep(0) explicitely being mentioned there.
Read it.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: furious programming on May 18, 2019, 02:36:43 pm
The scheduler's timer is accurate, the preemptive scheduler is not :-)

Yes. 8)

Quote
I reacted to your

Quote
It probably stops the program for about 16ms.

Based on old 18.2 clock timer resolutions, which is simply not true.  Since Nehalem, hpet timers are in uncore and constant in frequency and quite precise. Windows will use whatever resources it have to try to keep it short.

[…]

Too old, one of the two test systems is win98 for christ sake!

I know that it is old, but is was halpful for me. So below you have a tests on modern systems. The low means that the test uses default time period, and the high additionally calls TimeBeginPeriod(1) before loop. The tester code is in my previous post.

Code: Pascal  [Select][+][-]
  1.      WinXP                 Win7                Win10
  2.  
  3.  low       high       low       high       low       high
  4.  
  5. 1.84ms    1.69ms     8.41ms    2.88ms    11.79ms    1.17ms
  6. 1.88ms    1.79ms    15.13ms    0.61ms     9.46ms    1.80ms
  7. 1.93ms    1.94ms    15.36ms    0.70ms    14.31ms    1.80ms
  8. 1.88ms    1.93ms    15.52ms    0.64ms    14.89ms    1.88ms
  9. 1.88ms    1.93ms    15.19ms    0.62ms    14.99ms    1.89ms
  10. 1.88ms    1.92ms    15.35ms    0.44ms    14.68ms    1.87ms
  11. 1.88ms    1.93ms    15.54ms    0.59ms    15.08ms    1.72ms
  12. 1.88ms    1.88ms    15.54ms    0.55ms    15.47ms    1.87ms
  13. 1.92ms    1.89ms    15.53ms    0.57ms    15.37ms    1.87ms
  14. 1.88ms    1.89ms    15.45ms    0.58ms    15.01ms    1.88ms
  15. 1.88ms    1.88ms    15.15ms    0.59ms    14.87ms    1.86ms
  16. 1.88ms    1.93ms    15.43ms    0.82ms    15.03ms    1.90ms
  17. 1.88ms    1.93ms    15.17ms    0.58ms    14.99ms    1.84ms
  18. 1.93ms    1.88ms    15.52ms    0.73ms    14.70ms    1.88ms
  19. 1.91ms    1.81ms    15.19ms    0.59ms    15.19ms    1.88ms

There is something strange with the results of the high test on Win7 — the Sleep(1) freezes the thread for less than millisecond, on other systems, close to the 2ms. But the default period is about 15ms on both modern systems, so I was so close to the truth.

But this is not important. No matter who is right — if we use the Sleep procedure, we must take into account its inaccuracy.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: marcov on May 18, 2019, 02:43:06 pm
Note that comparing Windows versions that are not the same bittiness and not the same processor (and preferably also mobo chipset) is pointless. The same functions might use other implementations on different hardware, as I already said.

There is an version factor in that only newer versions might use newer hardware however.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: furious programming on May 18, 2019, 02:47:26 pm
If we designing the software, we do it in the way that it will work perfect on all supported systems (both bitness in the case of 32-bit application), on all processors and all hardware. If these differences are not taken into account, the software will be crappy.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: marcov on May 18, 2019, 02:56:58 pm

My point is that listing differences between "windows versions" without listing bittiness or the hardware (like processor generation) they run on is pointless
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: kinlion on May 20, 2019, 03:22:28 am
Learned a lot. Thanks to all  :)
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: bylaardt on May 20, 2019, 03:45:32 am
My point was that it does not freeze the program/thread,
why sleep?

can't you just use this code instead?
Code: Pascal  [Select][+][-]
  1. Application.ProcessMessages;
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: Cyrax on May 20, 2019, 11:39:10 am
My point was that it does not freeze the program/thread,
why sleep?

can't you just use this code instead?
Code: Pascal  [Select][+][-]
  1. Application.ProcessMessages;

Nope, you can't use Application.ProcessMessages from a thread. There will be a deadlock (or other disaster) if you call it in a context of thread.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: Thaddy on May 20, 2019, 11:46:49 am
Also note Sleep(0) means "relinquish time slice" whereas sleep(1) will do an actual stall. So Sleep(0) is what should be done....
This is weird, but true... Sleep(0) is a special case.... for threading...Sleep(1) is an actual sleep that causes this problem.
See: https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-sleep which is somewhat obscure and needs a good read....
https://stackoverflow.com/questions/3727420/significance-of-sleep0#3727460
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: 440bx on May 20, 2019, 11:55:52 am
Also note Sleep(0) means "relinquish time slice"
That's what it's _supposed_ to mean. 

So Sleep(0) is what should be done....
That's what people who believe the documentation think.   

This is weird, but true... Sleep(0) is a special case.... for threading...
You got that right.  It is a _very_ special case.

The API documentation is quite often what Microsoft wants you to believe, which is almost just as often, quite different from reality.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: furious programming on May 20, 2019, 12:30:19 pm
why sleep?

can't you just use this code instead?
Code: Pascal  [Select][+][-]
  1. Application.ProcessMessages;

No, I can't. The Sleep procedure is used to freeze the operation of the program for a specified time, so that the process or single thread does not consume the processor's power. The ProcessMessages method is used to process messages that are in the queue. As you can see, these are two different things.

Even if we could safely call this method in the side thread, it does not make sense, because in no way will it freeze the thread operation and, at the same time, save the processor's power.

I wrote about the operation of the Sleep procedure because OP was ”surprised” that calling it with a value of 0 causes a power consumption jump of up to 25% (i.e. 100% of one processor core that executes the thread code), and a call with a value of 1 does not.

However, I wrote about the accuracy of this procedure, because on practically every computer, for the same value of 1, the delay will be different and depend of the default system time period. So if someone uses this procedure with the idea of creating relatively precise delays, he must take into account the mentioned imperfection.


That's what it's _supposed_ to mean.

It's not as easy as it seems. What else to understand what these words mean, and what else to know what they actually mean in practice. And the documentation does not explain this in any way.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: bylaardt on May 20, 2019, 03:37:57 pm
Nope, you can't use Application.ProcessMessages from a thread. There will be a deadlock (or other disaster) if you call it in a context of thread.
I've always used application.processmessages on synchronize.
What's so bad about it?
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: furious programming on May 20, 2019, 05:01:40 pm
I've always used application.processmessages on synchronize.

Okay, but what is the purpose of calling this method?
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: bylaardt on May 20, 2019, 06:48:46 pm
Okay, but what is the purpose of calling this method?
to prevent core freezing.
I can improve the control of multiple parallel processes with a higher time response.
When the pipe has no system events and the data is asynchronous, waiting one millisecond for a response may be the worst solution.
PS: It's just part of the brainstorm, not a ultimate solution
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: 440bx on May 20, 2019, 10:14:40 pm
That's what it's _supposed_ to mean.

It's not as easy as it seems. What else to understand what these words mean, and what else to know what they actually mean in practice.
It's not really hard either.  A few small, well chosen, trivial test programs are very revealing about Sleep(0) and the Windows scheduler.

And the documentation does not explain this in any way.
That is true.  There are plenty of APIs to which that comment applies to some degree.  Another example of one like that, a very simple one that comes to mind at this time, is GetWindowModuleFileName https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowmodulefilenamea (https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowmodulefilenamea).  What the documentation leads you to believe about what it does and, what it actually does, are two different things.  That said it occasionally does what the documentation says. <chuckle>


Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: BrunoK on May 21, 2019, 11:33:05 am
I've always used application.processmessages on synchronize.

Okay, but what is the purpose of calling this method?
Maybe give the application a chance to process OnIdle "messages" since the application thread may be suspended due to an absence of  OS message activity ?
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: User137 on May 21, 2019, 05:08:37 pm
Sleep(1) is a nice thing indeed. It's the core of cpu saving in nxPascal game engine too. This is old (but very functional still) code from 2013:
https://github.com/Zaflis/nxpascal/blob/master/src/nxGame.pas#L147
Smooth 60 FPS animation still should always include it, regardless of its inaccuracy. Players won't see it, other than in the silentless of their cpu coolers.

But in principle if the OS causes sleep to take too long it processes 2 events in a row without sleeping between.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: scribly on May 22, 2019, 11:36:06 am
When sleep(0) is executed it checks which thread is currently not in a wait state and pass the execution on to that thread
That will most of the time result in the calling thread being picked because most other threads will be in a wait state (cpu % usage is just an inverted indication of how long the cpu is sleeping in a low power state waiting for a thread to wake up)

so unless your system is always running at 100% sleep(0) is not that useful and is not meant to lower power usage
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: marcov on May 22, 2019, 02:10:32 pm
Scribly: That's about what I know about it too.  Before multicore systems, there were more threads waiting, and it made more sense.

The first thing to do is avoid sleeps alltogether, since they are an indication of polling and latency. Wait on semaphores with a timeout allows also to do housekeeping once in a while, but if some other thread signals a chance it can interrupt immediately, so the sleeps can be much longer.

However it requires a waitfor with a timeout. I do most my multithreading programming on Windows currently, and then it is there. Afaik for linux it is now also there (based on sem_timedwaitfor or so), but that is relatively new, and maybe not yet in released versions
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: Thaddy on May 22, 2019, 03:48:32 pm
They are really distinct. Pseudo code:
Code: Pascal  [Select][+][-]
  1. var Amount: word  =0;
  2.  if sleep(amount) then
  3.     RelinguishTimeSlice // this is not a sleep!!!! but a signal...
  4.   else
  5.     RealSleep(amount);// not a signal, but a timer and can block...Do not use in multi-threading if you do not know the amount of cores
Sleep(0) has a different code path as can be seen in a good debugger (Ice, OllyDebug)

I don't think this has changed since the 90's. If so, I am wrong for a very long time (since NT3.5/Win3.1).
In Unix like systems this works different: that simply does not misuse a timer signal for a shorthand to a semaphore...
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: marcov on May 22, 2019, 04:36:46 pm
I don't think this has changed since the 90's. If so, I am wrong for a very long time (since NT3.5/Win3.1).

What has changed is the chance that a thread is waiting (since other tasks can run on other cores, and don't have to compete with a program running anymore), and the chance that the machine would be prohibited from going into low power state without the same thread continously being rescheduled, only to reliquish it nearly directly again with sleep(0).

As a form of possible busywaiting, the principle was just as bad in the nineties, it only mattered less.

Quote
In Unix like systems this works different: that simply does not misuse a timer signal for a shorthand to a semaphore...

Since Unix does not have waitmultiple, it is even more important to be able to regularly pauze waiting on one semaphore....
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: Thaddy on May 22, 2019, 04:51:52 pm
Those are the points. I Agree with that.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: 440bx on May 22, 2019, 09:25:21 pm
The first thing to do is avoid sleeps alltogether, since they are an indication of polling and latency.
That is bad advice.  Sleep(n) where n > 0 is simply a mechanism to inform the scheduler the thread does not require CPU cycles.   

One of the nice things about Sleep is that it doesn't require the application to create an object to wait on and the O/S to maintain and pay attention to it.  Sleep is very low overhead and lets the O/S know that for n milliseconds, the thread doesn't need any attention.

In addition to that, there are events for which there are no available objects that can be created to wait on.  e.g, at least in Windows, you can't wait on some window that belongs to another process to finish painting itself.

Polling, if done well, can be more efficient than waiting on an object (which the O/S scheduler has to pay attention to.)  A good combination of SRW locks and Sleep can produce much better results than using objects to wait on.  If you doubt that, compare the performance of Mutexes and Critical sections.   Using mutexes is higher overhead and roughly 1/20 the performance and a lot more work for the O/S.


Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: Peter H on May 22, 2019, 10:38:38 pm
Yes.
A good example ist multithreadingexample1 from Lazarus example code.
It refreshes the screen in an infinite loop and consumes a lot of CPU.
There is no reason to refresh the screen a thousand times per second.  8-)
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: scribly on May 22, 2019, 11:42:02 pm
I've attached an example project showing a scenario where sleep(0) has an effect as opposed to no sleep at all

When no sleep is used, the consumer thread will constantly read the value 0 over and over until it relinquishes it's allotted timeslice to the producer thread. Basically wasting a lot of cycles doing nothing but eating cpu power
When sleep(0) (or yield) is used the two threads will swap between eachother (and sometimes other threads in the system) wasting less time. It is of course slower than with no sleep at all
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: 440bx on May 23, 2019, 01:42:26 am
I've attached an example project showing a scenario where sleep(0) has an effect as opposed to no sleep at all
That is not a conclusion that can be derived from the example you attached.

I've modified your example to show what really happens.  You'll notice that calling sleep(0) can be said to have no effect at all.

To get the most out of the example, run it under the Lazarus debugger, set the console buffer to 9999 lines (the maximum) and make it run.

Pay attention to how much CPU is used in both cases (task manager or processhacker would help with that.)  You'll find that, there really isn't a difference when Sleep(0) is used, nor does the flip flopping between one thread and the other change.

Also, I didn't get rid of the array because I wanted you to see that the values shown in the listview are not even close to what is happening in reality.  The reality is what's displayed in the console.

You can get rid of the timer, the listview and the dynamic array.  They don't make any useful contribution.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: scribly on May 23, 2019, 08:36:26 am
I can't see what you mean. I've attached an image with the output. Left is no sleep, right is with sleep.
As you see left is reading out the old value many times while right it reads more evenly

this is on an intel i9-7960x at 2.8GHz

Also, I have to mention writeln, which uses locks to make sure the output buffer isn't accessed at the same time by other threads and when the buffer does go full eventually will cause a full sleep till the buffer is processed(while holding the lock), so not sure if you want to use that to show of threading or ever use in anything that's cpu intensive
(Changing the loops to infinite loops shows that with writeln the cpu usage is only 1/3th of it's max while when it's removed it'll go to 100%
And yes, it'll also go to 100% with sleep(0) because that's what it is supposed to do, pick a thread that isn't sleeping)

Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: marcov on May 23, 2019, 09:45:53 am
The first thing to do is avoid sleeps alltogether, since they are an indication of polling and latency.
That is bad advice.  Sleep(n) where n > 0 is simply a mechanism to inform the scheduler the thread does not require CPU cycles.   

Then it shouldn't either not be running (in case it only polled), or it should block to the next time it should actually do something.

Sleep(n) is not just saying that you don't  need cycles now, but at the same time a request to get them in "n". My reasoning is that THAT should be
avoided if possible.

Quote
One of the nice things about Sleep is that it doesn't require the application to create an object to wait on and the O/S to maintain and pay attention to it.  Sleep is very low overhead and lets the O/S know that for n milliseconds, the thread doesn't need any attention.

Objects can be reused. For the variation in overhead I'd like a reference. Afaik in both cases it is a scheduler lock on a condition.

Quote
In addition to that, there are events for which there are no available objects that can be created to wait on.  e.g, at least in Windows, you can't wait on some window that belongs to another process to finish painting itself.

There are always exceptions, and that was never denied. We are talking about the general case here. (and even then there is a lot possible with waitmultiplemessage variants)

Quote
Polling, if done well, can be more efficient than waiting on an object (which the O/S scheduler has to pay attention to.)  A good combination of SRW locks and Sleep can produce much better results than using objects to wait on.  If you doubt that, compare the performance of Mutexes and Critical sections.   Using mutexes is higher overhead and roughly 1/20 the performance and a lot more work for the O/S.

Afaik mutexes that are cross-apllication (global) in nature are fairly slow. Non named ones used within one process afaik aren't.
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: 440bx on May 23, 2019, 12:34:35 pm
@scribly

I can't see what you mean. I've attached an image with the output. Left is no sleep, right is with sleep.
As you see left is reading out the old value many times while right it reads more evenly
I cannot comment on the screenshot you posted because you didn't post the code that produced it.  The modified example I posted, shows very clearly that sleep has little to no effect on thread switching in that case.

Also, I have to mention writeln, which uses locks to make sure the output buffer isn't accessed at the same time by other threads and when the buffer does go full eventually will cause a full sleep till the buffer is processed(while holding the lock), so not sure if you want to use that to show of threading or ever use in anything that's cpu intensive
There will not be a "full sleep" until the buffer is processed.  When both threads send text to conhost.exe (which is a separate process), one thread will be blocked until the request to write from the other thread is complete but, that doesn't imply a thread switch to the other thread in the same process.

I agree that the writeln has an effect on how the results are presented but, the writeln(s) are not what causes the scheduler to decide which thread gets to run next.  As long as a thread has not used up its time slice, it will, generally speaking because there are other threads running in the system, keep running until it uses it up.

Post the program that produced that output.   

@marcov

Then it shouldn't either not be running (in case it only polled),
That's what "sleep" is for, to "not run", to let the scheduler know that the thread doesn't need any clock cycles.

or it should block to the next time it should actually do something.
When the thread is awaken, it will do something.  In the meantime, it doesn't use up system resources and scheduler clock cycles with synchronization objects.

Sleep(n) is not just saying that you don't  need cycles now, but at the same time a request to get them in "n".
No, that is not correct.  Sleep is not a request to get clock cycles after n milliseconds have elapsed.  The thread may, or may not, get clock cycles after n milliseconds.  This is the reason why sleep is considered by many to be "inaccurate", because of the mistaken belief that after the time has elapsed the scheduler will run it.

My reasoning is that THAT should be avoided if possible.
What should be avoided is to cause the scheduler to waste clock cycles on a thread that doesn't need them. That's what sleep(n) does.

Objects can be reused. For the variation in overhead I'd like a reference. Afaik in both cases it is a scheduler lock on a condition.
Yes, synchronization objects can definitely be reused.  The overhead is simple, a mutex causes a ring transition from ring3 to ring0 and requires scheduler clock cycles to determine if the mutex is signaled and then additional clock cycles once it's been signaled to find which thread(s) was/were waiting for the object to be signaled.

If you want to measure the best case overhead, simply code a loop that waits and releases a mutex about a 1,000,000 times.  That will give you an idea of a mutex cost.  Do the same thing for critical sections and Sleep(1) (shorten the loop for that last one:)) then compare the results (and pay attention to the CPU consumption in all cases.)

There are always exceptions, and that was never denied. We are talking about the general case here. (and even then there is a lot possible with waitmultiplemessage variants)
Marco, the point was that using Sleep is a good thing, and not something to be avoided. A thread should let the processor know when it doesn't need attention.  The thread that definitely should NOT be calling "sleep" is the thread that pumps messages.

As far as the general case, I'm inclined to believe it is more of synchronization between threads within the same process and not different processes.  For threads within the same process, polling using sleep produces code that is simpler, isn't subject to deadlocks and, uses less CPU. That said, it can be a bit slower than using some sort of synchronization, in those cases critical sections are usually a good option.  A combination of TryEnterCriticalSection and Sleep often produces excellent results.

Afaik mutexes that are cross-apllication (global) in nature are fairly slow. Non named ones used within one process afaik aren't.
I haven't tested the performance of unnamed mutexes but, if this is correct https://stackoverflow.com/questions/1666653/are-mutexes-really-slower (https://stackoverflow.com/questions/1666653/are-mutexes-really-slower) then unnamed mutexes are still kernel objects with all the associated overhead of a named mutex.

Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: scribly on May 23, 2019, 12:58:42 pm
Quote
Post the program that produced that output. 

the code you posted without any changes
https://youtu.be/3nHpf54_bwA

it's possible windows 10 'fixed' sleep. I tested it on an old win7 and there there is no difference between no sleep and sleep(0) (also slow cpu but not sure if that matter)
Title: Re: Sleep(1) in thread's loop can reduce CPU usage much
Post by: 440bx on May 23, 2019, 02:14:16 pm
Quote
Post the program that produced that output. 

the code you posted without any changes
https://youtu.be/3nHpf54_bwA

it's possible windows 10 'fixed' sleep. I tested it on an old win7 and there there is no difference between no sleep and sleep(0) (also slow cpu but not sure if that matter)

Very nicely done :)

I was looking at the video you posted and, it does look like, under Windows 10 Sleep(0) does cause a thread switch.  Under Windows 7 (which I am using) and older versions of Windows, it does not.

The CPU speed affects the results only at the top and bottom of the output.  One of the threads is going to start executing first, that will cause the other thread to output several lines at the bottom because it started later and couldn't catch up until the other one ended.

It would be really nice if they had fixed that problem with Sleep(0) in Windows 10 (about time they did too.)  There are a fair number of commercial programs that used Sleep(0) which caused them to use 100% of a core (the old Turbo Debugger - TD32.EXE - is one of them.)

But, even if they fixed it in Windows 10, I'd still use Sleep(1) to ensure the program is "friendly" to older versions of Windows.

Thank you for that video. 

TinyPortal © 2005-2018