我在课本中读到堆栈通过减少内存地址而增长; 也就是说,从较高地址到较低地址.这可能是一个糟糕的问题,但我没有把这个概念弄好.你可以解释吗?
x86架构上的Linux内核的默认内存页面大小是4 KB,我想知道这是如何计算的,为什么?
我需要"perf"实用程序来监控我的Mac上的程序.我知道linux附带了它,但它可以在Mac上使用吗?
我正在研究OSX 10.9 Mavericks并尝试使用perf或linux工具进行"端口搜索",但我无法获得任何结果.
我是汇编语言的新手.我正在阅读有关MIPS架构的内容,我遇到了跳转目标地址和分支目标地址以及如何计算它们.
考虑在x86 CPU上进行单个内存访问(单个读取或单个写入,而不是读取或写入)SSE指令.该指令访问16字节(128位)的存储器,访问的存储器位置对齐为16字节.
文档"英特尔®64架构内存订购白皮书"指出,对于"读取或写入地址在8字节边界上对齐的四字(8字节)的指令",内存操作似乎作为单个内存访问执行,而不管记忆类型.
问题:是否存在Intel/AMD/etc x86 CPU,它们保证读取或写入与16字节边界对齐的16字节(128位)作为单个内存访问执行?是这样,它是哪种特定类型的CPU(Core2/Atom/K8/Phenom/...)?如果您对此问题提供答案(是/否),请同时指定用于确定答案的方法 - PDF文档查找,强力测试,数学证明或您用于确定答案的任何其他方法.
此问题涉及http://research.swtch.com/2010/02/off-to-races.html等问题
更新:
我在C中创建了一个可以在您的计算机上运行的简单测试程序.请在您的Phenom,Athlon,Bobcat,Core2,Atom,Sandy Bridge或您碰巧拥有的任何支持SSE2的CPU上编译并运行它.谢谢.
// Compile with:
// gcc -o a a.c -pthread -msse2 -std=c99 -Wall -O2
//
// Make sure you have at least two physical CPU cores or hyper-threading.
#include <pthread.h>
#include <emmintrin.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef int v4si __attribute__ ((vector_size (16)));
volatile v4si x;
unsigned n1[16] __attribute__((aligned(64)));
unsigned n2[16] __attribute__((aligned(64)));
void* thread1(void *arg) {
for (int i=0; i<100*1000*1000; i++) { …Run Code Online (Sandbox Code Playgroud) 我正在编写一个带有x86后端的JIT编译器,并且随时学习x86汇编器和机器代码.大约20年前我使用ARM汇编程序,并对这些体系结构之间的成本模型差异感到惊讶.
具体来说,内存访问和分支在ARM上很昂贵,但在x86上等效的堆栈操作和跳转很便宜.我相信现代x86 CPU比ARM内核做更多的动态优化,我发现很难预测它们的影响.
编写x86汇编程序时要记住什么是好的成本模型?哪些指令组合便宜又昂贵?
例如,如果它总是生成用于加载整数或跳转到偏移的长格式,即使整数很小或偏移量接近但这会影响性能,我的编译器会更简单吗?
我还没有做任何浮动点,但我很快就会接受它.普通代码和浮动代码之间的相互作用有什么不明显的吗?
我知道有很多关于x86优化的参考文献(例如Michael Abrash),但我有一个预感,而不是几年前的任何东西都不适用于现代的x86 CPU,因为它们最近发生了很大的变化.我对么?
此循环在英特尔Conroe/Merom上每3个周期运行一次,imul按预期方式在吞吐量方面存在瓶颈.但是在Haswell/Skylake上,它每11个循环运行一次,显然是因为setnz al它依赖于最后一个循环imul.
; synthetic micro-benchmark to test partial-register renaming
mov ecx, 1000000000
.loop: ; do{
imul eax, eax ; a dep chain with high latency but also high throughput
imul eax, eax
imul eax, eax
dec ecx ; set ZF, independent of old ZF. (Use sub ecx,1 on Silvermont/KNL or P4)
setnz al ; ****** Does this depend on RAX as well as ZF?
movzx eax, al
jnz .loop ; }while(ecx);
Run Code Online (Sandbox Code Playgroud)
如果setnz al …
考虑使用以下 float 循环,使用 -O3 -mavx2 -mfma 编译
for (auto i = 0; i < a.size(); ++i) {
a[i] = (b[i] > c[i]) ? (b[i] * c[i]) : 0;
}
Run Code Online (Sandbox Code Playgroud)
Clang 在矢量化方面做得非常出色。它使用 256 位 ymm 寄存器,并了解 vblendps/vandps 之间的差异,以获得尽可能最佳的性能。
.LBB0_7:
vcmpltps ymm2, ymm1, ymm0
vmulps ymm0, ymm0, ymm1
vandps ymm0, ymm2, ymm0
Run Code Online (Sandbox Code Playgroud)
然而,海湾合作委员会的情况要糟糕得多。由于某种原因,它并没有比 SSE 128 位向量更好(-mprefer-vector-width=256 不会改变任何东西)。
.L6:
vcomiss xmm0, xmm1
vmulss xmm0, xmm0, xmm1
vmovss DWORD PTR [rcx+rax*4], xmm0
Run Code Online (Sandbox Code Playgroud)
如果将其替换为普通数组(如指南中所示),gcc 会将其矢量化为 AVX ymm。
int a[256], b[256], c[256];
auto foo …Run Code Online (Sandbox Code Playgroud) 在大多数处理器中,为什么L1缓存的大小小于L2缓存的大小?
假设我们有两个寄存器长度为 2有符号1 的整数,例如a和b。我们想要计算值(a + b) / 2,向上舍入、向下舍入、向零舍入或远离零舍入,无论哪种方式更容易(即我们不关心舍入方向)。
结果是另一个寄存器长度有符号整数(很明显,平均值必须在寄存器长度有符号整数的范围内)。
\n执行此计算最快的方法是什么?
\n您可以选择两个整数最初位于哪个寄存器中,以及平均值最终位于哪个寄存器中。
\n脚注1:对于无符号整数,我们可以用两条指令来完成。尽管循环进位在 Intel CPU 上超过 1 uop,但这可能是最快的方法。但当计数仅为 1 时,只有一对。 关于无符号均值的问答中的答案讨论了效率。
\nadd rdi, rsi\nrcr rdi, 1\nRun Code Online (Sandbox Code Playgroud)\nrdi这两个数字以和开始rsi,平均值以 结束rdi。但对于有符号数,-1 + 3将设置 CF,并将 a 旋转1到符号位。没有给出正确答案+1。
脚注 2:我指定了寄存器长度的有符号整数,这样我们就不能简单地用movsxdorcdqe指令对整数进行符号扩展。
我得到的最接近的解决方案使用四个指令,其中一个rcr在 Intel 上为 3 uops,在 AMD …