我正在使用Kinect2Grabber,并且想进行一些实时处理,但是我得到的性能约为1 fps。最终,我想估计一个空中掷球的轨迹。我无法通过如此缓慢的处理来做到这一点:(
我在AMD Ryzen Threadripper 1900X 8核处理器上使用Windows 10 64位,Visual Studio 2017,PCL 1.9.1多合一安装程序MSVC2017 x64。我的项目中启用了OpenMP,优化也启用了。但是,当我运行程序时,其CPU使用率约为12-13%。我在做什么错了?
int main(int argc, char* argv[])
{
boost::shared_ptr<visualization::PCLVisualizer> viewer(new visualization::PCLVisualizer("Point Cloud Viewer"));
viewer->setCameraPosition(0.0, 0.0, -1.0, 0.0, 0.0, 0.0);
PointCloud<PointType>::Ptr cloud(new PointCloud<PointType>);
// Retrieved Point Cloud Callback Function
boost::mutex mutex;
boost::function<void(const PointCloud<PointType>::ConstPtr&)> function = [&cloud, &mutex](const PointCloud<PointType>::ConstPtr& ptr) {
boost::mutex::scoped_lock lock(mutex);
//Point Cloud Processing
cloud = ptr->makeShared();
std::vector<int> indices;
removeNaNFromPointCloud<PointType>(*cloud, *cloud, indices);
pass_filter(0.5, 0.90, cloud);
outlier_removal(50, 1.0, cloud);
downsampling_vox_grid(0.005f, cloud);
normals(0.04, cloud, cloud_normals);
segmentation(cloud, cloud_normals);
};
boost::shared_ptr<Grabber> grabber = boost::make_shared<Kinect2Grabber>();
boost::signals2::connection connection = grabber->registerCallback(function);
grabber->start();
while (!viewer->wasStopped()) {
// Update Viewer
viewer->spinOnce();
boost::mutex::scoped_try_lock lock(mutex);
if (lock.owns_lock() && cloud) {
// Update Point Cloud
if (!viewer->updatePointCloud(cloud, "chmura")) {
viewer->addPointCloud(cloud, "chmura");
}
}
}
grabber->stop();
// Disconnect Callback Function
if (connection.connected()) {
connection.disconnect();
}
return 0;
}
pass_filter,outlier_removal等省略的代码直接从教程中获取,并且可以正常工作,但是从outlier_removal(含)开始非常慢。 您的帮助将不胜感激。
我不必使用Kinect2Grabber。在Windows上从Kinec2抓取和处理帧,一切都会很好。
答案 0 :(得分:0)
我看到一些缓解您的问题的方法。 Threadripper的12-13%的使用率听起来不错(100/16约为〜6.25%),因为这意味着完全使用了1个物理核心(1个线程用于IO,1个用于计算?只是我的猜测)。
要获得更好的性能,您需要进行概要分析以了解造成瓶颈的原因。 Perf是实现此目的的绝佳工具。有一个关于how to profile code by Chandler的精彩视频。这不是perf教程的最佳位置,但是 TL; DW :
-fno-omit-frame-pointer
标志或等效标志进行编译perf record -g <executable>
perf report -g
了解哪些功能占用最多的CPU周期perf report -g 'graph,0.5,caller'
了解哪些调用路径占用最多的CPU周期最有可能发现的问题是
VoxelGrid
之类的一次性对象:一次实例化对象可以更好地利用CPU周期grabber
的锁和IO 这将为您提供更高的帧速率,但仍将CPU利用率限制为12-13%,即单线程限制。
由于您使用的是ThreadRipper,因此可能会使用线程来使用其他CPU并分离IO,计算和可视化
这使您可以调整队列大小以丢弃帧以改善延迟。根据您的自定义Kinect2Grabber
的设计,可能不需要这样做。在您分析代码后,这一点将显而易见。
这有可能通过将CPU利用率提高到20%(因为抓取器和可视化线程将在全速状态下工作)来显着减少延迟并提高帧率。
为了充分利用所有线程,使用者线程可以将帧卸载到其他线程,以允许CPU一次处理多个帧。为此,您可以采用以下选项(它们不是唯一的。您可以将选项2用作选项1的主力军,以获取全部利益)
当您不打算使用诸如延迟之类的特定指标时,选项1是合适的。它还需要对代码进行最少的更改,但是需要在高延迟(上面指出当前的设计问题)或为每个线程创建一个对象副本之间进行权衡,以防止每次设置。
选项2适用于所需的等待时间很短并且需要订购帧的情况。但是,为了保持TaskFlow中的低延迟,您需要以CPU内核可以处理它们的速率来提供帧。否则,您可以使CPU过载,不留任何可用RAM导致页面抖动,并实际上降低性能
这两个选项都要求您确保输出以正确的顺序到达。可以使用promises
或掉落故障帧的队列来完成。通过实施部分或全部解决方案,您可以确保CPU利用率保持很高,甚至100%。
为了知道最适合您的情况,知道您的目标性能指标是什么,智能地配置代码并进行正确测试。