如何设计对象以进行性能



最近阅读了一本关于物理引擎开发的书时,我遇到了一个我从未考虑过的设计决定。这与CPU解决内存中的原始字节的方式有关。

考虑以下类:

class Foo
{
    public:
        float x;
        float y;
        float z;
        /* Constructors and Methods */
    private:
        float padding;
}

作者声称,填充物将对象的大小增加到X86体系结构中的四键,从而对性能带来了显着的好处。这是因为4个单词在内存中比3更干净地坐着,这是什么意思?用冗余数据填充一个物体以提高性能对我来说似乎很自相矛盾。

这也引出了另一个问题,大小1或2个单词的对象呢?如果我的班级类似:

class Bar
{
    public:
        float x;
        float y;
        /* Constructors and Methods */
    private:
        /* padding ?? */
}

我应该在此类中添加填充物,以便在内存中更清晰地

编译器的责任,决定什么是合理的填充(假设典型的访问模式)。编译器对您的机器的了解比您所了解的要多得多。此外,您的机器将与您同在几年。该程序将在数十年中,在各种平台上运行,但要受到各种用法模式的困扰。对于今天的i7来说,最好是明天的i8或ARMV11最糟糕的情况。

为追求难以捉摸的"性能"而混淆的代码直接落入过早的优化中。永远记住,您的时间(一周之后的写作,测试,调试,再次理解,对代码进行调整)要比浪费的计算机时间贵得多(除非上述代码每天运行数千次在数百万台机器上运行数千次, 那是)。代码调整根本没有任何意义,直到您有艰难的事实表明性能还不够,并且测量告诉您,围绕该结构的结构是一个值得担心的瓶颈。

处理器不"读取"字节作为人类的内存字节,它们会根据处理器的大小可变大小处理。这就是记忆访问粒度;

通过"存储器对齐"您的对象,ACESS时间可能更快,您也可以避免数据片段。

您可以在此处阅读有关数据校准的更多信息

编辑:我并不是说这是一种好是或坏习惯,只是分享我对此的了解。

回答这个问题有两个非常重要的话。

首先,如果您要调整绩效效益的代码,并且如果您认为这是值得的(无论出于何种原因),则您必须首先编写基准测试。您必须能够尝试并测量差异。

第二,这种调整将取决于汇编语言与硬件的交互方式。您必须能够读取汇编语言代码并了解不同的说明集和硬件访问模式,以了解为什么这些调整可能会起作用。

最后,您的问题没有孤立的答案。这取决于这些对象是单独分配还是在集合中分配;它们旁边是否还有其他对象;以及编译器如何为每种情况生成代码。在两个两个边界上的可能性对齐的可能性都比错位更快,但是适合缓存的集合比没有的藏品要快。我不会指望填充8或4个字节可以提高性能,但是如果很重要,我会尝试并测试结果。

最新更新