Recent

Author Topic: Synchronize not working  (Read 30871 times)

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Synchronize not working
« Reply #30 on: November 26, 2021, 01:36:58 pm »
It isn't and the fact that it consumes 100% of a core proves it.  If the thread was sleeping for _any_ amount of time, it wouldn't be consuming 100% of a core.

Are you trying to tell me that your monitoring utility calculates and displays this to full floating point precision? Because these days the amount of time required for the scheduler to spin amounts to a mere rounding error.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Synchronize not working
« Reply #31 on: November 26, 2021, 02:11:33 pm »
It would be interesting to see how two processes on the same CPU (e.g. via CPU pinning in task manager) behave if one does the following:
Code: Pascal  [Select][+][-]
  1. While True do;
and the other one does:
Code: Pascal  [Select][+][-]
  1. While True do Sleep(0);
I would guess that the second one should get a much smaller slice of the CPU time. But sadly I don't have the ability to test it right now

Got to do the test. Started two processes, spin.exe and sleep.exe. Spin spins with:
Code: Pascal  [Select][+][-]
  1. While True do;
While sleep does:
Code: Pascal  [Select][+][-]
  1. While True do Sleep(0);
When I pin then to different cores (Spin to CPU 10 and Sleep to CPU11) both take up 100% of that CPU (and 4% of the total usage, which exactly what you would expect when using 24 virtual CPUs). If I pin both on them to the same core (CPU 10), the spin takes up 100% of CPU time while sleep takes up 0% (of course rounding errors are included).

So Sleep(0) is behaving exactly as expected. It will call the scheduler and if there is no other process to schedule (because there are simply not so many tasks on a multicore system), it will immediately be rescheduled resulting in 100% CPU usage anyway.
If there is another process that takes CPU time, this process will be scheduled instead, resulting in a much smaller CPU share.
For good measure I also checked what happens when I assign two spin processes to the same CPU, which results in both of them getting 50% of the CPU time. And the same happens when starting two sleep processes on the same CPU.

Therefore Sleep behaves exactly as expected. It's just that the scheduler is so fast that it does not have a notable impact on the CPU usage

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Synchronize not working
« Reply #32 on: November 26, 2021, 02:20:45 pm »
Are you trying to tell me that your monitoring utility calculates and displays this to full floating point precision?
No, that's not what I've tried to say.  What I say is very simple: if the thread was giving up part of its time slice then it would NOT show a _consistent_ usage of 100% of a CPU  because the thread would actually spend some time _sleeping_.

As far as the utilities to watch the process, those include Process Explorer, Process Hacker and Task Manager among others.  They all agree, Sleep(0) causes a thread that has a loop with such a call to consume 100% of a core.  Also, the CPU says it too but, a different way, the fan starts revving faster.  Not only you can see the 100%, on some machines you can hear it too.


So Sleep(0) is behaving exactly as expected. It will call the scheduler and if there is no other process to schedule (because there are simply not so many tasks on a multicore system), it will immediately be rescheduled resulting in 100% CPU usage anyway.
Absolutely not.   Sleep tells the scheduler "don't schedule me", "don't give me clock cycles", it does not mean "put me to work", it means: for whatever the remaining amount of time I had left in the time slice, I want to do _nothing_.   It tells the scheduler, NOT to schedule the thread and, if the scheduler was doing that, that thread could never use 100% of a core.

Sleep does NOT behave as documented.  It does NOT.  If it did, the thread would not consume 100% of the CPU.

What you guys are saying is that, if some thread calls Sleep(3000) but, the system has nothing to do, the scheduler would reschedule the thread immediately completely disregarding the request to not be given any clock cycles the specified amount of time and, we know that is not what happens _except_ when the call is Sleep(0).

You want to write lousy code that hogs a cpu, put calls to Sleep(0) in there.  Be my guest.



« Last Edit: November 26, 2021, 02:22:16 pm by 440bx »
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Synchronize not working
« Reply #33 on: November 26, 2021, 02:29:50 pm »
@440bx: I'm disappointed that at your age you've never learnt what "zero" means :-)

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Synchronize not working
« Reply #34 on: November 26, 2021, 02:41:20 pm »
@440bx: I'm disappointed that at your age you've never learnt what "zero" means :-)

MarkMLl
At whatever your age is, I'm disappointed you haven't learned the meaning of "whatever remains of the time slice", which will very rarely be zero.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Synchronize not working
« Reply #35 on: November 26, 2021, 03:07:47 pm »
Absolutely not.   Sleep tells the scheduler "don't schedule me", "don't give me clock cycles", it does not mean "put me to work", it means: for whatever the remaining amount of time I had left in the time slice, I want to do _nothing_.   It tells the scheduler, NOT to schedule the thread and, if the scheduler was doing that, that thread could never use 100% of a core.

Sleep does NOT behave as documented.  It does NOT.  If it did, the thread would not consume 100% of the CPU.
Let's see the documentation: https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep
Quote
A value of zero causes the thread to relinquish the remainder of its time slice to any other thread that is ready to run. If there are no other threads ready to run, the function returns immediately, and the thread continues execution.
"If there are no other threads ready to run [...] the thread continues execution" sounds exactly as if it would result in 100% CPU usage. This behavior is fully compliant with the documentation. Also note that the doc specifically mentions that the function returns immediately, so it doesn't even go through the scheduler. It simply checks if there is another thread in queue, if yes it calls the scheduler if no it simply returns and has no effect on the scheduling behavior
« Last Edit: November 26, 2021, 03:10:23 pm by Warfley »

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Synchronize not working
« Reply #36 on: November 26, 2021, 03:27:30 pm »
Let's see the documentation: https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleep
Quote
A value of zero causes the thread to relinquish the remainder of its time slice to any other thread that is ready to run. If there are no other threads ready to run, the function returns immediately, and the thread continues execution.
"If there are no other threads ready to run [...] the thread continues execution" sounds exactly as if it would result in 100% CPU usage. This behavior is fully compliant with the documentation. Also note that the doc specifically mentions that the function returns immediately, so it doesn't even go through the scheduler. It simply checks if there is another thread in queue, if yes it calls the scheduler if no it simply returns and has no effect on the scheduling behavior
I'm pleased you read the documentation.

The documentation also says this:(look in the Remarks)
Quote
If you specify 0 milliseconds, the thread will relinquish the remainder of its time slice but remain ready. Note that a ready thread is not guaranteed to run immediately.
Supposedly, the thread relinquishes the remainder of its time slice (that's what the documentation says), goes into the ready state and, there is supposedly no guarantee that it will run immediately (yet, "amazingly" it does.)

The part that in bold is very clear.  If the thread relinquished the remainder of its time slice, it could not consume 100% of CPU.  The only way that can happen is if the scheduler does not put the thread to sleep for the remainder of the time slice and, worse, to consume 100% of the CPU, the scheduler has to reschedule it immediately, every time.

Too bad I can't relinquish money that way. 

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Synchronize not working
« Reply #37 on: November 26, 2021, 03:49:25 pm »
Supposedly, the thread relinquishes the remainder of its time slice (that's what the documentation says), goes into the ready state and, there is supposedly no guarantee that it will run immediately (yet, "amazingly" it does.)

The part that in bold is very clear.  If the thread relinquished the remainder of its time slice, it could not consume 100% of CPU.  The only way that can happen is if the scheduler does not put the thread to sleep for the remainder of the time slice and, worse, to consume 100% of the CPU, the scheduler has to reschedule it immediately, every time.

Too bad I can't relinquish money that way.
No the scheduler doesn't, as seen in my example where I pinned the spin and the sleep process to the same CPU. It only does so if no other thread is intendet to be scheduled on the CPU. If there is another thread requiring time on that CPU the process will yield
It looks to me as if you have a pretty outdated view on how modern schedulers work. The goal of the scheduler (besides not starving processes) is first and foremost to maximize cache locality. So if you have a process that yields it's time on one of the CPUs, the scheduler will prioritize rerunning this process on the same CPU immediately if possible.
If you have another process waiting to be scheduled, but hasn't been on a CPU for a while, it does not have any cache on the CPUs anymore, meaning that it doesn't matter for the OS on which CPU to schedule it. All are equally bad. While the process that just had a sleep 0 has it's cache still being hot, so the OS will try to reschedule it. So accasionally scheduled processes (long sleeps or event driven sleeps) will be scheduled on the CPUs such that the regular processes (those that only yield to the CPU to not starve the CPU) can continue on the same CPU.

Modern CPUs have >8 cores with hypethreading >16 virtual cpus. Unless I am doing something requireing a lot of parallel computing power, there is always a way for the OS to implicetly pin regular tasks to certain CPUs such that it will be optimized for cache locality.

Note that cache locality does not necessarily only referrs to the L1-L3 caches of the CPUs in this example, but also to the CPU and memory state. Loading a process onto the CPU requires loading all the registers and memory pages. So basically the OS always wants to keep long running processes pinned to a single CPU and do all the short running tasks on other CPUs, as this minimizes loading times and therefore time the CPU is not advancing any programs. "Modern" schedulers also referr to like since the inception of UNIX, so they aren't that modern anymore.

Your assumptions on how sleep "should" work are only valid on a system under very high load or on a system with only very old CPUs with only a few cores.
« Last Edit: November 26, 2021, 04:25:42 pm by Warfley »

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Synchronize not working
« Reply #38 on: November 26, 2021, 04:38:54 pm »
After it's all said and done, if you use Sleep(0) in a program, one core will be pegged at !00% and your users are not going to appreciate that.

TD32.exe (Turbo Debugger) has one of those.  It was a problem.  I patched the executable to do a Sleep(1), after that, everything nice and smooth the way it should be. 
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Synchronize not working
« Reply #39 on: November 26, 2021, 05:16:47 pm »
Yes sleep(0) will not reduce the CPU load, thats not the goal, it just yields to other processes so you don't starve them. If you want to actually reduce CPU usage you need to actually slow down your program (e.g. with sleep > 0)

440bx

  • Hero Member
  • *****
  • Posts: 3946
Re: Synchronize not working
« Reply #40 on: November 26, 2021, 05:35:57 pm »
Yes sleep(0) will not reduce the CPU load, thats not the goal, it just yields to other processes so you don't starve them.
Doesn't it strike you as a bit "unusual" that a function that is supposed to yield to other processes consumes 100% of a CPU in order to get that done ?

Just what every laptop user dreams of ...  ;)
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: Synchronize not working
« Reply #41 on: November 26, 2021, 05:45:47 pm »
Yeah but it makes sense, when calling sleep you say: "Let other CPUs run but schedule me again as soon as possible after the the ms have passed". If that time is 0 you say: "Let others have the CPU but reschedule me as soon as possible". So this is exactly what you would expect

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Synchronize not working
« Reply #42 on: November 26, 2021, 05:52:09 pm »
Yes sleep(0) will not reduce the CPU load, thats not the goal, it just yields to other processes so you don't starve them.
Doesn't it strike you as a bit "unusual" that a function that is supposed to yield to other processes consumes 100% of a CPU in order to get that done ?

Just what every laptop user dreams of ...  ;)

If power consumption is a factor I'm not convinced that running for 20 minutes at 50% is more efficient than running for 10 minutes at 100%.

Note that I'm saying "not convinced" here: on the one hand you've got overheads due to disc, backlight, PSU inefficiency etc. which will broadly vary proportional to time, on the other you've got battery life which could conceivably vary inverse to time.

But can I please point out that the only thing that is remotely relevant to OP's question is use of Application.ProcessMessages. All of this business about Sleep() etc. is spurious.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

loaded

  • Hero Member
  • *****
  • Posts: 824
Re: Synchronize not working
« Reply #43 on: November 26, 2021, 05:54:47 pm »
Yes sleep(0) will not reduce the CPU load, thats not the goal, it just yields to other processes so you don't starve them. If you want to actually reduce CPU usage you need to actually slow down your program (e.g. with sleep > 0)
Why use sleep when you can suspend and use resume.
They have no load on the processor.
Check out  loaded on Strava
https://www.strava.com/athletes/109391137

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: Synchronize not working
« Reply #44 on: November 26, 2021, 06:00:31 pm »
Why use sleep when you can suspend and use resume.
They have no load on the processor.

Because sleep(t) means "pause this thread for t mSec", i.e. it doesn't need anything external to kick it back into life. It's the sort of thing you'd use if e.g. enforcing a protocol delay in background communications.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018