相关疑难解决方法(0)

处理器如何读取内存?

我正在尝试重新实现 malloc 并且我需要了解对齐的目的。据我了解,如果内存对齐,代码将执行得更快,因为处理器不必采取额外的步骤来恢复被切割的内存位。我想我明白 64 位处理器读取 64 位 x 64 位内存。现在,让我们假设我有一个按顺序排列的结构(没有填充):一个字符、一个短字符、一个字符和一个整数。为什么短路会错位?我们拥有区块中的所有数据!为什么它必须在一个 2 的倍数的地址上。对于整数和其他类型,同样的问题?

我还有第二个问题:使用我之前提到的结构,处理器如何知道当它读取它的 64 位时前 8 位对应于一个字符,然后接下来的 16 位对应于一个短等等......?

c cpu cpu-architecture memory-alignment low-level

2
推荐指数
1
解决办法
743
查看次数

某些未定义的行为是否比其他行为更加未定义?

这就是我的意思:i++ + i++未定义,对数组的越界写入也是如此.

超出范围的数组写入的不确定性是可以理解的:它可能被利用来运行任意代码,这是您可以获得的未定义代码.让我们调用这个运行时未定义的行为.

对于i++ + i++,然而,故事似乎是不同的.假设编译器生成了一些东西.它究竟是什么未定义的.非常不确定.事实上,它是如此不确定,我们曾经听过猫可能怀孕(虽然最近 - 从CppCon 2016,我认为 - 人们开始意识到,未定义的行为毕竟不能让猫怀孕).

但是,一旦我们打开盒子,看看编译器生成了什么,并且它不是可利用的代码(注入,数据竞争等等 - 例如,编译器选择i++ + i++完全抛弃),是不是它将完全被执行 -是不是从那一点上完美定义了

换句话说,最后一种情况是我们可以称之为编译时未定义的行为.用猫来说,它类似于薛定谔的猫,在你打开盒子之前它的状态是未知(参见生成的装配),此时你会看到要执行的实际现实.(我想知道未定义的行为是否会使有毒的死猫怀孕.)

当然,未定义的行为是适用于该标准的法律术语.问题是关于现实中发生的"行为".

c++ undefined-behavior

1
推荐指数
1
解决办法
154
查看次数

__int128对齐段故障与gcc -O SSE优化

__int128用作struct的成员.它可以找到-O0(没有优化).

但是,如果启用了优化(-O1),则会因段故障而崩溃.

它在指令处崩溃movdqa,需要将var对齐16,而地址的分配malloc()仅由8对齐.

我尝试禁用SSE优化-mno-sse,但无法编译:

/usr/include/x86_64-linux-gnu/bits/stdlib-float.h:27:1: error: SSE register return with SSE disabled
Run Code Online (Sandbox Code Playgroud)

所以,我能做些什么,如果我想使用__int128-O1两者兼而有之?

在此先感谢吴

顺便说一下,如果__int128仅在堆栈上使用(不在堆上),似乎没问题.

====编辑====

对不起,我没说实话.

其实我没用过malloc().我使用了一个内存池lib,它返回8对齐的地址.我说malloc()只是为了让事情变得简单.

经过测试,我已经知道它malloc()与16对齐.并且__int128成员也在结构中对齐16.

所以问题是我的内存池lib.

非常感谢.

gcc sse memory-alignment compiler-optimization

1
推荐指数
1
解决办法
270
查看次数

Java指令重排序和CPU内存重排序

这是一个后续问题

如何演示Java指令重排序问题?

有很多文章和博客提到 Java 和 JVM 指令重新排序,这可能会导致用户操作中出现反直觉的结果。

当我要求演示 Java 指令重新排序导致意外结果时,有几条评论说,更普遍的关注领域是内存重新排序,并且很难在 x86 CPU 上进行演示。

指令重新排序只是内存重新排序、编译器优化和内存模型等更大问题的一部分吗?这些问题真的是 Java 编译器和 JVM 特有的吗?它们是否特定于某些 CPU 类型?

java cpu-architecture memory-barriers instruction-reordering

1
推荐指数
1
解决办法
515
查看次数

为什么大小小于 CPU 字大小的数据需要以其大小的倍数对齐?

我们假设有一个 32 位 CPU 和 2 字节short。我知道 4 字节int需要在 4 的倍数地址处对齐,以避免额外读取。

问题:

  1. 如果 处存储了短路,CPU 仍可以在一次操作中0x1读取。0x0那么,为什么 Shorts 需要以 2 的倍数地址对齐呢?
  2. 如果一个short存储在0x2,为什么它会被认为是对齐和高效的,因为CPU只能从0x0读取并丢弃前两个字节?

有一个问题与此非常相似,但是,答案仅告诉我们short结构体和独立变量中的对齐要求是相同的。还有一条获得 2 票赞成的评论说:

在许多机器上,当数量是 N 字节对齐时,访问 N 字节数量(至少是 {1, 2, 4, 8, 16} 中的 N)的效率最高。生活就是这样;习惯它,因为我怀疑芯片制造商会仅仅因为你认为它不应该是这样而改变它。

但为什么?

c memory cpu-architecture memory-alignment

1
推荐指数
1
解决办法
332
查看次数

基于 BitMask 在数组中设置值的本质

是否有一个内在函数可以在输入数组中的所有位置设置单个值,其中相应位置在提供的 BitMask 中具有 1 位?

10101010 是位掩码

值为 121

它将设置位置 0,2,4,6 值为 121

c x86 bit-manipulation intel intrinsics

0
推荐指数
1
解决办法
1854
查看次数

是不是__m128d本地对齐?

我有这个代码:

double a[bufferSize];
double b[voiceSize][bufferSize];
double c[voiceSize][bufferSize];

...

inline void AddIntrinsics(int voiceIndex, int blockSize) {
    // assuming blockSize / 2 == 0 and voiceIndex is within the range
    int iters = blockSize / 2;
    __m128d *pA = (__m128d*)a;
    __m128d *pB = (__m128d*)b[voiceIndex];
    double *pC = c[voiceIndex];

    for (int i = 0; i < iters; i++, pA++, pB++, pC += 2) {
        _mm_store_pd(pC, _mm_add_pd(*pA, *pB));
    }   
}
Run Code Online (Sandbox Code Playgroud)

但是,"有时",它提高访问内存冲突,我认为它是由于缺少我的3个数组的内存对齐的a,bc.

但是,由于我操作__m128d(使用__declspec(align(16))),当我转换为指针时,是否保证对齐? …

c++ sse simd memory-alignment intrinsics

0
推荐指数
1
解决办法
109
查看次数

x86 上是否需要 std::memory_order_acquire 栅栏?

鉴于 x86 具有强大的内存模型,是否有必要使用std::memory_order_acquirefence(不是 operation)?

例如,如果我有这个代码:

uint32_t read_shm(const uint64_t offset) {
   // m_head_memory_location is char* pointing to the beginning of a mmap-ed named shared memory segment
   // a different process on different core will write to it.
   return *(uint32_t*)(m_head_memory_location + offset);
}
....
int main() {
     uint32_t val = 0;
     while (0 != (val = shm.read(some location)));
     .... // use val
}
Run Code Online (Sandbox Code Playgroud)

我真的需要std::atomic_thread_fence(std::memory_order_acquire)在return语句之前吗?

我觉得没有必要,因为上面代码的目标是尝试从 读取前 4 个字节m_head_memory_location + offset,因此重新排序栅栏后的任何内存操作都不会影响结果。

或者有一些副作用使获取栅栏变得必要?

在 x86 上是否需要获取栅栏(不是操作)? …

c++ x86 memory-barriers c++11 stdatomic

0
推荐指数
1
解决办法
186
查看次数

如何避免在皮质 M4 上浮动的未对齐访问异常

我在某些计算带有整数操作数的浮点表达式的代码中遇到了 HardFault 异常。操作数按地址传递,然后将其转换(隐式或显式转换)为浮点数。当操作数不是 32 位对齐时(这不在我的控制之下),我得到异常。

我试图在这里重现 Godbolt 上的行为,生成的代码与我在设备上得到的一致。

基本上,下面的反汇编代码

vldr.32 s0, [r0]  @ int
Run Code Online (Sandbox Code Playgroud)

vldr需要对齐地址的指令中直接使用传递给函数的可能未对齐的地址。

我发现这个问题解决了类似的问题,但他们在那里谈论浮点指针。在这种情况下,我知道浮动不能未对齐。

在我的情况下,我正在处理整数,允许未对齐,但编译器假定它仍然可以使用 vldr 指令中的地址。更让我困惑的是这段代码

uint32_t pippo =  *(uint32_t *)src;

float pippof = pippo * 10.0f;
Run Code Online (Sandbox Code Playgroud)

当提供未对齐的地址时,可能会或可能不会产生异常,这取决于优化级别,因为-O0例如在堆栈上分配了一个整数。

所以我的问题是:

  • 这是编译器(或后端,也许)的正确行为吗?由于整数可以未对齐,我希望生成的代码从 CPU 寄存器传递。
  • 当即使通过临时 int 变量也不安全时,避免此类问题的正确策略是什么?

c assembly gcc arm memory-alignment

0
推荐指数
1
解决办法
317
查看次数