【问题标题】:Use an array of pointers to structs, or just an array of structs?使用指向结构的指针数组,还是仅使用结构数组?
【发布时间】:2011-07-19 19:16:36
【问题描述】:

我正在为微控制器使用 C 语言的 FFT 算法,在决定是将输入数据的实部和虚部仅存储在结构数组中还是使用指向结构数组的指针时遇到了麻烦.我面临着相互冲突的要求,即代码必须在少量内存中运行,而且还要尽可能快。我相信指向结构的指针数组会有更大的内存开销,但我的代码中有一行基本上如下所示:

for (uint8_t i = 0; i < RECORD_SIZE; i++)
{
    uint8_t decimateValue = fft_decimate(i);
    fftData[i]->realPart = fftTempData[decimateValue]->realPart;
    fftData[i]->imPart = fftTempData[decimateValue]->imPart;
}

我在想,如果我在上面的示例中使用指向结构的指针数组,那么编译的代码会更快,因为它只是重新洗牌指针,而不是实际将两个数据结构之间的所有数据复制为结构数组实现将。如果上面的代码部分运行得尽可能快,我愿意牺牲一些额外的内存。感谢您的任何建议。

【问题讨论】:

  • 为什么不直接运行两个版本的代码,看看哪个更快?

标签: c data-structures signal-processing


【解决方案1】:

每次通过指针数组访问数据时,都会有两次内存访问。这通常会导致流水线停顿,即使在微控制器上也是如此(除非它是没有流水线的非常小的微控制器)。

然后你必须考虑数据的大小。指针有多大? 2个字节? 4字节?结构有多大? 4字节? 8 个字节?

如果结构体的大小是指针的两倍,则使用指针对数据进行混洗的成本将降低一半。但是,以任何其他方式读取或修改数据将更加昂贵。所以这取决于你的程序做什么。如果您花费大量时间读取数据而只花一点时间对其进行洗牌,请针对读取数据进行优化。其他人说得对——简介。确保在您的微控制器上进行配置,而不是在您的工作站上。

【讨论】:

  • 该算法在读取上花费的时间比洗牌要多得多,所以看起来我应该使用直接数组实现。 IIRC,我认为 AVR Mega 系列有一个 2 阶段管道。
【解决方案2】:

如果您的结构非常小,那么拥有一个结构数组并将它们随机播放实际上会更快。如果你的结构很大,如果你只是在指针周围移动,这个特定的动作会更快。

等一下……再看一眼,您的代码中似乎没有在指针周围混洗,而是在访问这些指针引用的结构的字段;实际上,您仍在改组结构本身,而不是指针。这将比移动指针慢,也比移动结构慢,因为它必须取消引用指针,然后仍然移动结构。

【讨论】:

  • 我想我很好奇编译器是否会看到,因为我将每个结构的所有相同元素相互分配,真正需要做的就是改变指针的值在 fftData[i] 中指向 fftTempdata[decimateValue] 指向的任何内容。
【解决方案3】:

你是对的。指针数组会更快,但内存使用会产生开销。如果有内存可以使用指针,请使用它们。

【讨论】:

    【解决方案4】:

    首先:视情况而定。轮廓。

    缓存位置将在这里占据主导地位。我希望结构非常小(代表复数?)。在 FFT 中,我希望将实部和虚部存储在单独的数组中获得更多收益。

    然后您可以在 CPU 内核之间分配负载。

    如果它是关于更大的块(比如 1024 个样本块),我强烈怀疑改组指针更有效。它还可以让您更轻松地处理来自多个线程的相同(只读)数据。移动内存是使大量迭代器失效的一种特定方式,通常您希望任务(即线程)在数据的子范围上工作,即:它们所拥有的只是一个迭代器子范围。

    【讨论】:

    • 这个问题特别提到了微控制器,它们通常没有多核,也经常没有缓存。
    • @Dietrich:好点。对不起,我错过了。在这种情况下,我会避免让 CPU 做其他事情而不是计算操作数的有效地址
    猜你喜欢
    • 2013-08-02
    • 2012-02-25
    • 1970-01-01
    • 2017-06-03
    • 2012-02-18
    • 2012-12-07
    • 2016-06-20
    相关资源
    最近更新 更多