指令缓存和条件语句

时间:2012-06-03 22:10:12

标签: c++ cache-control data-oriented-design

我试图使用面向数据的设计尽可能高效地使用缓存,这是我第一次考虑这样的事情。我已经设法绕过在屏幕上绘制精灵的相同指令,发送到函数的向量包括所有游戏实体的位置和精灵。

我的问题是条件语句是否从指令缓存中删除了draw函数,从而破坏了我的计划?或者我只是做了一般疯狂的事情?

struct position
{
    position(int x_, int y_):x(x_), y(Y_)
    int x,y;
};

vector<position> thePositions;
vector<sprite> theSprites;
vector<int> theNoOfEntities; //eg 3 things, 4 thingies, 36 dodahs
int noOfEntitesTotal;

//invoking the draw function
draw(&thePositions[0], &theSprites[0], &theNoOfEntities[0], noOfEntitesTotal)

void draw(position* thepos, sprite* thesp, int* theints, int totalsize)
{
    for(int j=0;int i=0;i<totalsize;i++)
    {
        j+=i%size[j]?1:0;
        thesp[j].draw(thepos[i]);
    }
}

2 个答案:

答案 0 :(得分:1)

您是否验证条件在汇编中保留为条件?通常使用简单的条件(例如上面提到的条件),表达式可以优化为无分支序列(使用机器特定指令在机器级别,或使用某些奇特的位数学在IR级别)。

在你的情况下,你有条件地在x86上很好地折叠到一个平坦的序列(和AFAIK,这也会出现在大多数非x86平台上,因为它是一个数学优化,而不是机器特定的):

IDIV DWORD PTR SS:[ARG.1]
MOV EAX,EDX
NEG EAX                                  ; Converts EAX to boolean
SBB EAX,EAX
NEG EAX

所以这意味着除了你的外部循环之外,没有任何分支可以预测,它遵循一个模式,这意味着它不会导致任何错误预测(它可能在退出时错误预测,具体取决于生成的程序集,但它退出了,所以没关系)。

这提出了第二点,从不假设,总是进行概要和测试(汇编知识有很多帮助的情况之一),这样你可以花时间优化真正的地方很重要(您也可以更好地了解代码在您的目标平台上的内部和内部工作原理)。

如果您真的担心分支错误预测和罚款,请使用目标架构制造商提供的资源(不同的架构在分支误预测方面表现得非常不同),例如this和{{来自英特尔的3}} AMD的CodeAnalyst是检查分支误预测及其可能造成的惩罚的绝佳工具。

答案 1 :(得分:-1)

哇,伙计!没有冒犯,但看起来你已经读过有关国防部的内容而没有完全理解它的方式和原因。现在,您只需遵循有关DOD的文章中设置的指南,就像它们很重要一样。他们不是,在DOD中重要的是理解数据,理解计算机体系结构并理解您的代码如何使用您对架构的了解尽可能高效地操作数据。国防部文章中提出的指导方针只是提醒您需要考虑的常见事项。

想知道您何时以及为何需要使用DOD?了解您正在使用的架构。你知道一次缓存失败的成本吗?这真的非常低。算一算。我很认真,自己做数学,我可能会给你一些数字但是你不会学到很多东西。 因此,找出关于体系结构,处理器如何工作,内存和缓存如何工作,汇编语言如何工作,编译器生成的程序集的内容。一旦你了解并理解了所有这些,DOD只不过是在编写一些非常明显的指南来编写真正高效的代码。