【发布时间】:2018-02-16 07:07:00
【问题描述】:
(这是一个交叉的软件-硬件主题,对我来说是一个编程问题,但经过所有故障排除后,我认为它可能是一个硬件问题(也许更适合超级用户? ) 但是我还没有解决所以我不确定,希望这个社区有一些相关的cpu理论可以分享。无论如何......)
我正在编写一个实时渲染程序,并且一直受到每 2 秒持续发生的可见帧速率故障的困扰。经过大量分析后,我确定这是影响我程序中所有代码部分(包括图形 api 调用)的性能下降,所以我认为这是一个 cpu 问题,超出了程序的责任范围。
我可以在新的 Code::Blocks 项目中使用以下代码在我的机器上演示问题:
#include <cstdint>
#include <iostream>
#include <chrono>
int main(int argc, char* args[])
{
std::cout << std::fixed;
std::chrono::system_clock::time_point runStart = std::chrono::high_resolution_clock::now();
while(true)
{
uint64_t count = 0;
std::chrono::system_clock::time_point frameStart = std::chrono::high_resolution_clock::now();
{
for(uint64_t i = 0; i < 100000; ++i)
++count;
}
std::chrono::system_clock::time_point frameStop = std::chrono::high_resolution_clock::now();
double runTime = std::chrono::duration<double, std::chrono::seconds::period>(frameStop - runStart).count();
double frameTime = std::chrono::duration<double, std::chrono::seconds::period>(frameStop - frameStart).count();
if(frameTime > 0.0005)
std::cout << count << " runTime: " << runTime << " \tframeTime: " << frameTime << '\n';
}
return 0;
}
典型输出如下所示,每 2 秒清楚地显示一些较慢的帧:
100000 runTime: 0.000393 frameTime: 0.000393
100000 runTime: 0.000840 frameTime: 0.000393
100000 runTime: 0.001214 frameTime: 0.000369
100000 runTime: 0.002984 frameTime: 0.000389
100000 runTime: 0.003384 frameTime: 0.000395
100000 runTime: 0.003781 frameTime: 0.000393
100000 runTime: 0.004158 frameTime: 0.000371
100000 runTime: 0.005927 frameTime: 0.000386
100000 runTime: 0.006329 frameTime: 0.000398
100000 runTime: 0.006724 frameTime: 0.000390
100000 runTime: 0.007127 frameTime: 0.000398
100000 runTime: 0.007507 frameTime: 0.000375
100000 runTime: 0.994469 frameTime: 0.000511
100000 runTime: 3.042060 frameTime: 0.000465
100000 runTime: 3.077671 frameTime: 0.000405
100000 runTime: 5.093173 frameTime: 0.000496
100000 runTime: 5.128435 frameTime: 0.000366
100000 runTime: 5.488874 frameTime: 0.000391
100000 runTime: 7.135737 frameTime: 0.000367
100000 runTime: 7.152022 frameTime: 0.000484
100000 runTime: 7.457491 frameTime: 0.000360
100000 runTime: 9.179262 frameTime: 0.000478
100000 runTime: 9.211521 frameTime: 0.000368
100000 runTime: 9.226528 frameTime: 0.000353
100000 runTime: 11.217430 frameTime: 0.000391
100000 runTime: 11.262574 frameTime: 0.000352
也许其他一些机器会显示类似的输出? (根据需要调整输出阈值。)
我尝试使用 g++ 和 clang 进行编译,都产生了这种异常。 (g++ 版本的整体表现要好一些。)
我突然想到,自从我构建了这台计算机以来,除了我自己的项目之外,我没有在上面运行任何 3d 应用程序,所以我尝试运行 LunarG Vulkan API 和一些屏幕保护程序附带的全息图演示,果然,每 2 秒就会出现一次故障。 (在屏幕保护程序中不太明显。)所以我很欣慰地知道它至少是系统范围的,而不是我的程序做错了什么。
系统规格:
- cpu:AMD 锐龙 7 1800X
- 主板:微星 B350 战斧北极
- 内存:1x16GB DDR4 3200
- GPU:GeForce GTX 1050 Ti
- 电源:美洲狮 CMX 1000
- 操作系统:Linux Mint 18.1 64 位
看起来我用 1000W psu 过火了,所以功率不足不是问题。除非 Cougar psu 的某些缺陷导致每 2 秒短暂下降一次?
任何想法可能导致此问题以及我能做些什么?
编辑: 有关我的渲染问题的更多详细信息:
长期以来,我一直在围绕 OpenGL 构建我的引擎,并且只要我一直在这台机器上工作,就会遇到这个问题。在此之前,我的旧电脑上有类似的随机跳帧,它有自己的问题(电池寿命为 20 分钟的旧游戏笔记本电脑,并且容易过热以触发安全关闭)所以这就是为什么我没有立即想到这是一个硬件问题。我一直在计划将我的项目移植到 Vulkan,所以我推迟了对跳帧的担心,希望当我更改渲染 API 时它会消失。但现在我正在浏览this Vulkan tutorial,我已经看到在绘制教程中的旋转四边形时出现了跳帧。
我一直在尝试破解 Vulkan 交换链,试图围绕这个进行优化。我拥有的最佳解决方案是有一个专门用于每 1/60 秒调用一次 vkQueuePresentKHR 的线程(using std::this_thread::sleep_until 在调用之间等待),Vulkan 呈现模式设置为 VK_PRESENT_MODE_IMMEDIATE_KHR,并绘制另一个线程最多提前 7 个其他交换链映像,因此交换线程不必等待它们(我知道根据 Vulkan 规范,这可能不是最安全的方法)。使用此设置,对vkQueuePresentKHR 的调用通常需要 0.000050 到 0.000300 秒才能返回,但每 2 秒至少有 1 帧需要 > 0.01 秒,如果我使用 VK_PRESENT_MODE_FIFO_KHR 和call 几乎没有错过 vblank 并且不得不等待下一个,但我正在使用 VK_PRESENT_MODE_IMMEDIATE_KHR 所以我不知道发生了什么,除了在 vkQueuePresentKHR 内部调用的任何底层代码正在受到我的性能异常的严重影响。
【问题讨论】:
-
以
/usr/bin/time --verbose <executable>运行它并检查页面错误和上下文切换号。可能您的流程被取消计划,因为它耗尽了时间量。尝试以sudo chrt -f 99 /usr/bin/time --verbose <executable>运行,看看上下文切换次数是否变为0。 -
@maxim 添加
sudo chrt -f 99显着减少了非自愿上下文切换,但我仍然每 2 秒看到较慢的帧。当我用我的旋转四边形尝试它时,sudo chrt -f 99导致 Vulkan 吐出一堆错误,我的程序崩溃了。 -
那台电脑的温度如何?我知道许多现代 CPU 如果检测到它们开始过热,它们会放慢速度。
-
@Jeremy 上次检查时(几个月前),AM4 插座类型的一些规格尚未开源,所以很遗憾我无法读取温度传感器在 Linux 中,只能通过重新启动并查看 bios 来检查它,但是当我这样做时,它通常在 40 摄氏度左右,而且我从来没有听到泵启动的声音,所以我认为这不是问题。
标签: c++ performance cpu cpu-usage framebuffer