By default, the memory order on atomics is `seq_cst`. This is a relatively expensive ordering and it shows in situations where we're rapidly signaling a consumer to pick up something from a producer. I've instead attempted to switch these to `release` (producer) and `acquire` (consumer) to improve the performance of these signals. ## Validation Steps Performed - Run `time cat big.txt` and `time cat ls.txt` under VS Performance Profiler. ## PR Checklist * [x] Closes perf itch * [x] I work here * [x] Manual test * [x] Documentation irrelevant. * [x] Schema irrelevant. * [x] Am core contributor.
55 lines
1.5 KiB
C++
55 lines
1.5 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#include "pch.h"
|
|
|
|
#include "ThrottledFunc.h"
|
|
|
|
using namespace winrt::Windows::Foundation;
|
|
using namespace winrt::Windows::UI::Core;
|
|
using namespace winrt::Windows::UI::Xaml;
|
|
|
|
ThrottledFunc<>::ThrottledFunc(ThrottledFunc::Func func, TimeSpan delay, CoreDispatcher dispatcher) :
|
|
_func{ func },
|
|
_delay{ delay },
|
|
_dispatcher{ dispatcher },
|
|
_isRunPending{}
|
|
{
|
|
}
|
|
|
|
// Method Description:
|
|
// - Runs the function later, except if `Run` is called again before
|
|
// with a new argument, in which case the request will be ignored.
|
|
// - For more information, read the class' documentation.
|
|
// - This method is always thread-safe. It can be called multiple times on
|
|
// different threads.
|
|
// Arguments:
|
|
// - <none>
|
|
// Return Value:
|
|
// - <none>
|
|
void ThrottledFunc<>::Run()
|
|
{
|
|
if (_isRunPending.test_and_set(std::memory_order_acquire))
|
|
{
|
|
// already pending
|
|
return;
|
|
}
|
|
|
|
_dispatcher.RunAsync(CoreDispatcherPriority::Low, [weakThis = this->weak_from_this()]() {
|
|
if (auto self{ weakThis.lock() })
|
|
{
|
|
DispatcherTimer timer;
|
|
timer.Interval(self->_delay);
|
|
timer.Tick([=](auto&&...) {
|
|
if (auto self{ weakThis.lock() })
|
|
{
|
|
timer.Stop();
|
|
self->_isRunPending.clear(std::memory_order_release);
|
|
self->_func();
|
|
}
|
|
});
|
|
timer.Start();
|
|
}
|
|
});
|
|
}
|