मैं निम्नलिखित OpenCL गिरी है:वैश्विक या स्थानीय स्मृति के लिए लेखन 10000% से बढ़ जाती है कर्नेल निष्पादन समय
kernel void ndft(
global float *re, global float *im, int num_values,
global float *spectrum_re, global float *spectrum_im,
global float *spectrum_abs,
global float *sin_array, global float *cos_array,
float sqrt_num_values_reciprocal)
{
// MATH MAGIC - DISREGARD FROM HERE -----------
float x;
float y;
float sum_re = 0;
float sum_im = 0;
size_t thread_id = get_global_id(0);
//size_t local_id = get_local_id(0);
// num_values = 24 (live environment), 48 (test)
for (int i = 0; i < num_values; i++)
{
x = cos_array[thread_id * num_values + i] * sqrt_num_values_reciprocal;
y = sin_array[thread_id * num_values + i] * sqrt_num_values_reciprocal;
sum_re = sum_re + re[i] * x + im[i] * y;
sum_im = sum_im - re[i] * y + x * im[i];
}
// MATH MAGIC DONE ----------------------------
//spectrum_re[thread_id] = sum_re;
//spectrum_im[thread_id] = sum_im;
//spectrum_abs[thread_id] = hypot(sum_re, sum_im);
float asdf = hypot(sum_re, sum_im); // this is just a dummy calculation
}
इस तरह, निष्पादन समय के बारे में 15 हमें (कार्य समूह आकार = 567, 14 कार्य समूहों है , कुल 7 9 38 धागे के लिए)।
हालांकि, मुझे किसी भी तरह ऑपरेशन के परिणामों को पुनर्प्राप्त करने की आवश्यकता है, जो पिछले कुछ पंक्तियों के लिए है, (टिप्पणी की गई)। जैसे ही मैं उन स्मृति कार्यों में से एक करता हूं (और इससे कोई फर्क नहीं पड़ता कि spectrum_X
global
है, उदाहरण के लिए, या local
), कर्नेल का बहिष्करण समय ~ 1.4 से 1.5 एमएस तक बढ़ जाता है।
मैंने सोचा कि निष्पादन समय में वृद्धि कुछ प्रकार का निश्चित ओवरहेड था, इसलिए मैं केवल अधिक डेटा जमा करूंगा, ताकि उस प्रभाव के कारण खोए गए समय की सापेक्ष मात्रा कम हो। लेकिन जब मैं अपने धागे की संख्या दोगुना करता हूं (i. ई। डेटा की मात्रा से दोगुना), निष्पादन समय भी दोगुना हो जाता है (2.8 ~ 3.0 एमएस तक)।
मुझे पता चला कि अगर मैं केवल उन पंक्तियों के एक को असम्बद्ध करता हूं, तो मेरे पास एक ही निष्पादन समय है जैसे कि मैंने तीनों को अपूर्ण किया है। यहां तक कि अगर मैं if (thread_id == 0)
जोड़ता हूं और इसे चलाता हूं, तो मेरे पास एक ही निष्पादन समय होता है। हालांकि, यह इस तरह से बहुत धीमा तरीका है (मेरे आवेदन के लिए ऊपरी सीमा लगभग 30 है)। जब मैं इसे अपने सीपीयू पर सामान्य सी कोड में चलाता हूं तो यह लगभग 5 गुना तेज होता है।
अब मैं स्पष्ट रूप से कुछ गलत कर रहा हूं लेकिन मुझे यकीन नहीं है कि समाधान कहां से शुरू करना है।
जैसा कि मैंने talonmies 'उत्तर पर टिप्पणी की, मैं भी निम्नलिखित किया:
ऊपर कोड से, मैं पिछले 4 लाइनों
//spectrum_re[thread_id] = sum_re;
//spectrum_im[thread_id] = sum_im;
spectrum_abs[thread_id] = hypot(sum_re, sum_im);
//float asdf = hypot(sum_re, sum_im);
जैसी उम्मीद थी की तरह लग रहे बनाया है, निष्पादन समय ~ 1.8 एमएस अपने सिस्टम के लिए उत्पन्न कोडांतरक कोड है:
//
// Generated by NVIDIA NVVM Compiler
// Compiler built on Tue Apr 03 12:42:39 2012 (1333449759)
// Driver
//
.version 3.0
.target sm_21, texmode_independent
.address_size 32
.entry ndft(
.param .u32 .ptr .global .align 4 ndft_param_0,
.param .u32 .ptr .global .align 4 ndft_param_1,
.param .u32 ndft_param_2,
.param .u32 .ptr .global .align 4 ndft_param_3,
.param .u32 .ptr .global .align 4 ndft_param_4,
.param .u32 .ptr .global .align 4 ndft_param_5,
.param .u32 .ptr .global .align 4 ndft_param_6,
.param .u32 .ptr .global .align 4 ndft_param_7,
.param .f32 ndft_param_8
)
{
.reg .f32 %f;
.reg .pred %p;
.reg .s32 %r;
ld.param.u32 %r3, [ndft_param_2];
// inline asm
mov.u32 %r18, %envreg3;
// inline asm
// inline asm
mov.u32 %r19, %ntid.x;
// inline asm
// inline asm
mov.u32 %r20, %ctaid.x;
// inline asm
// inline asm
mov.u32 %r21, %tid.x;
// inline asm
add.s32 %r22, %r21, %r18;
mad.lo.s32 %r11, %r20, %r19, %r22;
setp.gt.s32 %p1, %r3, 0;
@%p1 bra BB0_2;
mov.f32 %f46, 0f00000000;
mov.f32 %f45, %f46;
bra.uni BB0_4;
BB0_2:
ld.param.u32 %r38, [ndft_param_2];
mul.lo.s32 %r27, %r38, %r11;
shl.b32 %r28, %r27, 2;
ld.param.u32 %r40, [ndft_param_6];
add.s32 %r12, %r40, %r28;
ld.param.u32 %r41, [ndft_param_7];
add.s32 %r13, %r41, %r28;
mov.f32 %f46, 0f00000000;
mov.f32 %f45, %f46;
mov.u32 %r43, 0;
mov.u32 %r42, %r43;
BB0_3:
add.s32 %r29, %r13, %r42;
ld.global.f32 %f18, [%r29];
ld.param.f32 %f44, [ndft_param_8];
mul.f32 %f19, %f18, %f44;
add.s32 %r30, %r12, %r42;
ld.global.f32 %f20, [%r30];
mul.f32 %f21, %f20, %f44;
ld.param.u32 %r35, [ndft_param_0];
add.s32 %r31, %r35, %r42;
ld.global.f32 %f22, [%r31];
fma.rn.f32 %f23, %f22, %f19, %f46;
ld.param.u32 %r36, [ndft_param_1];
add.s32 %r32, %r36, %r42;
ld.global.f32 %f24, [%r32];
fma.rn.f32 %f46, %f24, %f21, %f23;
neg.f32 %f25, %f22;
fma.rn.f32 %f26, %f25, %f21, %f45;
fma.rn.f32 %f45, %f24, %f19, %f26;
add.s32 %r42, %r42, 4;
add.s32 %r43, %r43, 1;
ld.param.u32 %r37, [ndft_param_2];
setp.lt.s32 %p2, %r43, %r37;
@%p2 bra BB0_3;
BB0_4:
// inline asm
abs.f32 %f27, %f46;
// inline asm
// inline asm
abs.f32 %f29, %f45;
// inline asm
setp.gt.f32 %p3, %f27, %f29;
selp.f32 %f8, %f29, %f27, %p3;
selp.f32 %f32, %f27, %f29, %p3;
// inline asm
abs.f32 %f31, %f32;
// inline asm
setp.gt.f32 %p4, %f31, 0f7E800000;
mov.f32 %f47, %f32;
@%p4 bra BB0_6;
mov.f32 %f48, %f8;
bra.uni BB0_7;
BB0_6:
mov.f32 %f33, 0f3E800000;
mul.rn.f32 %f10, %f8, %f33;
mul.rn.f32 %f47, %f32, %f33;
mov.f32 %f48, %f10;
BB0_7:
mov.f32 %f13, %f48;
// inline asm
div.approx.f32 %f34, %f13, %f47;
// inline asm
mul.rn.f32 %f39, %f34, %f34;
add.f32 %f38, %f39, 0f3F800000;
// inline asm
sqrt.approx.f32 %f37, %f38; // <-- this is part of hypot()
// inline asm
mul.rn.f32 %f40, %f32, %f37;
add.f32 %f41, %f32, %f8;
setp.eq.f32 %p5, %f32, 0f00000000;
selp.f32 %f42, %f41, %f40, %p5;
setp.eq.f32 %p6, %f32, 0f7F800000;
setp.eq.f32 %p7, %f8, 0f7F800000;
or.pred %p8, %p6, %p7;
selp.f32 %f43, 0f7F800000, %f42, %p8;
shl.b32 %r33, %r11, 2;
ld.param.u32 %r39, [ndft_param_5];
add.s32 %r34, %r39, %r33;
st.global.f32 [%r34], %f43; // <-- stores the hypot's result in spectrum_abs
ret;
}
दरअसल मेरे सभी गणना संचालन कर रहे हैं वहाँ -/कहते हैं की बहुत सारी mults के साथ-साथ hypot
समारोह के लिए एक sqrt
।
st.global.f32 [%r34], %f43;
जो लाइन है कि वास्तव में वैश्विक सरणी spectrum_abs
में डेटा संग्रहीत करता है: उपरोक्त एएसएम कोड से, मैं दूसरा अंतिम पंक्ति हटा दिया। तब मैंने clCreateProgramWithBinary
का उपयोग किया और इनपुट के रूप में संशोधित एएसएम कोड फ़ाइल का उपयोग किया। निष्पादन का समय 20 तक गिर गया।
आप इसे किस हार्डवेयर और ओपनसीएल स्वाद पर चल रहे हैं? – talonmies
@talonmies NVIDIA GeForce 555M जीटी, हाल ही में CUDA टूलकिट। – dialer
क्या आप बाद में सभी मूल्यों को जमा कर रहे हैं? क्या कोई विशेष कारण है कि प्रत्येक कार्य आइटम को 24 या 48 लगातार मूल्यों की गणना करने की आवश्यकता क्यों होती है? आपने अपने कर्नेल में पास करने से पहले sin_array और cos_array की गणना कैसे की? – mfa