Skip to content

Commit

Permalink
Use separate 32-bit second and nanosecond atomics for the clock
Browse files Browse the repository at this point in the history
  • Loading branch information
kcat committed Nov 21, 2024
1 parent 9cc0789 commit bc90872
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 19 deletions.
27 changes: 19 additions & 8 deletions alc/alc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1038,13 +1038,21 @@ auto CreateDeviceLimiter(const al::Device *device, const float threshold)
*/
inline void UpdateClockBase(al::Device *device)
{
using std::chrono::duration_cast;

const auto mixLock = device->getWriteMixLock();

auto samplesDone = device->mSamplesDone.load(std::memory_order_relaxed);
auto clockBase = device->mClockBase.load(std::memory_order_relaxed);
auto clockBaseSec = device->mClockBaseSec.load(std::memory_order_relaxed);
auto clockBaseNSec = nanoseconds{device->mClockBaseNSec.load(std::memory_order_relaxed)};
clockBaseNSec += nanoseconds{seconds{device->mSamplesDone.load(std::memory_order_relaxed)}}
/ device->Frequency;

clockBaseSec += duration_cast<DeviceBase::seconds32>(clockBaseNSec);
clockBaseNSec %= seconds{1};

clockBase += nanoseconds{seconds{samplesDone}} / device->Frequency;
device->mClockBase.store(clockBase, std::memory_order_relaxed);
device->mClockBaseSec.store(clockBaseSec, std::memory_order_relaxed);
device->mClockBaseNSec.store(duration_cast<DeviceBase::nanoseconds32>(clockBaseNSec),
std::memory_order_relaxed);
device->mSamplesDone.store(0, std::memory_order_relaxed);
}

Expand Down Expand Up @@ -2566,15 +2574,18 @@ ALC_API void ALC_APIENTRY alcGetInteger64vSOFT(ALCdevice *device, ALCenum pname,
case ALC_DEVICE_CLOCK_SOFT:
{
uint samplecount, refcount;
nanoseconds basecount;
seconds clocksec;
nanoseconds clocknsec;
do {
refcount = dev->waitForMix();
basecount = dev->mClockBase.load(std::memory_order_relaxed);
samplecount = dev->mSamplesDone.load(std::memory_order_relaxed);
clocksec = dev->mClockBaseSec.load(std::memory_order_relaxed);
clocknsec = dev->mClockBaseNSec.load(std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_acquire);
} while(refcount != dev->mMixCount.load(std::memory_order_relaxed));
basecount += nanoseconds{seconds{samplecount}} / dev->Frequency;
valuespan[0] = basecount.count();

valuespan[0] = nanoseconds{clocksec + clocknsec
+ nanoseconds{seconds{samplecount}}/dev->Frequency}.count();
}
break;

Expand Down
10 changes: 4 additions & 6 deletions alc/alu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1957,9 +1957,7 @@ void ProcessContexts(DeviceBase *device, const uint SamplesToDo)
{
ASSUME(SamplesToDo > 0);

const nanoseconds curtime{device->mClockBase.load(std::memory_order_relaxed) +
nanoseconds{seconds{device->mSamplesDone.load(std::memory_order_relaxed)}}/
device->Frequency};
const auto curtime = device->getClockTime();

auto proc_context = [SamplesToDo,curtime](ContextBase *ctx)
{
Expand Down Expand Up @@ -2203,10 +2201,10 @@ uint DeviceBase::renderSamples(const uint numSamples)
* also guarantees a stable conversion.
*/
auto samplesDone = mSamplesDone.load(std::memory_order_relaxed) + samplesToDo;
auto clockBase = mClockBase.load(std::memory_order_relaxed) +
std::chrono::seconds{samplesDone/Frequency};
auto clockBaseSec = mClockBaseSec.load(std::memory_order_relaxed) +
seconds32{samplesDone/Frequency};
mSamplesDone.store(samplesDone%Frequency, std::memory_order_relaxed);
mClockBase.store(clockBase, std::memory_order_relaxed);
mClockBaseSec.store(clockBaseSec, std::memory_order_relaxed);
}

/* Apply any needed post-process for finalizing the Dry mix to the RealOut
Expand Down
3 changes: 0 additions & 3 deletions core/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@
#include "mastering.h"


static_assert(std::atomic<std::chrono::nanoseconds>::is_always_lock_free);


DeviceBase::DeviceBase(DeviceType type)
: Type{type}, mContexts{al::FlexArray<ContextBase*>::Create(0)}
{
Expand Down
10 changes: 8 additions & 2 deletions core/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,13 @@ struct SIMDALIGN DeviceBase {
*/
NfcFilter mNFCtrlFilter{};

using seconds32 = std::chrono::duration<int32_t>;
using nanoseconds32 = std::chrono::duration<int32_t, std::nano>;

std::atomic<uint> mSamplesDone{0u};
std::atomic<std::chrono::nanoseconds> mClockBase{std::chrono::nanoseconds{}};
/* Split the clock to avoid a 64-bit atomic for certain 32-bit targets. */
std::atomic<seconds32> mClockBaseSec{seconds32{}};
std::atomic<nanoseconds32> mClockBaseNSec{nanoseconds32{}};
std::chrono::nanoseconds FixedLatency{0};

AmbiRotateMatrix mAmbiRotateMatrix{};
Expand Down Expand Up @@ -337,7 +342,8 @@ struct SIMDALIGN DeviceBase {
using std::chrono::nanoseconds;

auto ns = nanoseconds{seconds{mSamplesDone.load(std::memory_order_relaxed)}} / Frequency;
return mClockBase.load(std::memory_order_relaxed) + ns;
return nanoseconds{mClockBaseNSec.load(std::memory_order_relaxed)}
+ mClockBaseSec.load(std::memory_order_relaxed) + ns;
}

void ProcessHrtf(const std::size_t SamplesToDo);
Expand Down

0 comments on commit bc90872

Please sign in to comment.