以下示例代码生成一个size的矩阵N,并将其转换SAMPLES次数.当N = 512转置操作的平均执行时间是2144 ?s(coliru链接)时.乍一看,没有什么特别的,对吗?...
好吧,这是结果
N = 513 → 1451 ?s N = 519 → 600 ?sN = 530 → 486 ?sN = 540→ 492 ?s(终于!理论开始工作:).那么为什么在实践中这些简单的计算与理论如此不同呢?此行为是否与CPU缓存一致性或缓存未命中有关?如果是这样请解释.
#include <algorithm>
#include <iostream>
#include <chrono>
constexpr int N = 512; // Why is 512 specifically slower (as of 2016)
constexpr int SAMPLES = 1000;
using us = std::chrono::microseconds;
int A[N][N];
void transpose()
{
for ( int i = …Run Code Online (Sandbox Code Playgroud) 这个问题与这 两个循环体或一个(结果相同)相同, 但在我的情况下,我使用Java.
我有两个循环,运行十亿次.
int a = 188, b = 144, aMax = 0, bMax = 0;
for (int i = 0; i < 1000000000; i++) {
int t = a ^ i;
if (t > aMax)
aMax = t;
}
for (int i = 0; i < 1000000000; i++) {
int t = b ^ i;
if (t > bMax)
bMax = t;
}
Run Code Online (Sandbox Code Playgroud)
在我的机器中运行这两个循环所需的时间是4秒.当我将这两个循环融合到一个循环中并在该单循环中执行所有操作时,它将在2秒内运行.正如您所看到的那样,琐碎的操作构成了循环内容,因此需要恒定的时间.
我的问题是我在哪里获得这种性能提升?
我猜测性能在两个独立的循环中受影响的唯一可能的地方是它增加i并检查我是否<1000000000 20亿次而不是10亿次如果我将循环融合在一起.还有其他事吗?
谢谢!
在尝试选择推荐哪种索引方法时,我尝试了测试性能.然而,这些测量让我很困惑.我以不同的顺序多次运行,但测量结果保持一致.以下是我测量性能的方法:
for N = [10000 15000 100000 150000]
x = round(rand(N,1)*5)-2;
idx1 = x~=0;
idx2 = abs(x)>0;
tic
for t = 1:5000
idx1 = x~=0;
end
toc
tic
for t = 1:5000
idx2 = abs(x)>0;
end
toc
end
Run Code Online (Sandbox Code Playgroud)
这就是结果:
Elapsed time is 0.203504 seconds.
Elapsed time is 0.230439 seconds.
Elapsed time is 0.319840 seconds.
Elapsed time is 0.352562 seconds.
Elapsed time is 2.118108 seconds. % This is the strange part
Elapsed time is 0.434818 seconds.
Elapsed time is 0.508882 seconds. …Run Code Online (Sandbox Code Playgroud) 没有裂变的代码看起来像这样:
int check(int * res, char * map, int n, int * keys){
int ret = 0;
for(int i = 0; i < n; ++i){
res[ret] = i;
ret += map[hash(keys[i])]
}
return ret;
}
Run Code Online (Sandbox Code Playgroud)
裂变:
int check(int * res, char * map, int n, int * keys){
int ret = 0;
for(int i = 0; i < n; ++i){
tmp[i] = map[hash(keys[i])];
}
for(int i = 0; i < n; ++i){
res[ret] = i;
ret += tmp[i];
}
return …Run Code Online (Sandbox Code Playgroud) 在进行一些性能测试时,我遇到了一些我似乎无法解释的情况.
我写了以下C代码:
void multi_arr(int32_t *x, int32_t *y, int32_t *res, int32_t len)
{
for (int32_t i = 0; i < len; ++i)
{
res[i] = x[i] * y[i];
}
}
Run Code Online (Sandbox Code Playgroud)
我使用gcc将它与测试驱动程序一起编译成单个二进制文件.我还使用gcc将它自己编译成一个共享对象,我通过p/invoke从C#调用它.目的是衡量从C#调用本机代码的性能开销.
在C和C#中,我创建等长的随机值输入数组,然后测量multi_arr运行所需的时间.在C#和CI中,使用POSIX clock_gettime()调用进行计时.我已经在调用multi_arr之前和之后定位了定时调用,因此输入准备时间等不会影响结果.我运行100次迭代并报告平均时间和最小时间.
尽管C和C#正在执行完全相同的功能,但C#在大约50%的时间内提前出现,通常是大量的.例如,对于1,048,576的len,C#的最小值为768,400 ns,而C的最小值为1,344,105.C#的平均值为1,018,865,而C的1,852,880.我在这个图中添加了一些不同的数字(记住日志标度):
这些结果对我来说似乎非常错误,但工件在多个测试中是一致的.我检查了asm和IL来验证是否正确.比特是一样的.我不知道在这个程度上可能会影响性能.我已经把一个最小的例子再现了这里.
这些测试都是在Linux(KDE neon,基于Ubuntu Xenial)上使用dotnet-core 2.0.0和gcc 5.0.4运行的.
谁看过这个吗?
假设在速度关键代码中我们有一对经常一起使用的数组,其中确切的大小无关紧要,只需将其设置为合理的,例如
int a[256], b[256];
Run Code Online (Sandbox Code Playgroud)
这可能是一种悲观,因为低地址位相同会使缓存更难同时处理两个数组吗?指定例如300而不是256会更好吗?
分割for像这样的循环的开销是多少,
int i;
for (i = 0; i < exchanges; i++)
{
// some code
// some more code
// even more code
}
Run Code Online (Sandbox Code Playgroud)
分成这样的多个for循环?
int i;
for (i = 0; i < exchanges; i++)
{
// some code
}
for (i = 0; i < exchanges; i++)
{
// some more code
}
for (i = 0; i < exchanges; i++)
{
// even more code
}
Run Code Online (Sandbox Code Playgroud)
该代码是性能敏感的,但这样做后者将提高可读性显著.(如果重要的话,在每个循环中没有其他循环,变量声明或函数调用,除少数访问器外.)
我不是一个低级别的编程大师,所以如果有人能够衡量与基本操作相比的性能损失,那就更好了,例如 "每个额外的 …
我正在测试读取多个数据流如何影响CPU缓存性能.我正在使用以下代码来对此进行基准测试.基准测试读取顺序存储在内存中的整数,并按顺序写入部分和.从中读取的顺序块的数量是变化的.来自块的整数以循环方式读取.
#include <iostream>
#include <vector>
#include <chrono>
using std::vector;
void test_with_split(int num_arrays) {
int num_values = 100000000;
// Fix up the number of values. The effect of this should be insignificant.
num_values -= (num_values % num_arrays);
int num_values_per_array = num_values / num_arrays;
// Initialize data to process
auto results = vector<int>(num_values);
auto arrays = vector<vector<int>>(num_arrays);
for (int i = 0; i < num_arrays; ++i) {
arrays.emplace_back(num_values_per_array);
}
for (int i = 0; i < num_values; ++i) {
arrays[i%num_arrays].emplace_back(i);
results.emplace_back(0);
} …Run Code Online (Sandbox Code Playgroud) 有没有人有使用 Core 2 Duo 处理器的预取指令的经验?
我一直在为一系列 P4 机器成功使用(标准?)预取集(prefetchnta、prefetcht1等),但是在 Core 2 Duo 上运行代码时,prefetcht(i)指令似乎什么都不做,而且prefetchnta指令更少有效的。
我评估性能的标准是 BLAS 1 向量向量 (axpy) 操作的计时结果,当向量大小足以实现缓存外行为时。
英特尔是否引入了新的预取指令?
我创建了一个程序,它分配了两个C++双精度数组.首先包含从0到pi/4的x的sin(x)值.对于第二个,我写了sin(x)的二阶导数,使用三点公式计算:
(vals[i-1]-2*vals[i]+vals[i+1])/(dx*dx)
Run Code Online (Sandbox Code Playgroud)
我对不同大小的数组执行这些计算,重复几次,并输出平均计算时间.这样我得到了很好的图表,显示了计算特定大小数组的衍生物所需的时间.
这一切听起来都相当容易,但我遇到了一个奇怪的问题.看一下图表:
当数组很小时,没有什么奇怪的事情发生.但是,当它们大于10000个元素(有两个数组意味着大约16kB 160kB的内存)时,我得到了周期性的峰值,每个峰值大约在前面的512个元素之后.这种情况发生在多个CPU(AMD Sempron 3850,Intel Q9400和Intel Xeon 5310)上,并不会发生在其他CPU(Intel i5 5200U,Intel Nehalem-C)上.
如果这还不够,当阵列达到约65,000个元素时,Windows 7上的AMD 3850会突然增加.这不会发生在Debian上.
我认为它可能与CPU缓存,给定'神奇'数量的元素以及操作系统的调度有关,但我想不出任何具体的解释和方法来确认它(除了分析CPU缓存命中率) .
码:
int main(int, char**)
{
double maxerr=0.0;
double avgerr=0.0;
for(unsigned SIZE=5000u; SIZE<100000u; SIZE+=1u)
{
const unsigned REPEATS=10000000/SIZE+1;
const double STEP=1.0/(SIZE-1.0)*atan(1.0)*4.0;
double *vals;
double *derivs;
// Alokacja
vals= new double[SIZE];
derivs=new double[SIZE];
// Inicjalizacja
for(unsigned i=0u; i<SIZE; ++i)
{
vals[i]=sin(i*STEP);
derivs[i]=0.0;
}
// Obliczenia normalne
const double TIME_FPU_START=msclock();
for(unsigned r=0u; r<REPEATS; ++r)
{
const double STEP2RCP=1.0/(STEP*STEP);
for(unsigned i=1u; i<SIZE-1u; ++i)
{ …Run Code Online (Sandbox Code Playgroud)