そゆわけで、先週日曜は兎さんとやきそば食って
悟空茶荘で茶ぁしばきながら愛と平和を熱く語るはずもなく、
GPGPUがどーしたこーしたなんつーおよそ茶席にはそぐわぬ
ネタで盛り上がったわけですが。
兎さん曰く:「ATI Streamてばホスト-デバイス間のデータ転送が速くねぇ」
...そぉなの?
GPGPUはホスト(マザボ)にぶっ挿したデバイス(グラボ)に対し
あれやこれやと命令投げて処理を行います。
で、ホストはデバイスの持ってるメモリに直接アクセスできません。
なので必要に応じてホスト→デバイス,ホスト←デバイスなメモリ転送
コマンドを発行し、その完了を待たにゃならんです。そのスピードがイマイチとのこと。
おうち帰ってやってみた。1024x1024個のfloat(=4MB)領域に対し1000回の
書き込み(ホスト→デバイス)と読み込み(ホスト←デバイス)にかかる時間を計ってみる。
#include <iostream>
#include <vector>
#include <string>
#include <utility>
#include <cassert>
#include <Windows.h>
#define __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>
using namespace std;
int main() try {
vector<cl::Platform> platforms;
cl::Platform::get(&platforms);
assert( !platforms.empty() );
cl_context_properties properties[] =
{ CL_CONTEXT_PLATFORM, (cl_context_properties)(platforms[0])(), 0};
cl::Context context(CL_DEVICE_TYPE_GPU, properties);
std::vector<cl::Device> devices = context.getInfo<CL_CONTEXT_DEVICES>();
assert( !devices.empty() );
const size_t N = 1024*1024;
vector<float> host_buffer(N, 0.0f);
cl::Buffer buffer(context, CL_MEM_READ_WRITE, N*sizeof(float));
cl::CommandQueue queue(context, devices[0]);
DWORD t0, t1;
// かきかき
t0 = GetTickCount();
for ( int i = 0; i < 1000; ++i ) {
queue.enqueueWriteBuffer(buffer, CL_TRUE, 0, N*sizeof(float), &host_buffer[0]);
}
t1 = GetTickCount();
cout << "Write 1000 times: " << (t1-t0) << "[ms]\n";
// よみよみ
t0 = GetTickCount();
for ( int i = 0; i < 1000; ++i ) {
queue.enqueueReadBuffer(buffer,CL_TRUE, 0, N*sizeof(float), &host_buffer[0]);
}
t1 = GetTickCount();
cout << "Read 1000 times: " << (t1-t0) << "[ms]\n";
} catch ( const cl::Error& err ) {
cerr << "OpenCL error " << err.err() << " :" << err.what() << endl;
}
ATI Stream SDK 2.2 / ATI Radeon HD5450 DDR2-512MB での結果:
Write 1000 times: 11766[ms]
Read 1000 times: 5313[ms]
ほほー、書き込みは読み込みの倍以上の時間がかかるですね。
ホスト-デバイス間のメモリ転送(特にホスト→デバイス)はパフォーマンスを落とすのか。