关于uint_fast*_t类型族,C标准还不太清楚.在gcc-4.4.4 linux x86_64系统上,类型uint_fast16_t和uint_fast32_t大小均为8个字节.但是,8字节数的乘法似乎比4字节数的乘法慢得多.以下代码演示了:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int
main ()
{
uint_least16_t p, x;
int count;
p = 1;
for (count = 100000; count != 0; --count)
for (x = 1; x != 50000; ++x)
p*= x;
printf("%"PRIuLEAST16, p);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到了在程序上运行time命令
real 0m7.606s
user 0m7.557s
sys 0m0.019s
Run Code Online (Sandbox Code Playgroud)
如果我将类型更改为uint_fast16_t(和printf修饰符),则时间变为
real 0m12.609s
user 0m12.593s
sys 0m0.009s
Run Code Online (Sandbox Code Playgroud)
那么,如果stdint.h头文件uint_fast16_t(以及uint_fast32_t)定义为4字节类型,那会不会更好?
我正在为64位x86生成以下指令:
41 F3 0F 10 46 10 movss XMM0,014h[R14]
Run Code Online (Sandbox Code Playgroud)
不幸的是,它在该行上出现故障.gdb将其反汇编为:
0x0000000000402054 <+320>: rex.B
0x0000000000402055 <+321>: movss 0x14(%rsi),%xmm0
Run Code Online (Sandbox Code Playgroud)
请注意,无法识别rex.B覆盖,索引是RSI而不是R14.
指令无效吗?在AMD 64位指令参考中,我找不到任何迹象表明此编码无效.
objdump也无法将其识别为有效指令:
41 rex.B
f3 0f 10 46 10 movss 0x10(%rsi),%xmm0
Run Code Online (Sandbox Code Playgroud)
这里发生了什么?
我正在尝试学习x86_64程序集,我今天正在尝试标准输入输出并偶然发现这个帖子学习程序集 - echo程序名称如何从STDIN读取输入(使用SYSCALL指令)?特别是如果我知道输入将始终是一个整数,我想将其读入寄存器?
编辑: @Daniel Kozar在下面的回答帮助我理解了STDIN和STDOUT如何与Linux上的SYSCALL指令一起工作.我试图编写一个小程序,它从控制台输入中读取一个数字并打印与该数字对应的ascii字符.假如你输入65作为输入,你应该得到A作为输出.还有一个新的线条角色.如果有的话,它可以帮助任何其他人:-)
section .text
global _start
_start:
mov rdi, 0x0 ; file descriptor = stdin = 0
lea rsi, [rsp+8] ; buffer = address to store the bytes read
mov rdx, 0x2 ; number of bytes to read
mov rax, 0x0 ; SYSCALL number for reading from STDIN
syscall ; make the syscall
xor rax, rax ; clear off rax
mov rbx, [rsp+8] ; read the first byte read into rsp+8 by STDIN call …Run Code Online (Sandbox Code Playgroud) 我想检查在glibc中执行系统调用的代码.我发现了这样的事情.
ENTRY (syscall)
movq %rdi, %rax /* Syscall number -> rax. */
movq %rsi, %rdi /* shift arg1 - arg5. */
movq %rdx, %rsi
movq %rcx, %rdx
movq %r8, %r10
movq %r9, %r8
movq 8(%rsp),%r9 /* arg6 is on the stack. */
syscall /* Do the system call. */
cmpq $-4095, %rax /* Check %rax for error. */
jae SYSCALL_ERROR_LABEL /* Jump to error handler if error. */
L(pseudo_end):
ret /* Return to caller. */
Run Code Online (Sandbox Code Playgroud)
现在我的问题是系统调用(在cmpq指令之前)是否是指令?其次,如果它是一个指令,ENTRY(系统调用)的含义是什么?ENTRY的同名(我不知道ENTRY是什么)和指令?其次,L(pseudo_end)是什么?
在汇编指令级别分析代码时,如果现代CPU不按顺序或按顺序执行指令,那么指令指针的位置真正意味着什么呢?例如,假设以下x64汇编代码:
mov RAX, [RBX]; // Assume a cache miss here.
mov RSI, [RBX + RCX]; // Another cache miss.
xor R8, R8;
add RDX, RAX; // Dependent on the load into RAX.
add RDI, RSI; // Dependent on the load into RSI.
Run Code Online (Sandbox Code Playgroud)
指令指针大部分时间用在哪条指令上?我可以为所有人想出好的论点:
mov RAX, [RBX] 大概需要100个周期,因为这是一个缓存未命中.mov RSI, [RBX + RCX]也需要100个周期,但可能与前一个指令并行执行.它甚至意味着指令指针位于其中一个或另一个上?xor R8, R8 可能在内存加载完成之前执行乱序并完成,但指令指针可能会保留在此处,直到所有先前的指令也完成为止.add RDX, RAX生成管道停顿,因为它RAX是在缓慢的缓存未命中加载之后实际使用值的指令.add RDI, RSI也停滞,因为它依赖于负载RSI.64位Linux内核的地址空间是多少,也就是说,它所使用的代码,堆栈,堆和数据段的地址范围是多少.
我正在尝试编写一些合理快速的组件向量加法代码.我正在使用(签名,我相信)64位整数.
功能是
void addRq (int64_t* a, const int64_t* b, const int32_t dim, const int64_t q) {
for(int i = 0; i < dim; i++) {
a[i] = (a[i]+b[i])%q; // LINE1
}
}
Run Code Online (Sandbox Code Playgroud)
我在icc -std=gnu99 -O3IvyBridge(SSE4.2和AVX,但不是AVX2)上编译(icc以便我以后可以使用SVML).
我的基线是%q从LINE1中删除.100(迭代)函数调用dim=11221184需要1.6秒.ICC自动矢量化SSE代码; 大.
我真的想做模块化的补充.使用%q,ICC不会自动向量化代码,它在11.8秒(!)内运行.即使忽略了之前尝试的自动矢量化,这似乎仍然过分.
由于我没有AVX2,SSE的矢量化需要SVML,这也许就是为什么ICC没有自动矢量化的原因.无论如何,这是我尝试对内循环进行矢量化:
__m128i qs = _mm_set1_epi64x(q);
for(int i = 0; i < dim; i+=2) {
__m128i xs = _mm_load_si128((const __m128i*)(a+i));
__m128i ys = _mm_load_si128((const __m128i*)(b+i));
__m128i zs = _mm_add_epi64(xs,ys);
zs = _mm_rem_epi64(zs,qs);
_mm_store_si128((__m128i*)(a+i),zs);
}
Run Code Online (Sandbox Code Playgroud)
主循环的汇编是: …
在以下伪代码中:
if (rdtscp supported by hardware) {
Invoke "rdtscp" instruction
} else {
Invoke "rdtsc" instruction
}
Run Code Online (Sandbox Code Playgroud)
假设CPU不支持该rdtscp指令,因此我们回退到else语句.
如果CPU错误预测分支,指令管道是否可能尝试执行rdtscp并抛出Illgal Instruction错误?
当我objdump -D用来反汇编二进制时,典型的代码jmpq就像e9 7f fe ff ff是,用于表示负偏移.但是,x86-64的地址是64(48)位(据我所知),那么这个32位地址如何7f fe ff ff表示64位绝对地址的负偏移?
此外,还有像任何其他指令jmp和jmpq,但有64位地址位移?我怎样才能找到英特尔或AMD手册中的说明(我搜索jmpq但没有找到任何内容)?
当我搜索时,它似乎被称为RIP相对寻址.似乎并非所有说明都这样做.是否有64位相对寻址?如果是间接跳转,64位绝对地址将在寄存器或内存中,对吧?
我试图了解如何衡量性能并决定编写非常简单的程序:
section .text
global _start
_start:
mov rax, 60
syscall
Run Code Online (Sandbox Code Playgroud)
我用perf stat ./bin 这个程序运行我感到惊讶的stalled-cycles-frontend是太高了.
0.038132 task-clock (msec) # 0.148 CPUs utilized
0 context-switches # 0.000 K/sec
0 cpu-migrations # 0.000 K/sec
2 page-faults # 0.052 M/sec
107,386 cycles # 2.816 GHz
81,229 stalled-cycles-frontend # 75.64% frontend cycles idle
47,654 instructions # 0.44 insn per cycle
# 1.70 stalled cycles per insn
8,601 branches # 225.559 M/sec
929 branch-misses # 10.80% of all branches
0.000256994 seconds time elapsed …Run Code Online (Sandbox Code Playgroud) x86-64 ×10
assembly ×7
c ×3
linux ×3
performance ×2
gcc ×1
intrinsics ×1
linux-kernel ×1
low-level ×1
perf ×1
profiling ×1
sse ×1
stdin ×1
unsigned ×1