【问题标题】:Posix memalign fails on Broadwell but not on SkylakePosix memalign 在 Broadwell 上失败,但在 Skylake 上失败
【发布时间】:2020-09-30 20:57:35
【问题描述】:

以下代码使用 Posix Memalign 为每个内核分配四个缓冲区,每个缓冲区 128 字节。它在 Skylake 上成功,但在 Broadwell(较早一代)上失败,并显示以下消息:

posix memalign malloc.c:2401: sysmalloc: Assertion `(old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)' failed

根据 Linux 手册页,memalign 在以下情况下会失败:(1) 对齐参数不是 2 的幂,或者不是 sizeof(void *) 的倍数,或者 (2) 不够内存以满足分配请求。由于它会产生分段错误,因此我无法从 rax 获取错误号。 Broadwell 有 8GB 内存,所以内存不足不是问题。对齐是 64,所以这不是问题,而且无论如何它在我的 Skylake 上成功,所以它写得正确。

以下是相关代码块:

mov rax,2 ; number of cores
mov rbx,4 ; number of buffers to create
mul rbx
mov r14,rax
xor r13,r13

Memalign_Create_Loop:
mov rax,r15 ; number of cores
mov rbx,r12 ; number of buffers needed
 ; N ptrs per core x 8 bytes per pointer
mul rbx ; times the number of cores
mov r12,rax ; number of buffers needed x number of cores
lea rdi,[memalign_pointer]
mov rsi,64 ; alignment
mov rdx,r12
shl rdx,3
mov rdx,128 ; buffer size
;xor rax,rax    
sub rsp,40
call posix_memalign wrt ..plt
add rsp,40
lea r8,[internal_buffer_pointers]
lea rdi,[memalign_pointer]
mov rax,[rdi]
mov rbx,r13
shl rbx,3
mov [r8+rbx],rax
add r13,1
cmp r13,r14
jl Memalign_Create_Loop

它在“call posix_memalign wrt ..plt”处失败,并显示如上所示的错误消息以及分段错误消息。

这对我来说是个谜,因为它在 Skylake 上取得了成功,而且 posix_memalign 早于 Broadwell。

我组装并链接到:

sudo nasm -f elf64 -g -F dwarf NWL.asm

sudo ld -shared NWL.o /opt/P01_SH/_Library/Create_Threads_in_C-NWL.o /opt/P01_SH/_Library/Timer_for_NASM.o /opt/P01_SH/_Library/POSIX_Shared_Memory.o /opt/P01_SH/_Library/PThread_Mutex .o /opt/P01_SH/_Library/Create_Multi_Files.o -ldl -lrt -lpthread -lm -o NWL.so

感谢您对此提出任何想法。

【问题讨论】:

  • CPU 系列似乎不太可能成为决定性的特征。两台机器使用什么操作系统版本?另外,您使用什么命令来组装和链接? AFAIK plt 在 x86-64 上通常不需要;如果你只是call posix_memalign,它可以工作吗?
  • 我一直在使用过程链接表,但是您建议没有它的调用是有道理的,因为这可能是 seg 错误的来源(包括调用中的 plt)。我用汇编和链接字符串(NASM 编译器和 ld 链接)更新了我的问题。要查询 Linux 版本并在没有 plt 的情况下尝试调用,它是一个共享服务器,大约 30 分钟我无法访问。之后,我可以在这里更新答案。感谢您的 cmets。
  • 断言消息似乎表明存在堆损坏的情况。那么实际的错误将出现在早期的代码中,只有在您的函数尝试另一个分配时才会检测到损坏。两个 CPU 可能实现不同的向量指令集,并且许多高度优化的库具有针对每个 CPU 系列专门调整的代码,在运行时选择。这可能会导致不同大小的堆分配,而损坏只针对其中一种情况。
  • 好点@kisch。您是否尝试过调试 malloc 崩溃的常用技术,例如瓦尔格林? posix_memalignmalloc 是同一条船,在这里你使用哪一个并不重要。这很可能是一个简单的错误,您只是在某处注销了内存块的末尾,或者在释放内存后使用了内存,与 CPU 架构的深奥细节或分配大块还是小块无关。
  • @PeterCordes:感谢您的澄清,在评论之前我没有比较 CPU。这使得与调整库不同的堆使用模式不太可能。在这种情况下,我可能会寻找不同数量的内核,这可能会遇到多线程错误。特别是因为发布的代码明确提到了核心的数量。

标签: linux memory memory-management posix x86-64


【解决方案1】:

我从上面的 kisch 评论中解决了这个问题(“断言消息似乎表明堆损坏的情况。那么实际的错误将在早期的代码中,只有在你的函数尝试另一个分配时才会检测到损坏” )。

我的 NASM 代码包括两个带有内存分配代码的文件。在修复之前是:

; Create buffers to hold POSIX shared memory: 
mov rbx,2 ; 2 output buffers per core
%include "/opt/P01_SH/_Include_Utilities/POSIX_Shared_Memory.asm"

mov r15,1 ;[Number_Of_Cores_Seq]
mov r12,4 ; number of internal_buffers needed
%include "/opt/P01_SH/_Include_Utilities/Posix_Memalign_Internal.asm"

为了解决这个问题,我颠倒了调用顺序,使 Posix_Memalign_Internal.asm 包含在 Posix_Shared_Memory.asm 之前。

这是来自 Posix_Memalign_Internal.asm 的代码:

mov rax,r15
mov rbx,r12 ; passed in from calling function
mul rbx
mov r14,rax
xor r13,r13

Memalign_Create_Loop:

; Allocate the buffer for the memory pointers
; # of cores times N memory pointers needed (passed in from caller)
; int posix_memalign(void **memptr, size_t alignment, size_t size);

mov rax,r15 ; number of cores
mov rbx,r12 ; number of buffers needed
 ; N ptrs per core x 8 bytes per pointer
mul rbx ; times the number of cores
mov r12,rax ; number of buffers needed x number of cores
lea rdi,[memalign_pointer]
mov rsi,64 ; alignment
mov rdx,r12
shl rdx,3
mov rdx,128 ; buffer size
sub rsp,40
call posix_memalign wrt ..plt
add rsp,40
lea r8,[internal_buffer_pointers]
lea rdi,[memalign_pointer]
mov rax,[rdi]
mov rbx,r13
shl rbx,3
mov [r8+rbx],rax
add r13,1
cmp r13,r14
jl Memalign_Create_Loop

这是来自 Posix_Shared_Memory.asm 的代码:

mov rax,[Number_Of_Cores_Seq]
mul rbx
mov [shm_buffers_count],rax
shl rax,3
mov [shm_buffers_bytes],rax
mov r12,rax ; length of pointer buffer

; Buffer for shm pointers
mov rdi,r12
sub rsp,40
call [rel malloc wrt ..got]
mov qword [shm_buffers_ptr],rax
add rsp,40

; Buffer for shm fds
mov rdi,r12
sub rsp,40
call [rel malloc wrt ..got]
mov qword [shm_fds_ptr],rax
add rsp,40

; _________
; Allocate shared memory

xor r12,r12 ; buffer # (0, 8, 16, 24)
xor r13,r13 ; core# (0, 1, 2, 3, ...)
xor r14,r14 ; counter for shm_buffer

Get_ShmName:
lea rdi,[shm_base_name]
mov rsi,r12
mov rdx,r13
call [rel get_shm_name wrt ..got]
mov rdi,rax
push rdi ; shm_name ptr
call [rel unlink_shm wrt ..got]
pop rdi

; Create the shm buffer
mov rsi,[shm_size]
call [rel open_shm wrt ..got]
get_buffer:
mov rdi,rax
mov rax,[rdi]
get_buffer_data:
mov rbp,[shm_fds_ptr]
mov [rbp+r14],rax ; shm_fds
mov rbp,[shm_buffers_ptr]
mov rax,[rdi+8]
mov [rbp+r14],rax ; shm_ptrs
add r12,8
add r14,8
cmp r12,[shm_buffers_bytes]
jl Get_ShmName
next_core:
xor r12,r12
add r13,1
cmp r13,[Number_Of_Cores_Seq]
jl Get_ShmName

Posix_Memalign_Internal.asm 使用 posix_memalign 创建四个每个 128 字节的小缓冲区。 Posix_Shared_Memory.asm 创建两个 4MB 共享内存缓冲区。

我由此得出的结论是,当 posix_memalign 和 posix 共享内存在同一个程序中使用时,应该在创建 posix 共享内存缓冲区之前调用 posix_memalign。在最终的可执行文件中,它们出现在另一个之后,中间有三个指令。

我在代码块中没有看到任何解释为什么会这样的东西,但它在这里解决了这个问题。

最后一点,它今天在 Skylake 上失败了,因此 CPU 系列不相关,正如 Nate Eldredge 在上面的评论中所说。

感谢所有回复的人。

【讨论】:

  • posix_memalign 应该在创建 posix 共享内存缓冲区之前调用。 不,没有理由期望这种干扰。您的代码可能只是错误的。也许先调用一个会将他们的地址以不同的相对顺序排列,这使得内存损坏错误无害?
  • 另外,我真的不明白您为什么要在 asm 中手动编写这部分,特别是如果您使用的是比必要的指令慢的指令,例如 mul 而不是 imul r12, r15。只需用 C 语言编写它,然后让编译器将其优化为比您编写的代码更小和/或更快的代码,尤其是考虑到编译时常量,就像您在包含之前使用 mov r15,1 所做的那样。编译器会将所有计算优化为常量。 (或者你也可以使用汇编时表达式,但它不适用于运行时变量。编译器可以有效地处理任何一种方式。)
猜你喜欢
  • 1970-01-01
  • 2019-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多