我正在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。
感谢您的帮助。
[CPU_ZERO
和CPU_SET
是C宏,不是可以调用的函数。
您必须滚动自己的功能才能执行等效的清零/设置。
这些是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 0
或resq 16
,
CPU_ZERO
在您的情况下是免费的;您的静态分配的cpu_set_t
被静态初始化为零。由于某种原因,您将其放在.data
中,而不是.bss
中,因此可执行文件实际上必须包含那些零,但有相同的区别。
例如,如果您确实想在堆栈上将零置零,那么rep stosd
是一种简单的方法,或者xorps xmm0, xmm0
和8x movups
个存储也可以。
由于高性能不是必需的(CPU亲和力设置代码可能只运行一次),所以bts
是在位图中设置位(bts
)的非常方便的方法] >>。对于存储目标,它需要一个位索引,该位索引可以超出寻址模式选择的CPU_SET
。 dword
速度慢且已微编码(如Skylake上的10微秒),但对于代码大小来说不错。 bts mem, reg
仅3 oups,但bts mem, imm
仅2 uops。
or byte [mem + i/8], 1<<(i%8)
还允许您一次设置多个位,或更简单地说,or
存储一些包含所需的零和一的模式的字节。
但是TL:DR:它只是一个位图,可以按需要使用asm对其进行操作,甚至可以使用非零值进行静态初始化。