Kadang-kadang ada 1% kode yang cukup intensif secara komputasi yang membutuhkan jenis optimasi tingkat rendah terberat. Contohnya adalah pemrosesan video, pemrosesan gambar, dan semua jenis pemrosesan sinyal, secara umum.
Tujuannya adalah untuk mendokumentasikan, dan mengajarkan teknik pengoptimalan, sehingga kode tidak menjadi tidak dapat dipelihara dan cenderung dihapus oleh pengembang yang lebih baru. (*)
(*) Meskipun ada kemungkinan bahwa optimasi tertentu sama sekali tidak berguna di beberapa CPU mendatang yang tidak terduga, sehingga kode tersebut tetap akan dihapus.
Mempertimbangkan bahwa penawaran perangkat lunak (komersial atau open-source) mempertahankan keunggulan kompetitif mereka dengan memiliki kode tercepat dan memanfaatkan arsitektur CPU terbaru, penulis perangkat lunak sering perlu mengubah kode mereka untuk membuatnya berjalan lebih cepat sambil mendapatkan output yang sama untuk suatu produk tertentu. tugas, daftar putih mentolerir sejumlah kecil kesalahan pembulatan.
Biasanya, seorang penulis perangkat lunak dapat menyimpan banyak versi fungsi sebagai dokumentasi dari setiap optimasi / algoritma penulisan ulang yang terjadi. Bagaimana cara membuat versi ini tersedia bagi orang lain untuk mempelajari teknik optimasi mereka?
Terkait:
Jawaban:
Jawaban singkat
Buat optimisasi tetap lokal, jelaskan, dokumentasikan dengan baik, dan buat mudah untuk membandingkan versi yang dioptimalkan satu sama lain dan dengan versi yang tidak dioptimalkan, baik dalam hal kode sumber dan kinerja run-time.
Jawaban penuh
Jika optimisasi seperti itu benar - benar penting bagi produk Anda, maka Anda perlu tahu tidak hanya mengapa optimisasi bermanfaat sebelumnya, tetapi juga memberikan informasi yang cukup untuk membantu pengembang mengetahui apakah mereka akan berguna di masa depan.
Idealnya, Anda perlu mengabadikan pengujian kinerja ke dalam proses pembuatan Anda, sehingga Anda mengetahui kapan teknologi baru membatalkan optimisasi lama.
Ingat:
Untuk mengetahui apakah sekarang saatnya membutuhkan benchmarking dan pengujian.
Seperti yang Anda sebutkan, masalah terbesar dengan kode yang sangat optimal adalah sulitnya mempertahankannya, sejauh mungkin, Anda perlu menjaga bagian yang dioptimalkan terpisah dari bagian yang tidak dioptimalkan. Apakah Anda melakukan ini melalui menghubungkan waktu kompilasi, panggilan fungsi virtual runtime atau sesuatu di antaranya tidak masalah. Yang penting adalah bahwa ketika Anda menjalankan tes Anda, Anda ingin dapat menguji terhadap semua versi yang saat ini Anda minati.
Saya akan cenderung untuk membangun suatu sistem sedemikian rupa sehingga versi dasar kode produksi yang tidak dioptimalkan dapat selalu digunakan untuk memahami maksud dari kode tersebut, kemudian membangun berbagai modul yang dioptimalkan bersama dengan ini berisi versi atau versi yang dioptimalkan, secara eksplisit mendokumentasikan di mana pun versi yang dioptimalkan berbeda dari garis dasar. Ketika Anda menjalankan tes (unit dan integrasi), Anda menjalankannya pada versi yang tidak dioptimalkan dan pada semua modul yang dioptimalkan saat ini.
Contoh
Misalnya, katakanlah Anda memiliki fungsi Fast Fourier Transform . Mungkin Anda memiliki dasar, implementasi algoritmik,
fft.c
dan pengujianfft_tests.c
.Kemudian datanglah Pentium dan Anda memutuskan untuk mengimplementasikan versi titik tetap dalam
fft_mmx.c
menggunakan instruksi MMX . Kemudian pentium 3 datang dan Anda memutuskan untuk menambahkan versi yang menggunakan Streaming SIMD Extensions difft_sse.c
.Sekarang Anda ingin menambahkan CUDA , jadi Anda menambahkan
fft_cuda.c
, tetapi temukan bahwa dengan dataset uji yang telah Anda gunakan selama bertahun-tahun, versi CUDA lebih lambat daripada versi SSE! Anda melakukan beberapa analisis dan akhirnya menambahkan dataset yang 100 kali lebih besar dan Anda mendapatkan kecepatan yang Anda harapkan, tetapi sekarang Anda tahu bahwa waktu pengaturan untuk menggunakan versi CUDA adalah signifikan dan dengan dataset kecil Anda harus menggunakan algoritma tanpa biaya pengaturan itu.Dalam setiap kasus Anda menerapkan algoritma yang sama, semua harus berperilaku dengan cara yang sama, tetapi akan berjalan dengan efisiensi dan kecepatan yang berbeda pada arsitektur yang berbeda (jika mereka akan berjalan sama sekali). Dari sudut pandang kode, Anda dapat membandingkan setiap pasangan file sumber untuk mencari tahu mengapa antarmuka yang sama diimplementasikan dalam cara yang berbeda dan biasanya, cara termudah adalah merujuk kembali ke versi asli yang tidak dioptimalkan.
Semua hal yang sama berlaku untuk implementasi OOP di mana kelas dasar yang mengimplementasikan algoritma yang tidak dioptimalkan, dan kelas turunan menerapkan optimisasi yang berbeda.
Yang penting adalah menjaga hal-hal yang sama yang sama , sehingga perbedaannya jelas .
sumber
Khususnya karena Anda telah mengambil contoh pemrosesan Video dan Gambar seseorang dapat menyimpan kode sebagai bagian dari versi yang sama tetapi aktif atau tidak aktif tergantung pada konteksnya.
Meskipun Anda belum menyebutkan, saya berasumsi di
C
sini.Cara paling sederhana dalam
C
kode, kita melakukan optimasi (dan juga berlaku ketika mencoba membuat hal-hal portabel) adalah untuk tetapKetika Anda mengaktifkan
#define OPTIMIZATION_XYZ_ENABLE
selama kompilasi di Makefile, semuanya berjalan sesuai.Biasanya, memotong beberapa baris kode di tengah fungsi bisa menjadi berantakan ketika ada terlalu banyak fungsi yang dioptimalkan. Oleh karena itu, dalam hal ini seseorang mendefinisikan pointer fungsi yang berbeda untuk melakukan fungsi tertentu.
kode utama selalu dijalankan melalui fungsi pointer seperti
Tetapi pointer fungsi ditentukan tergantung pada jenis contoh (misalnya di sini fungsi idct dioptimalkan untuk arsitektur CPU yang berbeda.
Anda akan melihat kode libjpeg dan kode libmpeg2 dan mungkin ffmpeg untuk teknik seperti itu.
sumber
Sebagai seorang peneliti saya akhirnya menulis sedikit kode "bottleneck". Namun, begitu dimasukkan ke dalam produksi, tanggung jawab untuk mengintegrasikannya ke dalam produk dan memberikan dukungan berikutnya jatuh ke pengembang. Seperti yang dapat Anda bayangkan, mengomunikasikan dengan jelas apa dan bagaimana program seharusnya beroperasi adalah yang paling penting.
Saya telah menemukan bahwa ada tiga bahan penting dalam menyelesaikan langkah ini dengan sukses
Untuk langkah pertama, saya selalu menulis whitepaper pendek yang mendokumentasikan algoritma. Tujuannya di sini adalah untuk benar-benar menulisnya sehingga orang lain dapat menerapkannya dari awal hanya dengan menggunakan kertas putih. Jika itu adalah algoritma yang terkenal dan dipublikasikan, itu cukup untuk memberikan referensi dan mengulangi persamaan kunci. Jika ini adalah karya asli, Anda harus sedikit lebih eksplisit. Ini akan memberi tahu Anda apa yang seharusnya dilakukan kode .
Implementasi aktual yang diserahkan ke pengembangan harus didokumentasikan sedemikian rupa sehingga semua seluk-beluk diberikan secara eksplisit. Jika Anda mendapatkan kunci dalam urutan tertentu untuk menghindari kebuntuan, tambahkan komentar. Jika Anda beralih pada kolom alih-alih pada baris matriks karena masalah koherensi cache, tambahkan komentar. Jika Anda melakukan sesuatu yang sedikit pintar, komentari itu. Jika Anda dapat menjamin whitepaper dan kode tidak akan pernah dipisahkan (melalui VCS atau sistem serupa), Anda dapat merujuk kembali ke whitepaper. Hasilnya dengan mudah dapat lebih dari 50% komentar. Itu benar. Ini akan memberi tahu Anda mengapa kode melakukan apa yang dilakukannya.
Akhirnya, Anda harus bisa menjamin kebenaran dalam menghadapi perubahan. Untungnya kami alat yang berguna dalam pengujian otomatis dan platform integrasi berkelanjutan . Ini akan memberi tahu Anda apa yang sebenarnya dilakukan kode .
Rekomendasi saya yang paling tulus adalah jangan berhemat pada salah satu langkah. Anda akan membutuhkannya nanti;)
sumber
Saya percaya ini akan diselesaikan dengan baik melalui komentar komprehensif kode, ke titik di mana setiap blok kode signifikan memiliki komentar penjelas sebelumnya.
Komentar harus mencakup kutipan untuk spesifikasi atau bahan referensi perangkat keras.
Gunakan istilah-istilah industri dan algoritma luas yang sesuai - misalnya 'arsitektur X menghasilkan jebakan CPU untuk pembacaan yang tidak selaras, sehingga Perangkat Duff ini memenuhi batas penyelarasan berikutnya'.
Saya akan menggunakan penamaan variabel in-your-face untuk memastikan tidak ada kesalahpahaman tentang apa yang terjadi. Bukan Hongaria, tetapi hal-hal seperti 'langkah' untuk menggambarkan jarak dalam byte antara dua piksel vertikal.
Saya juga akan melengkapi ini dengan dokumen pendek yang dapat dibaca secara manusiawi yang memiliki diagram dan desain blok tingkat tinggi.
sumber