【问题标题】:Optimizing axis aligned bounding box check优化轴对齐边界框检查
【发布时间】:2013-01-29 08:43:38
【问题描述】:

我目前正在大量使用点云,并且我已经实现了一种分割算法,可以将具有特定最大距离的点聚集成段。

为了优化这一点,我给每个片段一个轴对齐的边界框,以检查给定点是否可能与片段匹配,然后再仔细观察并遍历这些点并计算距离(我实际上使用为此使用八叉树,将大部分点剪掉。)

我通过 gnuprof 运行了我的程序,结果如下:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total           
 time   seconds   seconds    calls   s/call   s/call  name    
 52.42      5.14     5.14 208995661     0.00     0.00  otree_node_out_of_bounds
 19.60      7.06     1.92 189594292     0.00     0.00  otree_has_point_in_range
 11.33      8.17     1.11   405834     0.00     0.00  otree_node_has_point_in_range
  9.29      9.08     0.91   352273     0.00     0.00  find_matching_segments
 [...]

如您所见,大部分计算时间都花在了otree_node_out_of_bounds,具体实现如下:

int otree_node_out_of_bounds(struct otree_node *t, void *p)
{
    vec3 *_p = p;
    return (_p->x < t->_llf[0] - SEGMENTATION_DIST 
        || _p->x > t->_urb[0] + SEGMENTATION_DIST
        || _p->y < t->_llf[1] - SEGMENTATION_DIST 
        || _p->y > t->_urb[1] + SEGMENTATION_DIST
        || _p->z < t->_llf[2] - SEGMENTATION_DIST 
        || _p->z > t->_urb[2] + SEGMENTATION_DIST);
}

SEGMENTATION DIST 是一个编译时常量,允许 gcc 做一些常量折叠。 _llf_urbfloat[3] 类型,代表八叉树的边界框。

所以,我的问题基本上是,是否可以对这个函数进行一些偷偷摸摸的优化,或者更一般地说,是否有更有效的方法来对 AABB 进行边界检查,或者用不同的方式来表达它,可以我通过使用一些 C/gcc 魔法以某种方式加快了比较速度?

如果您需要更多信息来回答这个问题,请告诉我:)

谢谢, 安迪。

【问题讨论】:

    标签: c optimization gcc aabb


    【解决方案1】:

    这是一个很小的叶子函数,被调用了很多次。分析结果总是过度代表这些函数的成本,因为测量调用的开销相对于函数本身的成本来说是很大的。通过正常优化,整个操作的成本(在最终调用此测试的外部循环级别)将占整个运行时的较低百分比。您可以通过使该函数内联并启用分析(例如使用__attribute__((__always_inline__)))来观察这一点。

    您的函数看起来不错。我怀疑您是否可以比您进一步优化这样的单个测试(或者如果可以,它不会是戏剧性的)。如果你想优化整个操作,你需要在更高的层次上做:

    • 您可以尝试其他结构(例如 kd-tree 而不是 octree)或利用数据中某些模式的全新算法。
    • 您可以将循环从“for each point check otrees”反转为“for each otree check points”,这样您就可以反复使用边界数据。
    • 您可以确保以最有效的方式访问数据(可能是点)(即顺序而不是随机跳转)。
    • 通过重组循环,您可以使用 SSE 在一条指令中执行多个边界测试(没有分支!)。

    【讨论】:

    • 感谢您的建议。我对他们每个人都有一些注意事项:1.)我考虑过使用 kdtree,事实上,我只是未能实现它们 :) 2.)我们在这里谈论潜在的数十亿点,所以我怀疑倒车循环会更快。 3.) 我是这样做的,我猜 4.) 我没听懂,但这听起来很有趣。你能提供更多细节吗?旁注:我不认为探查器过度代表了这个函数的成本,因为我整个运行时的超过 50% 都花在了那里:)
    • 我已按照您的建议内联并重新配置了程序,并且函数的性能影响确实降低了,正如预期的那样,由于删除了函数调用和返回。但是,在该功能上仍然花费了相当多的时间。
    • @AndreasGrapentin:正如我在回答中所说,加快结果的最有效方法是通过使用其他数据结构来尽可能多地避免这些“范围内”比较.如果做不到这一点,重新组织循环会对性能产生巨大影响。如果没有完整的问题描述(算法建议)或函数上方层次结构的代码(循环结构和 SSE 建议),很难更具体。
    • @AndreasGrapentin:另外,我正是遇到了一个问题,我手动优化了内部测试并获得了 10% 的加速,然后实现了由于错误的假设,调用它的算法意外地是 O(n) 而不是 O(log n)。当我修复它时,整个程序(包括许多其他操作)完成的速度快 27 倍
    • 我一直在认真思考有问题的算法,程序的当前状态确实比我最初的方法快得多,但我想我在那里碰壁了。我想不出一种直观的方法来改进一般计算。但是,我感谢您的指点,并将研究您建议的内容。再次感谢:)
    【解决方案2】:

    我觉得不错。我能想到的唯一微优化是将 *_p 声明为静态

    【讨论】:

    • 感谢您的建议。但是,当我将_p 声明为static vec3 *_p 时,gcc 会告诉我otree.c: In function 'otree_node_out_of_bounds': otree.c:74:2: error: initializer element is not constant `
    • 对不起,我的错。您的建议按预期工作,我会检查分析器:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多