[CPU_ZERO“未定义符号”在NASM中使用pthread_setaffinity_np

问题描述 投票:-1回答:2

我正在Ubuntu 18.04下的NASM中使用pthreads库。线程创建可以正常工作,但是我想使用pthread_setaffinity_np将每个线程分配给一个单独的核心。

以下是我用来初始化线程的代码部分。它按书面形式编译,但在运行时出现“未定义符号:CPU_ZERO”。

使用C语言中的示例,我在程序顶部插入了%define _GNU_SOURCE,但是仍然出现未定义的符号CPU_ZERO错误。

section .data align=16

; For thread scheduling:
cpuset: times 4 dq 0

section .text

label_0:

mov rdi,ThreadID            ; ThreadCount
mov rsi,pthread_attr_t  ; Thread Attributes
mov rdx,Test_fn         ; Function Pointer
mov rcx,pthread_arg
call pthread_create wrt ..plt

; Set affinity mask
mov rdi,cpuset
call CPU_ZERO wrt ..plt
call pthread_self wrt ..plt
push rax
mov rdi,rax
mov rsi,cpuset
call CPU_SET wrt ..plt
pop rax
mov rdi,rax
mov rsi,32
mov rdx,cpuset
call pthread_setaffinity_np wrt ..plt
; check the result with pthread_getaffinity_np

mov rax,[tcounter]
add rax,8
mov [tcounter],rax
mov rbx,[Number_Of_Cores]
cmp rax,rbx
jl label_0

我的问题是:如何在NASM(或任何其他汇编语言;我可以翻译成NASM)中使用CPU_ZERO和CPU_SET。

感谢您的帮助。

linux assembly pthreads x86-64 nasm
2个回答
3
投票

[CPU_ZEROCPU_SET是C宏,不是可以调用的函数。

您必须滚动自己的功能才能执行等效的清零/设置。


0
投票

这些是CPP宏,不起作用。您可以从全大写字母中分辨出来。 [the man page称它们为宏。

与往常一样,手册页的notes section包含对汇编有用的详细信息:

由于CPU集是以长字为单位分配的位掩码,因此动态分配的CPU集中的实际CPU数量为向上舍入到sizeof(unsigned long)的下一个倍数。一个应用程序应将这些额外位的内容视为未定义。

尽管名称相似,但请注意常数CPU_SETSIZE表示cpu_set_t数据类型中的CPU数量(因此,它实际上是位掩码中位的计数),而CPU _ * _ S()宏的setsize参数为字节大小。

在我的系统上(Arch Linux,glibc 2.29-4)

/usr/include/bits/cpu-set.h

...
#define __CPU_SETSIZE   1024
#define __NCPUBITS      (8 * sizeof (__cpu_mask))
...
typedef __CPU_MASK_TYPE __cpu_mask;  // ultimately unsigned long via some other headers
...
typedef struct
{
  __cpu_mask __bits[__CPU_SETSIZE / __NCPUBITS];
} cpu_set_t;

至少在具有该内核配置的系统上,cpu_set_t为1024位= 128字节= times 16 dq 0resq 16


CPU_ZERO在您的情况下是免费的;您的静态分配的cpu_set_t被静态初始化为零。由于某种原因,您将其放在.data中,而不是.bss中,因此可执行文件实际上必须包含那些零,但有相同的区别。

例如,如果您确实想在堆栈上将零置零,那么rep stosd是一种简单的方法,或者xorps xmm0, xmm0和8x movups个存储也可以。


由于高性能不是必需的(CPU亲和力设置代码可能只运行一次),所以bts是在位图中设置位(bts)的非常方便的方法] >>。对于存储目标,它需要一个位索引,该位索引可以超出寻址模式选择的CPU_SETdword速度慢且已微编码(如Skylake上的10微秒),但对于代码大小来说不错。 bts mem, reg仅3 oups,但bts mem, imm仅2 uops。

or byte [mem + i/8], 1<<(i%8)还允许您一次设置多个位,或更简单地说,or存储一些包含所需的零和一的模式的字节。

但是TL:DR:它只是一个位图,可以按需要使用asm对其进行操作,甚至可以使用非零值进行静态初始化。

© www.soinside.com 2019 - 2024. All rights reserved.