gpt4 book ai didi

c - 处理器如何读取内存?

转载 作者:行者123 更新时间:2023-12-01 23:14:47 24 4
gpt4 key购买 nike

我正在尝试重新实现malloc,我需要了解对齐的目的。据我了解,如果内存对齐,则代码将更快地执行,因为处理器无需采取额外的步骤来恢复被削减的内存位。我想我知道64位处理器读取64位乘64位内存。现在,让我们想象一下,我有一个按顺序排列的结构(不带填充):一个char,一个short,一个char和一个int。为什么短路会错位?我们将所有数据存储在块中!为什么它必须位于2的倍数的地址上?对于整数和其他类型也有相同的问题吗?

我还有第二个问题:利用我之前提到的结构,处理器如何在读取其64位时知道前8位对应于char,然后接下来的16位对应于short等...?

最佳答案

这些影响甚至可能包括正确性,而不仅仅是性能:如果您的short对象不满足alignof(short),则C不确定行为(UB)可能导致段错误或其他不良行为。 (在默认情况下需要对加载/存储指令进行对齐的ISA(如SPARC和MIPS64r6之前的MIPS),预计会发生故障)

或者,如果_Atomic int没有alignof(_Atomic int),则将破坏原子操作。

(在任何给定的ABI中,alignof(T) = sizeof(T)通常为最大大小,通常为寄存器宽度或更宽)。

malloc应该使用 alignof(max_align_t) 返回内存,因为您没有有关如何使用分配的任何类型信息。

对于小于sizeof(max_align_t)的分配,您可以根据需要返回仅自然对齐的内存(例如4字节的内存按4字节对齐),因为您知道存储不能用于具有更高对齐要求的任何内容。

动态对齐的alignas (16) int32_t foo等过度对齐的东西需要使用特殊的分配器,例如C11 aligned_alloc。如果要实现自己的分配器库,则可能要支持aligned_realloc和aligned_calloc,以填补没有明显原因的ISO C留下的空白。

如果分配的大小不是对齐的倍数,请确保您没有实现对aligned_alloc失败的braindead ISO C++ 17要求。没有人希望分配器拒绝从16个字节的边界开始分配101个浮点数的分配器,或者更大的分配器以获取更好的透明大页。 aligned_alloc function requirementsHow to solve the 32-byte-alignment issue for AVX load/store operations?


我想我知道64位处理器可以读取64位乘64位内存

不。数据总线宽度和突发大小,以及加载/存储执行单元的最大宽度或实际使用的宽度,不必与整数寄存器的宽度相同,或者由CPU定义其位数。 (并且在现代高性能CPU中通常没有,例如32位P5 Pentium具有64位总线;现代32位ARM具有执行原子64位访问的加载/存储对指令。)

处理器将整个缓存行从DRAM / L3 / L2缓存读取到L1d缓存;在现代x86上为64字节;在某些其他系统上为32个字节。

当读取单个对象或数组元素时,它们将从L1d缓存中读取元素宽度。例如对于2字节加载/存储,uint16_t数组可能仅受益于对齐2字节边界。

或者,如果编译器使用SIMD对循环进行 vector 化处理,则可以一次读取uint16_t数组16或32 字节,即8或16个元素的SIMD vector 。 (或者使用AVX512甚至为64)。将数组与期望的 vector 宽度对齐可能会有所帮助;当未对齐的SIMD加载/存储未越过缓存行边界时,它们可以在现代x86上快速运行。

高速缓存行拆分,尤其是页面拆分是现代x86因未对齐而减慢的地方。高速缓存行中未对齐的晶体管通常不是因为它们花费晶体管来进行快速未对齐的加载/存储。其他一些ISA在任何未对齐情况下都会减慢速度,甚至出现故障,甚至在高速缓存行内也是如此。解决方案是相同的:给类型自然对齐:alignof(T)= sizeof(T)。

在您的struct示例中,即使short未对齐,现代x86 CPU也不会受到任何影响。任何普通ABI中的alignof(int) = 4,因此整个结构都具有alignof(struct) = 4,因此char;short;char块从4字节边界开始。因此,short包含在单个4字节dword中,不跨越任何更宽的边界。 AMD和Intel都以充分的效率处理此问题。 (并且x86 ISA保证对它的访问在与P5 Pentium或更高版本兼容的CPU上是原子的,甚至是未缓存的:Why is integer assignment on a naturally aligned variable atomic on x86?)

某些非x86 CPU可能会因未对齐的短路而受到处罚,或者必须使用其他指令。 (由于您知道相对于对齐的32位块的对齐方式,因此对于负载,您可能会进行32位的加载和移位。)

因此,是的,访问包含short的单个单词没有问题,但是的问题是负载端口硬件将short提取并零扩展(或符号扩展)到完整寄存器中。 ,这是x86花费晶体管使速度更快的地方。 (此问题先前版本的@Eric's answer进一步详细介绍了所需的转换。)

将未对齐的存储提交回缓存也是很简单的。例如,L1d缓存可能在32位或64位块(我称为“缓存字”)中具有ECC(针对位翻转的纠错)。因此,由于这个原因,只写一部分高速缓存字是一个问题,而且要将其移到要访问的高速缓存字内的任意字节边界。 (在存储缓冲区中对相邻的狭窄存储区进行联合处理可以产生全宽度提交,从而避免了RMW周期来更新以这种方式处理狭窄存储区的单词的一部分)。请注意,我之所以说“单词”,是因为我所谈论的硬件更面向单词,而不是像现代x86那样围绕未对齐的加载/存储进行设计。 请参阅Are there any modern CPUs where a cached byte store is actually slower than a word store?(存储单个字节仅比未对齐的short稍微简单)

(如果short跨越两个缓存字,则当然需要分开RMW周期,每个字节一个。)

当然,由于short的简单原因,导致alignof(short) = 2失准,并且它违反了此ABI规则(假定具有此规则的ABI)。因此,如果将指向它的指针传递给其他函数,则可能会遇到麻烦。尤其是在负载发生错位错误的CPU上,而不是由硬件处理这种情况,即在运行时发现错位。然后,您会遇到Why does unaligned access to mmap'ed memory sometimes segfault on AMD64?这样的情况,其中GCC自动 vector 化有望通过对2字节元素进行标量的倍数来达到16字节边界,因此违反ABI会导致x86出现段错误(通常容忍未对齐)。

有关内存访问的完整详细信息,从DRAM RAS / CAS延迟到高速缓存带宽和对齐方式,请参阅What Every Programmer Should Know About Memory?

Purpose of memory alignment也有一个不错的答案。 SO的标签还有很多其他好的答案。

有关(某种程度上)现代英特尔加载/存储执行单元的更多详细信息,请参阅:https://electronics.stackexchange.com/questions/329789/how-can-cache-be-that-fast/329955#329955


当处理器读取其64位时,如何知道前8位对应于一个char,然后接下来的16位对应于short等...?

除了运行说明以这种方式处理数据的事实外,没有其他操作。

在asm /机器代码中,所有内容都只是字节。 每条指令都精确指定了处理哪些数据。在原始字节数组(主内存)之上,由编译器(或人工程序员)实现具有类型的变量以及C程序的逻辑。

我的意思是,在asm中,您可以运行所需的任何加载或存储指令,并且要在正确的地址上使用正确的指令。您可以将与两个相邻的int变量重叠的4个字节加载到浮点寄存器中,然后在其上运行addss(单精度FP加法),CPU不会抱怨。但是您可能不想这样做,因为让CPU将这4个字节解释为IEEE754 binary32 float不太有意义。

关于c - 处理器如何读取内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60133064/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com