Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I know its not the exact same kind of concern as presented here, but I have recently found that one technique for achieving extremely precise timing of execution is to just sacrifice an entire high priority thread to a busy wait loop that checks timing conditions as fast as the CPU will cycle instructions. This has the most obvious advantage of being trivial to implement, even in high level languages that only expose the most basic of threading primitives.

Thinking strategically about this approach, modern server CPUs expose upwards of 64/128 threads, so if 1 of these had to be sacrificed completely to the gods of time, you are only looking at 1-2% of your overall resources spent for this objective. Then, you could reuse this timing service for sequencing work against the other 98-99% of resources. Going back just a few years, throwing away 12/25/50% of your compute resources for the sake of precise timing would have been a non-starter.

For reference, I find that this achieves timing errors measured in the 100-1000 nanoseconds range in my .NET Core projects when checking a trivial # of events. I have not bothered to optimize for large # of events yet, but I believe this will just be a pre-processing concern with an ordered queue of future events. I have found that this is precise enough timing to avoid the sort of logic you would otherwise need to use to calculate for time error and compensate on future iterations (e.g. in non-deterministic physics simulations or frame timing loops).



Yes, definitely turn off HT/SMT and use a single app thread per core with busy waiting. I'm working on a low latency application design guide exploring this more in depth.


I haven't measured this yet, but I question whether SMT would actually introduce any meaningful jitter into the timing loop. If my event is off by 10-100 nanoseconds, I probably don't care that much.

I am not actually sure how precise this approach could be in theory, so if the noise floor could be low enough for it to matter, then it's certainly a factor for some applications.

If we prove that SMT has a certain bounded impact, then it may be possible to say that for a certain range of applications you get a 2x feasibility bump because you can leave SMT enabled.


It shouldn't, that's the whole reason SMT exists. If there is detectable jitter that would be notable.

People have a bad taste in their mouth that was left circa ~2000(?) from some Intel parts with a pipeline that was too deep. Ever since that was fixed most workloads do see a 2x speedup when enabling SMT.


SMT sibling threads can definitely impact each other. It works great for common workloads. If you have a highly tuned workload with high IPC or want to trade off throughput for latency, disabling SMT can be a win. Disabling SMT also increases effective L1 and L2 cache which can be beneficial.


With busy polling you basically halve the SMT sibling thread's memory bandwidth. But yeah it might work well for a specific usecase anyway.


What kind of tasks would said thread be concerned with? Delegation and I/O?


I am currently using it to drive timing of frame generation and processing of UI events (i.e. animations, cursor flashing, etc) in a custom 2d graphics engine.

The API I currently have is:

int RegisterTimer(int afterMicroseconds, Action action)

void CancelTimer(int timerId)

It is really nice having this level of timing resolution and consistency in such a simple interface. I can just assume that whatever action I set up for delayed execution is running precisely when I wanted it to (in practical terms).


If understand that right you have a thread that only looks for now-open jobs and assigns them to workers? How do they receive their work?

Funny enough, what you're describing is basically the timer api that was used in warcraft 3 scripting.


Or the thread is doing the work directly?


In some cases the thread will, in others it will enqueue the event in an LMAX Disruptor for execution on one of the other available threads.


Keep in mind that by spinning, you're preventing the CPU from sleeping thus wasting a lot of energy.

At the very least, make sure you stop spinning when the game loses focus.


For reference, the domain of usage of this timer thread is in a server-side application. Clients do not have to run this. The server application handles many clients simultaneously, so cost of spinning is amortized across many users.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: