诚然,我不明白.假设您的内存中包含长度为1个字节的内存字.为什么不能在未对齐地址的单个内存访问中访问一个4字节长的变量(即不能被4整除),因为对齐地址就是这种情况?
我在Cortex-M4微控制器上有一些代码,并希望使用二进制协议与PC通信.目前,我正在使用具有GCC特定packed属性的压缩结构.
这是一个粗略的轮廓:
struct Sensor1Telemetry {
int16_t temperature;
uint32_t timestamp;
uint16_t voltageMv;
// etc...
} __attribute__((__packed__));
struct TelemetryPacket {
Sensor1Telemetry tele1;
Sensor2Telemetry tele2;
// etc...
} __attribute__((__packed__));
Run Code Online (Sandbox Code Playgroud)
我的问题是:
TelemetryPacket对MCU和客户端应用程序上的结构使用完全相同的定义,上述代码是否可以跨多个平台移植?(我对x86和x86_64很感兴趣,需要它在Windows,Linux和OS X上运行.)编辑:
我在SO上看到这篇文章,其中包含C代码以获取最新的CPU周期数:
基于CPU周期计算的C/C++ Linux x86_64中的分析
有没有办法在C++中使用这个代码(欢迎使用windows和linux解决方案)?虽然用C语言编写(而C是C++的一个子集)但我不太确定这段代码是否适用于C++项目,如果没有,如何翻译呢?
我使用的是x86-64
EDIT2:
找到此功能但无法让VS2010识别汇编程序.我需要包含任何内容吗?(我相信我必须换uint64_t到long long窗户......?)
static inline uint64_t get_cycles()
{
uint64_t t;
__asm volatile ("rdtsc" : "=A"(t));
return t;
}
Run Code Online (Sandbox Code Playgroud)
EDIT3:
从上面的代码我得到错误:
"错误C2400:'操作码'中的内联汇编语法错误;找到'数据类型'"
有人可以帮忙吗?
我很想知道我的64位应用程序是否存在对齐错误.
在Windows中,生成对齐错误的应用程序将引发异常,
EXCEPTION_DATATYPE_MISALIGNMENT.
- 在x64体系结构上,默认情况下禁用对齐异常,并且修复由硬件完成.应用程序可以通过设置几个寄存器位来启用对齐异常,在这种情况下,除非用户使操作系统屏蔽异常,否则将引发异常
SEM_NOALIGNMENTFAULTEXCEPT.(有关详细信息,请参阅AMD体系结构程序员手册第2卷:系统编程.)[编者按:强调我的]
在x86体系结构中,操作系统不会使对齐故障对应用程序可见.在这两个平台上,您还会在对齐故障方面遇到性能下降,但它的严重程度将远远低于Itanium,因为硬件将对内存进行多次访问以检索未对齐的数据.
在Itanium上,默认情况下,操作系统(OS)将使该异常对应用程序可见,并且在这些情况下终止处理程序可能很有用.如果您没有设置处理程序,那么您的程序将挂起或崩溃.在清单3中,我们提供了一个示例,说明如何捕获EXCEPTION_DATATYPE_MISALIGNMENT异常.
忽略了参考AMD架构程序员手册的方向,我将参考英特尔64和IA-32架构软件开发人员手册
5.10.5检查对齐
当CPL为3时,可以通过设置CR0寄存器中的AM标志和EFLAGS寄存器中的AC标志来检查存储器参考的对齐情况.未对齐的内存引用会生成对齐异常(#AC).在特权级别0,1或2下操作时,处理器不会生成对齐异常.有关在启用对齐检查时对齐要求的说明,请参阅表6-7.
优秀.我不确定这意味着什么,但非常好.
然后还有:
2.5控制寄存器
控制寄存器(CR0,CR1,CR2,CR3和CR4;见图2-6)确定处理器的操作模式和当前正在执行的任务的特性.在所有32位模式和兼容模式下,这些寄存器均为32位.
在64位模式下,控制寄存器扩展到64位.MOV CRn指令用于操作寄存器位.这些指令的操作数大小前缀将被忽略.
控制寄存器总结如下,并且这些控制寄存器中的每个架构定义的控制字段被单独描述.在图2-6中,64位模式下寄存器的宽度用括号表示(CR0除外).- CR0 - 包含控制处理器的操作模式和状态的系统控制标志
AM
对齐掩码(CR0的第18位) - 设置时启用自动对齐检查; 清除时禁用对齐检查.仅当AM标志置位,EFLAGS寄存器中的AC标志置位,CPL为3,处理器工作在受保护或虚拟8086模式时,才执行对齐检查.
我实际使用的语言是Delphi,但假装它是与语言无关的伪代码:
void UnmaskAlignmentExceptions()
{
asm
mov rax, cr0; //copy CR0 flags into RAX
or rax, 0x20000; //set bit 18 (AM)
mov cr0, rax; //copy flags back
}
Run Code Online (Sandbox Code Playgroud)
第一条指令
mov rax, cr0;
Run Code Online (Sandbox Code Playgroud)
没有特权指令例外.
如何在x64上为我的进程启用对齐异常?
我发现x86有以下指令:
PUSHF,POPF …我总是听说未对齐的访问很糟糕,因为它们会导致运行时错误并导致程序崩溃或减慢内存访问速度.但是我找不到任何关于它们会减慢速度的实际数据.
假设我在x86上并且有一些(但未知)未对齐访问的共享 - 实际可能的最差减速是什么?如何在不消除所有未对齐访问和比较两个版本代码的运行时间的情况下估算它?
我发现了一条来自 的评论crossbeam。
从 Intel 的 Sandy Bridge 开始,空间预取器现在一次提取成对的 64 字节缓存线,因此我们必须对齐到 128 字节而不是 64。
资料来源:
我在英特尔的手册中没有找到这样的说法。但直到最新的提交,folly仍然使用 128 字节填充,这让我很有说服力。所以我开始编写代码来看看是否可以观察到这种行为。这是我的代码。
#include <thread>
int counter[1024]{};
void update(int idx) {
for (int j = 0; j < 100000000; j++) ++counter[idx];
}
int main() {
std::thread t1(update, 0);
std::thread t2(update, 1);
std::thread t3(update, 2);
std::thread t4(update, 3);
t1.join();
t2.join();
t3.join();
t4.join();
}
Run Code Online (Sandbox Code Playgroud)
我的CPU是锐龙3700X。当索引为0、1、2、3时,大约需要 1.2 秒才能完成。当索引为0, 16, 32,时 …
我正在玩这个答案的代码,稍微修改一下:
BITS 64
GLOBAL _start
SECTION .text
_start:
mov ecx, 1000000
.loop:
;T is a symbol defined with the CLI (-DT=...)
TIMES T imul eax, eax
lfence
TIMES T imul edx, edx
dec ecx
jnz .loop
mov eax, 60 ;sys_exit
xor edi, edi
syscall
Run Code Online (Sandbox Code Playgroud)
没有lfence我,我得到的结果与答案中的静态分析一致.
当我介绍一个单一 lfence我期望的CPU执行imul edx, edx的序列的第k个平行于迭代imul eax, eax的下一个(的序列K + 1个)迭代.
像这样的东西(调用一个的imul eax, eax序列和d的imul edx, edx一个): …
有人可以解释英特尔内部指南中给出的延迟和吞吐量值吗?
我是否正确理解延迟是指令运行所需的时间单位,吞吐量是每个时间单位可以启动的指令数量?
如果我的定义是正确的,为什么某些指令的延迟在较新的CPU版本上更高(例如mulps)?
这三个片段的执行时间:
pageboundary: dq (pageboundary + 8)
...
mov rdx, [rel pageboundary]
.loop:
mov rdx, [rdx - 8]
sub ecx, 1
jnz .loop
Run Code Online (Sandbox Code Playgroud)
还有这个:
pageboundary: dq (pageboundary - 8)
...
mov rdx, [rel pageboundary]
.loop:
mov rdx, [rdx + 8]
sub ecx, 1
jnz .loop
Run Code Online (Sandbox Code Playgroud)
还有这个:
pageboundary: dq (pageboundary - 4096)
...
mov rdx, [rel pageboundary]
.loop:
mov rdx, [rdx + 4096]
sub ecx, 1
jnz .loop
Run Code Online (Sandbox Code Playgroud)
对于第一个片段,在4770K上,每次迭代大约5个周期,对于第二个片段,每次迭代大约9个周期,然后是第三个片段的5个周期.它们都访问完全相同的地址,这是4K对齐的.在第二个片段中,只有地址计算跨越页面边界:rdx并且rdx + 8不属于同一页面,负载仍然是对齐的.如果偏移量很大,则会再次回到5个周期.
这种效果一般如何起作用?
通过ALU指令从加载路由结果,如下所示:
.loop:
mov rdx, …Run Code Online (Sandbox Code Playgroud)