- Kuliah assembly pertama FFmpeg merangkum pada tingkat pemula mengapa SIMD assembly yang ditulis manual diperlukan dalam pemrosesan multimedia dan konvensi penulisan fungsi ala FFmpeg
- Pembaca sasaran harus memahami pointer C serta konsep skalar dan vektor, penjumlahan dan perkalian setingkat SMA; kuliah ini menggunakan x86 64-bit dan sintaks Intel sebagai acuan
- Di FFmpeg, assembly function, SIMD, dan vectorise digunakan dengan arti yang hampir sama, dan cara memproses beberapa elemen data sekaligus sangat cocok untuk pemrosesan gambar, video, dan audio
- Dari sisi performa, assembly manual lebih disukai; intrinsics biasanya 10–15% lebih lambat, dan dibandingkan dengan kasus vektorisasi otomatis dav1d yang sekitar 2x, versi yang ditulis manual mencapai hingga 8x
- Fungsi contoh pertama menggunakan
x86inc.asm, INIT_XMM sse2, cglobal, movu, paddb, dan RET untuk menjumlahkan nilai 16 byte dari dua buffer uint8_t dengan SIMD lalu menyimpannya kembali ke buffer pertama
Tujuan kuliah dan pengetahuan prasyarat
- FFmpeg Assembly Language Lesson One adalah kuliah pengantar yang membahas dasar-dasar cara bahasa assembly ditulis di FFmpeg, serta membantu memahami apa yang sebenarnya terjadi di dalam komputer
- Pengetahuan yang diperlukan adalah sebagai berikut
- Bahasa C, terutama pointer
- Jika belum tahu C, disarankan mempelajari The C Programming Language
- Konsep skalar dan vektor, penjumlahan, serta perkalian setingkat matematika SMA
Bahasa assembly dan SIMD
- Bahasa assembly adalah bahasa pemrograman yang menuliskan kode yang dapat dibaca manusia dan berkorespondensi langsung dengan instruksi yang diproses CPU
- Kode assembly yang dapat dibaca manusia diubah oleh assembler menjadi data biner machine code yang dipahami CPU
- Kode assembly FFmpeg sebagian besar berbentuk SIMD(Single Instruction Multiple Data)
- Satu instruksi bekerja pada beberapa elemen data secara bersamaan
- Juga disebut pemrograman vektor
- Pemrograman skalar biasa memproses satu elemen data pada satu waktu
- SIMD sangat cocok untuk pemrosesan gambar, video, dan audio yang menangani banyak data yang tersusun berurutan di memori
- Di FFmpeg, ungkapan berikut digunakan dengan arti yang hampir sama
assembly function
SIMD
vectorise
- Artinya menulis fungsi assembly secara manual untuk memproses beberapa elemen data sekaligus
Mengapa FFmpeg menulis assembly secara langsung
- Tujuan utamanya adalah meningkatkan kecepatan pemrosesan multimedia
- Peningkatan kecepatan lebih dari 10x umum terjadi dengan menulis kode assembly
- Penting untuk mengurangi tersendat saat pemutaran video real-time
- Dapat mengurangi penggunaan energi dan memperpanjang daya tahan baterai
- Fungsi encoding dan decoding video digunakan sangat luas oleh pengguna akhir dan pusat data, sehingga peningkatan kecil pun cepat terakumulasi
- FFmpeg menggunakan assembly yang ditulis manual alih-alih intrinsics
- Intrinsics adalah fungsi mirip C yang berkorespondensi dengan instruksi assembly
- Biasanya 10–15% lebih lambat daripada assembly yang ditulis manual
- Angka ini bergantung pada compiler, dan pendukung intrinsics bisa saja tidak setuju
- Ada juga pendapat bahwa penggunaannya sulit dibaca karena memakai Hungarian Notation
- inline assembly mungkin masih ada di sebagian kode lama FFmpeg atau proyek seperti Linux Kernel
- Ini adalah cara menulis assembly langsung di dalam kode C, bukan di file terpisah
- Dalam proyek seperti FFmpeg, pandangan yang dominan adalah cara ini sulit dibaca, dukungan compilernya tidak luas, dan sulit dipelihara
- Pendapat bahwa vektorisasi otomatis compiler saja sudah cukup disarankan untuk diabaikan demi tujuan pembelajaran
- Dalam pengujian terbaru dari proyek dav1d, vektorisasi otomatis menunjukkan peningkatan kecepatan sekitar 2x
- Versi yang ditulis manual dapat mencapai hingga 8x
Cakupan sintaks dan referensi
- Kuliah ini berfokus pada assembly x86 64-bit
- Juga disebut amd64, dan berjalan juga di CPU Intel
- Assembly untuk CPU lain seperti ARM dan RISC-V mungkin diperluas di masa mendatang
- Sintaks assembly x86 mencakup AT&T dan Intel
- Sintaks AT&T lebih tua dan dianggap lebih sulit dibaca daripada sintaks Intel
- Kuliah ini menggunakan sintaks Intel
- Buku umum atau materi online seperti Stack Overflow mungkin tidak terlalu berguna sebagai referensi assembly FFmpeg
- Sebab FFmpeg menggunakan assembly sintaks Intel yang ditulis manual
- Banyak materi online berfokus pada pemrograman sistem operasi, pemrograman hardware, atau kode non-SIMD
- Assembly FFmpeg adalah pendekatan unik yang dikhususkan untuk pemrosesan gambar berperforma tinggi
- Diagram di bagian akhir The Art of 64-bit assembly yang memvisualisasikan instruksi dan operasi SIMD dapat membantu
- Server Discord untuk pertanyaan disediakan
Konsep dasar register
- Register adalah area di dalam CPU tempat data diproses
- CPU tidak melakukan operasi langsung pada memori; CPU memuat data ke register, memprosesnya, lalu menuliskannya kembali ke memori
- Dalam assembly, secara umum data tidak dapat disalin langsung dari satu lokasi memori ke lokasi memori lain, melainkan harus melalui register terlebih dahulu
General-purpose register
- GPR(General Purpose Register) adalah register serbaguna yang dapat menyimpan data atau alamat memori
- Di sini dapat menyimpan nilai hingga 64-bit
- Dapat juga menyimpan pointer
- Dapat melakukan operasi seperti penjumlahan, perkalian, dan shift
- Banyak buku assembly membahas detail dan latar belakang historis GPR secara panjang lebar
- Dalam kode assembly FFmpeg, GPR terutama digunakan seperti scaffolding, sehingga sebagian besar kompleksitasnya tidak diperlukan atau diabstraksikan
Register vektor dan ukuran data
- Register vektor menyimpan beberapa elemen data
- Register vektor utama pada x86 adalah sebagai berikut
mm: register MMX, berukuran 64-bit, historis dan kini tidak banyak digunakan
xmm: register XMM, berukuran 128-bit, tersedia luas
ymm: register YMM, berukuran 256-bit, memiliki beberapa kompleksitas saat digunakan
zmm: register ZMM, berukuran 512-bit, kemungkinan penggunaannya terbatas
- Sebagian besar perhitungan dalam kompresi dan dekompresi video berbasis integer, sehingga kuliah ini juga berfokus pada integer
- Satu register
xmm 128-bit dapat ditafsirkan sebagai berikut
- 16 byte, masing-masing 8-bit
- 8 word, masing-masing 16-bit
- 4 doubleword, masing-masing 32-bit
- 2 quadword, masing-masing 64-bit
- Singkatan akan menjadi penting nanti
- byte: data 8-bit
- word: data 16-bit
- doubleword: data 32-bit
- quadword: data 64-bit
- double quadword: data 128-bit
Peran x86inc.asm
x86inc.asm adalah lapisan abstraksi ringan yang digunakan oleh FFmpeg, x264, dan dav1d
- Ia menyediakan berbagai fitur yang membantu programmer assembly menulis kode dengan lebih mudah
- Salah satu fitur penting di awal adalah memberi label seperti
r0, r1, r2 pada GPR
- Tidak perlu mengingat nama register sebenarnya
- Karena GPR di FFmpeg terutama berperan sebagai scaffolding, beban penulisan menjadi lebih ringan
Contoh asm skalar sederhana
mov r0q, 3
inc r0q
dec r0q
imul r0q, 5
- Baris pertama menyimpan immediate value
3 ke register r0 sebagai quadword
- Immediate value adalah nilai yang disimpan di dalam kode assembly itu sendiri, bukan nilai yang diambil dari memori
- Dalam sintaks Intel, operand sumber di kanan diteruskan ke operand tujuan di kiri
- Dapat dibaca seperti
r0q = 3
- Urutannya mirip dengan cara kerja
memcpy
- Sufiks
q pada r0q menunjukkan bahwa register digunakan sebagai quadword
- Operasi berikutnya adalah sebagai berikut
- Dengan
inc, nilainya menjadi 4
- Dengan
dec, nilainya kembali menjadi 3
- Dengan
imul, nilainya dikalikan 5 sehingga akhirnya r0q menjadi 15
- Instruksi yang dapat dibaca manusia seperti
mov dan inc disebut mnemonic
- Assembler mengubahnya menjadi machine code
- Huruf besar
MOV, INC dan huruf kecil mov, inc sama saja
- Di FFmpeg, mnemonic ditulis dengan huruf kecil, sedangkan huruf besar disisakan untuk makro
Contoh fungsi SIMD pertama
%include "x86inc.asm"
SECTION .text
;static void add_values(uint8_t *src, const uint8_t * src2)
INIT_XMM sse2
cglobal add_values, 2, 2, 2, src, src2
movu m0, [srcq]
movu m1, [src2q]
paddb m0, m1
movu [srcq], m0
RET
- Fungsi ini menjumlahkan data
src dan src2 dengan SIMD, lalu menyimpan hasilnya kembali ke lokasi src
%include "x86inc.asm" menyertakan helper, nama yang telah didefinisikan sebelumnya, dan makro yang dikembangkan oleh komunitas x264, FFmpeg, dan dav1d
SECTION .text menunjukkan section tempat kode yang akan dieksekusi berada
- Data konstanta dapat ditempatkan di section
.data
;static void add_values(uint8_t *src, const uint8_t * src2) adalah komentar yang menunjukkan bentuk argumen fungsi C
- Dalam assembly, tanda titik koma
; berperan sebagai komentar seperti // di C
INIT_XMM sse2 membuat kode menggunakan register XMM dan instruction set sse2
- Karena
paddb adalah instruksi sse2
cglobal add_values, 2, 2, 2, src, src2 mendefinisikan fungsi C add_values
- Jumlah argumen fungsi adalah 2
- GPR yang akan digunakan dalam fungsi, termasuk argumen, berjumlah 2
- Jumlah register XMM yang akan digunakan adalah 2
- Dua item terakhir adalah label argumen fungsi
src, src2
- Kode lama dapat langsung menggunakan GPR seperti
r0, r1 tanpa label argumen
load, packed add, store
movu m0, [srcq]
movu m1, [src2q]
movu adalah singkatan dari movdqu, yang berarti move double quad unaligned
- Alignment akan dibahas pada kuliah berikutnya; di sini anggap saja sebagai instruksi yang memindahkan 128-bit dari
[srcq]
- Dalam
mov, tanda kurung siku berarti dereference alamat
- Konsepnya mirip dengan
*src di C
- Operasi ini adalah load
- Sufiks
q menunjukkan ukuran pointer
- Pada sistem 64-bit, ini berarti 8 byte, ukuran pointer di C
- x86asm menggunakan 32-bit pada sistem 32-bit
- Load sebenarnya berukuran 128-bit
- Register vektor dirujuk sebagai
m0 yang diabstraksikan, bukan nama lengkap seperti xmm0
- Ini terkait dengan cara membuat kode yang sama mendukung beberapa ukuran register SIMD pada kuliah berikutnya
paddb m0, m1
paddb menjumlahkan elemen byte pada masing-masing register
- Prefiks
p berarti packed, dan digunakan untuk membedakan instruksi vektor dari instruksi skalar
- Sufiks
b menunjukkan penjumlahan per byte
- Jika dua register yang berisi 16 byte dijumlahkan, elemen yang bersesuaian di tiap posisi dijumlahkan, seperti
a+q, b+r, c+s
movu [srcq], m0
RET
movu [srcq], m0 menuliskan kembali data hasil ke alamat yang ditunjuk oleh pointer srcq
RET adalah makro yang menunjukkan bahwa fungsi kembali
- Hampir semua fungsi assembly FFmpeg memodifikasi data yang diterima sebagai argumen, alih-alih mengembalikan nilai
- Dalam tugas, materi dilanjutkan dengan membuat function pointer untuk fungsi assembly yang tersedia dan menggunakannya
1 komentar
Opini Hacker News
Materi lain tentang topik yang sama: https://blogs.gnome.org/rbultje/2017/07/14/writing-x86-simd-...
Jika melihat komentar di sini, pandangan tentang kegunaan SIMD yang ditulis tangan terbagi dari “sama sekali tidak jelas” sampai “wajib untuk misi”, dan karena kubu “sama sekali tidak jelas” tampaknya lebih banyak, saya akan sedikit menjelaskan sisi wajib untuk misi
FFmpeg adalah contoh yang jelas karena frekuensi penggunaannya, tetapi menurut saya decoder AV1 produksi serbaguna dav1d adalah contoh yang lebih mudah untuk menguantifikasi dampak SIMD yang ditulis tangan
dav1d dipakai hampir di everywhere, dari browser utama hingga sistem operasi Android, menggantikan libgav1, dan alasan besar keberhasilannya adalah kecepatannya yang luar biasa; ini dimungkinkan karena sebagian besar codebase-nya berupa SIMD yang ditulis tangan
Bagus jika bahasa seperti Zig memiliki dukungan SIMD bawaan, tetapi untuk sebagian penggunaan yang patut diteliti karena potensi selisih performanya, penulisan langsung menjadi diperlukan. Beberapa baris kode di dav1d dieksekusi triliunan kali per hari, sehingga harus secepat mungkin, dan perbedaan antara SIMD yang ditulis tangan dan SIMD yang dihasilkan compiler bisa mencapai hingga 50% dalam beberapa kasus, jadi ini penting
Saya sendiri juga cukup terlibat dalam pekerjaan menulis kode yang akan dieksekusi sangat sering dengan cara serupa, jadi menurut saya materi seperti sekolah bahasa assembly FFmpeg cukup penting agar teknik seperti ini tidak hilang
Calling convention bisa berbeda untuk tiap method, sehingga penyimpanan dan pemuatan stack jauh lebih sedikit dibanding kode yang dihasilkan compiler yang mengikuti calling convention platform umum
Misalnya, perkalian matriks baru kami lebih cepat daripada library terkenal untuk inferensi LLM, bahkan dalam kasus ketika pihak lain memakai AMX dan kami memakai AVX512BF16. Alasannya mungkin bottleneck threading atau mungkin penyebab lain, tetapi ketika JIT terlibat, hal itu sulit dipahami
Hasil seperti ini tidak akan muncul jika kami harus menulis kernel khusus platform secara langsung. Waktu dalam sehari terbatas, dan berkat menulis satu implementasi dengan Highway, kami bisa menjelajahi ruang desain yang lebih luas, termasuk auto-tuner yang memilih bukan hanya jenis kernel baru dan ukuran blok, tetapi juga strategi paralelisasi beserta parameternya
Pada tahap kedua, sebagian bisa saja di-tuning secara manual, tetapi saya berharap eksplorasi yang lebih luas dilakukan lebih dulu sebelum mikro-optimasi alokasi register dan calling convention
Saya suka Zig, tetapi sejauh pemahaman saya, dalam kebanyakan kasus tetap harus memakai fungsi bawaan khusus CPU seperti di C/C++
GCC dan Clang mendukung atribut
vector_sizeserta overload operator aritmetika untuk tipe yang “tervektorisasi” itu, dan masih ada jauh lebih banyak lagi. Bahkan intrinsic seperti_mm256_mul_pssebenarnya diimplementasikan seperti#define _mm256_mul_ps(a,b) (__m256)((v8sf)(a) * (v8sf)(b))Kegunaan fitur-fitur seperti ini jauh lebih besar daripada yang dimungkinkan di Zig
Di sisi encoder, khususnya, sering kali masalah perlu “distrukturkan” agar loop dan load bisa dihilangkan lebih awal, dan compiler tidak bisa menghasilkan kode auto-vectorization semacam itu
Dulu saya cukup banyak membuat versi SIMD dari fungsi-fungsi inti, tetapi sekarang hampir tidak lagi. Cara yang layak dicoba adalah memisahkan kode tersebut lalu menjalankannya di Compiler Explorer [0] yang luar biasa
Lalu tinggal melihat kode yang dihasilkan
Sekarang auto-vectorization sering kali menghasilkan versi SIMD dari sebuah fungsi dengan cukup baik, dan sering kali kita hanya perlu memberi “petunjuk” kepada compiler. Misalnya dengan menyatakan alignment secara eksplisit, atau menyediakan tipe sumber/tujuan vektor secara langsung
Banyak hal bisa dilakukan jika kita “menata gaya” kode C sambil memikirkan apa yang mungkin dapat dilakukan compiler. Misalnya memakai lebih banyak variabel antara, dan memecah operasi yang diinginkan menjadi bagian-bagian yang sangat kecil
Bahkan dalam kasus terburuk ketika compiler tidak cukup pintar, kita bisa memodifikasi assembly yang dihasilkan tanpa harus menulis boilerplate sendiri
Dalam kebanyakan kasus, fungsi C hasilnya tervectorize sama baiknya atau lebih baik daripada yang saya tulis tangan, dan dalam banyak kasus lain pun “cukup dekat” sehingga tidak ada perbedaan besar. Selain itu, kode tersebut kemungkinan besar juga akan tervectorize dengan baik untuk WASM atau NEON tanpa versi eksplisit
[0] https://godbolt.org/
GCC dan Clang sama-sama mendukung sebagian ekstensi vektor, sehingga hal-hal seperti load/store tersebar, shuffle, dan masking elemen dalam satu register—yang sulit diekspresikan secara jelas dalam C “murni” agar mudah dibaca manusia dan selalu menghasilkan kode yang diharapkan di berbagai versi compiler—bisa diimplementasikan dengan portabilitas tertentu
Namun karena kami juga harus mendukung compiler dan platform lain, dalam build sebenarnya kami akhirnya mengambil assembly yang dihasilkan dari file sumber tersebut dan menggunakannya
Ini adalah penjumlahan saturasi byte tanpa tanda. Di x86-64 dan ARM64, ini didukung langsung dengan satu instruksi, yaitu PADDUSB dan UQADD.16B
Namun semua compiler mengacaukannya dari deskripsi yang intuitif, entah gagal melakukan vectorization atau menghasilkan kode vectorized yang lebih besar dan lebih lambat dari yang diperlukan
Padahal ini operasi primitif vectorization yang mendasar dan sederhana. Membuat compiler memakai instruksi yang lebih kompleks seperti rounded narrowing saturating right shift (UQRSHRN) itu sulit atau nyaris mustahil
Biasanya lebih cepat menulisnya sendiri saja
pshufbyang lebih lebar dari 16 byte dalam kasus umumBahkan untuk lebar 16 byte, jika memakai definisi sebenarnya dari
pshufb, kita tidak mendapatkanpshufb; tetapi jika memakai versi yang memiliki undefined behavior, barulahpshufbkeluarSaya penulis kuliah ini
Silakan tanya apa saja
Jika assembly sebanyak itu, rasanya seperti keajaiban FFmpeg bisa berjalan di Mac saya. Apakah semuanya dipindahkan secara manual?
Saya penasaran pada titik mana kita menyadari “ini mungkin bisa dipercepat dengan assembly”. Jika sudah menemukan fungsi yang benar-benar akan cepat bila dibuat dalam assembly, bagaimana menuliskannya? Apakah memulai dari output yang diubah compiler menjadi assembly, atau menulis dari awal? Apakah itu penting?
Bagaimana pengalaman pengguna developer dan performa kodenya dibandingkan SIMD tradisional? Apakah kita sedang menuju dunia dengan lebih sedikit jenis set instruksi SIMD yang harus diprogram?
x86asm.incyang menanganinya, atau memang tidak dipedulikanTidak bisakah kita hanya menulis test, lalu membiarkan LLM mencoba 10.000 algoritma dan memprofilkan hasilnya?
Atau bahkan dengan 10.000 seed acak, apakah LLM tetap sulit menemukan solusi optimal?
Saya hanya bertanya karena penasaran. Mengoptimalkan x86 secara manual tidak mudah. Untuk memikirkannya, kita harus memasukkan semua register ke kepala dan mempertimbangkan kombinasinya, serta tahu berapa lama setiap kombinasi instruksi akan memakan waktu. Selain itu, beberapa instruksi memiliki kasus pengecualian aneh yang sulit diperhitungkan manusia, sehingga kadang jauh lebih lama atau jauh lebih cepat
Penasaran kepada orang-orang yang benar-benar pernah mencobanya. Apakah dalam mempelajari atau mengimplementasikan assembly ada kesenangan tertentu seperti LISP atau RISC-V, ataukah ini dipelajari untuk melakukan hal lain, seperti belajar COBOL karena pekerjaan sistem tertentu?
Saya selalu tertarik, tetapi dalam pekerjaan sehari-hari tidak ada alasan khusus untuk mendalaminya. Penasaran apakah layak menginvestasikan waktu untuk bersenang-senang
Sekarang saya cukup suka coding assembly. Setelah tutorial itu, saya tidak banyak melakukannya selain membuat library array yang bisa dipanggil dari C
Menurut saya pada level ini hampir tidak ada sihir yang tersisa, jadi terasa menyenangkan. Anda benar-benar mengatakan dengan tepat apa yang harus terjadi, dan apa yang terlihat umumnya menjadi hasilnya apa adanya
Saya juga jadi jauh lebih memahami linking, dan itu membantu memahami hal-hal yang pada level tinggi sudah saya tahu, tetapi detailnya masih samar
Sekarang saya juga ingin melihat tutorial FFmpeg ini. Karena ini x86, bukan ARM
Ada juga model teoretis yang lebih sederhana seperti mesin Turing atau kalkulus lambda, tetapi arsitektur yang benar-benar ditangani programmer punya sifat yang sampai taraf tertentu lebih memaafkan
Ini bukan sesuatu yang perlu ditakuti. Assembly bukan rumit, melainkan panjang lebar. Untuk setiap hal yang dilakukan, load dan store, load dan store berulang tanpa henti
Jika ditambah sedikit macro dan pemeriksaan saat build, atau ditempatkan dalam konteks sistem Forth yang membungkus interpreter untuk “menjalankan gumpalan assembly” sehingga memungkinkan pengembangan interaktif dan scripting, jaraknya tidak terlalu jauh dari C, sekaligus menghilangkan sihir compiler
Saya juga menyarankan pendekatan retro. Mesin 8-bit di dalam emulator membatasi model kerja ke ranah yang kecil dan terdokumentasi baik, dan keterbatasannya membuat cara berpikir untuk melakukan lebih banyak pekerjaan dengan assembly menjadi bernilai. Pada arsitektur pasca-32-bit, ketika sumber daya melimpah, kasus seperti ini tidak umum
Orang yang mengembangkan assembly sebagai pekerjaan mungkin punya preferensi yang lebih spesifik, tetapi bagi pemula, yang paling dibutuhkan adalah lingkungan dengan dokumentasi dan contoh yang baik. Rosetta Code punya contoh assembly yang bagus untuk belajar
Saya ingat di kelas universitas kami pernah berkompetisi siapa yang bisa membuat program assembly paling cepat untuk tugas tertentu. Semua orang mencoba berbagai variasi loop unrolling untuk memeras performa terbaik dan menghindari branch prediction yang buruk
Saya tidak tahu apakah malam sebelum pengumpulan saya mencapai Ballmer Peak, tetapi saya mencoba konfigurasi yang dilewatkan sebagian besar orang lain dan menang tipis
Selain itu, ada juga kesenangan luar biasa saat melihat https://github.com/chrislgarry/Apollo-11 lalu bisa bercanda, “Ini sistem Unix, saya tahu ini!” Kekaguman karena bisa membaca bahasa yang membawa umat manusia ke bulan tidak pernah hilang
Jawaban singkatnya: ya
Momen ketika memahami bagaimana transistor, logic gate, arsitektur CPU, dan pemrograman tingkat tinggi saling terkait layak untuk usaha yang dikeluarkan, sekalipun secara profesional sama sekali tidak memakai assembly
Kadang-kadang berguna juga, tetapi kesenangan besarnya datang dari menempatkan byte terakhir tepat pada tempatnya, membongkar binary yang tidak pernah dilihat siapa pun selama puluhan tahun, atau membuat emulator yang dulu mustahil dibuat
Ini salah satu dari sedikit bidang yang masih terasa seperti sihir bagi saya, sama seperti saat pertama kali mulai
Secara pribadi, saya tidak melihat banyak nilai dalam menulis assembly langsung alih-alih memakai intrinsic, tetapi membaca assembly benar-benar membantu
Saya sering memakai Compiler Explorer(https://godbolt.org/) untuk melihat assembly yang dihasilkan, dan memahami optimisasi yang dilakukan compiler saat mengoptimalkan performa
“Tujuannya adalah mempercepat pemrosesan multimedia. Dengan menulis kode assembly, peningkatan kecepatan lebih dari 10 kali sangat umum terjadi, dan ini terutama penting ketika ingin memutar video secara real-time tanpa tersendat”
Senang melihat referensi K&R. Itu buku yang saya beli untuk belajar C dan pemrograman secara umum
Awalnya saya mencoba C++ sebagai bahasa pertama, tetapi terus penasaran apa yang terjadi di dalamnya, sehingga terasa terlalu abstrak dan sulit dipelajari
Materi ini pas sekali. Saya tahu assembly x86 dari era 386, tetapi pada prosesor yang lebih canggih, semuanya terlalu rumit
Saya ingin belajar lebih banyak tentang SIMD pada CPU modern, dan ini terlihat seperti materi yang bagus
Kalimat “perhatikan bahwa sufiks
qmengacu pada ukuran pointer *(*yaitu dalam C berarti *sizeof(*src) == 8 pada sistem 64-bit, dan x86asm cukup pintar untuk memakai 32-bit pada sistem 32-bit) tetapi load sebenarnya adalah 128-bit” membingungkanSepertinya
i.eseharusnya menjadii.e.,, dan apa maksud*(*? Bukankah itu seharusnya hanya tanda kurung buka?Saya juga tidak tahu dalam konteks apa
*sizeof(*src)bisa dianggap valid. Setahu sayasizeoftidak menghasilkan pointerRasanya ada tanda bintang acak yang tersebar di kalimat itu, atau ada upaya mencampur tanda bintang untuk italic dengan sintaks C tetapi hasilnya salah
Saya tidak peduli soal cara pembagiannya, saya hanya ingin mengatakan bahwa panduan ini benar-benar bagus
Dulu saat saya tertarik pada hal-hal yang sangat low-level, saya berharap ada materi seperti ini
Assembly dikatakan 10 kali lebih cepat daripada C? Pada suatu masa itu pasti benar, tetapi apakah masih begitu sekarang? Apakah compiler benar-benar mandek sampai tidak bisa mendekati assembly yang ditulis tangan?
Para pengembang FFmpeg terkenal agak keras menentang intrinsic, dan kalau ingatan saya benar, meski performanya sebaik assembly yang setara, mereka tetap tidak mengizinkannya di codebase. Namun, menurut perkiraan tulisan itu sendiri pun, perbedaan antara intrinsic dan assembly kira-kira hanya di kisaran 10–15%
Jika membandingkan assembly yang dioptimalkan dengan teliti dengan C yang naif, ketika vektorisasi memungkinkan tetapi compiler tidak memanfaatkannya, perbedaan 10 kali bisa terlihat. Ini cukup umum terjadi; auto-vectorization, di luar kasus-kasus sepele, sejauh ini masih umumnya kurang bagus
Namun tidak mengherankan jika kode yang ditulis ahli mengungguli kode naif
Lebih sederhananya, compiler C tidak bisa menyimpulkan, hanya dari implementasi C biasa, bahwa penulisnya ingin mengekspresikan matematika tertentu sebagai intrinsic SIMD yang lebih efisien. Sebab compiler tidak punya akses ke maksud matematis penulis
Ada juga pertimbangan per target. Compiler pada dasarnya adalah compiler serbaguna. Masalah resource, misalnya alokasi register, bersifat NP-complete dan setara dengan knapsack problem. Hampir tidak ada orang yang ingin compiler menghabiskan berjam-jam untuk mencari keluaran assembly yang benar-benar optimal. Apakah optimalitas itu bisa diketahui secara statis juga persoalan lain
Compiler memang pintar untuk kode umum, tetapi codec bukan kode umum. Saya bukan programmer FFmpeg, tetapi punya latar belakang menangani audio
Untuk masalah yang dapat menerapkan SIMD, cukup masuk akal mengharapkan percepatan sekitar 2 sampai 16 kali dibanding implementasi skalar yang naif
Saya sendiri tidak bisa menulis assembly yang 10 kali lebih baik daripada C, tetapi saya tidak akan berasumsi bahwa tidak ada orang yang bisa