问题
很长一段时间我的印象是,使用嵌套std::vector<std::vector...>来模拟N维数组通常很糟糕,因为内存不保证是连续的,并且可能有缓存未命中.我认为最好使用平面矢量并从多个维度映射到1D,反之亦然.所以,我决定测试它(最后列出的代码).这非常简单,我定时读取/写入嵌套的3D矢量与我自己的1D矢量3D包装器.我用两者编译了代码,g++并且打开clang++了-O3优化.对于每次运行,我都改变了尺寸,因此我可以很好地了解这种行为.令我惊讶的是,这些是我在我的机器MacBook Pro(Retina,13英寸,2012年末),2.5GHz i5,8GB RAM,OS X 10.10.5上获得的结果:
g ++ 5.2
dimensions nested flat
X Y Z (ms) (ms)
100 100 100 -> 16 24
150 150 150 -> 58 98
200 200 200 -> 136 308
250 250 250 -> 264 746
300 300 300 -> 440 1537
Run Code Online (Sandbox Code Playgroud)
clang ++(LLVM 7.0.0)
dimensions nested flat
X Y Z (ms) (ms)
100 100 100 -> 16 18
150 150 150 -> 53 61
200 …Run Code Online (Sandbox Code Playgroud) 我有一个关于装配的基本问题.
如果它们也可以在内存上工作,为什么我们只在寄存器上进行算术运算呢?
例如,以下两个原因(基本上)都将相同的值计算为答案:
片段1
.data
var dd 00000400h
.code
Start:
add var,0000000Bh
mov eax,var
;breakpoint: var = 00000B04
End Start
Run Code Online (Sandbox Code Playgroud)
片段2
.code
Start:
mov eax,00000400h
add eax,0000000bh
;breakpoint: eax = 0000040B
End Start
Run Code Online (Sandbox Code Playgroud)
从我所看到的,大多数文本和教程主要在寄存器上进行算术运算.使用寄存器只是更快吗?
编辑:那很快:)
给出了一些很好的答案; 根据第一个好的答案选择了最佳答案.
我用AVX一次计算八个点产品.在我目前的代码中,我做了类似的事情(在展开之前):
常春藤桥/桑迪桥
__m256 areg0 = _mm256_set1_ps(a[m]);
for(int i=0; i<n; i++) {
__m256 breg0 = _mm256_load_ps(&b[8*i]);
tmp0 = _mm256_add_ps(_mm256_mul_ps(arge0,breg0), tmp0);
}
Run Code Online (Sandbox Code Playgroud)
Haswell的
__m256 areg0 = _mm256_set1_ps(a[m]);
for(int i=0; i<n; i++) {
__m256 breg0 = _mm256_load_ps(&b[8*i]);
tmp0 = _mm256_fmadd_ps(arge0, breg0, tmp0);
}
Run Code Online (Sandbox Code Playgroud)
我需要多少次为每个案例展开循环以确保最大吞吐量?
对于使用FMA3的Haswell,我认为答案是每个循环的FLOPS用于沙桥和haswell SSE2/AVX/AVX2.我需要将循环展开10次.
对于Ivy Bridge,我认为它是8.这是我的逻辑.AVX添加的延迟为3,延迟乘以5.Ivy Bridge可以使用不同的端口同时进行一次AVX乘法和一次AVX添加.使用符号m进行乘法,a表示加法,x表示无操作,以及表示部分和的数字(例如m5表示乘以第5部分和)我可以写:
port0: m1 m2 m3 m4 m5 m6 m7 m8 m1 m2 m3 m4 m5 ...
port1: x x x x x a1 a2 a3 a4 a5 a6 a7 a8 ...
Run Code Online (Sandbox Code Playgroud)
因此,通过在9个时钟周期后使用8个部分和(4个来自负载,5个来自乘法),我可以在每个时钟周期提交一个AVX负载,一个AVX加法和一个AVX乘法.
我想这意味着在Ivy …
我先说我是 SIMD 内在函数的完全初学者。
本质上,我有一个支持 AVX2 内在 ( Intel(R) Core(TM) i5-7500T CPU @ 2.70GHz)的 CPU 。我想知道计算两个std::vector<float>size的点积的最快方法512。
我在网上做了一些挖掘,发现了这个和这个,这个堆栈溢出问题建议使用以下函数__m256 _mm256_dp_ps(__m256 m1, __m256 m2, const int mask);,但是,这些都表明了执行点积的不同方法我不确定什么是正确的(和最快的)方法它。
特别是,我正在寻找对大小为 512 的向量执行点积的最快方法(因为我知道向量大小会影响实现)。
感谢您的帮助
编辑 1:我也对-mavx2gcc 标志有点困惑。如果我使用这些 AVX2 函数,我编译时是否需要添加标志?另外,-OFast如果我编写了一个天真的点积实现,gcc 是否能够为我做这些优化(比如我使用gcc 标志)?
编辑 2 如果有人有时间和精力,如果您能编写完整的实现,我将不胜感激。我相信其他初学者也会重视这些信息。
我试图在Intel i3处理器上找到32个元素(每个1字节数据)的总和减少量.我这样做了:
s=0;
for (i=0; i<32; i++)
{
s = s + a[i];
}
Run Code Online (Sandbox Code Playgroud)
但是,由于我的应用程序是一个需要更少时间的实时应用程序,因此需要花费更多时间.请注意,最终金额可能超过255.
有没有办法可以使用低级SIMD SSE2指令实现这一点?不幸的是我从未使用过SSE.我试图为此目的搜索sse2函数,但它也不可用.(sse)是否可以保证减少这种小型问题的计算时间?
有什么建议??
注意:我已经使用OpenCL和CUDA实现了类似的算法,虽然问题规模很大,但效果很好.对于小型问题,开销成本更高.不确定它在SSE上是如何工作的
write(1,"hi",3)在linux上反汇编,gcc -s -nostdlib -nostartfiles -O3结果如下:
ba03000000 mov edx, 3 ; thanks for the correction jester!
bf01000000 mov edi, 1
31c0 xor eax, eax
e9d8ffffff jmp loc.imp.write
Run Code Online (Sandbox Code Playgroud)
我不是到编译器的开发,但由于移动到这些寄存器的每一个值是恒定的和已知的编译时间,我很好奇,为什么不GCC使用dl,dil和al来代替.也许有人会说,此功能不会让任何性能上的差异,但有一个在之间的可执行文件的大小有很大的区别mov $1, %rax => b801000000,并mov $1, %al => b001当我们谈论数千寄存器的程序访问.如果软件的优雅部分不仅体积小,它确实会对性能产生影响.
有人可以解释为什么"海湾合作委员会决定"它无所谓?
我正在研究大型矩阵乘法并运行以下实验来形成基线测试:
这是天真的C++实现:
#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
constexpr size_t dim = 4096;
float* x = new float[dim*dim];
float* y = new float[dim*dim];
float* z = new float[dim*dim];
random_device rd;
mt19937 gen(rd());
normal_distribution<float> dist(0, 1);
for (size_t i = 0; i < dim*dim; i++)
{
x[i] = dist(gen);
y[i] = dist(gen);
}
for (size_t row = 0; row < dim; row++)
for (size_t col = 0; col < …Run Code Online (Sandbox Code Playgroud) 因此,对于我在计算机系统课程中的最终作业,我们需要优化这些forloops,使其比原始版本更快.使用我们的linux服务器,基本等级不到7秒,完整等级不到5秒.我在这里的代码大约需要5.6秒.我想我可能需要以某种方式使用指针来使它更快,但我不是很确定.任何人都可以提供我的任何提示或选项吗?非常感谢!
QUICKEDIT:文件必须保持50行或更少,我忽略了教师所包含的那些注释行.
#include <stdio.h>
#include <stdlib.h>
// You are only allowed to make changes to this code as specified by the comments in it.
// The code you submit must have these two values.
#define N_TIMES 600000
#define ARRAY_SIZE 10000
int main(void)
{
double *array = calloc(ARRAY_SIZE, sizeof(double));
double sum = 0;
int i;
// You can add variables between this comment ...
register double sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0, sum5 = 0, …Run Code Online (Sandbox Code Playgroud) 我希望能够手动预测任意算术的长度(即没有分支或内存,尽管这也很好)x86-64汇编代码将采用特定的体系结构,考虑到指令重新排序,超标量,延迟,消费者价格指数等
什么/描述必须遵循的规则才能实现这一目标?
我想我已经找到了一些初步规则,但是我没有找到任何关于将任何示例代码分解为这个详细程度的引用,所以我不得不做一些猜测.(例如,英特尔优化手册甚至几乎没有提到指令重新排序.)
至少,我正在寻找(1)确认每条规则是正确的,或者是每条规则的正确陈述,以及(2)我可能忘记的任何规则的列表.
addps并且subps使用相同的功能) unit?我如何确定?).和:4此循环已经发出少于超标量宽度(通常)指令的数量.例如,请考虑以下示例代码(计算交叉产品):
shufps xmm3, xmm2, 210
shufps xmm0, xmm1, 201
shufps xmm2, xmm2, 201
mulps xmm0, xmm3
shufps xmm1, xmm1, 210
mulps xmm1, xmm2
subps xmm0, xmm1
Run Code Online (Sandbox Code Playgroud)
我试图预测Haswell的延迟看起来像这样:
; `mulps` Haswell latency=5, CPI=0.5
; `shufps` Haswell latency=1, CPI=1
; `subps` Haswell latency=3, CPI=1
shufps xmm3, xmm2, 210 ; cycle 1
shufps xmm0, xmm1, 201 ; cycle 2
shufps xmm2, xmm2, 201 ; …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用SSE42和STTNI指令并得到奇怪的结果 - PcmpEstrM(使用显式长度字符串)比PcmpIstrM(隐式长度字符串)运行慢两倍.
两者都是"常春藤桥" - 奇怪的是他们有如此不同的"差异"(至少我看不出他们的规格有任何技术差异 - http://www.cpu-world.com/Compare_CPUs/Intel_AW8063801013511,Intel_CM8063701093302 /).
英特尔64和IA-32架构优化参考手册提到了PcmpEstrM和PcmpIstrM的相同吞吐量= 11和延迟= 3.因此,我预计两者的表现相似.
问:差异是我实际设计/预期的,还是我以错误的方式使用这些指令?
下面是我的虚拟测试场景(VS 2012).逻辑非常简单 - 扫描16MB文本以查找匹配字符.由于干草堆和针头串都没有包含零终结器 - 我希望E和I具有相似的性能.
PS:我尝试在intel的开发论坛上发布这个问题,但他们将其识别为垃圾邮件:(
#include "stdafx.h"
#include <windows.h>
#define BEGIN_TIMER(NAME) \
{ \
LARGE_INTEGER __freq; \
LARGE_INTEGER __t0; \
LARGE_INTEGER __t1; \
double __tms; \
const char* __tname = NAME; \
char __tbuf[0xff]; \
\
QueryPerformanceFrequency(&__freq); \
QueryPerformanceCounter(&__t0);
#define END_TIMER() \ …Run Code Online (Sandbox Code Playgroud)