Gotta Go Fast: Membangun untuk Kecepatan di iOS. Bagian 2



Terkadang Anda dapat menemukan diri Anda dalam situasi di mana aplikasi Anda tidak dapat bekerja dengan baik. Jadi, berikut adalah beberapa instrumen yang dapat Anda gunakan dan praktik terbaik yang dapat Anda terapkan untuk membuat segalanya lebih baik.

Ini adalah bagian kedua dari artikel berdasarkan ceramah utama yang disampaikan oleh Luke Parham, seorang insinyur iOS di Fyusion dan seorang penulis tutorial untuk pengembangan iOS di RayWenderlich.com, pada Konferensi Pengembang Seluler Internasional MBLT DEV pada 2017.

Instrumen animasi inti


Jika Anda telah melakukan banyak profil dan Anda telah menemukan semua kemacetan Anda, kadang-kadang masih ada masalah kinerja. Ini karena cara kerja barang-barang UI di iOS. Setiap kali Anda mengatur bingkai atau membuat UIViews, apa yang sebenarnya terjadi di bawah tenda adalah Anda membuat transaksi CAT atau sistem membuatnya untuk Anda. Dan ini dikirim ke hal yang disebut "server render". Server rendering bertugas melakukan animasi. Jika Anda melakukan UIView animateWith: apa pun, itu semua akan terjadi pada server render yang merupakan utas lainnya dan menangani semua animasi aplikasi.



Berikut adalah Time Profiler yang memiliki pengukur laju bingkai di bagian atas. Dan di bagian bawah adalah opsi debug bagian paling penting. Kami akan menceritakan tentang dua hal yang paling penting dan paling mudah untuk diperbaiki.



Yang pertama adalah lapisan warna campuran. Ini sangat mudah diperbaiki. Dan ini membawa kita ke bagian pertama polisi kinerja. Pada dasarnya, banyak aplikasi memiliki masalah: bahkan iMessage, aplikasi Apple tercinta, melakukan banyak hal yang tidak terlalu hebat. Di sini kita melihat bahwa ada banyak warna merah:



Merah berarti Anda memiliki label yang memiliki latar belakang putih. Dan kemudian mereka berada di atas latar belakang putih lain dan untuk beberapa alasan, mereka tidak diatur menjadi buram. Jadi blender memadukan warna-warna ini, putih dan putih dan hasilnya mendapatkan warna putih. Untuk setiap piksel yang berwarna merah, ia melakukan perhitungan ekstra tanpa manfaat, Anda tetap mendapatkan warna putih di latar belakang.

Untuk menghindari ini, Anda dapat membuat lapisan buram bila memungkinkan jika mereka memiliki warna yang sama pada warna yang sama. Jika subview memiliki warna latar belakang yang sama, pencampuran tidak perlu. Yang harus Anda lakukan adalah mengatur opacity layer Anda ke 1 dan kemudian memastikan warna latar belakang diatur. Jika warna latar belakang Anda jelas, itu akan selalu tidak buram.



Render pada layar


Elemen yang ditampilkan di layar akan ditampilkan dengan warna kuning jika Anda mengaktifkan opsi ini. Yang menyenangkan tentang instrumen Core Animation adalah Anda dapat melihat aplikasi lain. Anda dapat mengaktifkan opsi ini dan kemudian pergi ke aplikasi apa pun di sistem Anda dan Anda dapat melihat apa yang mereka lakukan salah. Dalam hal ini, Instagram memiliki gelembung-gelembung kecil ini di bagian atas yang menunjukkan kepada Anda cerita orang.



Seperti yang Anda lihat mereka semua berwarna kuning. Pada iPhone 5 mereka sangat lambat. Dan ini karena rendering di luar layar jauh lebih buruk daripada alpha blending. Ini menunda GPU. Akhirnya harus melakukan perhitungan ekstra bolak-balik antara GPU dan CPU, sehingga Anda mendapatkan kios tambahan yang sebagian besar tidak perlu.

Bezier path bukannya view cornering


Aturan selanjutnya: jangan gunakan properti radius sudut. Jika Anda memiliki tampilan dan Anda mengatur view.layer.cornerRadius, maka ini selalu memperkenalkan rendering di luar layar. Sebagai gantinya, Anda dapat menggunakan jalur bezier dan jenis barang CGBitmap yang sama dari sebelumnya. Dalam hal ini, konteks UIGraphics. Fungsi ini beroperasi dengan UIImage yang dibutuhkan dalam ukuran, melakukan sudut membulat berdasarkan ukuran itu dan menggunakan jalur bezier untuk klip. Lalu kami klip gambar dan mengembalikannya dari konteks UIImage. Jadi ini akan mengembalikan gambar yang sudah dibulatkan bulat daripada membulatkan pandangan bahwa gambar itu berada di dalamnya.



Contoh terakhir. Inilah Twitter dan ini adalah tampilan real-time dari animasi ini berjalan. Seharusnya terbuka dan menunjukkan informasi kepada Anda, tetapi semua teks dan hal-hal ini telah ditampilkan di luar layar sehingga memperlambat animasi menjadi merangkak. Ini adalah hal yang paling sedikit performan yang pernah saya temukan di aplikasi yang ada di App Store.



Jadi bagaimana ini bisa terjadi? Satu hal yang menyebabkan ini terjadi adalah properti shouldRasterize dari CALayer. Ini merupakan opsi pada lapisan yang memungkinkan Anda untuk menembolok tekstur yang telah dirender. Ada banyak aturan aneh. Seperti jika belum digunakan dalam jumlah milidetik tertentu, ia akan meninggalkan cache. Dan kemudian, jika ia meninggalkan cache, itu akan ditampilkan di luar layar pada setiap frame. Ini tidak benar-benar sepadan dengan kemungkinan manfaat yang dimilikinya. Dan sulit untuk memeriksa apakah itu benar-benar menguntungkan Anda.

Ringkasan


Hindari rendering di luar layar dan alpha blending jika Anda bisa. Pencampuran alfa terkadang diperlukan. Ini lebih baik daripada rendering di luar layar. Perenderan di luar layar terjadi karena beberapa alasan. Itu bisa terjadi dari bayangan; itu bisa terjadi dari sudut pembulatan; itu bisa terjadi karena topeng.

Buat tampilan buram bila memungkinkan. Jangan gunakan properti radius sudut gunakan jalur Bezier sebanyak yang Anda bisa. Juga, jangan gunakan properti layer shadow jika Anda melakukan bayangan teks. Anda dapat menggunakan NSShadow sebagai gantinya.

Jejak aktivitas


Jejak aktivitas adalah sejenis versi tingkat jauh lebih rendah dari sesuatu yang akan dilakukan oleh profiler waktu. Ini memberi Anda pandangan tentang semua utas Anda dan bagaimana mereka berinteraksi. Dan itu sangat rumit. Tetapi memiliki fitur yang sangat bagus yang dapat Anda atur.

Jejak sistem


Gunakan Jejak Sistem untuk melacak waktu untuk peristiwa tertentu. Anda dapat mengatur cara untuk melacak peristiwa dan bagian kode tertentu dan melihat berapa lama waktu yang dibutuhkan dalam aplikasi dunia nyata. Ini memungkinkan Anda untuk mendapatkan informasi yang lengkap tentang apa yang terjadi di sistem Anda.

  • Gunakan "Sign Post" untuk memberi sinyal ketika sesuatu yang penting terjadi.
  • Poin adalah peristiwa tunggal ketika / jika Anda ingin melihat seperti animasi terjadi atau sesuatu seperti itu.
  • Daerah memiliki awal dan akhir. Untuk penguraian gambar, Anda bisa melihat kapan itu dimulai dan kapan itu berakhir sehingga Anda bisa memperkirakan berapa lama biasanya.




Di sini adalah bagaimana Anda mengatur templat jejak sistem. Anda membuat daftar acara yang bisa terjadi. Jadi nomor satu adalah unduhan gambar. Dua adalah decoding gambar, dan tiga adalah animasi miring yang saya tambahkan. Pada dasarnya, Anda mengatur beberapa opsi tambahan untuk melihat warna apa yang akan terjadi. Pada dasarnya, Anda mengirim nomor seperti 1 atau 2, itu akan menjadi merah atau hijau berdasarkan apa yang Anda kirim di sana.



Jika Anda berada di Objective-C, Anda harus mengimpor header kdebug_signpost ini. Di Swift, ini hanya tersedia untuk Anda.



Dan kemudian Anda harus memanggil fungsi ini, baik kdebug_signpost atau kdebug_signpost_start dan kdebug_ signpost_end. Dan mereka bekerja dari kode yang Anda berikan. Jadi kami menyiapkan tiga acara dengan angka-angka itu. Kemudian Anda memasukkan nomor itu di sini. Anda memberikannya objek yang pada dasarnya adalah kunci untuk acara ini. Dan kemudian, angka terakhir adalah warna. Jadi 2 seperti Anda tahu merah atau sesuatu.

Saya memiliki proyek contoh Swift di GitHub . Saya agak menyederhanakan hal-hal. Ada awal dan akhir yang sedikit lebih mudah untuk dihadapi.

Ini akan terlihat seperti setelah Anda menjalankan jejak. Itu tidak akan menunjukkan apa pun pada awalnya. Kemudian, ketika Anda mematikan aplikasi, itu akan melakukan beberapa perhitungan dan menunjukkan barang-barang Anda di sini.



Di sini kita dapat melihat unduhan gambar kami yang memakan waktu sekitar 200 milidetik. Dan kemudian, ada decoding gambar yang mengambil seperti 40 milidetik. Ini sangat keren jika Anda memiliki banyak hal gila yang terjadi di aplikasi Anda. Anda dapat mengatur semua acara ini dan kemudian hanya melihat pembacaan berapa lama mereka masing-masing mengambil dan bagaimana mereka berinteraksi satu sama lain. Itu untuk jejak sistem.

Bonus


Lihatlah contoh pelambatan kamera di mana kita dapat melihat apa yang terjadi jika ada hal-hal AR dalam aplikasi:



Kami menerapkan efek dan mengambil 26,4% dari semua perhitungan pada setiap frame hanya untuk menghitung satu efek. Dan itu memperlambat kamera ke sesuatu yang gila seperti 10 frame per detik.

Ketika saya menggali di sini dan melihat kemacetan besar ini, saya melihat bahwa hal terbaik yang paling banyak dilakukan adalah penggunaan NSDispatchData yang intens.



Ini adalah subkelas dari NSData. Dan semua ini mendapatkan byte dengan fungsi rentang. Dan itu adalah fungsi yang sederhana. Yang diperlukan hanyalah mengambil beberapa byte dari data dan meletakkannya di tempat lain. Ini tidak terlalu gila tetapi, tampaknya, semua hal yang dilakukan secara internal mengambil 18% dari 26% ini.

Aturan # 1

Ini adalah NSData dan mendapatkan byte. Itu adalah hal Objective-C yang sederhana tetapi jika Anda mengalami itu dan itu adalah hambatan, maka sekarang saatnya untuk beralih menggunakan C sebagai gantinya. Karena bottleneck adalah sekitar satu panggilan untuk mengambil nilai float, Anda bisa menggunakan memcpy (). Dengan memcpy () Anda dapat memindahkan sepotong data di tempat lain. Memotong overhead yang cukup banyak.

Jika Anda melihat seperti NSData, kelas-kelas ini seperti ribuan baris. Jadi ada banyak hal yang terjadi di sana. Dalam hal ini, kami memiliki yang asli berwarna merah.



Di sini Anda mendapatkan kisaran, ambil beberapa byte dan salin ke buffer. Versi memcpy () hampir persis sama. Itu tidak terlihat lebih rumit dan itu melakukan lebih sedikit hal agresif.



Ketika kami mengubahnya dan kami jalankan lagi, segalanya berubah dari 26% menjadi 0,6% dengan mengubah satu baris menjadi memcpy (). Dan kemudian, frame rate melonjak secara dramatis.

Aturan # 2

Hindari penarikan berlebih jika Anda melakukan semacam perenderan aplikasi atau bahkan jika Anda melakukan sesuatu seperti bilah pemuatan. Banyak kali peristiwa akan terjadi lebih dari 60 frame per detik. Dalam hal ini, Anda dapat membatasi pembaruan UI ini dengan menggunakan CADisplayLink. Ia memiliki properti bernama preferFramesPerSecond. Itu hanya untuk iOS 10 atau lebih tinggi. Untuk yang lebih tua, Anda harus melakukannya secara manual tetapi masih bermanfaat.



Anda dapat mengatur framerate yang diinginkan. Banyak kali untuk memuat seperti bar saya akan mengaturnya sekitar 15 frame per detik karena itu tidak masalah. Itu tidak harus memperbarui 60 frame per detik. Ini dapat menghemat banyak pekerjaan yang sebenarnya Anda lakukan jika semuanya terlihat sama.

Aturan # 3

Gunakan caching IMP. Ini berguna hanya untuk Objective-C. InObjective-C, ketika Anda memanggil metode di bawah tenda, Anda sebenarnya memanggil fungsi pengiriman pesan Objective-C (objc_msgSend ()). Jika Anda melihat panggilan ini dalam jejak yang menghabiskan banyak waktu, ini adalah sesuatu yang dapat Anda singkirkan dengan mudah. Ini pada dasarnya adalah tabel cache tempat Anda mencari pointer fungsi dengan memberinya nama beberapa metode. Alih-alih melakukan pencarian itu setiap kali Anda dapat men-cache fungsi pointer dan panggil saja secara langsung. Paling tidak dua kali lebih cepat biasanya.



Jika Anda tidak memiliki cached pointer, Anda dapat mengambilnya dengan memanggil methodForSelector:. Kemudian kita panggil metode ini seperti panggilan fungsi biasa. Anda mengirimkan objek pemilih dan kemudian argumen datang setelah itu.

Aturan # 4

Jangan gunakan ARC. ARC adalah sesuatu yang menambahkan banyak overhead. Dalam kode Anda, Anda memiliki semua hal ini terjadi dan menaburkan semua dengan retain dan rilis. Ia melakukan sebanyak yang harus dilakukan, dan ia melakukan lebih banyak. Jadi jika Anda benar-benar ingin mengoptimalkan, jika Anda melihat bahwa Anda memiliki banyak panggilan penahan dan pelepasan di jejak Anda dan mereka mengambil banyak waktu, Anda bisa beralih ke tidak menggunakan ARC yang merupakan pekerjaan yang jauh lebih banyak.

Sulit juga membuat rekan setim Anda setuju untuk melakukan ini dan tidak marah karenanya.

Jangan gunakan Swift jika sangat sensitif terhadap kinerja. Swift adalah bahasa yang bagus. Itu punya beberapa fitur yang sangat rapi. Tapi itu juga menggunakan lebih banyak boilerplate yang terjadi di dalam untuk mendapatkan fungsionalitas tingkat tinggi. Jika Anda ingin cepat, Anda harus mendekati perakitan sedekat mungkin dengan hal-hal tingkat rendah. Dan itu akan lebih cepat karena kode kurang otomatis.

Jika Anda melihat ke hal-hal jika Anda pikir itu menarik, ada buku yang sangat bagus yang disebut "iOS dan MacOS: Performance Tuning" oleh Marcel Weiher. Ini masuk sangat mendalam ke banyak hal ini dan lebih banyak melewati ini. Saya juga punya seri video. Saya membuat video untuk RayWenderlich. Ada serangkaian instrumen praktis yang saya lakukan yang lebih mendalam dan yang menjelaskan hal-hal ini sedikit lebih banyak dan memiliki beberapa contoh. Jadi jika Anda ingin mempelajari lebih lanjut tentang instrumen secara khusus, Anda dapat menonton serial video itu. Dan kemudian, video WWDC - ada banyak dari mereka yang menjelaskan hal-hal kinerja yang berbeda seperti ini.

Video


Di sini Anda dapat menemukan bagian pertama dari sebuah artikel berdasarkan ceramah Luke. Tonton pembicaraan lengkap di sini:

Source: https://habr.com/ru/post/id436440/


All Articles