我正在尝试测试我的GTX680的计算性能,因为我有点怀疑它的真实性能。我想知道是否有人也可以测试他的GTX 680,如果给出相同的结果,或者告诉我可以做些什么来更好地从卡中获得更多性能
我写过这个小程序
#include <stdlib.h>
#include <stdio.h>
#include <float.h>
#include "cuComplex.h"
#include "time.h"
#include "cuda_runtime.h"
#include <iostream>
using namespace std;
__global__ void test(int loop, int *out)
{
register int a=0;
for (int x=0;x<loop;x++)
{
a+=x*loop;
}
if (out!=NULL) *out=a;
}
int main(int argc, char *argv[])
{
float timestamp;
cudaEvent_t event_start,event_stop;
// Initialise
cudaDeviceReset();
cudaDeviceReset();
cudaSetDevice(0);
cudaThreadSetCacheConfig(cudaFuncCachePreferShared);
// Allocate and generate buffers
cudaEventCreate(&event_start);
cudaEventCreate(&event_stop);
cudaEventRecord(event_start, 0);
dim3 threadsPerBlock;
dim3 blocks;
int b=1000;
threadsPerBlock.x=32;
threadsPerBlock.y=32;
threadsPerBlock.z=1;
blocks.x=1;
blocks.y=1000;
blocks.z=1;
test<<<blocks,threadsPerBlock,0>>>(300,
NULL
);
cudaEventRecord(event_stop, 0);
cudaEventSynchronize(event_stop);
cudaEventElapsedTime(×tamp, event_start, event_stop);
printf("Calculated in %f", timestamp);
}
使用nvcc进行编译我得到了这个PTX
//
// Generated by NVIDIA NVVM Compiler
// Compiler built on Sat Sep 22 02:35:14 2012 (1348274114)
// Cuda compilation tools, release 5.0, V0.2.1221
//
.version 3.1
.target sm_30
.address_size 64
.file 1 "/tmp/tmpxft_00000e7b_00000000-9_perf.cpp3.i"
.file 2 "/opt/home/daniel/a/perf.cu"
.visible .entry _Z4testiPi(
.param .u32 _Z4testiPi_param_0,
.param .u64 _Z4testiPi_param_1
)
{
.reg .pred %p<4>;
.reg .s32 %r<15>;
.reg .s64 %rd<3>;
ld.param.u32 %r6, [_Z4testiPi_param_0];
ld.param.u64 %rd2, [_Z4testiPi_param_1];
cvta.to.global.u64 %rd1, %rd2;
mov.u32 %r13, 0;
.loc 2 12 1
setp.lt.s32 %p1, %r6, 1;
mov.u32 %r14, %r13;
mov.u32 %r11, %r13;
@%p1 bra BB0_2;
BB0_1:
.loc 2 14 1
mad.lo.s32 %r14, %r11, %r6, %r14;
.loc 2 12 20
add.s32 %r11, %r11, 1;
.loc 2 12 1
setp.lt.s32 %p2, %r11, %r6;
mov.u32 %r13, %r14;
@%p2 bra BB0_1;
BB0_2:
.loc 2 18 1
setp.eq.s64 %p3, %rd2, 0;
@%p3 bra BB0_4;
.loc 2 18 1
st.global.u32 [%rd1], %r13;
BB0_4:
.loc 2 21 2
ret;
}
内核运行时间为1.936ms
我的计算表明,GFLOPS的性能是1.1 TFLOP,仅为3TFLOPS理论值的三分之一(参考:http://www.geforce.com/hardware/desktop-gpus/geforce-gtx-680)。为什么它这么慢?
我的计算详情如下
mad.lo.s32 %r14, %r11, %r6, %r14; //2 FLOPS
.loc 2 12 20
add.s32 %r11, %r11, 1; //1 FLOP
.loc 2 12 1
setp.lt.s32 %p2, %r11, %r6; //1 FLOP
mov.u32 %r13, %r14; // 1 FLOP
@%p2 bra BB0_1; //1 FLOP
+ 1 FLOP (just as a buffer as I don't know branching how much it takes)
循环中1次迭代的总FLOPS为7 FLOPS
仅考虑迭代
我们每个线程有300次迭代 我们有1024 * 1000块
总迭代次数FLOPS = 300 * 1024 * 1000 * 7 = 2.15 GFLOPS
总内核时间是1.936ms
因此吞吐量= 1.11 TFLOPS
提前感谢您的帮助
丹尼尔
答案 0 :(得分:3)
此示例程序以@Robert Crovella答案为基础。 Robert的内核受数据依赖性的限制。通过减少FMA指令之间的数据依赖性,这个内核应该在GTX680上实现2.4-2.5 TFLOPS。
当前实现是指令获取和数据依赖性受限。应该能够调整内核以将已实现的FLOPS提高10%。
Nsight Visual Studio Edition 2.x和新的3.0 RC候选版提供了分析此内核所需的指标。
在2.x和3.0中,您应该使用以下实验来分析内核:
在Robert的内核的情况下,执行依赖性非常高,因为每个指令都具有读写后依赖性。通过增加指令级并行性,我们将性能提高了三倍。内核现在主要是取指令限制。
新的Nsight VSE 3.0 RC(今天可用)还将显示使用每条指令统计信息注释的汇编或源代码,例如执行的指令数和每条指令的活动线程数。在此示例中,该工具可用于识别数据依赖性,并确保编译器生成FMA指令,这些指令需要达到理论上实现的FLOPS的50%以上。
__global__ void test(float loop, float *out)
{
register float a=1.0f;
register float b=1.0f;
register float c=1.0f;
register float d=1.0f;
register float e=1.0f;
register float f=1.0f;
register float g=1.0f;
register float h=1.0f;
for (float x=0;x<loop;x++)
{
a+=x*loop;
b+=x*loop;
c+=x*loop;
d+=x*loop;
e+=x*loop;
f+=x*loop;
g+=x*loop;
h+=x*loop;
a+=x*loop;
b+=x*loop;
c+=x*loop;
d+=x*loop;
e+=x*loop;
f+=x*loop;
g+=x*loop;
h+=x*loop;
a+=x*loop;
b+=x*loop;
c+=x*loop;
d+=x*loop;
e+=x*loop;
f+=x*loop;
g+=x*loop;
h+=x*loop;
a+=x*loop;
b+=x*loop;
c+=x*loop;
d+=x*loop;
e+=x*loop;
f+=x*loop;
g+=x*loop;
h+=x*loop;
a+=x*loop;
b+=x*loop;
c+=x*loop;
d+=x*loop;
e+=x*loop;
f+=x*loop;
g+=x*loop;
h+=x*loop;
}
if (out!=NULL) *out=a+b+c+d+e+f+g+h;
}
int main(int argc, char *argv[])
{
float timestamp;
cudaEvent_t event_start,event_stop;
// Initialise
cudaDeviceReset();
cudaSetDevice(0);
cudaThreadSetCacheConfig(cudaFuncCachePreferShared);
// Allocate and generate buffers
cudaEventCreate(&event_start);
cudaEventCreate(&event_stop);
cudaEventRecord(event_start, 0);
dim3 threadsPerBlock;
dim3 blocks;
threadsPerBlock.x=32;
threadsPerBlock.y=32;
threadsPerBlock.z=1;
blocks.x=1;
blocks.y=1000;
blocks.z=1;
test<<<blocks,threadsPerBlock,0>>>(30,NULL);
cudaEventRecord(event_stop, 0);
cudaEventSynchronize(event_stop);
cudaEventElapsedTime(×tamp, event_start, event_stop);
printf("Calculated in %f\n", timestamp);
}
答案 1 :(得分:1)
我认为问题在于你使用的是整数乘法。计算能力3.0体系结构上的32位整数乘法仅为32位浮点吞吐量的1/6(参见下表,取自CUDA C编程指南5.5版)。将32位整数乘法性能与3.0体系结构的32位浮点性能进行比较。
主要在计算应用程序中使用的一些其他整数操作和类型转换在3.0上的性能也同样降低。
答案 2 :(得分:0)
使用此代码查看您是否获得了更好的结果。这只是一个例子,它与你的代码没有完全相同的东西,我认为你将不得不重新计算翻牌。
#include <stdio.h>
using namespace std;
__global__ void test(float loop, float *out)
{
register float a=1.0f;
for (float x=0;x<loop;x++)
{
a+=x*loop;
a+=x*loop;
a+=x*loop;
a+=x*loop;
a+=x*loop;
a+=x*loop;
a+=x*loop;
a+=x*loop;
a+=x*loop;
a+=x*loop;
}
if (out!=NULL) *out=a;
}
int main(int argc, char *argv[])
{
float timestamp;
cudaEvent_t event_start,event_stop;
// Initialise
cudaDeviceReset();
cudaSetDevice(0);
cudaThreadSetCacheConfig(cudaFuncCachePreferShared);
// Allocate and generate buffers
cudaEventCreate(&event_start);
cudaEventCreate(&event_stop);
cudaEventRecord(event_start, 0);
dim3 threadsPerBlock;
dim3 blocks;
threadsPerBlock.x=32;
threadsPerBlock.y=32;
threadsPerBlock.z=1;
blocks.x=1;
blocks.y=1000;
blocks.z=1;
test<<<blocks,threadsPerBlock,0>>>(30,
NULL
);
cudaEventRecord(event_stop, 0);
cudaEventSynchronize(event_stop);
cudaEventElapsedTime(×tamp, event_start, event_stop);
printf("Calculated in %f\n", timestamp);
}
当我用arch = sm_20或sm_30编译它时,我在内核循环中连续获得10个fma指令,没有中间代码。我认为它会比你的代码运行得更快,更接近峰值理论翻转。是的,整数OP /秒和浮点OP /秒之间存在差异。如果你确实运行了这段代码,请回复一下,让我知道你计算的性能是多少。
答案 3 :(得分:0)
您的测试内核正在执行整数运算,而不是浮点运算。因此,FLOPS是该内核的错误指标。
FLOPS = FLoating point Operations Per Second
回到最初的问题,你的内核很慢,因为GPU针对浮点计算进行了优化,而不是整数计算。
要进行正确的测试,请尝试将测试内核转换为使用浮点数而不是整数。
此外,在您将FLOPS注释到步骤的循环中,FLOPS再次没有意义,因为它是每秒度量并且这些是整数运算。转换后,只需将它们计为单独的浮点运算,而不是每秒浮点运算。