Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Go
Code

Jadikan Program Go Anda Berjalan Cepat dengan Profiling

by
Difficulty:IntermediateLength:LongLanguages:

Indonesian (Bahasa Indonesia) translation by Ari Ana (you can also view the original English article)

Go sering digunakan untuk menulis sistem terdistribusi, penyimpanan data tingkat lanjut, dan microservices. Kinerja adalah kunci dalam domain ini.

Dalam tutorial ini, Anda akan mempelajari cara membuat profil program agar secepat kilat (memanfaatkan CPU lebih baik) atau seringan bulu (menggunakan lebih sedikit memori). Saya akan membahas pembuatan profil CPU dan memori, menggunakan pprof (profiler Go), memvisualisasikan profil, dan bahkan grafik api.

Profiling adalah mengukur kinerja program Anda dalam berbagai dimensi. Go dilengkapi dengan dukungan besar untuk membuat profil dan dapat membuat profil dimensi berikut secara default:

  • sampling waktu CPU per fungsi DAN instruksi
  • sampling dari semua heap allocations
  • tumpukan jejak dari semua goroutines saat ini
  • tumpukan jejak yang mengarah pada pembuatan thread OS baru
  • tumpukan jejak yang menyebabkan pemblokiran pada synchronization primitives
  • tumpukan jejak holders dari contended mutexes

Anda bahkan dapat membuat profil kustom jika Anda mau. Go profiling melibatkan pembuatan file profil dan kemudian menganalisanya menggunakan alat pprof go.

Cara Membuat File Profil

Ada beberapa cara untuk membuat file profil.

Menggunakan "go test" untuk Menghasilkan File Profil

Cara termudah adalah menggunakan go test. Ini memiliki beberapa penanda yang memungkinkan Anda membuat file profil. Berikut adalah cara menghasilkan file profil CPU dan file profil memori untuk pengujian di direktori saat ini: go test -cpuprofile cpu.prof -memprofile mem.prof -bench.

Mengunduh Data Profil Langsung dari Layanan yang Berjalan Lama

Jika Anda ingin profil layanan web yang berjalan lama, Anda dapat menggunakan antarmuka HTTP bawaan untuk menyediakan data profil. Tambahkan pernyataan impor berikut:

import _ "net/http/pprof"

Sekarang, Anda dapat mengunduh data profil langsung dari URL /debug/pprof/. Info lebih lanjut tersedia dalam dokumentasi paket net/http/pprof.

Profil dalam Kode

Anda juga dapat menambahkan profil langsung ke kode Anda untuk kontrol penuh. Pertama Anda perlu mengimpor runtime/pprof. Profil CPU dikontrol oleh dua panggilan:

  • pprof.StartCPUProfile()
  • pprof.StopCPUProfile()

Pembuatan profil memori dilakukan dengan memanggil runtime.GC() diikuti oleh pprof.WriteHeapProfile().

Semua fungsi profil menerima handle file bahwa Anda bertanggung jawab untuk membuka dan menutup dengan tepat.

Program Sampel

Untuk melihat profiler beraksi, saya akan menggunakan program yang menyelesaikan Problem 8 dari Project Euler. Masalahnya adalah: diberi nomor 1.000-digit, temukan 13 digit yang berdekatan dalam angka ini yang memiliki produk terbesar.

Berikut ini adalah solusi sepele yang mengiterasi semua urutan 13 digit, dan untuk setiap urutan tersebut mengalikan semua 13 digit dan mengembalikan hasilnya. Hasil terbesar disimpan dan akhirnya dikembalikan:

Kemudian, setelah membuat profil, kita akan melihat beberapa cara untuk meningkatkan kinerja dengan solusi lain.

Profil CPU

Mari buat profil CPU dari program kami. Saya akan menggunakan metode go test menggunakan pengujian ini:

Perhatikan bahwa saya menjalankan tes 100.000 kali karena profiler go adalah profiler sampling yang membutuhkan kode untuk benar-benar menghabiskan waktu yang signifikan (beberapa milidetik kumulatif) pada setiap baris kode. Berikut adalah perintah untuk menyiapkan profil:

Butuh waktu lebih dari 13 detik (untuk 100.000 iterasi). Sekarang, untuk melihat profil, gunakan alat pprof go untuk masuk ke prompt interaktif. Ada banyak perintah dan opsi. Perintah paling dasar adalah topN; dengan opsi -cum itu menunjukkan fungsi N teratas yang mengambil waktu paling kumulatif untuk dieksekusi (sehingga fungsi yang membutuhkan waktu sangat sedikit untuk dieksekusi, tetapi dipanggil berkali-kali, bisa berada di atas). Biasanya ini yang saya mulai dengan.

Mari kita pahami hasilnya. Setiap baris mewakili sebuah fungsi. Saya telah melewati jalur ke masing-masing fungsi karena keterbatasan ruang, tetapi akan ditampilkan dalam keluaran nyata sebagai kolom terakhir.

Flat berarti waktu (atau persentase) yang dihabiskan dalam fungsi, dan Cum singkatan cumulative—waktu yang dihabiskan dalam fungsi dan semua fungsi yang dipanggilnya. Dalam hal ini, testing.tRunner sebenarnya memanggil TestFindLargestProduct(), yang memanggil FindLargestProduct(), tetapi karena hampir tidak ada waktu yang dihabiskan di sana, profiler sampling menghitung waktu flat mereka sebagai 0.

Profil Memori

Profil memori serupa, kecuali Anda membuat profil memori:

Anda dapat menganalisis penggunaan memori Anda menggunakan alat yang sama.

Menggunakan pprof untuk Mengoptimalkan Kecepatan Program Anda

Mari kita lihat apa yang bisa kita lakukan untuk menyelesaikan masalah dengan lebih cepat. Melihat profil, kita melihat bahwa calcProduct() membutuhkan 8,17% dari runtime flat, tetapi makeSlice(),yang dipanggil dari calcProduct(), mengambil 72% (kumulatif karena memanggil fungsi lain). Ini memberikan indikasi yang cukup bagus tentang apa yang perlu kita optimalkan. Apa yang dilakukan kodenya? Untuk setiap urutan 13 angka yang berdekatan, ia mengalokasikan sebuah irisan:

Itu hampir 1.000 kali per jalankan, dan kami menjalankan 100.000 kali. Alokasi memori itu lambat. Dalam hal ini, sebenarnya tidak perlu mengalokasikan irisan baru setiap waktu. Sebenarnya, tidak perlu mengalokasikan irisan sama sekali. Kita hanya cukup memindai array masukan.

Potongan kode berikut menunjukkan bagaimana menghitung produk yang sedang berjalan dengan hanya membagi dengan digit pertama dari urutan sebelumnya dan mengalikan dengan digit cur.

Berikut ini daftar singkat dari beberapa pengoptimalan algoritmik:

  • Komputasi produk yang sedang berjalan. Misalkan kita menghitung produk pada indeks N... N+13 dan menyebutnya P(N). Sekarang kita perlu menghitung produk pada indeks N+1..N+13. P(N+1) sama dengan P(N) kecuali bahwa angka pertama pada indeks N sudah hilang dan kita perlu memperhitungkan nomor baru pada indeks N+14T. Ini dapat dilakukan dengan membagi produk sebelumnya dengan nomor pertama dan mengalikan dengan nomor baru.
  • Tidak menghitung urutan 13 angka yang mengandung 0 (produk akan selalu nol).
  • Menghindari pembagian atau perkalian dengan 1.

Program lengkapnya ada di sini. Ada beberapa logika berduri untuk mengatasi nol, tetapi selain itu cukup mudah. Yang utama adalah bahwa kita hanya mengalokasikan satu array 1000 byte di awal, dan kita meneruskannya dengan pointer (jadi tidak ada salinan) ke fungsi findLargestProductInSeries() dengan rentang indeks.

Pengujiannya sama. Mari kita lihat bagaimana kami melakukannya dengan profil:

Secara langsung, kita dapat melihat bahwa runtime turun dari lebih dari 13 detik menjadi kurang dari satu detik. Itu bagus sekali. Saatnya mengintip ke dalam. Mari gunakan hanya top10, yang diurutkan berdasarkan waktu datar.

Ini luar biasa. Hampir seluruh waktu proses dihabiskan di dalam kode kami. Tidak ada alokasi memori sama sekali. Kita bisa menyelam lebih dalam dan melihat level pernyataan dengan perintah list:

Ini sangat menakjubkan. Anda mendapatkan pernyataan dengan waktu pernyataan dari semua poin penting. Perhatikan bahwa panggilan pada baris 73 untuk fungsi f() sebenarnya adalah panggilan untuk findLargestProductInSeries(), yang saya ubah namanya di profil karena keterbatasan ruang. Panggilan ini membutuhkan waktu 20 ms. Mungkin, dengan menanamkan kode fungsi di tempat, kita dapat menyimpan panggilan fungsi (termasuk mengalokasikan tumpukan dan menyalin argumen) dan menghemat 20 ms tersebut. Mungkin ada pengoptimalan bermanfaat lainnya bahwa tampilan ini dapat membantu penentuan.

Visualisasi

Melihat profil teks ini bisa sulit untuk program besar. Go memberi Anda banyak opsi visualisasi. Anda harus menginstal Graphviz untuk bagian selanjutnya.

Alat pprof dapat menghasilkan keluaran dalam banyak format. Salah satu cara termudah (keluaran svg) hanyalah dengan mengetik 'web' dari prompt interaktif pprof, dan browser Anda akan menampilkan grafik yang bagus dengan hot path yang ditandai dengan warna merah muda.

Visualization

Grafik Api

Grafik bawaan itu bagus dan bermanfaat, tetapi dengan program yang besar, bahkan grafik ini bisa sulit untuk dijelajahi. Salah satu alat paling populer untuk memvisualisasikan hasil kinerja adalah grafik api. Alat pprof tidak mendukungnya di langsung, tetapi Anda dapat bermain dengan grafik api yang sudah menggunakan alat go-torch Uber. Ada pekerjaan yang sedang berlangsung untuk menambahkan dukungan bawaan untuk grafik api ke pprof.

Kesimpulan

Go adalah bahasa pemrograman sistem yang digunakan untuk membangun sistem terdistribusi kinerja tinggi dan penyimpanan data. Go dilengkapi dengan dukungan yang sangat baik yang terus menjadi lebih baik untuk membuat profil program Anda, menganalisis kinerja mereka, dan memvisualisasikan hasilnya.

Ada banyak penekanan oleh tim Go dan komunitas untuk meningkatkan peralatan di sekitar kinerja. Kode sumber lengkap dengan tiga algoritme yang berbeda dapat ditemukan di GitHub.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.