4 ms·
If you have any other suggestion I'd like to hear it. Calling sleep or using an OS timer isn't precise enough.
by superdisk 8y ago
If you have any other suggestion I'd like to hear it. Calling sleep or using an OS timer isn't precise enough.
- asveikau 8y agoWhat if you tally up the amount of delay you should have done, then when it gets to a big enough granularity where a sleep call would actually give you that amount, sleep. Eg. Don't try to sleep accurately between the simulated cycles. Let things happen "too fast" for longer and do the delays in batches. Not sure if this would wind up perceivably too bursty. Just an idea based on things I have seen in other domains. For the record I don't think spinning is too bad of it's a very short duration, shorter than the scheduler will give you when you take your thread off the CPU.
- superdisk 8y agoSleep, at least on Windows, is allowed to have +/- 15 ms (default system heartbeat interval) of accuracy, which I don't think would work for this case. https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-sleep https://docs.microsoft.com/en-us/windows/desktop/api/synchap... I could mess around with the Win32 API or the NT API or something to make the heartbeat rate more granular, but according to the docs that kills battery, so I'm guessing it's going to be doing pretty much the same thing as what I'm doing manually.
- asveikau 8y agoYeah I am well aware. I faced issues that reminded me of this when doing some audio stuff. Including on Windows.
- morcheeba 8y ago... that can still work. Measure how much time it actually slept and adjust accordingly. Or, is there some timer that runs at a reasonable rate (100Hz) where you csn yield once you've done 10msec worth of emulation? (I don't know the windows API, so just spitballing from the embedded world here)
- nothanksmydude 8y agoYou seem like you appreciate good timers. If you ever want to revolt in horror/have a few hearty belly laughs, look into how windows has and does handle various granularities of timing
- hrydgard 8y agoRaising the timer interrupt to 1ms with timeBeginPeriod should still be less costly (with regards to power consumption) than a spin loop. But yeah it's all tradeoffs..
- gambiting 8y agoYep, we had this exact issue on our live servers deployed to Windows Server 2016 in a VM - essentially I would do: 1) post tasks to process some data 2) while(tasksNotFinished) Sleep(1); Well, very quickly found out that the Sleep(1) was always a minimum of 16ms(or a multiple of 16ms), which made the whole thing stupidly slow. We fixed it by running timeBeginPeriod(1) which overrides the system timer resolution to 1ms. Yes it would kill the battery on laptops, but on a server this is not an issue.
- asveikau 8y agoThe way I would solve that is an event and a count of tasks. When the last thread to complete its job sees InterlockedDecrement(&ntasks) == 0, call SetEvent to wake up the waiting thread.
- gambiting 8y agoYes, that was another solution we considered but we needed to deploy a patch quickly and setting the timer resolution was considered less risky and faster to do. But it would have worked as well as it should wake up the waiting thread immediately when used with WaitForMultipleObjectsEx.
- nothanksmydude 8y agoAFAIK, most modern game engines have a threshold of headroom for leftover time that must be hit to eliminate needless spin, but also stay responsive. Back when everyone was targeting 60fps, >~2.25ms of 'leftover time' was needed during the individual 16.6667ms run of that loop to actually trigger sleep instead of spinning. Note that's specific to the graphical rendering thread, and things like the mouse/kb input have their own sleep durations, with or without thresholds.
- deleted 8y ago[deleted]
- pjc50 8y agoIDXGIOutput::WaitForVBlank()?
- nothanksmydude 8y agoDoes this actually work now? It used to be broken to the point that everyone rolled their own
- ungzd 8y agoYou can run period of emulation time at full speed as long as difference in speed is not observable from outside. There's no point to delay regular memory reads and writes by synchronizing every CPU cycle to real time: no one will notice that. If it writes to video memory, result is usually not instantly visible too, and becomes visible only when screen scan position approaches that position in memory. Probably Game Boy has some sprite hardware and changing few registers can cause huge changes on screen, but anyway it's not possible to output changes on screen instantly to host system, so you can draw whole virtual frame at full host speed, considering that you keep track of scan position based on elapsed CPU cycles (T-states or something like that). Once your emulation time period between two screen frames is completed, you can pause emulation until it catches up to next frame in real time, making process sleeping and not consuming CPU in between frames. Input events and sound add additional complexity, but it's doable.
- Doxin 8y agoA nice way to implement this is with a frame budget. You simply keep a variable that keeps track of how many miliseconds of budget you have left. Every time you render to the screen you increase the budget by 1000/fps. Then you simply run the emulation until the budget runs out. if the emulation gets too far ahead of the rendering you can consume extra budget by simply sleeping -- which is now less important to get exactly right, you can simply sleep away 90% of the budget for example, so if the sleep overshoots you've got some play.