我想知道为什么对Float64值进行操作比对 进行操作更快Float16:
julia> rnd64 = rand(Float64, 1000);\n\njulia> rnd16 = rand(Float16, 1000);\n\njulia> @benchmark rnd64.^2\nBenchmarkTools.Trial: 10000 samples with 10 evaluations.\n Range (min \xe2\x80\xa6 max): 1.800 \xce\xbcs \xe2\x80\xa6 662.140 \xce\xbcs \xe2\x94\x8a GC (min \xe2\x80\xa6 max): 0.00% \xe2\x80\xa6 99.37%\n Time (median): 2.180 \xce\xbcs \xe2\x94\x8a GC (median): 0.00%\n Time (mean \xc2\xb1 \xcf\x83): 3.457 \xce\xbcs \xc2\xb1 13.176 \xce\xbcs \xe2\x94\x8a GC (mean \xc2\xb1 \xcf\x83): 12.34% \xc2\xb1 3.89%\n\n \xe2\x96\x81\xe2\x96\x88\xe2\x96\x88\xe2\x96\x84\xe2\x96\x82\xe2\x96\x82\xe2\x96\x86\xe2\x96\x86\xe2\x96\x84\xe2\x96\x82\xe2\x96\x81 \xe2\x96\x82\xe2\x96\x86\xe2\x96\x84\xe2\x96\x81 \xe2\x96\x82\xe2\x96\x82\xe2\x96\x82\xe2\x96\x81 \xe2\x96\x82\n \xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x87\xe2\x96\x87\xe2\x96\x86\xe2\x96\x86\xe2\x96\x87\xe2\x96\x86\xe2\x96\x85\xe2\x96\x87\xe2\x96\x88\xe2\x96\x88\xe2\x96\x86\xe2\x96\x86\xe2\x96\x85\xe2\x96\x85\xe2\x96\x86\xe2\x96\x84\xe2\x96\x84\xe2\x96\x81\xe2\x96\x81\xe2\x96\x83\xe2\x96\x83\xe2\x96\x81\xe2\x96\x81\xe2\x96\x84\xe2\x96\x81\xe2\x96\x83\xe2\x96\x84\xe2\x96\x81\xe2\x96\x83\xe2\x96\x81\xe2\x96\x84\xe2\x96\x83\xe2\x96\x81\xe2\x96\x81\xe2\x96\x86\xe2\x96\x87\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x88\xe2\x96\x87 \xe2\x96\x88\n 1.8 \xce\xbcs Histogram: log(frequency) by time 10.6 \xce\xbcs <\n\n …Run Code Online (Sandbox Code Playgroud) Microsoft提供了InterlockedCompareExchange执行原子比较和交换操作的功能.还有一个内在的._InterlockedCompareExchange
在x86上,这些是使用lock cmpxchg指令实现的.
但是,通过阅读这三种方法的文档,他们似乎并不同意对齐要求.
英特尔的参考手册没有说明对齐(除了如果启用了对齐检查并且进行了未对齐的内存引用,则会生成异常)
我也查找了lock前缀,具体说明了这一点
锁定前缀的完整性不会受到内存领域的对齐方式.
(强调我的)
所以英特尔似乎认为对齐是无关紧要的.无论如何,这个操作都是原子的.
该_InterlockedCompareExchange固有的文档也只字未提对齐,但是InterlockedCompareExchange 功能指出,
该函数的参数必须在32位边界上对齐; 否则,该函数将在多处理器x86系统和任何非x86系统上表现不可预测.
什么给出了什么?对齐要求是否InterlockedCompareExchange只是为了确保该功能即使在cmpxchg指令不可用的486之前的CPU上也能正常工作?这看起来很可能基于上述信息,但在依赖它之前我想确定一下.:)
或者ISA需要对齐以保证原子性,我只是在英特尔的参考手册中找错了地方?
我在尝试 inttypes.h 时编写的简单程序:
#include <stdio.h>
#include <stdbool.h>
#include <inttypes.h>
bool get_bit(uint32_t x, uint8_t n) {
x >>= n;
return x & 1;
}
int main() {
uint32_t x;
uint8_t n;
printf ("Enter x: ");
scanf("%"SCNu32, &x);
printf ("Enter n: ");
scanf("%"SCNu8, &n);
printf("The %"PRIu8"th bit of %"PRIu32" is: %d", n, x, get_bit(x, n));
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在我的手机(64 位八核 ARN LTE Soc Android 10)上,它工作正常:
Enter x: 1
Enter n: 0
The 0th bit of 1 is: 1
Run Code Online (Sandbox Code Playgroud)
但在我的计算机(64 位 x86 Windows …
我并不是真的想要优化任何东西,但我记得我一直都是从程序员那里听到的,我把它当作一个真理.毕竟他们应该知道这些东西.
但我想知道为什么除法实际上比乘法慢?分裂只是一个美化的减法,乘法是一个美化的加法吗?所以在数学上我不明白为什么一种方式或另一种方式在计算上有非常不同的成本.
任何人都可以澄清这个的原因/原因所以我知道,而不是我从其他程序员那里听到的,我之前询问的是:"因为".
int 0x80在Linux上总是调用32位ABI,不管是什么模式,这就是所谓的:在args ebx,ecx...和系统调用号的/usr/include/asm/unistd_32.h.(或者在没有编译的64位内核上崩溃CONFIG_IA32_EMULATION).
64位代码应该使用syscall,从呼叫号码/usr/include/asm/unistd_64.h,并在args rdi,rsi等见什么调用约定UNIX和Linux系统上的i386和x86-64调用.如果您的问题被打上这样一个重复的,看你怎么说链接,细节应当使32位或64位代码的系统调用. 如果你想了解到底发生了什么,请继续阅读.
sys_write系统调用比syscall系统调用快,所以使用本机64位,int 0x80除非你正在编写多格式机器代码,当执行32或64位时运行相同的机器代码.(syscall始终以32位模式返回,因此它在64位用户空间中没有用,尽管它是有效的x86-64指令.)
相关:Linux系统的权威指南(在x86上)调用如何进行sysenter或int 0x8032位系统调用,或sysenter64位系统调用,或调用vDSO进行"虚拟"系统调用syscall.加上有关系统调用的背景知识.
使用gettimeofday可以编写将以32位或64位模式组合的内容,因此它可以int 0x80在微基准测试结束时使用.
标准化函数和系统调用约定的官方i386和x86-64 System V psABI文档的当前PDF文件链接自https://github.com/hjl-tools/x86-psABI/wiki/X86-psABI.
有关初学者指南,x86手册,官方文档和性能优化指南/资源,请参阅x86标记wiki.
但是,由于人们不断发布与使用代码的问题exit_group()在64位代码,或不小心建立64位二进制文件从源代码对于32位写的,我不知道是什么确切不会对当前的Linux怎样呢?
是否int 0x80保存/恢复所有的64位寄存器?它会将任何寄存器截断为32位吗?如果传递上半部分非零的指针args会发生什么?
如果你传递32位指针它是否有效?
在另一个帖子中,我被告知在速度和紧凑性方面switch可能比查找表更好.
所以我想了解这个之间的区别:
static void func1(){}
static void func2(){}
typedef enum
{
FUNC1,
FUNC2,
FUNC_COUNT
} state_e;
typedef void (*func_t)(void);
const func_t lookUpTable[FUNC_COUNT] =
{
[FUNC1] = &func1,
[FUNC2] = &func2
};
void fsm(state_e state)
{
if (state < FUNC_COUNT)
lookUpTable[state]();
else
;// Error handling
}
Run Code Online (Sandbox Code Playgroud)
还有这个:
static void func1(){}
static void func2(){}
void fsm(int state)
{
switch(state)
{
case FUNC1: func1(); break;
case FUNC2: func2(); break;
default: ;// Error handling
}
}
Run Code Online (Sandbox Code Playgroud)
我认为查找表更快,因为编译器尝试在可能的情况下将switch语句转换为跳转表.既然这可能是错的,我想知道为什么!
谢谢你的帮助!
我对空间和时间局部的含义有点困惑.我希望通过一个数组示例来看它,这将有助于我更好地理解它.
在这样的例子中:A [0] [1],A [0] [2],A [0] [3] ......等
这是否证明了时间局部性?我看到同一行被多次访问但是在不同的偏移处...这是否意味着访问了不同的地址?
另外,我说的是这样的例子:A [1],A [2],A [3] ......等等
展示空间位置?
希望对实时代码中时空局部性如何工作的一些澄清将有助于我更好地理解它们.
我最近写了一些代码(ISO/ANSI C),并对它所取得的糟糕表现感到惊讶.长话短说,事实证明罪魁祸首就是这个floor()功能.它不仅速度慢,而且没有矢量化(使用英特尔编译器,也称为ICL).
以下是为2D矩阵中的所有单元格执行底板的一些基准:
VC: 0.10
ICL: 0.20
Run Code Online (Sandbox Code Playgroud)
将其与简单的演员比较:
VC: 0.04
ICL: 0.04
Run Code Online (Sandbox Code Playgroud)
怎么会floor()比简单演员慢得多?!它基本上是相同的(负数除外).第二个问题:有人知道超快的floor()实施吗?
PS:这是我进行基准测试的循环:
void Floor(float *matA, int *intA, const int height, const int width, const int width_aligned)
{
float *rowA=NULL;
int *intRowA=NULL;
int row, col;
for(row=0 ; row<height ; ++row){
rowA = matA + row*width_aligned;
intRowA = intA + row*width_aligned;
#pragma ivdep
for(col=0 ; col<width; ++col){
/*intRowA[col] = floor(rowA[col]);*/
intRowA[col] = (int)(rowA[col]);
}
}
}
Run Code Online (Sandbox Code Playgroud) 据我所知道的,唯一的区别__asm { ... };,并__asm__("...");是第一个使用mov eax, var第二个使用movl %0, %%eax与:"=r" (var)结尾.还有什么其他差异?那又怎么样asm?