วิธีการที่ทันสมัยในการทำให้ std :: vector จัดสรรหน่วยความจำที่จัดตำแหน่งไว้


11

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

ฉันกำลังพยายามให้หน่วยความจำที่ทำงานสอดคล้องกันอย่างถูกต้องสำหรับ SIMD ในขณะที่ยังคงสามารถเข้าถึงข้อมูลทั้งหมดได้

ใน Intel ถ้าฉันสร้างเวกเตอร์ลอยชนิด__m256และลดขนาดลง 8 เท่ามันจะทำให้ฉันมีหน่วยความจำที่สอดคล้องกัน

เช่น std::vector<__m256> mvec_a((N*M)/8);

ในทางที่แฮ็กเล็กน้อยฉันสามารถชี้พอยน์เตอร์ไปยังองค์ประกอบเวกเตอร์เพื่อลอยตัวซึ่งทำให้ฉันสามารถเข้าถึงค่าลอยตัวส่วนบุคคล

แต่ฉันต้องการให้มีการstd::vector<float>จัดตำแหน่งที่ถูกต้องและสามารถโหลดลงใน__m256และ SIMD ประเภทอื่น ๆ ได้โดยไม่ต้องแบ่งไฟล์

ฉันได้รับการมองเข้าไปในaligned_alloc

นี่สามารถให้อาเรย์แบบ C ที่จัดเรียงอย่างถูกต้อง:

auto align_sz = static_cast<std::size_t> (32);
float* marr_a = (float*)aligned_alloc(align_sz, N*M*sizeof(float));

อย่างไรก็ตามฉันไม่แน่ใจว่าจะทำเช่นนี้std::vector<float>ได้อย่างไร ให้std::vector<float>เป็นเจ้าของไม่ได้ดูเหมือนจะเป็นไปได้marr_a

ฉันเคยเห็นคำแนะนำบางอย่างที่ฉันควรเขียนตัวจัดสรรแบบกำหนดเองแต่ดูเหมือนว่าจะทำงานได้มากและบางทีด้วย C ++ ที่ทันสมัยมีวิธีที่ดีกว่า


1
โดยไม่ต้อง segfaulting ... _mm256_loadu_ps(&vec[i])หรือไม่มีการชะลอตัวที่อาจเกิดขึ้นจากการแยกแคชเส้นเมื่อคุณใช้ (ถึงแม้จะทราบว่ามีตัวเลือกการปรับแต่งค่าเริ่มต้น GCC แยกไม่รับประกัน-ชิดโหลด 256-bit / ร้านค้าเข้า vmovups XMM / vinsertf128. จึงมีเป็นข้อได้เปรียบในการใช้_mm256_loadมากกว่าloaduถ้าคุณดูแลเกี่ยวกับวิธีการคอมไพล์รหัสของคุณใน GCC ถ้าลืมใครสักคน ใช้-mtune=...หรือ-march=ตัวเลือก)
Peter Cordes

คำตอบ:


1

คอนเทนเนอร์ทั้งหมดในไลบรารี C ++ มาตรฐานรวมถึงเวกเตอร์มีพารามิเตอร์เทมเพลตเผื่อเลือกที่ระบุตัวจัดสรรของคอนเทนเนอร์และมันไม่ได้เป็นงานที่ต้องใช้ตัวคุณเอง:

class my_awesome_allocator {
};

std::vector<float, my_awesome_allocator> awesomely_allocated_vector;

คุณจะต้องเขียนโค้ดเล็กน้อยที่ใช้ตัวจัดสรรของคุณ แต่มันจะไม่เป็นโค้ดมากกว่าที่คุณเขียนไว้แล้ว หากคุณไม่ต้องการการสนับสนุน pre-C ++ 17 คุณจะต้องใช้เมธอดallocate ()และdeallocate () เท่านั้นนั่นแหละ


พวกเขายังต้องมีความเชี่ยวชาญallocator_traits
NathanOliver

1
นี่อาจเป็นสถานที่ที่ดีสำหรับคำตอบที่เป็นที่ยอมรับด้วยตัวอย่างที่ผู้คนสามารถคัดลอก / วางเพื่อข้ามผ่านห่วงที่น่ารำคาญของ C ++ (คะแนนโบนัสหากมีวิธีให้ std :: vector พยายาม realloc แบบแทนการใช้ braindead C ++ จะจัดสรร + copy เสมอ) และแน่นอนว่านี่vector<float, MAA>ไม่ใช่ประเภทที่เข้ากันได้กับvector<float>(และไม่สามารถเป็นเพราะ อะไรที่ไม่.push_backเกี่ยวกับธรรมดาstd::vector<float>เรียบเรียงโดยไม่ต้องจัดสรรนี้สามารถทำจัดสรรใหม่และคัดลอกลงในหน่วยความจำน้อยที่สุดชิดและใหม่ / ลบกันไม่ได้กับ aligned_alloc / ฟรี).
ปีเตอร์ Cordes

1
ฉันไม่คิดว่าจะมีการรับประกันใด ๆ ว่าตัวชี้ที่ส่งคืนจากตัวจัดสรรนั้นจะถูกใช้โดยตรงเป็นที่อยู่ฐานของstd::vectorอาร์เรย์ ตัวอย่างเช่นฉันสามารถจินตนาการถึงการนำไปใช้ของstd::vectorตัวชี้เพียงตัวเดียวไปยังหน่วยความจำที่จัดสรรซึ่งจัดเก็บจุดสิ้นสุด / ความจุ / ตัวจัดสรรในหน่วยความจำก่อนช่วงของค่า นั่นสามารถทำลายการจัดตำแหน่งที่ทำได้โดยตัวจัดสรร
Dietmar Kühl

1
ยกเว้นว่าstd::vectorจะรับประกันมัน นั่นคือสิ่งที่มันใช้สำหรับ บางทีคุณควรตรวจสอบสิ่งที่มาตรฐาน C ++ ระบุไว้ที่นี่
Sam Varshavchik

1
> พวกเขายังต้องมีความเชี่ยวชาญallocator_traits- ไม่พวกเขาทำไม่ได้ สิ่งที่จำเป็นทั้งหมดคือการใช้ตัวจัดสรรที่เข้ากันได้
Andrey Semashev
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.