【问题标题】:The effects of data (mis)alignment数据(错误)对齐的影响
【发布时间】:2012-10-24 18:13:47
【问题描述】:

我正在使用 x86 intel 机器和 Windows 7,以及 Visual C++(2005/2012 版 express)

我一直在玩对齐(我只是将其作为学习练习。)当然,我理解填充方面对类/结构大小的影响。我相信我理解由于 CPU 指令的工作方式和期望数据的方式,它也可以更好地对齐。

我一直在查看许多不同的资源,例如(有趣) c++ data alignment /member order & inheritance (以及维基百科等其他链接)http://en.wikipedia.org/wiki/Data_structure_alignment

一个可能受到影响的领域(我读过)似乎是性能,因为数据需要为寄存器的特定大小,未对齐的数据可能会导致问题(请参阅维基百科)。

我编写了一些代码,其中创建了 3 个结构,所有结构都具有相同的成员,打包设置为 1 ,正常对齐,并且重新排列了成员。这给了我大小为 8、10 和 12 的对象。我为每个对象运行了类似于以下的代码:

struct MixedData1
{
    char Data1;
    short Data2;
    int Data3;
    char Data4;

    void operator() (MixedData1& md)
    {
        md.Data1 = 'a';
        md.Data2 = 1024;
        md.Data3 = 1000000;
        md.Data4 = 'b';
    }
};

typedef std::vector<MixedData1> MDVector;


int main(int argc, char* argv[])
{
    MixedData1 md;
    for(int count = 0; count < 10 ; count++)
    {    
        {
        std::cout << sizeof(md) << std::endl;
        boost::timer::auto_cpu_timer t;
        MDVector mdv(10000000); 
        std::fill(mdv.begin(),mdv.end(),md );
        std::for_each(mdv.begin(),mdv.end(),md);
        }
    }
}

我对这些值并不真正感兴趣,因此向量中的每个元素都被初始化为相同的。无论如何,我得到的结果表明运行时间随着结构的大小而增加 - I.E with pack(1) (8 bytes) 我得到了最快的 0.08s,而正常对齐 (12 bytes) 我得到了最慢的 0.105 。

我的问题是关于错误对齐的影响。作为一名 C++ 程序员,我认为在我的 X 年中我从来没有遇到过任何对齐问题,但当然它可能只是让我忽略了。

(1) 对齐在我的测试(编辑)中产生了影响(我相信)但是正如 Neil 发布的那样,这只是由于结构大小的差异。我尝试按照他的回复访问该成员,但我在那里没有看到任何实际效果....有更清晰的例子吗?有没有办法让我看到错位的巨大影响? (2)如果可能的话,有没有办法引起由错位引起的碰撞。

【问题讨论】:

  • 在 68000 系列芯片上(旧 Mac 曾经拥有它们),未对齐的数据导致操作系统崩溃。这是相当戏剧性的。
  • @John 我会挖出我的旧 atari ST :P

标签: c++ visual-studio alignment


【解决方案1】:

简短的回答:在实践中并不重要。

原因如下:1 或 2 次缓存未命中可能需要不到一毫秒的时间,因此只有在以下情况下访问未对齐的数据才会成为问题:

  1. 数据跨越两个缓存行
  2. 您访问了许多未对齐的数据,这些数据在内存中并不连续。

由于 2. 无论如何都会产生大量缓存未命中,因此即使数据对齐,您也不应该处于这种情况。改进对齐方式可以将缓存未命中次数提高不超过 2 倍,但连续存储数据可以将性能提高很多倍。

有些指令需要对齐数据。如果您需要这些说明,您要么知道它,要么您的编译器应该为您确保对齐。这是否会影响性能取决于您的处理器的微架构和编译器。无论如何,您应该首先分析您的程序以找到瓶颈。如果对齐显着影响程序的性能,请修复它。否则别担心。

【讨论】:

  • 非常感谢您提供的额外信息 - 我认为关于它是什么以及它有什么影响的基本知识比追求小细节更重要。所以我同意你在这里的回答。正如我所说,多年来我没有遇到任何与对齐有关的问题,我猜这可能是由于我使用的架构和编译器,但我很高兴现在能更好地理解这一点 - 再次感谢 :)
【解决方案2】:

您的代码所做的只是测试处理器复制内存的速度。内存越大,复制越慢。结构中各个成员的对齐方式与复制速度无关,重要的是结构的大小。

如果您想查看对齐的效果,您需要编写实际访问各个未对齐结构成员的代码。例如,您可以编写一个循环来增加每个结构的 data3 成员。根据架构,编译器可能会意识到它必须使用不同的指令来执行算术;在 x86 上通常不是这种情况,编译器会发出看起来自然的代码,因为处理器能够处理未对齐的访问。一些处理器实际上可以以与对齐数据相同的速度读取和写入未对齐数据。一个简单的例子是 8088,因为它只有一个 8 位数据总线,所以无论如何所有 16 位指令都是使用两个负载来模拟的,但是最新的处理器大部分时间都花在从高速缓存行中读取,因此唯一的时间是未对齐的数据可能会有所不同的是数据何时越过缓存线。

如果你想通过错位引发崩溃,那么通常你需要在不同类型之间转换指针。然后编译器可能并不总是意识到您的指针可能未对齐,并且不会为未对齐的访问生成正确的指令。例如,您可以尝试在 cast char* 指针上调用 SSE 指令。

【讨论】:

  • 老实说,我有一种感觉,谢谢你的信息,我会进一步玩和更新。
  • 是的,我没有看到明显的差异,现在我正在访问成员 (Data3)...+1 的帮助 - 谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-24
  • 1970-01-01
  • 1970-01-01
  • 2021-09-17
  • 1970-01-01
相关资源
最近更新 更多