Dalam
artikel sebelumnya, kami belajar tentang alasan ketidakstabilan tes unit dan cara menanganinya. Sekarang kami ingin mempertimbangkan salah satu alat baru Apple untuk debugging dan kode profil. Kita berbicara tentang kerangka pencatatan os_log yang disajikan di WWDC 2018, yang diperluas oleh alat analisis kinerja, os_signpost.

Dalam salah satu sprint, kami ditugaskan untuk mengimplementasikan pembuatan dokumen pdf di sisi klien. Kami menyelesaikan tugas dan berhasil menunjukkan hasilnya kepada tim. Tetapi kami ingin memastikan keefektifan nuansa teknis dari keputusan tersebut. Plang membantu kami dengan ini. Dengan itu, kami dapat mempercepat tampilan dokumen beberapa kali.
Untuk mempelajari lebih lanjut tentang teknologi aplikasi os_signpost, lihat di mana itu dapat membantu Anda dan bagaimana hal itu telah membantu kami, buka di bawah kucing.
Lebih dalam ke masalah ini
Ada banyak aplikasi di ponsel pengguna, dan semuanya menggunakan sumber daya sistem yang umum: CPU, RAM, jaringan, baterai, dll. Jika aplikasi Anda melakukan tugasnya dan tidak macet, ini tidak berarti aplikasi itu bekerja secara efisien dan benar. Di bawah ini kami jelaskan kasus-kasus yang mungkin Anda temui.
Algoritma suboptimal dapat menyebabkan beban CPU yang lama.- Pada awal aplikasi, setelah 20 detik menunggu, sistem akan mematikan aplikasi, dan pengguna bahkan tidak akan melihat layar pertama. Dalam hal ini, sistem akan menetapkan laporan kerusakan, fitur yang membedakannya adalah tipe pengecualian - EXC_CRASH (SIGKILL) dengan tipe 0x8badf00d .
- Proses intensif sumber daya di latar belakang dapat memengaruhi responsif UI, meningkatkan konsumsi baterai, dan memaksa aplikasi untuk menghentikan sistem (jika terjadi panas berlebih pada CPU).
Kasus RAM:Spesifikasi untuk ponsel di situs web Apple tidak memberikan informasi tentang RAM, tetapi sumber lain menyediakan alokasi memori berikut untuk model ponsel:
Jenis
| 4S
| 5
| 5C
| 5s
| 6
| 6P
| 6S
| 6SP
|
RAM, GB
| 0,5
| 1
| 1
| 1
| 1
| 1
| 2
| 2
|
Jenis
| SE
| X
| 7
| 7P
| 8
| 8P
| XS
| XSM
| Xr
|
RAM, GB
| 2
| 3
| 2
| 3
| 2
| 3
| 4
| 4
| 3
|
Ketika RAM terlalu sedikit, iOS mulai mencari memori untuk dikosongkan, secara bersamaan mengirimkan peringatan memori ke semua aplikasi yang berjalan. Proses ini secara implisit mempengaruhi CPU dan baterai perangkat. Jika peringatan memori diabaikan, dan alokasi memori berlanjut, sistem secara paksa menghentikan proses aplikasi. Untuk pengguna, ini terlihat seperti macet, tanpa jejak balik dalam laporan kerusakan.
Penggunaan berlebihan permintaan jaringan . Ini juga menyebabkan penurunan masa pakai baterai. Duplikasi permintaan dan / atau kurangnya pembatalan permintaan yang tidak perlu juga menyebabkan penggunaan CPU yang tidak efisien.
Jangan lupa tentang CoreLocation . Semakin sering dan lebih akurat kami meminta lokasi pengguna, semakin banyak baterai perangkat dihabiskan. Untuk memverifikasi kebenaran pemrosesan kasus yang dijelaskan, kami sarankan menggunakan os_signpost untuk membuat profil proses aplikasi dan kemudian menganalisis data yang diperoleh.
Integrasi alat dalam proyek
Di tingkat atas, proses membuat PDF terdiri dari tiga langkah:
- menerima data melalui jaringan;
- pembentukan dokumen;
- tampilan di layar - kami memutuskan untuk membagi dan mencatat tahapan pembuatan dokumen, mulai dari pengguna mengklik tombol "Buat" dan diakhiri dengan tampilan dokumen di layar.
Misalkan kita dihadapkan dengan tugas menganalisis permintaan jaringan asinkron. Markup dalam kode akan terlihat seperti ini:
import os.signpost let pointsOfInterestLog = OSLog(subsystem: "com.example.your-app", category: . pointsOfInterest) let networkLog = OSLog(subsystem: "com.example.your-app", category: "NetworkOperations") os_signpost(.event, log: pointsOfInterestLog, name: "Start work") os_signpost(.begin, log: networkLog, name: "Overall work") for element in elements { os_signpost(.begin, log: networkLog, name: "Element work") makeWork(for: element) os_signpost(.end, log: networkLog, name: "Element work") } os_signpost(.end, log: networkLog, name: "Overall work")
Langkah-langkah untuk menggunakan plang adalah sebagai berikut:
- Impor kerangka kerja os.signpost.
- Buat instance OSLog. Layak untuk mempertimbangkan bahwa ada beberapa jenis peristiwa: untuk acara interval (misalnya, permintaan jaringan), Anda dapat menggunakan kategori sewenang-wenang, dan untuk acara simultan (misalnya, mengklik tombol), poin kategori yang telah ditentukanOfInterest / OS_LOG_CATEGORY_POINTS_OF_INTEREST.
- Untuk acara interval, panggil fungsi os_signpost dengan tipe .begin dan .end di awal dan di akhir tahap yang sedang diselidiki. Untuk acara secara bersamaan, gunakan tipe .event.
- Jika kode yang sedang diselidiki dapat dieksekusi secara tidak sinkron, maka tambahkan ID Signpost, yang akan memungkinkan Anda untuk memisahkan interval dari jenis operasi yang sama dengan objek yang berbeda.
- Secara opsional, Anda dapat menambahkan data tambahan (metadata) ke acara yang dikirim. Misalnya, ukuran gambar yang diunduh melalui jaringan atau jumlah halaman PDF yang dihasilkan. Informasi tersebut akan membantu untuk memahami apa yang sebenarnya terjadi pada tahap eksekusi kode yang diselidiki.
Demikian pula pada obj-c:
@import os.signpost; os_log_t pointsOfInterestLog = os_log_create("com.example.your-app", OS_LOG_CATEGORY_POINTS_OF_INTEREST); os_log_t networkLog = os_log_create("com.example.your-app", "NetworkOperations"); os_signpost_id_t operationIdentifier = os_signpost_id_generate(networkLog); os_signpost_event_emit(pointsOfInterestLog, operationIdentifier, "Start work"); os_signpost_interval_begin(networkLog, operationIdentifier, "Overall work"); for element in elements { os_signpost_id_t elementIdentifier = os_signpost_id_make_with_pointer(networkLog, element); os_signpost_interval_begin(networkLog, elementIdentifier, "Element work"); [element makeWork]; os_signpost_interval_end(networkLog, elementIdentifier, "Element work"); } os_signpost_interval_end(networkLog, operationIdentifier, "Overall work");
Sebagai catatan. Jika proyek harus berjalan di iOS sebelum versi 12.0, Xcode akan menawarkan untuk membungkus panggilan os_signpost di versi if tersedia. Agar tidak mengacaukan kode, Anda dapat menempatkan logika ini di kelas yang terpisah.
Perlu dipertimbangkan bahwa os_signpost memerlukan string string literal sebagai parameter nama acara. Untuk menambahkan lebih banyak pengetikan yang ketat, Anda bisa membuat enum dengan tipe acara, dan dalam implementasi kelas, petakan ke string literal. Menempatkan OSLog di kelas terpisah akan menambah logika untuk menonaktifkannya untuk skema rilis (ada perintah OSLog terpisah untuk ini).
import os.signpost let networkLog: OSLog if ProcessInfo.processInfo.environment.keys.contains("SIGNPOSTS_FOR_NETWORK") { networkLog = OSLog(subsystem: "com.example.your-app", category: "NetworkOperations" } else { networkLog = .disabled }
Anda bisa menambahkan nilai dari properti apa pun ke penandaan acara dengan decoder tipe berikut untuk pemformatan yang nyaman:
Jenis nilai
| Specifier khusus
| Contoh output
|
time_t
| % {time_t} d
| 2016-01-12 19:41:37
|
batas waktu
| % {timeval}. * P
| 2016-01-12 19: 41: 37.774236
|
timespec
| % {timespec}. * P
| 2016-01-12 19: 41: 37.2382382823
|
errno
| % {errno} d
| Pipa yang rusak
|
iec-byte
| % {iec-byte} d
| 2,64 MiB
|
bitrate
| % {bitrate} d
| 123 kbps
|
iec-bitrate
| % {iec-bitrate} d
| 118 kibps
|
uuid_t
| % {uuid_t}. * 16P % {uuid_t}. * P
| 10742E39-0657-41F8-AB99-878C5EC2DCAA
|
Sekarang, ketika membuat profil aplikasi, peristiwa dari os_signpost akan dikirim ke Instrumen dalam bentuk data tabular. Untuk beralih ke alat, gunakan pintasan keyboard Cmd + I, lalu pilih alat yang diperlukan untuk pembuatan profil. Untuk melihat data yang ditandai, cukup nyalakan alat os_signpost dan Point of Interest di sisi kanan antarmuka alat.

Secara default, acara dikelompokkan ke dalam kategori dan ditampilkan dalam tabel, di mana jumlah dan statistiknya pada saat runtime dihitung. Selain itu, ada tampilan grafis pada timeline, yang memudahkan untuk membandingkan acara yang diterima dengan hasil di alat lain. Ada juga kemungkinan menyesuaikan tampilan statistik dan sistem pakar penulisan - tetapi topik ini layak mendapat artikel terpisah.
Contoh Penggunaan
Kasus No. 1. PDFKit vs WKWebView
Melalui penggunaan os_signpost, kami melihat bahwa untuk dokumen kecil (beberapa halaman) langkah terpanjang adalah langkah terakhir - menampilkan dokumen - daripada bekerja dengan jaringan atau grafik. Ini mengarahkan kami pada keputusan untuk mengganti
WKWebView dengan
PDFView , yang mempercepat tampilan dokumen dari 1,5 detik menjadi 30 milidetik. Pada grafik, terlihat seperti ini:
Menampilkan dokumen PDF (WKWebView) di Time Profiler
Menampilkan dokumen PDF (PDFView) di Time ProfilerData yang dihasilkan dapat diimplementasikan dalam alat lain yang disediakan Xcode. Seperti yang ditunjukkan oleh alat Alokasi, keuntungan dalam kecepatan unduhan dicapai dengan meningkatkan penggunaan RAM.
Kasus No. 2. Peringatan Memori Rendah
Dokumen PDF dibuat secara tidak sinkron, dan pembentukannya membutuhkan alokasi sejumlah besar memori. Dalam hal memori tidak mencukupi, kami memutuskan untuk menambahkan kemampuan untuk menghentikan operasi asinkron pembuatan dokumen.
Seperti yang Anda ketahui, saat menggunakan NSOperationQueue, metode cancelAllOperation membebaskan antrian yang ada, tetapi tidak berhenti sudah menjalankan operasi. Dari sini kami menyimpulkan bahwa dalam pelaksanaan operasi perlu untuk menentukan kondisinya secara berkala dan berhenti bekerja. Dengan demikian membebaskan sumber daya jika diatur ke status Dibatalkan.
Langkah selanjutnya adalah operasi asinkron yang harus kita periksa untuk pembatalan. Tetapi pada saat yang sama, tidak jelas dengan frekuensi apa yang melakukan pemeriksaan ini. Kami memiliki dua opsi - pemeriksaan baris demi baris dan pemeriksaan halaman-demi-halaman. os_signpost membantu di sini juga. Ternyata, menambahkan cek untuk pembatalan dalam siklus baris demi baris rendering tabel dalam dokumen, kami meningkatkan waktu yang dibutuhkan untuk menghasilkan dokumen (150 halaman) sebanyak 2 kali. Opsi kedua lebih optimal dalam hal kinerja dan sebenarnya tidak menambah waktu yang dibutuhkan untuk membuat dokumen. Akibatnya, ketika kami menerima acara peringatan memori, kami membatalkan operasi secara terprogram dan menampilkan layar kesalahan untuk pengguna.
Untuk memastikan bahwa memori benar-benar dibebaskan, kita juga dapat menggunakan os_signpost. Kali ini dengan menambahkan penanda tentang awal acara di metode didRecieveMemoryWarning dan penanda tentang akhir di viewDidLoad dari layar kesalahan. Omong-omong, Anda dapat meniru peristiwa memori yang tidak mencukupi dalam simulator (shift + command + m).
Kasus No. 3. Pembaruan kendala
Plang mungkin berguna dalam proses tata letak. Untuk membuat batasan, kami menggunakan kerangka
pasangan bata . Dokumentasi untuk framework mengatakan bahwa disarankan untuk menggunakan metode updateConstraints () untuk membuat constrates. Tetapi Apple sangat tidak menyarankannya, dan Anda dapat memverifikasi ini dengan markup rambu.

Menurut dokumentasi Apple, updateConstraints hanya boleh digunakan untuk mengubah batasan jika kita tidak bisa melakukannya di tempat perubahan terjadi.

Setelah menganalisis hasil, kami menyimpulkan bahwa dalam aplikasi kami panggilan updateConstraints tidak begitu sering - kira-kira setiap kali tampilan muncul di layar.
Meskipun demikian, untuk menghindari kemungkinan cacat kinerja, kami menyarankan Anda untuk mengikuti saran Apple.
Kesimpulan
Pada 2018, Apple memberi pengembang kesempatan untuk memperluas alat profil secara mandiri. Tentu saja, Anda dapat menggunakan alat debugging lain: breakpoints, output ke konsol, timer, profiler khusus. Tetapi mereka membutuhkan lebih banyak waktu untuk mengimplementasikan atau tidak selalu memberikan gambaran lengkap tentang apa yang terjadi.
Pada artikel selanjutnya, kami akan mempertimbangkan cara menggunakan informasi yang diterima dari plang secara lebih efisien dengan menulis sistem pakar kami sendiri (Instrumen Khusus).
Tautan yang bermanfaatArtikel ini ditulis dengan @victoriaqb - Victoria Kashlina, pengembang iOS.