OK, Anda mendefinisikan masalah di mana tampaknya tidak ada banyak ruang untuk perbaikan. Itu cukup langka, menurut pengalaman saya. Saya mencoba menjelaskan ini dalam artikel Dr. Dobbs pada bulan November 1993, dengan memulai dari program non-sepele yang dirancang secara konvensional tanpa limbah yang jelas dan membawanya melalui serangkaian optimisasi hingga waktu jam dinding berkurang dari 48 detik. menjadi 1,1 detik, dan ukuran kode sumber dikurangi dengan faktor 4. Alat diagnostik saya adalah ini . Urutan perubahan adalah ini:
Masalah pertama yang ditemukan adalah penggunaan daftar cluster (sekarang disebut "iterators" dan "kelas kontainer") terhitung lebih dari separuh waktu. Itu diganti dengan kode yang cukup sederhana, membawa waktu ke 20 detik.
Sekarang pengambil waktu terbesar lebih banyak membangun daftar. Sebagai persentase, sebelumnya tidak terlalu besar, tetapi sekarang karena masalah yang lebih besar telah dihapus. Saya menemukan cara untuk mempercepatnya, dan waktu turun menjadi 17 detik.
Sekarang lebih sulit untuk menemukan penyebab yang jelas, tetapi ada beberapa yang lebih kecil yang dapat saya lakukan sesuatu, dan waktu turun menjadi 13 detik.
Sekarang saya sepertinya telah menabrak tembok. Sampel memberi tahu saya persis apa yang dilakukannya, tetapi saya tidak dapat menemukan apa pun yang dapat saya perbaiki. Kemudian saya merenungkan desain dasar program, pada struktur yang didorong transaksi, dan bertanya apakah semua pencarian daftar yang dilakukannya benar-benar diamanatkan oleh persyaratan masalah.
Kemudian saya menemukan desain ulang, di mana kode program sebenarnya dihasilkan (melalui macro preprocessor) dari satu set sumber yang lebih kecil, dan di mana program tidak terus-menerus mencari tahu hal-hal yang diketahui oleh pemrogram cukup dapat diprediksi. Dengan kata lain, jangan "menafsirkan" urutan hal yang harus dilakukan, "kompilasi".
- Perancangan ulang itu dilakukan, mengecilkan kode sumber dengan faktor 4, dan waktu dikurangi menjadi 10 detik.
Sekarang, karena semakin cepat, sulit untuk dicoba, jadi saya berikan 10 kali lebih banyak pekerjaan yang harus dilakukan, tetapi waktu berikut ini didasarkan pada beban kerja asli.
Lebih banyak diagnosis mengungkapkan bahwa ia menghabiskan waktu dalam manajemen antrian. Sejalan ini mengurangi waktu hingga 7 detik.
Sekarang pengambil waktu yang besar adalah pencetakan diagnostik yang telah saya lakukan. Siram itu - 4 detik.
Sekarang pencatat waktu terbesar adalah panggilan ke malloc dan gratis . Mendaur ulang objek - 2,6 detik.
Melanjutkan ke sampel, saya masih menemukan operasi yang tidak sepenuhnya diperlukan - 1,1 detik.
Total faktor percepatan: 43.6
Sekarang tidak ada dua program yang sama, tetapi dalam perangkat lunak non-mainan saya selalu melihat perkembangan seperti ini. Pertama Anda mendapatkan hal-hal yang mudah, dan kemudian yang lebih sulit, sampai Anda mencapai titik pengembalian yang semakin berkurang. Kemudian wawasan yang Anda peroleh mungkin mengarah pada desain ulang, memulai putaran baru percepatan, hingga Anda kembali mendapatkan hasil yang semakin berkurang. Sekarang ini adalah titik di mana ia mungkin masuk akal untuk bertanya-tanya apakah ++i
atau i++
atau for(;;)
atau while(1)
lebih cepat: jenis pertanyaan saya melihat begitu sering di Stack Overflow.
PS Mungkin bertanya-tanya mengapa saya tidak menggunakan profiler. Jawabannya adalah bahwa hampir setiap "masalah" ini adalah situs panggilan fungsi, yang menumpuk sampel dengan tepat. Profiler, bahkan hari ini, hampir tidak menyangkal bahwa pernyataan dan instruksi panggilan lebih penting untuk ditemukan, dan lebih mudah diperbaiki, daripada seluruh fungsi.
Saya benar-benar membangun profiler untuk melakukan ini, tetapi untuk keintiman nyata turun-dan-kotor dengan apa yang dilakukan kode, tidak ada pengganti untuk mendapatkan jari Anda tepat di dalamnya. Bukan masalah bahwa jumlah sampel kecil, karena tidak ada masalah yang ditemukan sangat kecil sehingga mereka mudah terjawab.
TAMBAH: jerryjvl meminta beberapa contoh. Inilah masalah pertama. Ini terdiri dari sejumlah kecil baris kode terpisah, bersama-sama mengambil alih separuh waktu:
/* IF ALL TASKS DONE, SEND ITC_ACKOP, AND DELETE OP */
if (ptop->current_task >= ILST_LENGTH(ptop->tasklist){
. . .
/* FOR EACH OPERATION REQUEST */
for ( ptop = ILST_FIRST(oplist); ptop != NULL; ptop = ILST_NEXT(oplist, ptop)){
. . .
/* GET CURRENT TASK */
ptask = ILST_NTH(ptop->tasklist, ptop->current_task)
Ini menggunakan daftar cluster ILST (mirip dengan kelas daftar). Mereka diimplementasikan dengan cara biasa, dengan "menyembunyikan informasi" yang berarti bahwa pengguna kelas tidak harus peduli bagaimana mereka diimplementasikan. Ketika baris-baris ini ditulis (dari sekitar 800 baris kode) pemikiran tidak diberikan pada gagasan bahwa ini bisa menjadi "bottleneck" (Saya benci kata itu). Mereka hanyalah cara yang disarankan untuk melakukan sesuatu. Mudah untuk mengatakan di belakang bahwa ini harus dihindari, tetapi dalam pengalaman saya semua masalah kinerja seperti itu. Secara umum, ada baiknya mencoba menghindari menciptakan masalah kinerja. Bahkan lebih baik untuk menemukan dan memperbaiki yang dibuat, meskipun mereka "seharusnya dihindari" (di belakang).
Inilah masalah kedua, dalam dua baris terpisah:
/* ADD TASK TO TASK LIST */
ILST_APPEND(ptop->tasklist, ptask)
. . .
/* ADD TRANSACTION TO TRANSACTION QUEUE */
ILST_APPEND(trnque, ptrn)
Ini adalah daftar bangunan dengan menambahkan item ke ujungnya. (Cara mengatasinya adalah mengumpulkan item dalam array, dan membuat daftar sekaligus.) Yang menarik adalah bahwa pernyataan ini hanya berharga (mis. Ada di tumpukan panggilan) 3/48 dari waktu asli, jadi mereka tidak ada dalam Bahkan masalah besar di awal . Namun, setelah menghilangkan masalah pertama, harganya 3/20 dari waktu dan sekarang menjadi "ikan yang lebih besar". Secara umum, begitulah caranya.
Saya dapat menambahkan bahwa proyek ini disuling dari proyek nyata yang saya bantu. Dalam proyek itu, masalah kinerja jauh lebih dramatis (seperti halnya speedup), seperti memanggil rutin akses database dalam loop batin untuk melihat apakah tugas selesai.
REFERENSI DITAMBAH: Kode sumber, baik yang asli maupun yang dirancang ulang, dapat ditemukan di www.ddj.com , untuk tahun 1993, dalam file 9311.zip, file slug.asc dan slug.zip.
EDIT 2011/11/26: Sekarang ada proyek SourceForge yang berisi kode sumber dalam Visual C ++ dan deskripsi blow-by-blow tentang bagaimana itu disetel. Itu hanya melewati paruh pertama skenario yang dijelaskan di atas, dan tidak mengikuti urutan yang persis sama, tetapi masih mendapat urutan 2-3 percepatan magnitudo.
Saran:
Kelemahan : jika beberapa nilai pra-komputasi benar-benar digunakan, hal ini dapat memperburuk keadaan, juga pencarian dapat mengambil memori yang signifikan.
Kelemahan : menulis kode tambahan berarti lebih banyak area permukaan untuk bug.
Kelemahan : Ya ... jawabannya tidak tepat.
sumber
Ketika Anda tidak dapat meningkatkan kinerja lagi - lihat apakah Anda dapat meningkatkan kinerja yang dirasakan sebagai gantinya.
Anda mungkin tidak dapat membuat algoritma fooCalc Anda lebih cepat, tetapi seringkali ada cara untuk membuat aplikasi Anda tampak lebih responsif terhadap pengguna.
Beberapa contoh:
Ini tidak akan membuat program Anda lebih cepat, tetapi mungkin membuat pengguna Anda lebih bahagia dengan kecepatan yang Anda miliki.
sumber
Saya menghabiskan sebagian besar hidup saya di tempat ini saja. Langkah luasnya adalah menjalankan profiler Anda dan merekamnya:
__restrict
secara bebas untuk menjanjikan kompilator tentang aliasing.Dan satu hal lagi yang ingin saya lakukan:
sumber
Examples on the PowerPC ...
<- Yaitu, beberapa implementasi PowerPC. PowerPC adalah ISA, bukan CPU.lea
.Lempar lebih banyak perangkat keras padanya!
sumber
Lebih banyak saran:
Hindari I / O : I / O apa pun (disk, jaringan, port, dll.) Akan selalu jauh lebih lambat daripada kode apa pun yang melakukan perhitungan, jadi singkirkan I / O yang tidak Anda perlukan secara ketat.
Pindahkan I / O di muka : Muat semua data yang Anda perlukan untuk perhitungan di muka, sehingga Anda tidak perlu mengulangi I / O dalam inti dari algoritma kritis (dan mungkin akibatnya diulang disk mencari, ketika memuat semua data dalam satu pukulan dapat menghindari pencarian).
Keterlambatan I / O : Jangan menuliskan hasil Anda sampai perhitungan selesai, simpan hasilnya dalam struktur data dan kemudian buang hasilnya dalam sekali jalan saat kerja keras selesai.
I / O Berulir : Untuk yang cukup berani, gabungkan 'I / O di muka' atau 'Tunda I / O' dengan perhitungan aktual dengan memindahkan pemuatan ke thread paralel, sehingga saat Anda memuat lebih banyak data, Anda dapat bekerja pada perhitungan pada data yang sudah Anda miliki, atau saat Anda menghitung kumpulan data berikutnya Anda dapat secara bersamaan menuliskan hasil dari kumpulan terakhir.
sumber
mmap()
untuk input, lakukanmadvise()
panggilan yang sesuai dan gunakanaio_write()
untuk menulis potongan besar output (= beberapa MiB).Karena banyak masalah kinerja melibatkan masalah basis data, saya akan memberi Anda beberapa hal spesifik untuk dilihat ketika menyetel kueri dan prosedur tersimpan.
Hindari kursor di sebagian besar basis data. Hindari perulangan juga. Sebagian besar waktu, akses data harus berbasis set, bukan catatan dengan pemrosesan catatan. Ini termasuk tidak menggunakan kembali prosedur penyimpanan rekaman tunggal ketika Anda ingin memasukkan 1.000.000 catatan sekaligus.
Jangan pernah menggunakan pilih *, hanya mengembalikan bidang yang sebenarnya Anda butuhkan. Ini terutama benar jika ada gabungan karena bidang gabungan akan diulang dan dengan demikian menyebabkan beban yang tidak perlu pada server dan jaringan.
Hindari penggunaan subquery yang berhubungan. Gunakan gabungan (termasuk gabungan ke tabel turunan jika memungkinkan) (Saya tahu ini benar untuk Microsoft SQL Server, tetapi uji saran saat menggunakan backend differnt).
Indeks, indeks, indeks. Dan perbarui statistik tersebut jika berlaku untuk basis data Anda.
Buat kueri menjadi lebih murah . Berarti menghindari hal-hal yang membuat tidak mungkin untuk menggunakan indeks seperti menggunakan wildcard dalam karakter pertama klausa suka atau fungsi dalam bergabung atau sebagai bagian kiri pernyataan di mana.
Gunakan tipe data yang benar. Lebih cepat melakukan matematika tanggal pada bidang tanggal daripada harus mencoba mengubah string tipe data ke tipe tanggal, kemudian melakukan perhitungan.
Jangan sekali-kali membuat loop apa pun menjadi pemicu!
Sebagian besar database memiliki cara untuk memeriksa bagaimana eksekusi permintaan akan dilakukan. Dalam Microsoft SQL Server ini disebut rencana eksekusi. Periksa yang pertama untuk melihat di mana letak masalah.
Pertimbangkan seberapa sering kueri berjalan serta berapa lama untuk menjalankan saat menentukan apa yang perlu dioptimalkan. Kadang-kadang Anda bisa mendapatkan lebih banyak kinerja dari sedikit tweak ke kueri yang berjalan jutaan kali sehari daripada Anda bisa menghapus waktu dari permintaan long_running yang hanya berjalan sebulan sekali.
Gunakan semacam alat profiler untuk mengetahui apa yang sebenarnya dikirim ke dan dari database. Saya dapat mengingat suatu saat di masa lalu di mana kami tidak dapat mengetahui mengapa halaman tersebut sangat lambat dimuat ketika prosedur yang tersimpan cepat dan menemukan melalui profil bahwa halaman web meminta permintaan berkali-kali alih-alih sekali.
Profiler juga akan membantu Anda menemukan siapa yang memblokir siapa. Beberapa kueri yang dijalankan dengan cepat saat berjalan sendiri mungkin menjadi sangat lambat karena kunci dari kueri lain.
sumber
Satu-satunya faktor pembatas terpenting saat ini adalah keterbatasan memori bandwitdh . Multicores hanya memperburuk ini, karena bandwidth dibagi antara core. Selain itu, area chip terbatas yang ditujukan untuk mengimplementasikan cache juga dibagi di antara inti dan utas, semakin memperburuk masalah ini. Akhirnya, pensinyalan antar-chip yang diperlukan untuk menjaga agar cache berbeda tetap koheren juga meningkat dengan peningkatan jumlah core. Ini juga menambah penalti.
Ini adalah efek yang perlu Anda kelola. Terkadang melalui pengelolaan mikro kode Anda, tetapi kadang-kadang melalui pertimbangan dan refactoring yang cermat.
Banyak komentar yang menyebutkan kode ramah cache. Setidaknya ada dua rasa berbeda dari ini:
Masalah pertama secara khusus berkaitan dengan membuat pola akses data Anda lebih teratur, memungkinkan prefetcher perangkat keras untuk bekerja secara efisien. Hindari alokasi memori dinamis yang menyebarkan objek data Anda di dalam memori. Gunakan wadah linier alih-alih daftar terkait, hash, dan pohon.
Masalah kedua berkaitan dengan meningkatkan penggunaan kembali data. Ubah algoritma Anda untuk bekerja pada himpunan bagian dari data Anda yang cocok dengan cache yang tersedia, dan gunakan kembali data itu sebanyak mungkin saat masih dalam cache.
Pengepakan data lebih ketat dan memastikan Anda menggunakan semua data dalam garis cache di loop panas, akan membantu menghindari efek lain ini, dan memungkinkan pemasangan data yang lebih berguna dalam cache.
sumber
sumber
Meskipun saya menyukai jawaban Mike Dunlavey, sebenarnya itu adalah jawaban yang bagus dengan contoh yang mendukung, saya pikir itu bisa diungkapkan dengan sangat sederhana sebagai berikut:
Cari tahu apa yang membutuhkan jumlah waktu terbesar pertama, dan pahami alasannya.
Ini adalah proses identifikasi babi waktu yang membantu Anda memahami di mana Anda harus memperbaiki algoritma Anda. Ini adalah satu-satunya jawaban agnostik bahasa yang mencakup semua yang dapat saya temukan untuk masalah yang sudah seharusnya dioptimalkan sepenuhnya. Juga anggap Anda ingin arsitektur independen dalam pencarian Anda untuk kecepatan.
Jadi, sementara algoritme mungkin dioptimalkan, implementasinya mungkin tidak. Identifikasi memungkinkan Anda untuk mengetahui bagian mana: algoritma atau implementasi. Jadi, siapa pun yang paling banyak menghabiskan waktu adalah kandidat utama Anda untuk ditinjau. Tetapi karena Anda mengatakan Anda ingin memeras beberapa% terakhir, Anda mungkin ingin juga memeriksa bagian yang lebih rendah, bagian yang Anda belum memeriksanya sedekat itu pada awalnya.
Terakhir sedikit coba-coba dengan angka kinerja tentang cara berbeda untuk mengimplementasikan solusi yang sama, atau algoritma yang berpotensi berbeda, dapat membawa wawasan yang membantu mengidentifikasi pemboros waktu dan penghemat waktu.
HPH, silakan pindahkan.
sumber
Anda mungkin harus mempertimbangkan "perspektif Google", yaitu menentukan bagaimana aplikasi Anda dapat menjadi sebagian besar diparalelkan dan bersamaan, yang pada akhirnya juga akan berarti untuk mendistribusikan aplikasi Anda di berbagai mesin dan jaringan yang berbeda, sehingga idealnya dapat skala hampir linier dengan perangkat keras yang Anda lemparkan padanya.
Di sisi lain, orang-orang Google juga dikenal karena melemparkan banyak tenaga kerja dan sumber daya untuk menyelesaikan beberapa masalah dalam proyek, alat dan infrastruktur yang mereka gunakan, seperti misalnya seluruh optimasi program untuk gcc dengan memiliki tim insinyur yang berdedikasi meretas internal gcc untuk mempersiapkannya untuk skenario kasus penggunaan khas Google.
Demikian pula, membuat profil suatu aplikasi tidak lagi hanya sekadar membuat profil kode program, tetapi juga semua sistem dan infrastruktur di sekitarnya (bayangkan jaringan, switch, server, array RAID) untuk mengidentifikasi redudansi dan potensi optimisasi dari sudut pandang sistem.
sumber
sumber
sumber
Memecah dan menaklukkan
Jika dataset yang sedang diproses terlalu besar, lakukan perulangan. Jika Anda telah melakukan kode dengan benar, implementasi harus mudah. Jika Anda memiliki program monolitik, sekarang Anda tahu lebih baik.
sumber
Pertama-tama, seperti disebutkan dalam beberapa jawaban sebelumnya, pelajari apa yang menggigit kinerja Anda - apakah itu memori atau prosesor atau jaringan atau database atau sesuatu yang lain. Tergantung pada ...
... jika itu ingatan - temukan salah satu buku yang sudah lama ditulis oleh Knuth, salah satu seri "The Art of Computer Programming". Kemungkinan besar ini tentang penyortiran dan pencarian - jika ingatan saya salah maka Anda harus mencari tahu di mana ia berbicara tentang cara menangani penyimpanan data pita lambat. Mentransformasi pasangan memori / tape secara mental menjadi pasangan cache / memori utama (atau pasangan cache L1 / L2) secara berurutan. Pelajari semua trik yang ia jelaskan - jika Anda tidak menemukan sesuatu yang menyelesaikan masalah Anda, maka sewalah ilmuwan komputer profesional untuk melakukan penelitian profesional. Jika masalah memori Anda adalah kebetulan dengan FFT (cache meleset pada indeks bit-reversed ketika melakukan kupu-kupu radix-2) maka jangan mempekerjakan seorang ilmuwan - sebagai gantinya, optimalkan secara manual melewati satu-per-satu sampai Anda apakah menang atau menemui jalan buntu. Anda menyebutkanmemeras hingga beberapa persen terakhir kan? Jika sedikit, Anda kemungkinan besar akan menang.
... jika prosesor - beralih ke bahasa assembly. Mempelajari spesifikasi prosesor - apa yang perlu kutu , VLIW, SIMD. Panggilan fungsi kemungkinan besar adalah tick-eaters yang dapat diganti. Pelajari transformasi loop - saluran pipa, buka gulungannya. Penggandaan dan pembagian mungkin bisa diganti / diinterpolasi dengan pergeseran bit (dikalikan dengan bilangan bulat kecil mungkin bisa diganti dengan penambahan). Cobalah trik dengan data yang lebih pendek - jika Anda beruntung satu instruksi dengan 64 bit mungkin berubah tergantikan dengan dua pada 32 atau bahkan 4 pada 16 atau 8 pada 8 bit. Coba juga lebih lamadata - mis. perhitungan float Anda mungkin menjadi lebih lambat daripada yang dua kali lipat pada prosesor tertentu. Jika Anda memiliki barang trigonometri, lawanlah dengan tabel yang sudah dihitung sebelumnya; juga perlu diingat bahwa nilai sinus yang kecil dapat diganti dengan nilai tersebut jika kehilangan presisi berada dalam batas yang diizinkan.
... jika itu jaringan - pikirkan untuk mengompresi data yang Anda lewati. Ganti transfer XML dengan biner. Protokol penelitian. Coba UDP alih-alih TCP jika Anda entah bagaimana dapat menangani kehilangan data.
... jika itu adalah basis data, pergilah ke forum basis data mana saja dan mintalah saran. Kotak data dalam memori, mengoptimalkan rencana permintaan, dll. Dll.
HTH :)
sumber
Caching! Cara murah (dalam upaya programmer) untuk membuat hampir semua hal lebih cepat adalah dengan menambahkan lapisan abstraksi caching ke area pergerakan data program Anda. Baik itu I / O atau hanya lewat / kreasi objek atau struktur. Seringkali mudah untuk menambahkan cache ke kelas pabrik dan pembaca / penulis.
Terkadang cache tidak akan banyak membantu Anda, tetapi ini adalah metode yang mudah untuk menambahkan semua caching dan menonaktifkannya di tempat yang tidak membantu. Saya sering menemukan ini untuk mendapatkan kinerja besar tanpa harus menganalisa kode secara mikro.
sumber
Saya pikir ini sudah dikatakan dengan cara yang berbeda. Tetapi ketika Anda berurusan dengan algoritma intensif prosesor, Anda harus menyederhanakan segala sesuatu di dalam loop paling dalam dengan mengorbankan yang lainnya.
Itu mungkin tampak jelas bagi sebagian orang, tetapi itu adalah sesuatu yang saya coba fokuskan terlepas dari bahasa yang saya gunakan. Jika Anda berurusan dengan loop bersarang, misalnya, dan Anda menemukan peluang untuk menurunkan beberapa kode, Anda dalam beberapa kasus dapat secara drastis mempercepat kode Anda. Sebagai contoh lain, ada beberapa hal kecil yang perlu dipikirkan seperti bekerja dengan integer alih-alih variabel floating point kapan pun Anda bisa, dan menggunakan perkalian alih-alih pembagian kapan pun Anda bisa. Sekali lagi, ini adalah hal-hal yang harus dipertimbangkan untuk loop paling dalam Anda.
Kadang-kadang Anda mungkin menemukan manfaat melakukan operasi matematika Anda pada bilangan bulat di dalam lingkaran dalam, dan kemudian turunkan ke variabel floating point yang dapat Anda kerjakan setelahnya. Itu adalah contoh pengorbanan kecepatan di satu bagian untuk meningkatkan kecepatan di bagian lain, tetapi dalam beberapa kasus pembayarannya sepadan.
sumber
Saya telah menghabiskan beberapa waktu bekerja untuk mengoptimalkan sistem bisnis klien / server yang beroperasi melalui jaringan bandwidth rendah dan latensi panjang (misalnya satelit, jarak jauh, lepas pantai), dan mampu mencapai beberapa peningkatan kinerja yang dramatis dengan proses yang cukup berulang.
Ukur : Mulailah dengan memahami kapasitas dan topologi jaringan yang mendasarinya. Berbicara dengan orang-orang jaringan yang relevan dalam bisnis, dan menggunakan alat-alat dasar seperti ping dan traceroute untuk menetapkan (minimal) latensi jaringan dari setiap lokasi klien, selama periode operasional yang khas. Selanjutnya, lakukan pengukuran waktu akurat atas fungsi pengguna akhir tertentu yang menampilkan gejala bermasalah. Catat semua pengukuran ini, beserta lokasi, tanggal, dan waktunya. Pertimbangkan untuk membangun fungsionalitas "pengujian kinerja jaringan" pengguna akhir ke dalam aplikasi klien Anda, memungkinkan pengguna listrik Anda untuk berpartisipasi dalam proses peningkatan; memberdayakan mereka seperti ini dapat memiliki dampak psikologis yang sangat besar ketika Anda berurusan dengan pengguna yang frustrasi dengan sistem yang berkinerja buruk.
Analisis : Menggunakan setiap dan semua metode logging yang tersedia untuk menetapkan data apa yang sedang dikirim dan diterima selama pelaksanaan operasi yang terkena dampak. Idealnya, aplikasi Anda dapat menangkap data yang dikirim dan diterima oleh klien dan server. Jika ini termasuk cap waktu, bahkan lebih baik. Jika pencatatan yang memadai tidak tersedia (mis. Sistem tertutup, atau ketidakmampuan untuk menyebarkan modifikasi ke lingkungan produksi), gunakan sniffer jaringan dan pastikan Anda benar-benar memahami apa yang terjadi di tingkat jaringan.
Cache : Cari kasus di mana data statis atau jarang berubah sedang dikirim berulang-ulang dan pertimbangkan strategi cache yang tepat. Contoh umum termasuk nilai "daftar pilih" atau "entitas referensi" lainnya, yang bisa sangat besar di beberapa aplikasi bisnis. Dalam banyak kasus, pengguna dapat menerima bahwa mereka harus memulai ulang atau menyegarkan aplikasi untuk memperbarui data yang jarang diperbarui, terutama jika dapat mencukur waktu yang signifikan dari tampilan elemen antarmuka pengguna yang umum digunakan. Pastikan Anda memahami perilaku sebenarnya dari elemen-elemen caching yang sudah digunakan - banyak metode caching umum (misalnya HTTP ETag) masih memerlukan round-trip jaringan untuk memastikan konsistensi, dan di mana latensi jaringan mahal, Anda mungkin dapat menghindarinya sama sekali dengan pendekatan caching yang berbeda.
Paralelise : Cari transaksi sekuensial yang tidak perlu secara logis dikeluarkan secara berurutan, dan ulang sistem untuk menerbitkannya secara paralel. Saya berurusan dengan satu kasus di mana permintaan end-to-end memiliki keterlambatan jaringan yang melekat ~ 2s, yang bukan masalah untuk satu transaksi, tetapi ketika 6 perjalanan 2s berurutan diperlukan sebelum pengguna mendapatkan kembali kendali atas aplikasi klien , itu menjadi sumber frustrasi besar. Menemukan bahwa transaksi ini sebenarnya independen memungkinkan mereka untuk dieksekusi secara paralel, mengurangi keterlambatan pengguna akhir menjadi sangat dekat dengan biaya satu kali perjalanan.
Combine : Jika permintaan berurutan harus dijalankan secara berurutan, cari peluang untuk menggabungkannya menjadi satu permintaan yang lebih komprehensif. Contoh umum termasuk pembuatan entitas baru, diikuti oleh permintaan untuk menghubungkan entitas tersebut dengan entitas lain yang ada.
Kompres : Carilah peluang untuk meningkatkan kompresi muatan, baik dengan mengganti bentuk teks dengan bentuk biner, atau menggunakan teknologi kompresi yang sebenarnya. Banyak tumpukan teknologi modern (yaitu dalam satu dekade) mendukung hal ini hampir secara transparan, jadi pastikan itu dikonfigurasi. Saya sering terkejut dengan dampak signifikan dari kompresi di mana tampak jelas bahwa masalahnya pada dasarnya laten daripada bandwidth, menemukan setelah fakta bahwa itu memungkinkan transaksi untuk masuk ke dalam satu paket atau sebaliknya menghindari kehilangan paket dan karenanya memiliki ukuran yang lebih besar. berdampak pada kinerja.
Ulangi : Kembali ke awal dan ukur kembali operasi Anda (di lokasi dan waktu yang sama) dengan perbaikan di tempat, catat dan laporkan hasil Anda. Seperti halnya semua pengoptimalan, beberapa masalah mungkin telah dipecahkan dengan mengekspos masalah lain yang kini mendominasi.
Pada langkah-langkah di atas, saya fokus pada proses optimasi terkait aplikasi, tetapi tentu saja Anda harus memastikan jaringan yang mendasarinya dikonfigurasi dengan cara yang paling efisien untuk mendukung aplikasi Anda juga. Libatkan spesialis jaringan dalam bisnis dan tentukan apakah mereka dapat menerapkan peningkatan kapasitas, QoS, kompresi jaringan, atau teknik lain untuk mengatasi masalah tersebut. Biasanya, mereka tidak akan memahami kebutuhan aplikasi Anda, jadi penting Anda dilengkapi (setelah langkah Analisis) untuk mendiskusikannya dengan mereka, dan juga untuk membuat kasus bisnis untuk setiap biaya yang Anda akan meminta mereka untuk menanggung . Saya mengalami kasus di mana konfigurasi jaringan yang salah menyebabkan data aplikasi dikirim melalui tautan satelit lambat daripada tautan darat, hanya karena menggunakan port TCP yang tidak "dikenal" oleh spesialis jaringan; jelas memperbaiki masalah seperti ini dapat memiliki dampak dramatis pada kinerja, tanpa kode perangkat lunak atau perubahan konfigurasi yang diperlukan sama sekali.
sumber
Sangat sulit untuk memberikan jawaban umum untuk pertanyaan ini. Itu sangat tergantung pada domain masalah Anda dan implementasi teknis. Teknik umum yang cukup netral bahasa: Identifikasi hotspot kode yang tidak dapat dihilangkan, dan optimalkan kode assembler.
sumber
Beberapa% terakhir sangat tergantung pada CPU dan aplikasi ....
Daftarnya terus .... Tapi hal-hal seperti ini adalah pilihan terakhir ...
Bangun untuk x86, dan jalankan Valgrind / Cachegrind terhadap kode untuk profil kinerja yang tepat. Atau CCStudio dari Texas Instruments memiliki profiler yang manis. Maka Anda akan benar-benar tahu di mana harus fokus ...
sumber
Did you know that a CAT6 cable is capable of 10x better shielding off extrenal inteferences than a default Cat5e UTP cable?
Untuk proyek non-offline, sembari memiliki perangkat lunak dan perangkat keras terbaik, jika throughput Anda lemah, maka garis tipis itu akan memeras data dan memberi Anda penundaan, meskipun dalam milidetik ... tetapi jika Anda berbicara tentang tetes terakhir , itu adalah beberapa tetes yang didapat, 24/7 untuk setiap paket yang dikirim atau diterima.
sumber
Tidak sedalam atau serumit jawaban sebelumnya, tetapi begini: (ini lebih pemula / tingkat menengah)
sumber
Tidak mungkin dikatakan. Tergantung pada seperti apa kode itu. Jika kita dapat berasumsi bahwa kode itu sudah ada, maka kita bisa melihatnya dan mencari tahu, bagaimana cara mengoptimalkannya.
Lokalitas cache yang lebih baik, loop terbuka, Coba hilangkan rantai ketergantungan lama, untuk mendapatkan paralelisme tingkat instruksi yang lebih baik. Pilih gerakan kondisional di atas cabang jika memungkinkan. Manfaatkan petunjuk SIMD bila memungkinkan.
Pahami apa yang dilakukan kode Anda, dan pahami perangkat keras yang digunakan. Maka menjadi cukup sederhana untuk menentukan apa yang perlu Anda lakukan untuk meningkatkan kinerja kode Anda. Itu benar-benar nasihat yang benar-benar umum yang bisa saya pikirkan.
Nah, itu, dan "Tunjukkan kode pada SO dan minta saran optimasi untuk potongan kode tertentu".
sumber
Jika perangkat keras yang lebih baik adalah sebuah pilihan maka pasti pergi untuk itu. Jika tidak
sumber
Cara google adalah salah satu opsi "Cache itu .. Sebisa mungkin jangan menyentuh disk"
sumber
Berikut adalah beberapa teknik optimasi cepat dan kotor yang saya gunakan. Saya menganggap ini sebagai optimasi 'first pass'.
Pelajari di mana waktu dihabiskan Cari tahu persis apa yang meluangkan waktu. Apakah ini file IO? Apakah ini waktu CPU? Apakah ini jaringan? Apakah ini Basis Data? Tidak ada gunanya mengoptimalkan untuk IO jika itu bukan hambatan.
Ketahui Lingkungan Anda Mengetahui tempat untuk mengoptimalkan biasanya tergantung pada lingkungan pengembangan. Dalam VB6, misalnya, melewati dengan referensi lebih lambat daripada melewati dengan nilai, tetapi dalam C dan C ++, dengan referensi jauh lebih cepat. Di C, masuk akal untuk mencoba sesuatu dan melakukan sesuatu yang berbeda jika kode pengembalian menunjukkan kegagalan, sementara di Dot Net, menangkap pengecualian jauh lebih lambat daripada memeriksa kondisi yang valid sebelum mencoba.
Indeks Membangun indeks pada bidang basis data yang sering ditanyakan. Anda hampir selalu dapat bertukar ruang untuk kecepatan.
Hindari pencarian Di dalam loop untuk dioptimalkan, saya menghindari harus melakukan pencarian. Temukan offset dan / atau indeks di luar loop dan gunakan kembali data di dalamnya.
Minimalkan IO coba desain dengan cara yang mengurangi berapa kali Anda harus membaca atau menulis terutama melalui koneksi jaringan
Kurangi Abstraksi Semakin banyak lapisan abstraksi yang harus dikerjakan kode, semakin lambat. Di dalam lingkaran kritis, kurangi abstraksi (mis. Ungkapkan metode tingkat rendah yang menghindari kode tambahan)
Spawn Threads untuk proyek dengan antarmuka pengguna, menelurkan utas baru untuk membentuk tugas yang lebih lambat membuat aplikasi terasa lebih responsif, meskipun tidak.
Pra-proses Anda biasanya dapat memperdagangkan ruang untuk kecepatan. Jika ada perhitungan atau operasi intensif lainnya, lihat apakah Anda dapat melakukan precompute beberapa informasi sebelum Anda berada di loop kritis.
sumber
Jika Anda memiliki banyak matematika floating point yang sangat paralel - terutama presisi tunggal - coba turunkan ke prosesor grafis (jika ada) menggunakan OpenCL atau (untuk chip NVidia) CUDA. GPU memiliki daya komputasi floating point yang sangat besar dalam shader mereka, yang jauh lebih besar daripada CPU.
sumber
Menambahkan jawaban ini karena saya tidak melihatnya termasuk dalam semua yang lain.
Minimalkan konversi implisit antara jenis dan tanda:
Ini berlaku untuk C / C ++ setidaknya, Bahkan jika Anda sudah berpikir Anda bebas dari konversi - kadang-kadang baik untuk menguji menambahkan peringatan kompiler di sekitar fungsi yang membutuhkan kinerja, terutama waspada terhadap konversi dalam loop.
Spesifik GCC: Anda dapat menguji ini dengan menambahkan beberapa pragma bertele-tele di sekitar kode Anda,
Saya telah melihat kasus di mana Anda bisa mendapatkan beberapa persen percepatan dengan mengurangi konversi yang ditimbulkan oleh peringatan seperti ini.
Dalam beberapa kasus, saya memiliki tajuk dengan peringatan ketat yang saya tetap sertakan untuk mencegah konversi tidak disengaja, namun ini merupakan trade-off karena Anda mungkin akhirnya menambahkan banyak gips ke konversi yang disengaja yang disengaja yang mungkin hanya membuat kode lebih berantakan untuk minimal keuntungan.
sumber
Terkadang mengubah tata letak data Anda dapat membantu. Di C, Anda dapat beralih dari array atau struktur ke struktur array, atau sebaliknya.
sumber
Tweak OS dan kerangka kerjanya.
Mungkin terdengar berlebihan tetapi pikirkan seperti ini: Sistem Operasi dan Kerangka dirancang untuk melakukan banyak hal. Aplikasi Anda hanya melakukan hal-hal yang sangat spesifik. Jika Anda bisa mendapatkan OS lakukan dengan tepat apa yang dibutuhkan aplikasi Anda dan membuat aplikasi Anda memahami bagaimana kerangka kerja (php, .net, java) bekerja, Anda bisa mendapatkan jauh lebih baik dari perangkat keras Anda.
Facebook, misalnya, mengubah beberapa kernel levelys di Linux, mengubah cara kerja memcached (misalnya mereka menulis proxy memcached, dan menggunakan udp alih-alih tcp ).
Contoh lain untuk ini adalah Window2008. Win2K8 memiliki versi di mana Anda dapat menginstal hanya OS dasar yang diperlukan untuk menjalankan aplikasi X (misalnya Aplikasi Web, Aplikasi Server). Ini mengurangi banyak overhead yang dimiliki OS pada menjalankan proses dan memberi Anda kinerja yang lebih baik.
Tentu saja, Anda harus selalu memasukkan lebih banyak perangkat keras sebagai langkah pertama ...
sumber