私が取り組んでいる大規模な CUDA カーネルの命令スループットを理解しようとしています。加算命令とシフト命令のスループットを比較するために、2 つの小さなプログラムを作成しました。CUDA C Programming Guide によると、shift 命令のスループットは add 命令の半分です。しかし、Tesla M2070 で 2 つのプログラムの実行時間を測定すると、時間はまったく同じです。誰かがなぜこれが当てはまるのか説明してもらえますか?
追加プログラム:
#include <limits.h>
#include <stdio.h>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <stdint.h>
using namespace std;
__global__ void testAdd(int numIterations, uint1* result){
int total = 1;
for(int i=0; i< numIterations;i ++){
total = total+i;
}
result[0] = make_uint1(total);
}
int main(){
uint1* result;
cudaMalloc((void**)(&(result)), sizeof(uint1));
float totalElapsedTime = 0;
int i;
for(i = 0; i < 10; i++){
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);
testAdd<<<1,1>>>(100000, result);
cudaError_t e50 = cudaGetLastError();
if(e50 == cudaSuccess){
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
float elapsedTime;
cudaEventElapsedTime(&elapsedTime, start, stop);
totalElapsedTime += elapsedTime;;
//cout << "Elapsed Time:" << elapsedTime << endl;
}else{
cout << "Error launching kernel: " << e50 << endl;
}
cudaEventDestroy(start);
cudaEventDestroy(stop);
}
cout << "Elapsed Time: " << totalElapsedTime/i << endl;
cudaFree(result);
}
シフトプログラム:
#include <limits.h>
#include <stdio.h>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <stdint.h>
using namespace std;
__global__ void testShift(int numIterations, uint1* result){
int total = 1;
for(int i=0; i< numIterations;i ++){
total = total<<i;
}
result[0] = make_uint1(total);
}
int main(){
uint1* result;
cudaMalloc((void**)(&(result)), sizeof(uint1));
float totalElapsedTime = 0;
int i;
for(i = 0; i < 10; i++){
cudaEvent_t start, stop;
cudaEventCreate(&start);
cudaEventCreate(&stop);
cudaEventRecord(start, 0);
testShift<<<1,1>>>(100000, result);
cudaError_t e50 = cudaGetLastError();
if(e50 == cudaSuccess){
cudaEventRecord(stop, 0);
cudaEventSynchronize(stop);
float elapsedTime;
cudaEventElapsedTime(&elapsedTime, start, stop);
totalElapsedTime += elapsedTime;;
//cout << "Elapsed Time:" << elapsedTime << endl;
}else{
cout << "Error launching kernel: " << e50 << endl;
}
cudaEventDestroy(start);
cudaEventDestroy(stop);
}
cout << "Elapsed Time: " << totalElapsedTime/i << endl;
cudaFree(result);
}
編集:ptxコードの追加およびシフトプログラムの追加。ご覧のとおり、唯一の違いは 78 行目です。つまり、add 命令と shl 命令です。
PTX コードを追加:
.entry _Z7testAddiP5uint1 (
.param .s32 __cudaparm__Z7testAddiP5uint1_numIterations,
.param .u64 __cudaparm__Z7testAddiP5uint1_result)
{
.reg .u32 %r<8>;
.reg .u64 %rd<3>;
.reg .pred %p<4>;
.loc 16 10 0
// 6 #include <stdint.h>
// 7
// 8 using namespace std;
// 9
// 10 __global__ void testAdd(int numIterations, uint1* result){
$LDWbegin__Z7testAddiP5uint1:
ld.param.s32 %r1, [__cudaparm__Z7testAddiP5uint1_numIterations];
mov.u32 %r2, 0;
setp.le.s32 %p1, %r1, %r2;
@%p1 bra $Lt_0_2306;
ld.param.s32 %r1, [__cudaparm__Z7testAddiP5uint1_numIterations];
mov.s32 %r3, %r1;
mov.s32 %r4, 0;
mov.s32 %r5, 1;
mov.s32 %r6, %r3;
$Lt_0_1794:
//<loop> Loop body line 10, nesting depth: 1, estimated iterations: unknown
.loc 16 13 0
// 11 int total = 1;
// 12 for(int i=0; i< numIterations;i ++){
// 13 total = total+i;
add.s32 %r5, %r4, %r5;
add.s32 %r4, %r4, 1;
.loc 16 10 0
ld.param.s32 %r1, [__cudaparm__Z7testAddiP5uint1_numIterations];
.loc 16 13 0
setp.ne.s32 %p2, %r1, %r4;
// 6 #include <stdint.h>
// 7
// 8 using namespace std;
// 9
// 10 __global__ void testAdd(int numIterations, uint1* result){
$LDWbegin__Z7testAddiP5uint1:
ld.param.s32 %r1, [__cudaparm__Z7testAddiP5uint1_numIterations];
mov.u32 %r2, 0;
setp.le.s32 %p1, %r1, %r2;
@%p1 bra $Lt_0_2306;
ld.param.s32 %r1, [__cudaparm__Z7testAddiP5uint1_numIterations];
mov.s32 %r3, %r1;
mov.s32 %r4, 0;
mov.s32 %r5, 1;
mov.s32 %r6, %r3;
$Lt_0_1794:
//<loop> Loop body line 10, nesting depth: 1, estimated iterations: unknown
.loc 16 13 0
// 11 int total = 1;
// 12 for(int i=0; i< numIterations;i ++){
// 13 total = total+i;
add.s32 %r5, %r4, %r5;
add.s32 %r4, %r4, 1;
.loc 16 10 0
ld.param.s32 %r1, [__cudaparm__Z7testAddiP5uint1_numIterations];
.loc 16 13 0
setp.ne.s32 %p2, %r1, %r4;
@%p2 bra $Lt_0_1794;
bra.uni $Lt_0_1282;
$Lt_0_2306:
mov.s32 %r5, 1;
$Lt_0_1282:
.loc 16 15 0
// 14 }
// 15 result[0] = make_uint1(total);
ld.param.u64 %rd1, [__cudaparm__Z7testAddiP5uint1_result];
st.global.u32 [%rd1+0], %r5;
.loc 16 16 0
// 16 }
exit;
$LDWend__Z7testAddiP5uint1:
} // _Z7testAddiP5uint1
シフト PTX コード:
.entry _Z9testShiftiP5uint1 (
.param .s32 __cudaparm__Z9testShiftiP5uint1_numIterations,
.param .u64 __cudaparm__Z9testShiftiP5uint1_result)
{
.reg .u32 %r<8>;
.reg .u64 %rd<3>;
.reg .pred %p<4>;
.loc 16 10 0
// 6 #include <stdint.h>
// 7
// 8 using namespace std;
// 9
// 10 __global__ void testShift(int numIterations, uint1* result){
$LDWbegin__Z9testShiftiP5uint1:
ld.param.s32 %r1, [__cudaparm__Z9testShiftiP5uint1_numIterations];
mov.u32 %r2, 0;
setp.le.s32 %p1, %r1, %r2;
@%p1 bra $Lt_0_2306;
ld.param.s32 %r1, [__cudaparm__Z9testShiftiP5uint1_numIterations];
mov.s32 %r3, %r1;
mov.s32 %r4, 0;
mov.s32 %r5, 1;
mov.s32 %r6, %r3;
$Lt_0_1794:
//<loop> Loop body line 10, nesting depth: 1, estimated iterations: unknown
.loc 16 13 0
// 11 int total = 1;
// 12 for(int i=0; i< numIterations;i ++){
// 13 total = total<<i;
shl.b32 %r5, %r5, %r4;
add.s32 %r4, %r4, 1;
.loc 16 10 0
.reg .u64 %rd<3>;
.reg .pred %p<4>;
.loc 16 10 0
// 6 #include <stdint.h>
// 7
// 8 using namespace std;
// 9
// 10 __global__ void testShift(int numIterations, uint1* result){
$LDWbegin__Z9testShiftiP5uint1:
ld.param.s32 %r1, [__cudaparm__Z9testShiftiP5uint1_numIterations];
mov.u32 %r2, 0;
setp.le.s32 %p1, %r1, %r2;
@%p1 bra $Lt_0_2306;
ld.param.s32 %r1, [__cudaparm__Z9testShiftiP5uint1_numIterations];
mov.s32 %r3, %r1;
mov.s32 %r4, 0;
mov.s32 %r5, 1;
mov.s32 %r6, %r3;
$Lt_0_1794:
//<loop> Loop body line 10, nesting depth: 1, estimated iterations: unknown
.loc 16 13 0
// 11 int total = 1;
// 12 for(int i=0; i< numIterations;i ++){
// 13 total = total<<i;
shl.b32 %r5, %r5, %r4;
add.s32 %r4, %r4, 1;
.loc 16 10 0
ld.param.s32 %r1, [__cudaparm__Z9testShiftiP5uint1_numIterations];
.loc 16 13 0
setp.ne.s32 %p2, %r1, %r4;
@%p2 bra $Lt_0_1794;
bra.uni $Lt_0_1282;
$Lt_0_2306:
mov.s32 %r5, 1;
$Lt_0_1282:
.loc 16 15 0
// 14 }
// 15 result[0] = make_uint1(total);
ld.param.u64 %rd1, [__cudaparm__Z9testShiftiP5uint1_result];
st.global.u32 [%rd1+0], %r5;
.loc 16 16 0
// 16 }
exit;
$LDWend__Z9testShiftiP5uint1:
} // _Z9testShiftiP5uint1