Pendekatan modern untuk membuat std :: vector mengalokasikan memori yang selaras

11

Pertanyaan berikut terkait, namun jawabannya sudah lama, dan komentar dari pengguna Marc Glisse menyarankan ada pendekatan baru sejak C ++ 17 untuk masalah ini yang mungkin tidak cukup dibahas.

Saya mencoba menyelaraskan memori yang berfungsi dengan baik untuk SIMD, sementara masih memiliki akses ke semua data.

Pada Intel, jika saya membuat vektor tipe float __m256, dan mengurangi ukuran saya dengan faktor 8, itu memberi saya memori yang selaras.

Misalnya std::vector<__m256> mvec_a((N*M)/8);

Dengan cara yang sedikit kabur, saya bisa mengarahkan pointer ke elemen vektor untuk mengapung, yang memungkinkan saya untuk mengakses nilai float individual.

Sebagai gantinya, saya lebih suka memiliki std::vector<float>yang disejajarkan dengan benar, dan dengan demikian dapat dimuat ke dalam __m256dan jenis SIMD lainnya tanpa segfaulting.

Saya telah mencari di aligned_alloc .

Ini bisa memberi saya array gaya-C yang disejajarkan dengan benar:

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

Namun saya tidak yakin bagaimana melakukan ini std::vector<float>. Memberi std::vector<float>kepemilikan marr_a tampaknya tidak mungkin .

Saya telah melihat beberapa saran bahwa saya harus menulis pengalokasi kustom , tetapi ini sepertinya banyak pekerjaan, dan mungkin dengan C ++ modern ada cara yang lebih baik?

Prunus Persica
sumber
1
tanpa segfaulting ... atau tanpa potensi pelambatan dari celah cache-line saat Anda gunakan _mm256_loadu_ps(&vec[i]). (Meskipun catatan bahwa dengan pilihan tuning default, GCC membagi tidak dijamin-blok 256-bit beban / toko ke vmovups XMM / vinsertf128. Jadi ada adalah keuntungan untuk menggunakan _mm256_loadlebih loadujika Anda peduli tentang bagaimana mengkompilasi kode Anda di GCC jika lupa seseorang untuk gunakan -mtune=...atau -march=opsi.)
Peter Cordes

Jawaban:

1

Semua kontainer di pustaka C ++ standar, termasuk vektor, memiliki parameter templat opsional yang menentukan pengalokasi penampung , dan itu tidak benar-benar banyak pekerjaan untuk menerapkan Anda sendiri:

class my_awesome_allocator {
};

std::vector<float, my_awesome_allocator> awesomely_allocated_vector;

Anda harus menulis sedikit kode yang mengimplementasikan pengalokasi Anda, tetapi itu tidak akan menjadi lebih banyak kode daripada yang sudah Anda tulis. Jika Anda tidak memerlukan dukungan pra-C ++ 17, Anda hanya perlu menerapkan metode alokasi () dan membatalkan alokasi () , itu saja.

Sam Varshavchik
sumber
Mereka juga perlu berspesialisasiallocator_traits
NathanOliver
1
Ini mungkin tempat yang baik untuk jawaban kanonik dengan contoh yang dapat disalin / ditempelkan oleh orang-orang untuk melompati lingkaran C ++ yang menjengkelkan. (Poin bonus jika ada cara untuk membiarkan std :: vector mencoba merealokasi di tempat alih-alih braindead C ++ yang biasa selalu mengalokasikan + copy.) Juga tentu saja perhatikan bahwa ini vector<float, MAA>bukan tipe yang kompatibel dengan vector<float>(dan tidak bisa karena apa pun yang dilakukan .push_backpada dataran yang std::vector<float>dikompilasi tanpa pengalokasi ini dapat melakukan alokasi baru dan menyalin ke memori minimal-aligned. Dan baru / delete tidak kompatibel dengan aligned_alloc / gratis)
Peter Cordes
1
Saya tidak berpikir ada jaminan bahwa pointer yang dikembalikan dari pengalokasi secara langsung digunakan sebagai alamat dasar dari std::vectorarray. Sebagai contoh, saya bisa membayangkan implementasi std::vectormenggunakan hanya satu pointer ke memori yang dialokasikan yang menyimpan akhir / kapasitas / pengalokasi dalam memori sebelum rentang nilai. Itu bisa dengan mudah menggagalkan penyelarasan yang dilakukan oleh pengalokasi.
Dietmar Kühl
1
Kecuali itu std::vectormenjaminnya. Untuk itulah ia menggunakannya. Mungkin Anda harus meninjau apa yang ditentukan oleh standar C ++ di sini.
Sam Varshavchik
1
> Mereka juga perlu berspesialisasi allocator_traits- Tidak, mereka tidak. Yang diperlukan hanyalah menerapkan pengalokasi yang sesuai.
Andrey Semashev