Bagaimana mengukur kompleksitas dalam praktiknya dalam proyek perangkat lunak besar Anda?

11

Di universitas, di kursus algoritme kami, kami belajar cara menghitung dengan tepat kompleksitas berbagai algoritma sederhana yang digunakan dalam praktik, seperti tabel hash atau pengurutan cepat.

Tapi sekarang dalam proyek perangkat lunak besar, ketika kita ingin membuatnya lebih cepat, yang kita lakukan hanyalah melihat potongan-potongan individual - ada beberapa loop bersarang di sana yang dapat digantikan oleh tabel hash yang lebih cepat, pencarian lambat di sini yang dapat dipercepat oleh teknik yang lebih mewah - tetapi kami tidak pernah menghitung kompleksitas dari seluruh saluran pipa kami.

Apakah ada cara untuk melakukan itu? Atau apakah orang dalam praktik hanya mengandalkan "lokal" menggunakan algoritma cepat, untuk membuat keseluruhan aplikasi lebih cepat, daripada mempertimbangkan aplikasi secara global?

(Karena bagi saya nontrivial menunjukkan bahwa jika Anda menumpuk banyak algoritma yang dikenal sangat cepat sendiri, Anda juga berakhir dengan aplikasi cepat secara keseluruhan.)

Saya menanyakan hal ini, karena saya ditugaskan untuk mempercepat proyek besar yang telah ditulis oleh orang lain, di mana banyak algoritma berinteraksi dan bekerja pada data input, jadi tidak jelas bagi saya bagaimana dampak dari pembuatan algoritma tunggal lebih cepat pada seluruh aplikasi.

pengguna7088941
sumber
1) Ini membutuhkan pendekatan pengujian, untuk menemukan poin untuk ditingkatkan. Pengujian patok banding, Pengujian ketahanan, Pengujian dinamis (dengan memonitor metrik memori / CPU dari masing-masing komponen). 2) Setelah menemukan poin untuk ditingkatkan, Anda akan menemukan akar penyebab untuk poin-poin tersebut. 3) Temukan solusi untuk menyelesaikan akar permasalahan, dengan mempertahankan kebenaran.
overexchange
Anda memerlukan beberapa alat untuk tes ini yang disebutkan dalam poin 1
overexchange
1
Analisis O besar tidak memberi tahu Anda bagaimana suatu algoritma akan melakukan. Ini memberitahu Anda bagaimana kinerja akan skala , sebagai nmeningkat.
John Wu

Jawaban:

5

Proyek perangkat lunak besar terdiri dari banyak komponen yang berbeda, dan tidak semua dari mereka biasanya menjadi hambatan. Justru sebaliknya: untuk hampir semua program telah melihat dalam hidup saya di mana kinerja rendah adalah masalah, prinsip Pareto diterapkan: lebih dari 80% dari kenaikan kinerja dapat dicapai dengan mengoptimalkan kurang dari 20% dari kode (pada kenyataannya, saya pikir jumlahnya sering lebih dari 95% hingga 5%).

Jadi mulai melihat potongan-potongan individual seringkali merupakan pendekatan terbaik. Itulah sebabnya membuat profil (seperti dijelaskan dalam jawaban David Arno ) baik-baik saja, karena membantu Anda mengidentifikasi 5% kode yang disebutkan di mana pengoptimalan akan memberi Anda "pukulan terbesar untuk uang". Mengoptimalkan "seluruh aplikasi" mengandung risiko overengineering tertentu, dan jika Anda mengoptimalkan 95% itu bahkan dengan faktor 10, seringkali tidak akan memiliki efek yang dapat diukur. Perhatikan juga bahwa pembuatan profil memberi tahu Anda jauh lebih banyak daripada estimasi kompleksitas algoritma hipotetis mana pun, karena algoritme sederhana yang membutuhkan langkah O (N ^ 3) masih bisa lebih cepat daripada algoritme kompleks yang membutuhkan O (N log (N)) selama N cukup kecil.

Setelah profil mengungkapkan titik panas, orang dapat mengoptimalkannya. Tentu saja, "hot spot" bisa lebih besar dari hanya satu atau dua baris kode, kadang-kadang kita harus mengganti seluruh komponen untuk membuatnya lebih cepat, tetapi itu biasanya masih merupakan bagian kecil dari basis kode dalam program yang lebih besar .

Teknik optimisasi khas termasuk

  • meningkatkan penggunaan algoritma dan struktur data

  • fine tuning dari mantan

  • optimasi mikro di beberapa titik panas nyata

  • pengodean ulang bagian-bagian penting menggunakan kode rakitan atau CUDA

Perhatikan teknik ini bekerja pada berbagai tingkat abstraksi, beberapa dari mereka melihat komponen lebih "secara keseluruhan" daripada yang lain. Jadi itu tergantung pada apa yang Anda maksud dengan "semua yang kita lakukan adalah melihat setiap bagian" - jika Anda hanya memiliki optimasi mikro dalam pikiran, saya tidak setuju bahwa "kami" hanya bekerja pada itu. Tetapi jika Anda bermaksud menerapkan optimasi skala penuh pada bagian atau komponen yang terisolasi, daripada "kami" mungkin bekerja pada bagian yang tepat, dan Anda harus mempertanyakan harapan Anda.

Doc Brown
sumber
13

Cara standar, dicoba dan diuji adalah dengan membuat profil kode . Anda melakukan analisis dinamis dari sistem yang sedang berjalan untuk mengukur timing, penggunaan memori, dll. Kemudian menganalisis hasilnya untuk menemukan hambatan kinerja.

Kemacetan tersebut kemudian secara eksperimental ditulis ulang dan hasilnya diprofilkan sekali lagi untuk menentukan bahwa peningkatan kecepatan, pengurangan penggunaan memori, dll telah tercapai. Proses ini kemudian diulangi hingga perolehan kinerja yang dapat diterima tercapai.

David Arno
sumber
1
Ini menyelesaikan masalah kinerja, itulah sebabnya kami melakukannya, tetapi tidak menjawab pertanyaan awal. Saya pikir khususnya waktu terburuk atau kompleksitas ruang yang terbaik akan dipecahkan dengan menggunakan alat analisis program statis, yang mungkin hilang. Tes kinerja sangat bagus untuk skenario tertentu, tetapi mereka tidak memberi tahu Anda banyak tentang situasi terburuk yang mungkin terjadi.
Frank Hileman
3
@ FrankHileman Saya pikir intinya di sini adalah bahwa kinerja adalah masalah praktis dan hanya dapat diukur secara praktis. Anda tidak menggunakan matematika untuk menemukan hambatan perangkat lunak Anda, bahkan jika Anda mungkin menyelesaikannya setelah ditemukan menggunakan matematika (algoritma).
Wildcard
Pada catatan yang terkait, dalam presentasi tayangan slide waktu lama (kaca slide), ada seluruh teknologi berpura-pura tentang bagaimana dengan susah payah menghitung kepadatan rata-rata slide lentera secara matematis untuk menentukan kecerahan cahaya yang digunakan. Sama sekali tidak berguna: jika gambar tidak muncul dengan baik, Anda mendapatkan cahaya yang lebih terang!
Wildcard
@ Kartu Memori Sementara kinerja hanya dapat diukur pada waktu berjalan, namun dapat diprediksi secara statis. Pilihan struktur data yang buruk mungkin terlihat bagus, bijaksana kinerja, dalam tes kinerja, tetapi gagal total dalam kasus tepi yang dapat diprediksi dalam analisis statis. Ini adalah alasan yang sama kita melihat analisis kompleksitas kasus terburuk untuk struktur data secara umum.
Frank Hileman
@ Kartu Memori: Anda benar, namun Frank juga sangat benar bahwa posting ini tidak menjawab pertanyaan.
Doc Brown
3

Meskipun jawaban lainnya benar dan memberikan beberapa panduan, saya pikir mereka melewatkan satu langkah. Dalam sistem yang kompleks seperti yang sedang Anda kerjakan sekarang, memahami berbagai komponen yang membentuk sistem adalah kunci untuk memahami mengapa sesuatu berjalan lambat.

Langkah pertama saya adalah mendapatkan diagram arsitektur rinci atau membuat sendiri. Cari tahu langkah apa yang diambil oleh komponen apa dalam perangkat lunak dan berapa lama setiap langkah.

Juga, cari tahu bagaimana komponen berinteraksi satu sama lain. Ini dapat membuat semua perbedaan.

Sebagai contoh, saya telah melihat kode dalam C # di mana antarmuka antara dua komponen melewati sebuah IEnumerable yang dibangun oleh komponen pertama, yang kemudian disebutkan oleh komponen kedua. Dalam C # ini membutuhkan pengalihan konteks, yang dapat mahal dalam keadaan tertentu. Memecahkannya tidak berdampak pada algoritma. .ToList () yang sederhana pastikan hasilnya dikumpulkan sebelum langkah selanjutnya menyelesaikan masalah ini.

Hal lain yang perlu dipertimbangkan adalah dampak pada sistem Anda menjalankan kode. Interaksi perangkat keras jelas dapat menjadi faktor dalam sistem yang kompleks. Cari IO Disk, alokasi memori besar, dan IO jaringan. Kadang-kadang ini dapat diselesaikan lebih efisien dengan mengutak-atik sistem atau bahkan mengganti perangkat keras.

Jonathan van de Veen
sumber