我的理解是两种方法的主要区别在于,在"直写"方法中,数据立即通过高速缓存写入主存,而在"回写"数据则是在"后期"写入.
我们还需要在"后期"等待内存,那么"直写"的好处是什么?
为什么此代码不打印相同的数字?:
long long a, b;
a = 2147483647 + 1;
b = 2147483648;
printf("%lld\n", a);
printf("%lld\n", b);
Run Code Online (Sandbox Code Playgroud)
我知道 int 变量的最大数量是 2147483647,因为 int 变量是 4 字节。但据我所知,long long 变量是 8 字节,但为什么这段代码会这样呢?
我在编译器资源管理器中摆弄,我发现传递给 std::min 的参数顺序改变了发出的程序集。
这是 Godbolt Compiler Explorer 上的示例
double std_min_xy(double x, double y) {
return std::min(x, y);
}
double std_min_yx(double x, double y) {
return std::min(y, x);
}
Run Code Online (Sandbox Code Playgroud)
这被编译(例如,在 clang 9.0.0 上使用 -O3):
std_min_xy(double, double): # @std_min_xy(double, double)
minsd xmm1, xmm0
movapd xmm0, xmm1
ret
std_min_yx(double, double): # @std_min_yx(double, double)
minsd xmm0, xmm1
ret
Run Code Online (Sandbox Code Playgroud)
如果我将 std::min 更改为老式三元运算符,这种情况仍然存在。它也适用于我尝试过的所有现代编译器(clang、gcc、icc)。
底层指令是minsd. 阅读文档,第一个参数minsd也是答案的目的地。显然 xmm0 是我的函数应该放置其返回值的地方,所以如果 xmm0 用作第一个参数,则movapd不需要。但是如果 xmm0 是第二个参数,那么它必须movapd xmm0, xmm1将值放入 xmm0。(编者注:是的,x86-64 System V在 …
为了说清楚,我不打算在这里使用任何类型的便携性,所以任何将我绑定到某个盒子的解决方案都可以.
基本上,我有一个if语句将99%的时间评估为true,并且我试图剔除每个性能的最后一个时钟,我可以发出某种编译器命令(使用GCC 4.1.2和x86 ISA,如果告诉分支预测器它应该缓存该分支吗?
在阅读了这篇文章后(在StackOverflow上回答)(在优化部分),我想知道为什么条件移动不容易受到分支预测失败的影响.我在一篇关于cond移动的文章中找到了(PDF由AMD提供).在那里,他们声称cond的性能优势.移动.但为什么会这样呢?我没有看到它.在评估ASM指令的时刻,前面的CMP指令的结果尚未知晓.
谢谢.
optimization performance assembly cpu-architecture branch-prediction
考虑:
#include <time.h>
#include <unistd.h>
#include <iostream>
using namespace std;
const int times = 1000;
const int N = 100000;
void run() {
for (int j = 0; j < N; j++) {
}
}
int main() {
clock_t main_start = clock();
for (int i = 0; i < times; i++) {
clock_t start = clock();
run();
cout << "cost: " << (clock() - start) / 1000.0 << " ms." << endl;
//usleep(1000);
}
cout << "total cost: " << …Run Code Online (Sandbox Code Playgroud) 根据 C11 标准的 \xc2\xa76.3.2.3 \xc2\xb63,C 中的空指针常量可以由实现定义为整数常量表达式0或转换为 的此类表达式void *。在 C 语言中,空指针常量由宏定义NULL。
我的实现(GCC 9.4.0)NULL通过stddef.h以下方式定义:
#define NULL ((void *)0)\n#define NULL 0\nRun Code Online (Sandbox Code Playgroud)\n为什么上述两个表达式在 的上下文中被认为在语义上等效NULL?更具体地说,为什么存在两种而不是一种表达同一概念的方式?
如果数据结构中包含多个元素,则它的原子版本不能(始终)无锁.我被告知这对于较大的类型是正确的,因为CPU不能在不使用某种锁的情况下以原子方式更改数据.
例如:
#include <iostream>
#include <atomic>
struct foo {
double a;
double b;
};
std::atomic<foo> var;
int main()
{
std::cout << var.is_lock_free() << std::endl;
std::cout << sizeof(foo) << std::endl;
std::cout << sizeof(var) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
输出(Linux/gcc)是:
0
16
16
Run Code Online (Sandbox Code Playgroud)
由于原子和foo大小相同,我不认为锁存储在原子中.
我的问题是:
如果一个原子变量使用一个锁,它存储在哪里,这对该变量的多个实例意味着什么?
双值存储更高的精度并且是浮点数的两倍,但英特尔CPU是否针对浮点数进行了优化?
也就是说,双重操作与+, - ,*和/的浮点运算一样快或快.
对于64位架构,答案是否会改变?
我在一个系统std::fill上观察到,与常量值或动态值相比,std::vector<int>设置常量值时,大型系统显着且持续地较慢:01
5.8 GiB/s vs 7.5 GiB/s
但是,对于较小的数据大小,结果是不同的,其中fill(0)更快:
对于4个GiB数据大小的多个线程,fill(1)显示更高的斜率,但达到的峰值远低于fill(0)(51 GiB/s对90 GiB/s):
这提出了次要问题,为什么峰值带宽fill(1)要低得多.
测试系统是一个双插槽Intel Xeon CPU E5-2680 v3,设置为2.5 GHz(通道/sys/cpufreq),带有8x16 GiB DDR4-2133.我使用GCC 6.1.0(-O3)和英特尔编译器17.0.1(-fast)进行了测试,结果都相同.GOMP_CPU_AFFINITY=0,12,1,13,2,14,3,15,4,16,5,17,6,18,7,19,8,20,9,21,10,22,11,23被设定了.Strem/add/24个线程在系统上获得85 GiB/s.
我能够在不同的Haswell双插槽服务器系统上重现这种效果,但没有任何其他架构.例如在Sandy Bridge EP上,内存性能是相同的,而在缓存fill(0)中则要快得多.
这是重现的代码:
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <omp.h>
#include <vector>
using value = int;
using vector = std::vector<value>;
constexpr size_t write_size = 8ll * 1024 * 1024 * 1024;
constexpr size_t …Run Code Online (Sandbox Code Playgroud) c++ ×6
x86 ×5
performance ×4
c ×3
assembly ×2
android ×1
atomic ×1
benchmarking ×1
c++11 ×1
caching ×1
cpu-cache ×1
gcc ×1
intel ×1
linux ×1
memset ×1
null ×1
null-pointer ×1
optimization ×1
stdatomic ×1