我们在调试构建下触发了一个断言来检查对齐情况。断言适用于加载到 using 中的字节uint8x16_t数组vld1q_u8。当断言触发时,我们没有观察到SIG_BUS.
下面是代码中的使用:
const byte* input = ...;
...
assert(IsAlignedOn(input, GetAlignmentOf(uint8x16_t));
uint64x2_t message = vreinterpretq_u64_u8(vld1q_u8(input));
Run Code Online (Sandbox Code Playgroud)
我还尝试了以下操作,并触发断言以进行对齐uint8_t*:
assert(IsAlignedOn(input, GetAlignmentOf(uint8_t*));
uint64x2_t message = vreinterpretq_u64_u8(vld1q_u8(input));
Run Code Online (Sandbox Code Playgroud)
将字节数组加载到 with 时有哪些对齐uint8x16_t要求vld1q_u8?
上面的代码中,input是一个函数参数。IsAlignedOn检查其两个参数的对齐方式,确保第一个参数至少与第二个参数对齐。GetAlignmentOf是检索类型或变量的对齐方式的抽象。
uint8x16_t和uint64x2_t是 128 位 ARM NEON 向量数据类型,预计放置在 Q 寄存器中。vld1q_u8是一个 NEON 伪指令,预计会被编译成VLD1.8指令。vreinterpretq_u64_u8是一条 NEON 伪指令,可简化数据类型的使用。
我最近发布了一个关于未对齐内存访问的问题,但给出答案后,我有点迷失。我经常听到“对齐的内存访问比未对齐的访问效率要高得多”,但我实际上不确定什么是未对齐的内存。最后:
我有一个问题需要了解是否有更好的解决方案。我编写了以下代码,将一些变量从编写器线程传递到读取器线程。这些线程固定到共享相同 L2 缓存的不同 CPU(禁用超线程)。
writer_thread.h
struct a_few_vars {
uint32_t x1;
uint32_t x2;
uint64_t x3;
uint64_t x4;
} __attribute__((aligned(64)));
volatile uint32_t head;
struct a_few_vars xxx[UINT16_MAX] __attribute__((aligned(64)));
Run Code Online (Sandbox Code Playgroud)
reader_thread.h
uint32_t tail;
struct a_few_vars *p_xxx;
Run Code Online (Sandbox Code Playgroud)
写入线程增加头变量,读取线程检查头变量和尾变量是否相等。如果它们不相等,则按如下方式读取新数据
while (true) {
if (tail != head) {
.. process xxx[head] ..
.. update tail ..
}
}
Run Code Online (Sandbox Code Playgroud)
性能是迄今为止最重要的问题。我使用的是 Intel Xeon 处理器,读取器线程每次都会从内存中获取 head 值和 xxx[head] 数据。我使用对齐数组来实现无锁
就我而言,是否有任何方法可以尽快将变量刷新到读取器CPU缓存中。我可以从写入器 CPU 触发读取器 CPU 的预取吗?如果存在的话,我可以使用 __asm__ 来使用特殊的英特尔指令。总之,在固定到不同 CPU 的线程之间传递结构中的变量的最快方法是什么?
提前致谢
它们有何不同?
我读到 SUBALIGN() 以某种方式强制进行某种对齐。还有其他区别吗?
什么时候应该使用 ALIGN(),什么时候应该使用 SUBALIGN()?
我注意到,当在结构体周围使用 #pragma pack 时,它内部的对齐方式并不是唯一受到影响的对齐方式,而且结构体本身的对齐方式也会发生变化。考虑以下:
#include <stdio.h>
#include <stdint.h>
#pragma pack(1)
typedef struct _TEST
{
uint32_t a;
} TEST;
#pragma pack()
volatile uint8_t n;
TEST b;
int main()
{
printf("Address %lX rem %lu\n", (long unsigned int)&b, (long unsigned int)(&b)%(sizeof(int)));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
您可以在这里尝试此代码: https: //onlinegdb.com/BkebdxZEU
程序返回Address 601041 rem 1,这意味着该编译指示也对结构体产生了aligned(1) 的效果。
这是为什么?这是一个定义的行为吗?
我在p0019r8上读到以下内容:
Run Code Online (Sandbox Code Playgroud)atomic_ref(T& obj);要求:引用的对象应与 对齐
required_alignment。
当未对齐时, cppreference将其解释为 UB:
如果 obj 未与 required_alignment 对齐,则行为未定义。
那么您期望实现如何处理它呢?
并且实现可以检查编译时 alignof,但实际上类型可能比对齐更对齐alignof。实现可以解释指针位并检查运行时对齐,但这是额外的运行时检查。
最终我看到以下选项:
alignof) 并在错误时发出警告alignof) ,如果错误不正确,则编译时失败,alignof),如果错误不正确,则在运行时失败,alignof) 并在错误时回退到基于锁我试图了解结构填充在 C 中的工作原理。特别是在 Linux x86-64 环境中。为此,我重新排列了给定结构的成员的顺序,以查看在不需要时是否不会应用填充。然而,当我编译并运行打印每个结构的大小的代码时,填充被应用于它们两个,即使第二个结构(struct b)的成员以这样的方式排列,连续地将它们存储在内存中不会导致其中之一占据多个字块。
#include <stdio.h>
struct a {
int ak;
char ac;
char* aptr;
};
struct b {
char* bptr;
int bk;
char bc;
};
int main(int argc, char* argv[]) {
printf("%lu\n", sizeof(struct a));
printf("%lu\n", sizeof(struct b));
}
Run Code Online (Sandbox Code Playgroud)
输出:
16
16
Run Code Online (Sandbox Code Playgroud) 假设我有结构:
typedef struct my_char {
char c;
} my_char_t;
Run Code Online (Sandbox Code Playgroud)
我可以假设任何时候内存地址都会对齐吗?
我想也许是的,因为在教程中我看到了这样的结构:
typedef struct my_char2 {
char c;
int i;
} my_char2_t;
Run Code Online (Sandbox Code Playgroud)
c和之间有填充i,因此看起来假设c是对齐的。
在 C 中,如果我尝试通过未对齐的指针访问类型,则可能会发生不好的事情:
int x[2]; // Assuming CHAR_BIT == 8 && sizeof(int) == 4
*(int *)((char *)x+1) = 10; /* Undefined behavior due to unaligned pointer dereference
even though there are no out of bounds accesses */
Run Code Online (Sandbox Code Playgroud)
但是,如果相关类型是 a但我只访问不具有对齐要求union的成员,该怎么办?union
union X {
int i;
char c[4];
} x[2];
((union X *)((char *)x+1))->i = 10; /* I am guessing this is still undefined behavior
because accessing an unaligned int through a union does not make a difference as …Run Code Online (Sandbox Code Playgroud) c memory-alignment undefined-behavior unions language-lawyer
我正在处理大小范围从 2,000x2,000 到 5,000x5,000 的矩阵,执行乘法和 QR 分解等运算。例如,我很好奇是否应该将所有矩阵的步长对齐 64,以获得最佳性能。另外,由于缓存关联性,我是否应该避免步幅为某些页面大小的倍数,或者这不适用于 GPU 内存?