2 poin oleh GN⁺ 2025-02-23 | 1 komentar | Bagikan ke WhatsApp
  • 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
    • Operasi ini adalah store
  • 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

 
GN⁺ 2025-02-23
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

    • Salah satu hal menarik dari dav1d adalah karena ditulis dalam assembly, ia bisa memakai calling convention-nya sendiri
      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
    • Saya juga berada di sisi wajib untuk misi, tetapi ada juga contoh tandingan yang menarik. Jika terlalu fokus pada detail kecil atau terjebak dalam kompleksitas insidental, optimasi algoritmik bisa menjadi kurang terlihat, dan jika ada terlalu banyak kode khusus platform sehingga friksi perubahan membesar, sulit untuk keluar dari local minimum
      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 penasaran apa yang Zig sediakan sebagai dukungan SIMD bawaan selain overload operasi aritmetika sepele. 90% kegunaan SIMD berada di luar operasi sederhana semacam itu
      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_size serta overload operator aritmetika untuk tipe yang “tervektorisasi” itu, dan masih ada jauh lebih banyak lagi. Bahkan intrinsic seperti _mm256_mul_ps sebenarnya 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
    • Tepat sekali. Di sisi sebaliknya, yaitu encoder, SIMD yang ditulis tangan juga sangat banyak dipakai karena alasan serupa
      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/

    • Kami juga melakukan sesuatu yang agak mirip. Untuk bagian-bagian terpisah yang sangat jarang, misalnya upload/download dan konversi gambar yang tidak didukung oleh driver GPU atau tidak cukup besar untuk meluncurkan pekerjaan GPU, awalnya kami menulisnya dalam C, lalu memakai anotasi compiler seperti alignment atau aliasing pointer yang diperbolehkan agar kode yang diinginkan bisa dihasilkan
      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
    • Sebagai contoh tandingan, saya secara rutin menemui kasus sepele yang tidak berhasil diauto-vectorize dengan baik oleh compiler: https://gcc.godbolt.org/z/rjEqzf1hh
      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
    • Masalahnya adalah kita harus memeriksa output compiler dan membandingkannya dengan ekspektasi. Mungkin perlu sedikit mengutak-atik sampai cocok dengan kode yang akan kita tulis sendiri
      Biasanya lebih cepat menulisnya sendiri saja
    • Berdasarkan pengalaman saya, auto-vectorization adalah optimisasi yang rapuh dan bisa gagal diam-diam dalam berbagai kondisi, jadi saya tidak ingin bergantung padanya
    • Saya tidak tahu cara membuat compiler menghasilkan pshufb yang lebih lebar dari 16 byte dalam kasus umum
      Bahkan untuk lebar 16 byte, jika memakai definisi sebenarnya dari pshufb, kita tidak mendapatkan pshufb; tetapi jika memakai versi yang memiliki undefined behavior, barulah pshufb keluar
  • Saya penulis kuliah ini
    Silakan tanya apa saja

    • Sebagai pengguna ARM Mac, saya penasaran: seberapa besar usaha yang diperlukan agar kode optimisasi seperti ini berperilaku sama di semua platform? Sepertinya perlu pengujian yang sangat menyeluruh dan algoritma pengganti
      Jika assembly sebanyak itu, rasanya seperti keajaiban FFmpeg bisa berjalan di Mac saya. Apakah semuanya dipindahkan secara manual?
    • Sebagai orang yang baru sebatas bisa membaca assembly, tetapi belum punya intuisi untuk memecah ide menjadi assembly lalu menuliskannya, saya punya pertanyaan. Apakah Anda bisa merekomendasikan cara untuk mempelajari atau meningkatkannya?
      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?
    • Saya penasaran bagaimana Anda melihat set instruksi SIMD dengan lebar variabel seperti ARM SVE atau ekstensi RISC-V V
      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?
    • Bagaimana FFmpeg menghasilkan tabel SEH untuk fungsi assembly di Windows? Saya penasaran apakah x86asm.inc yang menanganinya, atau memang tidak dipedulikan
    • Sebagai seseorang yang pada tahun 90-an secara profesional menulis kode optimisasi x86, apakah pada 2025 ini masih harus dilakukan secara manual?
      Tidak 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

    • Karena ingin belajar lebih jauh, saya mengerjakan 27 bab pertama tutorial ini dan sangat menikmatinya: https://mariokartwii.com/armv8/
      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
    • Mempelajari satu bahasa assembly saja sangat memuaskan. Karena itu membuat kita bersentuhan dengan bentuk pemrograman nyata yang paling primitif
      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
    • Salah satu hal menariknya adalah bahwa ini lebih tingkat tinggi daripada yang mungkin dibayangkan. Karena chip sebenarnya melakukan hal-hal seperti branch prediction dan pipelining, yang hanya bisa dikendalikan manusia sangat sedikit
      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
    • Mempelajari assembly punya makna mendalam bagi saya. Selama 30 tahun coding, saya tidak pernah benar-benar menggunakannya, tetapi itu melengkapi gambaran dari transistor hingga pemrograman tingkat tinggi
      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
    • Selama sekitar 25 tahun terakhir saya sangat mendalami assembly karena menyenangkan
      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

    • Pernyataan itu secara langsung bertentangan dengan isi tulisannya
      “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 q mengacu 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” membingungkan
    Sepertinya i.e seharusnya menjadi i.e.,, dan apa maksud *(*? Bukankah itu seharusnya hanya tanda kurung buka?
    Saya juga tidak tahu dalam konteks apa *sizeof(*src) bisa dianggap valid. Setahu saya sizeof tidak menghasilkan pointer
    Rasanya ada tanda bintang acak yang tersebar di kalimat itu, atau ada upaya mencampur tanda bintang untuk italic dengan sintaks C tetapi hasilnya salah

    • Benar. Sepertinya ada yang salah pada Markdown itu sendiri atau dalam proses mengonversi materi asli ke Markdown
    • Dua tanda bintang pertama tampaknya dipakai seperti pasangan catatan kaki
    • Bukankah itu mengembalikan ukuran pointer? Sepertinya hanya dipakai untuk menangani perbedaan arsitektur
  • 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?

    • C yang memakai intrinsic bisa sangat mendekati performa assembly murni
      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
    • Ini bukan soal compiler yang mandek. Compiler tidak mengetahui informasi yang dipakai penulis assembly dalam perancangan
      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
    • Ini tentang kode yang sangat tervektorisasi yang memakai semua hack yang mungkin untuk memanfaatkan CPU sepenuhnya
      Compiler memang pintar untuk kode umum, tetapi codec bukan kode umum. Saya bukan programmer FFmpeg, tetapi punya latar belakang menangani audio
    • Compiler C masih cukup buruk dalam auto-vectorization
      Untuk masalah yang dapat menerapkan SIMD, cukup masuk akal mengharapkan percepatan sekitar 2 sampai 16 kali dibanding implementasi skalar yang naif
    • Mungkin ada hal-hal yang sangat niche
      Saya sendiri tidak bisa menulis assembly yang 10 kali lebih baik daripada C, tetapi saya tidak akan berasumsi bahwa tidak ada orang yang bisa