Bagikan melalui


Tips untuk Meningkatkan Kode Kritis Waktu

Menulis kode cepat memerlukan pemahaman semua aspek aplikasi Anda dan bagaimana ia berinteraksi dengan sistem. Artikel ini menyarankan alternatif untuk beberapa teknik pengodean yang lebih jelas untuk membantu Anda memastikan bahwa bagian penting waktu kode Anda berkinerja memuaskan.

Untuk meringkas, meningkatkan kode kritis waktu mengharuskan Anda:

  • Ketahui bagian mana dari program Anda yang harus cepat.

  • Ketahui ukuran dan kecepatan kode Anda.

  • Ketahui biaya fitur baru.

  • Ketahui pekerjaan minimum yang diperlukan untuk menyelesaikan pekerjaan.

Untuk mengumpulkan informasi tentang performa kode, Anda dapat menggunakan monitor performa (perfmon.exe).

Bagian dalam Artikel ini

Kesalahan Cache dan Kesalahan Halaman

Hit cache yang terlewat, pada cache internal dan eksternal, serta kesalahan halaman (masuk ke penyimpanan sekunder untuk instruksi program dan data) memperlambat performa program.

Hit cache CPU dapat dikenakan biaya siklus jam 10-20 program Anda. Hit cache eksternal dapat dikenakan biaya 20-40 siklus jam. Kesalahan halaman dapat menelan biaya satu juta siklus jam (dengan asumsi prosesor yang menangani 500 juta instruksi/detik dan waktu 2 milidetik untuk kesalahan halaman). Oleh karena itu, kepentingan terbaik dari eksekusi program untuk menulis kode yang akan mengurangi jumlah hit cache yang terlewat dan kesalahan halaman.

Salah satu alasan program lambat adalah karena mereka mengambil lebih banyak kesalahan halaman atau melewatkan cache lebih sering daripada yang diperlukan. Untuk menghindari masalah ini, penting untuk menggunakan struktur data dengan lokalitas referensi yang baik, yang berarti menjaga hal-hal terkait bersama-sama. Terkadang struktur data yang terlihat hebat ternyata mengerikan karena lokalitas referensi yang buruk, dan kadang-kadang kebalikannya adalah benar. Berikut dua contohnya:

  • Daftar tertaut yang dialokasikan secara dinamis dapat mengurangi performa program. Saat Anda mencari item, atau saat Anda melintasi daftar ke akhir, setiap tautan yang dilewati dapat melewatkan cache atau menyebabkan kesalahan halaman. Implementasi daftar berdasarkan array sederhana mungkin lebih cepat karena penembolokan yang lebih baik dan lebih sedikit kesalahan halaman. Bahkan jika Anda mengizinkan fakta bahwa array akan lebih sulit untuk tumbuh, itu mungkin masih lebih cepat.

  • Tabel hash yang menggunakan daftar tertaut yang dialokasikan secara dinamis dapat menurunkan performa. Berdasarkan ekstensi, tabel hash yang menggunakan daftar tertaut yang dialokasikan secara dinamis untuk menyimpan kontennya mungkin berkinerja jauh lebih buruk. Bahkan, dalam analisis akhir, pencarian linier sederhana melalui array mungkin benar-benar lebih cepat (tergantung pada keadaan). Penggunaan tabel hash berbasis array (yang disebut "hashing tertutup") adalah implementasi yang sering diabaikan yang sering memiliki performa unggul.

Pengurutan dan Pencarian

Pengurutan secara inheren memakan waktu dibandingkan dengan banyak operasi umum. Cara terbaik untuk menghindari perlambatan yang tidak perlu adalah dengan menghindari pengurutan pada waktu kritis. Anda mungkin dapat:

  • Menuangkan pengurutan hingga waktu yang tidak kritis performa.

  • Urutkan data pada waktu yang lebih lama dan tidak kritis performa.

  • Urutkan hanya bagian data yang benar-benar perlu diurutkan.

Terkadang, Anda dapat membuat daftar dalam urutan yang diurutkan. Berhati-hatilah, karena jika Anda perlu menyisipkan data dalam urutan yang diurutkan, Anda mungkin memerlukan struktur data yang lebih rumit dengan lokalitas referensi yang buruk, yang menyebabkan kesalahan cache dan kesalahan halaman. Tidak ada pendekatan yang berfungsi dalam semua kasus. Coba beberapa pendekatan dan ukur perbedaannya.

Berikut adalah beberapa tips umum untuk pengurutan:

  • Gunakan pengurutan stok untuk meminimalkan bug.

  • Pekerjaan apa pun yang dapat Anda lakukan sebelumnya untuk mengurangi kompleksitas semacam itu bermanfaat. Jika satu kali melewati data Anda menyederhanakan perbandingan dan mengurangi pengurutan dari O(n log n) ke O(n), Anda hampir pasti akan keluar ke depan.

  • Pikirkan tentang lokalitas referensi algoritma pengurutan dan data yang Anda harapkan untuk dijalankan.

Ada lebih sedikit alternatif untuk pencarian daripada pengurutan. Jika pencarian sangat penting waktu, pencarian biner atau pencarian tabel hash hampir selalu terbaik, tetapi seperti halnya pengurutan, Anda harus mengingat lokalitas. Pencarian linier melalui array kecil dapat lebih cepat daripada pencarian biner melalui struktur data dengan banyak penunjuk yang menyebabkan kesalahan halaman atau cache meleset.

Pustaka MFC dan Kelas

Kelas Microsoft Foundation (MFC) dapat sangat menyederhanakan penulisan kode. Saat menulis kode kritis waktu, Anda harus mengetahui overhead yang melekat di beberapa kelas. Periksa kode MFC yang digunakan kode kritis waktu Anda untuk melihat apakah kode tersebut memenuhi persyaratan performa Anda. Daftar berikut mengidentifikasi kelas dan fungsi MFC yang harus Anda ketahui:

  • CString MFC memanggil pustaka run-time C untuk mengalokasikan memori secara CString dinamis. Secara umum, CString sama efisiennya dengan string lain yang dialokasikan secara dinamis. Seperti halnya string yang dialokasikan secara dinamis, ia memiliki overhead alokasi dan rilis dinamis. Seringkali, array sederhana char pada tumpukan dapat melayani tujuan yang sama dan lebih cepat. Jangan gunakan CString untuk menyimpan string konstanta. Gunakan const char * sebagai gantinya. Setiap operasi yang CString Anda lakukan dengan objek memiliki beberapa overhead. Menggunakan fungsi string pustaka run-time mungkin lebih cepat.

  • CArray Memberikan CArray fleksibilitas bahwa array reguler tidak, tetapi program Anda mungkin tidak memerlukannya. Jika Anda mengetahui batas spesifik untuk array, Anda dapat menggunakan array tetap global sebagai gantinya. Jika Anda menggunakan CArray, gunakan CArray::SetSize untuk menetapkan ukurannya dan menentukan jumlah elemen yang tumbuh ketika realokasi diperlukan. Jika tidak, menambahkan elemen dapat menyebabkan array Anda sering direalokasikan dan disalin, yang tidak efisien dan dapat memfragmentasi memori. Selain itu, jika Anda menyisipkan item ke dalam array, CArray memindahkan item berikutnya dalam memori dan mungkin perlu menumbuhkan array. Tindakan ini dapat menyebabkan kesalahan cache dan kesalahan halaman. Jika Anda melihat melalui kode yang digunakan MFC, Anda mungkin melihat bahwa Anda dapat menulis sesuatu yang lebih spesifik untuk skenario Anda untuk meningkatkan performa. Karena CArray merupakan templat, misalnya, Anda mungkin menyediakan CArray spesialisasi untuk jenis tertentu.

  • CList CList adalah daftar yang ditautkan dua kali lipat, sehingga penyisipan elemen cepat di kepala, ekor, dan pada posisi yang diketahui (POSITION) dalam daftar. Mencari elemen berdasarkan nilai atau indeks memerlukan pencarian berurutan, namun, yang bisa lambat jika daftar panjang. Jika kode Anda tidak memerlukan daftar tertaut dua kali lipat, Anda mungkin ingin mempertimbangkan kembali menggunakan CList. Menggunakan daftar yang ditautkan secara senyap menyimpan overhead memperbarui pointer lain untuk semua operasi dan memori untuk pointer tersebut. Memori tambahan tidak besar, tetapi ini adalah kesempatan lain untuk kesalahan cache atau kesalahan halaman.

  • IsKindOf Fungsi ini dapat menghasilkan banyak panggilan dan dapat mengakses memori di area data yang berbeda, yang mengarah ke lokalitas referensi yang buruk. Ini berguna untuk build debug (dalam panggilan ASSERT, misalnya), tetapi cobalah untuk menghindari penggunaannya dalam build rilis.

  • PreTranslateMessage Gunakan PreTranslateMessage ketika pohon jendela tertentu membutuhkan akselerator keyboard yang berbeda atau ketika Anda harus menyisipkan penanganan pesan ke dalam pompa pesan. PreTranslateMessage mengubah pesan pengiriman MFC. Jika Anda mengambil alih PreTranslateMessage, lakukan hanya pada tingkat yang diperlukan. Misalnya, tidak perlu mengambil alih CMainFrame::PreTranslateMessage jika Anda hanya tertarik pada pesan yang masuk ke anak-anak dari tampilan tertentu. PreTranslateMessage Ganti untuk kelas tampilan sebagai gantinya.

    Jangan menghindari jalur pengiriman normal dengan menggunakan PreTranslateMessage untuk menangani pesan apa pun yang dikirim ke jendela mana pun. Gunakan prosedur jendela dan peta pesan MFC untuk tujuan tersebut.

  • OnIdle Peristiwa diam dapat terjadi kadang-kadang yang tidak Anda harapkan, seperti antara WM_KEYDOWN dan WM_KEYUP peristiwa. Timer mungkin merupakan cara yang lebih efisien untuk memicu kode Anda. Jangan paksa OnIdle untuk dipanggil berulang kali dengan menghasilkan pesan palsu atau dengan selalu kembali TRUE dari penimpaan OnIdle, yang tidak akan pernah memungkinkan utas Anda tidur. Sekali lagi, timer atau utas terpisah mungkin lebih tepat.

Pustaka bersama

Penggunaan kembali kode diinginkan. Namun, jika Anda akan menggunakan kode orang lain, Anda harus memastikan Anda tahu persis apa yang dilakukannya dalam kasus-kasus di mana performa sangat penting bagi Anda. Cara terbaik untuk memahaminya adalah dengan menelusuri kode sumber atau dengan mengukur dengan alat seperti PView atau Monitor Performa.

Tumpukan

Gunakan beberapa timbunan dengan kebijaksanaan. Timbunan tambahan yang dibuat dengan HeapCreate dan HeapAlloc memungkinkan Anda mengelola lalu membuang sekumpulan alokasi terkait. Jangan menerapkan terlalu banyak memori. Jika Anda menggunakan beberapa timbunan, beri perhatian khusus pada jumlah memori yang awalnya dilakukan.

Alih-alih beberapa timbunan, Anda dapat menggunakan fungsi pembantu untuk berinteraksi antara kode Anda dan timbunan default. Fungsi pembantu memfasilitasi strategi alokasi kustom yang dapat meningkatkan performa aplikasi Anda. Misalnya, jika Anda sering melakukan alokasi kecil, Anda mungkin ingin melokalisasi alokasi ini ke salah satu bagian dari timbunan default. Anda dapat mengalokasikan blok memori yang besar dan kemudian menggunakan fungsi pembantu untuk melakukan suballocate dari blok tersebut. Kemudian Anda tidak akan memiliki beberapa tumpukan dengan memori yang tidak digunakan, karena alokasi keluar dari tumpukan default.

Namun, dalam beberapa kasus, menggunakan timbunan default dapat mengurangi lokalitas referensi. Gunakan Pemantau Proses, Spy++, atau Monitor Performa untuk mengukur efek memindahkan objek dari timbunan ke timbunan.

Ukur timbunan Anda sehingga Anda dapat memperhitungkan setiap alokasi pada timbunan. Gunakan rutinitas tumpukan debug run-time C untuk mengecek dan membuang tumpukan Anda. Anda dapat membaca output ke dalam program lembar bentang seperti Microsoft Excel dan menggunakan tabel pivot untuk melihat hasilnya. Perhatikan jumlah total, ukuran, dan distribusi alokasi. Bandingkan hasil ini dengan ukuran set kerja. Lihat juga pengklusteran objek berukuran terkait.

Anda juga dapat menggunakan penghitung kinerja untuk memantau penggunaan memori.

Utas

Untuk tugas latar belakang, penanganan peristiwa diam yang efektif mungkin lebih cepat daripada menggunakan utas. Lebih mudah untuk memahami lokalitas referensi dalam program utas tunggal.

Aturan praktis yang baik adalah menggunakan utas hanya jika pemberitahuan sistem operasi yang Anda blokir berada di akar pekerjaan latar belakang. Utas adalah solusi terbaik dalam kasus seperti itu karena tidak praktis untuk memblokir utas utama pada suatu peristiwa.

Utas juga menyajikan masalah komunikasi. Anda harus mengelola tautan komunikasi antara utas Anda, dengan daftar pesan atau dengan mengalokasikan dan menggunakan memori bersama. Mengelola tautan komunikasi biasanya memerlukan sinkronisasi untuk menghindari kondisi balapan dan masalah kebuntuan. Kompleksitas ini dapat dengan mudah berubah menjadi bug dan masalah performa.

Untuk informasi selengkapnya, lihat Pemrosesan Perulangan Menganggur dan Multithreading.

Set Kerja Kecil

Set kerja yang lebih kecil berarti lokalitas referensi yang lebih baik, lebih sedikit kesalahan halaman, dan lebih banyak temuan cache. Set kerja proses adalah metrik terdekat yang disediakan sistem operasi secara langsung untuk mengukur lokalitas referensi.

Lihat juga

Mengoptimalkan Kode Anda