สตรีมข้อมูลไปยังเคอร์เนล CUDA โดยไม่ต้องเปิดหลายครั้ง

ฉันกำลังพยายาม GPU เร่งอัลกอริธึมโดยที่ฉันได้รับกระแสอนุภาคแบบอะซิงโครนัสในพื้นที่ 3 มิติ $p=[x,y,t]$ เวกเตอร์แต่ละตัว $p_n$ ต้องคูณด้วยเมทริกซ์การแปลงจำนวนหนึ่ง เนื่องจากการเปลี่ยนแปลงเหล่านี้เป็นอิสระจากกัน จึงสามารถเกิดขึ้นพร้อมกันได้ ดังนั้นฉันจึงเขียนเคอร์เนล CUDA เพื่อทำเช่นนั้น มันทำงานได้ดี แต่แน่นอนว่าสำหรับ $p_n$ ที่เข้ามาแต่ละครั้ง ฉันจะต้องเปิดเคอร์เนล CUDA ใหม่อีกครั้ง การเปิดตัวเคอร์เนล CUDA จะต้องเสียเวลาอย่างมาก ดังนั้นฉันจึงสูญเสียข้อได้เปรียบจากการเร่งความเร็วของ GPU คำถามของฉันคือ ฉันสามารถเปิดเคอร์เนลค้างไว้และสตรีมอนุภาคไปที่เคอร์เนลได้หรือไม่

ในกรณีที่มีความช่วยเหลือใด ๆ นี่คือเคอร์เนลปัจจุบันของฉัน:

__global__
void project(float *projection_matrix, float *vector, float *output_matrix) {
    int col_index = blockIdx.x * blockDim.x + threadIdx.x;
    int row_index = blockIdx.y * blockDim.x + threadIdx.y;
    int output_index = (col_index*3 + threadIdx.y);
    int transform_first_element = col_index * 9 + threadIdx.y * 3;
    int stride = blockDim.x*blockDim.y*gridDim.x;

    while (output_index < (NUMBER_OF_TRANSFORMS * 3)) {
        output_matrix[output_index] = projection_matrix[transform_first_element]*vector[0]+ projection_matrix[(transform_first_element+1)]*vector[1] + projection_matrix[(transform_first_element+2)]*vector[2];
        output_index += stride;
    }
}

และนี่คือที่ฉันเรียกมันว่า:

...
project <<<num_blocks_dim, block_dim >>> (transformationList, inputVector, outputMatrix);
cudaDeviceSynchronize();
...

person Mr Squid    schedule 26.10.2017    source แหล่งที่มา
comment
ได้ คุณสามารถเปิดเคอร์เนลไว้และสตรีมอนุภาคไปที่เคอร์เนลได้ มันถูกเรียกว่ากระบวนทัศน์การออกแบบเคอร์เนลแบบถาวร และมีบทความที่เขียนเกี่ยวกับมันตลอดจนคำถามเกี่ยวกับ SO ที่นี่   -  person Robert Crovella    schedule 26.10.2017
comment
@RobertCrovella - ขอบคุณสำหรับการตอบกลับของคุณ มันทำให้ฉันมีคำหลักที่ดีมากมายในการติดตามผล ซึ่งฉันจะไม่รู้มาก่อน ฉันเจอตัวอย่างที่จัดวางอย่างสวยงามนี้ - จริงๆ แล้วคุณเขียนเอง! (stackoverflow.com/questions/33150040/) การออกแบบของผู้ผลิต/ผู้บริโภคประเภทนี้คือสิ่งที่คุณอยากแนะนำสำหรับกรณีการใช้งานของฉันหรือไม่ ตอนนี้เราจะแตกต่างไปจากเมื่อปี 2015 ไหม?   -  person Mr Squid    schedule 27.10.2017
comment
ฉันไม่เห็นคำอธิบายกรณีการใช้งานของคุณเพียงพอที่จะให้คำแนะนำ ฉันตอบคำถามเป็นหลักว่าฉันสามารถเปิดเคอร์เนลและสตรีมอนุภาคไปที่มันได้หรือไม่ การเปลี่ยนแปลงที่ฉันจะทำในวันนี้เทียบกับปี 2558 คือการใช้กลุ่มความร่วมมือซึ่งเป็นคุณสมบัติใหม่ใน CUDA 9 เพื่อจัดการการออกแบบเคอร์เนลแบบถาวร   -  person Robert Crovella    schedule 27.10.2017


คำตอบ (1)


คุณจะต้องแบทช์คำขอเป็นบล็อกที่ใหญ่ขึ้นและเรียกใช้เคอร์เนลบนอนุภาคจำนวนมาก คุณอาจใช้มิติที่สามของเคอร์เนลเพื่อวนซ้ำพวกมันได้ วิธีหนึ่งในการทำเช่นนี้คือการสะสมอนุภาคที่เข้ามาในขณะที่เคอร์เนลกำลังทำงาน หากคุณมีอนุภาคไม่เพียงพอที่จะพิสูจน์การเปิดเคอร์เนล ให้ประมวลผลอนุภาคนั้นบน CPU

หากมีการสร้างอนุภาคบน GPU คุณมีตัวเลือกในการเปิดเคอร์เนลจากเคอร์เนลที่มี CUDA เวอร์ชันใหม่กว่า แต่คุณยังคงต้องมีบล็อกขนาดใหญ่พอที่จะทำให้ชนะได้

หากสิ่งเหล่านี้มาจาก CPU แล้วกลับไปที่ CPU ฉันจะแปลกใจหากคุณสามารถทำให้มันคุ้มค่าได้เลย เว้นแต่ว่าจำนวนเมทริกซ์จะค่อนข้างมาก (เปรียบเทียบกับรหัส SIMD CPU ที่ได้รับการปรับปรุงอย่างดี)

person Zalman Stern    schedule 26.10.2017
comment
@ZalmanStein ฉันไม่ได้ถือว่า SIMD เป็นทางเลือกอื่น ฉันไม่อยากเริ่มเรียนรู้เกี่ยวกับ SSE อย่างแน่นอนเพราะมันดูซับซ้อนสำหรับฉัน แต่ฉันอาจสามารถบรรลุสิ่งที่ฉันต้องการได้ด้วยไลบรารีระดับที่สูงกว่าเช่น Intel MKL คุณคิดอย่างไร ตามหลักการทั่วไป ฉันควรพิจารณาใช้ CPU SIMD แทนการเร่งความเร็ว GPU ในกรณีการใช้งานใด - person Mr Squid; 27.10.2017
comment
ปัญหาหลักคือต้นทุนของกระแสข้อมูล มีค่าใช้จ่ายคงที่ในการถ่ายโอนข้อมูลส่วนเล็กๆ ไปยัง/จาก GPU และจะต้องใช้การคำนวณจำนวนมากเพื่อให้คุ้มค่าในการดำเนินการดังกล่าว ลองเข้าไปดู Halide, halide-lang.org อาจอนุญาตให้เขียนโค้ดในลักษณะที่ช่วยให้กำหนดเป้าหมาย CPU และ GPU ได้อย่างมีประสิทธิภาพ (ขึ้นอยู่กับข้อมูลเฉพาะเจาะจงเล็กน้อย ตามข้อจำกัดความรับผิดชอบ ฉันทำงานกับ Halide) - person Zalman Stern; 27.10.2017