Saya telah membaca banyak tentang manfaat pengorganisasian data ke dalam 'Structs of Arrays' (SoA) alih-alih 'Array of Structs' (AoS) untuk mendapatkan hasil yang lebih baik saat menggunakan instruksi SIMD . Sementara 'mengapa' masuk akal bagi saya, saya tidak yakin berapa banyak yang harus dilakukan ketika bekerja dengan hal-hal seperti vektor.
Vektor sendiri dapat dianggap sebagai struct dari array (ukuran tetap) data, sehingga Anda dapat mengkonversi array ini menjadi struct dari array X, Y dan Z. Melalui ini, Anda dapat bekerja pada 4 vektor sekaligus sebagai lawan satu pada satu waktu.
Sekarang, untuk alasan spesifik saya memposting ini di GameDev:
Apakah ini masuk akal untuk bekerja dengan vektor di SPU? Lebih khusus, apakah masuk akal untuk beberapa array DMA hanya untuk satu vektor? Atau lebih baik tetap menggunakan DMA array array dan membuka gulungannya ke komponen yang berbeda untuk bekerja dengan?
Saya bisa melihat manfaat dari memotong membuka gulungan (jika Anda melakukannya 'AoS'), tetapi sepertinya Anda bisa dengan cepat kehabisan saluran DMA jika Anda mengambil rute ini dan sedang bekerja dengan beberapa set vektor sekaligus.
(Catatan: belum ada pengalaman profesional dengan Cell, tetapi telah bermain-main di OtherOS untuk sementara waktu)
sumber
SPU sebenarnya merupakan kasus khusus yang menarik ketika datang ke kode vektor. Instruksi dibagi menjadi keluarga "aritmatika" dan "memuat / menyimpan", dan kedua keluarga berjalan pada saluran pipa terpisah. SPU dapat mengeluarkan satu dari setiap jenis per siklus.
Kode matematika jelas sangat terikat oleh instruksi matematika - jadi biasanya loop matematika pada SPU akan memiliki banyak dan banyak siklus terbuka pada pipa load / store. Karena shuffles terjadi pada pipa load / store, Anda sering memiliki cukup instruksi load / store gratis untuk merombak bentuk xyzxyzxyzxyz ke dalam bentuk xxxxyyyyzzzz tanpa overhead sama sekali.
Teknik ini paling tidak digunakan di Naughty Dog - lihat presentasi perakitan SPU mereka ( bagian 1 dan bagian 2 ) untuk detailnya.
Sayangnya kompiler sering kali tidak cukup pintar untuk melakukan ini secara otomatis - jika Anda memutuskan untuk pergi rute ini Anda harus menulis sendiri perakitan atau membuka gulungan Anda menggunakan intrinsik dan memeriksa assembler untuk memastikan itu yang Anda inginkan. Jadi jika Anda ingin menulis kode lintas platform umum yang berjalan dengan baik di SPU, Anda mungkin ingin menggunakan SoA atau AoSoA (seperti yang disarankan jpaver.)
sumber
Seperti halnya optimasi, profil! Keterbacaan menjadi prioritas utama, dan seharusnya hanya dikorbankan ketika pembuatan profil mengidentifikasi kemacetan tertentu dan Anda telah kehabisan semua pilihan Anda untuk menyetel algoritma tingkat tinggi (cara tercepat untuk melakukan pekerjaan adalah tidak harus melakukan pekerjaan!) Anda harus selalu membuat profil ulang mengikuti setiap optimasi tingkat rendah untuk memastikan bahwa Anda benar-benar telah membuat segala sesuatunya lebih cepat daripada sebaliknya, terutama dengan saluran pipa yang seanik Sel.
Teknik apa yang Anda gunakan akan tergantung pada rincian kemacetan. Secara umum, ketika bekerja dengan tipe vektor, komponen vektor yang Anda abaikan dalam suatu hasil merepresentasikan kerja yang sia-sia. Mengalihkan SoA / AoS tidak masuk akal kecuali memungkinkan Anda untuk melakukan pekerjaan yang lebih bermanfaat dengan mengisi komponen yang tidak digunakan tersebut (misalnya produk satu titik pada PPU PS3 vs produk empat titik secara paralel dalam jumlah waktu yang sama). Untuk menjawab pertanyaan Anda, menghabiskan waktu mengocok komponen hanya untuk melakukan satu operasi pada satu vektor terdengar seperti pesimis kepada saya!
Sisi lain pada SPU adalah bahwa sebagian besar biaya transfer DMA kecil dalam pengaturan; apa pun yang kurang dari 128 byte akan memerlukan jumlah siklus yang sama untuk ditransfer, dan apa pun yang kurang dari sekitar satu kilobita hanya beberapa siklus lagi. Jadi jangan khawatir tentang DMA data lebih dari yang Anda butuhkan; mengurangi jumlah transfer DMA berurutan yang dipicu, dan melakukan pekerjaan saat transfer DMA terjadi - dan karenanya membuka loop prolog dan epilog untuk membentuk jaringan perangkat lunak - adalah kunci untuk kinerja SPU yang baik, dan paling mudah untuk menangani kasus sudut dengan mengambil data tambahan • buang hasil yang dihitung sebagian daripada melompat-lompat untuk mencoba mengatur jumlah data yang tepat yang perlu dibaca dan diproses.
sumber
Tidak, itu tidak masuk akal secara umum karena kebanyakan opcodes vektor beroperasi pada vektor secara keseluruhan dan bukan pada komponen yang terpisah. Jadi Anda sudah dapat mengalikan vektor dalam 1 instruksi, sedangkan dengan memisahkan komponen yang terpisah Anda akan menghabiskan 4 instruksi di atasnya. Jadi karena pada dasarnya Anda melakukan banyak operasi secara umum pada bagian struct, Anda lebih baik mengemasnya dalam sebuah array, tetapi Anda hampir tidak pernah melakukan hal-hal hanya pada satu komponen vektor, atau sangat berbeda pada setiap komponen sehingga mematahkannya. keluar tidak akan berhasil.
Tentu saja, jika Anda menemukan situasi di mana Anda harus melakukan sesuatu untuk hanya (katakanlah) x komponen vektor itu mungkin berhasil, namun hukuman dari swizzling semuanya kembali ketika Anda membutuhkan vektor yang sebenarnya tidak akan murah sehingga Anda bisa bertanya-tanya apakah Anda tidak harus menggunakan vektor untuk memulai tetapi hanya sebuah array float yang memungkinkan opcode vektor untuk melakukan perhitungan spesifik mereka.
sumber