flucoma / flucoma-core

Core algorithms and objects for the Fluid Corpus Manipulation Library
BSD 3-Clause "New" or "Revised" License
75 stars 14 forks source link

On Windows, both Max's and SC's FluidBufThreadDemo take significatively longer than the requested time #11

Open tremblap opened 3 years ago

tremblap commented 3 years ago

Situation: On MacOS and Linux, the tutorial object 'FluidBufThreadDemo' yields its result in the requested time. On Windows, it takes much longer. It is not a real issue for the other objects as they seem to behave in timings that are in a similar ballpark, but that can be pedagogically misleading.

AlexHarker commented 2 years ago

This is almost certainly explained by the use of td::this_thread::sleep_for in the client in a static loop of 1000 iterations.

Windows has much larger timing granularity than other OSes and so the sleep of x microseconds is almost certainly increased to a larger time value - this is then repeated 1000 times so the error multiplies. What is more sleep_for can go disastrously wrong on windows if the clock changes (like doing a wait of an hour rather than a few microseconds). I entirely removed it from another project in which it was in a time critical path for these reasons.

If timing is really important for this object then the solution is to do a busy wait where you poll a monotonic clock, rather than sleeping a thread - that would be likely to perform better if you time the overall required interval (not a smaller one and loop). I suspect the engineering cost is not worth it, but that is the likely cause.

This also would explain why you don't see issues in other objects, as this issue is specific to this client.

AlexHarker commented 2 years ago

[And note]:

From

https://en.cppreference.com/w/cpp/thread/sleep_for

"Blocks the execution of the current thread for at least the specified sleep_duration."

weefuzzy commented 2 years ago

Cheers, yes I poked into it (perhaps before this issue was made) and found out broadly those things.

The object exists only to demonstrate threading mechanisms, so tight timing isn't important but the whole bit where Windows might just pick a different, much longer time to sleep for probably suggests doing something more reliable one day.

AlexHarker commented 2 years ago

This is what I do on windows where on other OSes I would do a micro sleep. this is specifically coded to 100 ns, but the principle should be clear. This is the dumbest busiest version of this, but assuming you don't actually need the thread to be asleep something similar would work.

inline void threadReduceContention()
{
        using Clock = std::chrono::steady_clock;

        auto timeOut = Clock::now() + std::chrono::nanoseconds(100);

        // Busy waiting

        while (Clock::now() < timeOut) 
        {}
  }
AlexHarker commented 2 years ago

Technically speaking any implementation might choose a longer time period, but I think a fairly likely scenario under windows is that you ask for a handful of microseconds and get at least 1 millisecond.