我有点麻烦,我要求提示。我在Windows平台上,以下列方式进行计算:
int input = 0;
int output; // junk bytes here
while(true) {
async_enqueue_upload(input); // completes instantly, but transfer will take 10us
async_enqueue_calculate(); // completes instantly, but computation will take 80us
async_enqueue_download(output); // completes instantly, but transfer will take 10us
sync_wait_finish(); // must wait while output is fully calculated, and there is no junk
input = process(output); // i cannot launch next step without doing it on the host.
}
我问的是wait_finish()的事情。我必须等待所有设备完成,结合所有结果并以某种方式处理数据并上传新部分,这是基于先前的计算步骤。我需要在每个步骤之间同步数据,因此我无法并行化步骤。我知道,这不是一个非常有效的案例。所以我们继续提问。
我在wait_finish()中有两种检查完成的方法。首先是让线程进入睡眠状态,直到它被完成事件唤醒:
while( !is_completed() )
Sleep(1);
它的性能非常低,因为实际计算需要100us,并且最小的Windows sheduler时间步长为1ms,因此它的性能降低了不到10倍。
第二种方法是在空无限循环中检查完成:
while( !is_completed() )
{} // do_nothing();
它具有10倍的良好计算性能。但它也是不合适的解决方案,因为它使得完整的cpu核心利用率,绝对无用的工作。如何让cpu“睡觉”到我需要的时间? (每一步都有相同的工作量)
如果计算时间对于主动旋转等待来说太大,但与sheduler时间步长相比太小,这种情况通常会如何解决?还有相关的子问题 - 如何在linux上做到这一点?
答案 0 :(得分:0)
幸运的是,我已经成功地找到了答案。简而言之 - 我应该使用linux。
我的调查显示以下内容。在Windows上,ntdll中有隐藏功能,NtDelayExecution()
。它不是通过SDK公开的,但可以通过以下方式加载:
static int(__stdcall *NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval) = (int(__stdcall*)(BOOL, PLARGE_INTEGER)) GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtDelayExecution");
它允许在100ns周期内设置睡眠间隔。然而,即使不能很好地运作,如以下基准所示:
SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); // requires Admin privellegies
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
uint64_t hpf = qpf(); // QueryPerformanceFrequency()
uint64_t s0 = qpc(); // QueryPerformanceCounter()
uint64_t n = 0;
while (1) {
sleep_precise(1); // NtDelayExecution(-1); waits one 100-nanosecond interval
auto s1 = qpc();
n++;
auto passed = s1 - s0;
if (passed >= hpf) {
std::cout << "freq=" << (n * hpf / passed) << " hz\n";
s0 = s1;
n = 0;
}
}
产生的东西低于2000赫兹的循环速率,结果因字符串而异。这导致我转向windows线程切换sheduler,这完全不适合实时任务。它的最小间隔为0.5ms(+开销)。顺便问一下,有谁知道如何调整这个值?
接下来是linux问题,它能做什么?所以我用buildroot的方法构建了自定义微内核4.14,并测试了那里的基准代码。我将qpc()
替换为clock_gettime()
数据,时间为CLOCK_MONOTONIC
,而qpf()
只返回秒内的纳秒数和sleep_precise()
刚刚调用的clock_nanosleep()
}。我未能找出CLOCK_MONOTONIC
和CLOCK_REALTIME
之间的区别。
我非常惊讶,开箱即可获得18.4khz的频率,这非常稳定。虽然我测试了几个间隔,但我发现我可以将环路设置为几乎任何频率高达18.4khz,但实际测量的等待时间结果也不同于我要求的1.6倍。例如,如果我要求睡100美元它实际上睡眠约160 us,给出~6.25 khz频率。系统上没有其他任何东西,只有内核,busybox和这个测试。我不是一个经验丰富的linux用户,我仍然想知道如何将其调整为更加实时和确定性。我可以将频率推得更高吗?