44
Оптимизация UI потока Куркин Дмитрий

Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

  • Upload
    ontico

  • View
    266

  • Download
    10

Embed Size (px)

Citation preview

Page 1: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Оптимизация UI потокаКуркин Дмитрий

Page 2: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Беда - UI тормозит

• iOS приложение тоже может тормозить• У вас все отлично – у тестировщика тормозит• Пользователь хочет написать, а приложение занято

своими делами• У всех все отлично, но 30% неведомых пользователей

жалуются на тормоза

Page 3: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Как систематически решать проблему тормозов?• Тормоза UI – это когда главный поток чем-то занят и не

может 60 раз в секунду отдавать картинку приложения• Нужно ловить процедуры, которые занимают главный

поток слишком долго

Page 4: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

WatchDogWatchDog – это процесс или поток, который следит за другим процессом или потоком

Page 5: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Схема реализации с опросом UI потока

Ping Ping UI thread

WatchDog threadЗамер итерации

Превышение временного лимита

https://blog.testmunk.com/why-the-facebook-app-is-rated-below-2-stars/

https://github.com/wojteklu/Watchdog

Page 6: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Схема реализации на итерации RunLoop

WatchDog thread

UI thread

Run Loop

Замер итерации

Превышение временного лимита

https://gist.github.com/jspahrsummers/419266f5231832602bec

Page 7: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Сбор результатов

Page 8: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Логировать превышение лимита времени

NSLog(@"%@: iteration of run loop %p took %.f

ms to execute", self, self.runLoop, (double)duration

* 1000);

NSLog(@"WATCHDOG: task took longer than %d

seconds", self.timeout);

Main thread was blocked for 1.25s

+ Можно собирать проблемы без остановки приложения

− Сложно понять, что является источником проблемы

Page 9: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Кидать исключение для создания крэшлога

Exception Type: SIGABRTException Codes: #0 at 0x383bc1f0Crashed Thread: 20

Thread 0:0 libsystem... semaphore_wait_trap + 81 TCC TCCAccessPreflight + 2102 AddressBook ABCDBContextCreateWithPathAndAddressBook + 703 AddressBook ABCCreateAddressBookWithDatabaseDirectoryA...4 AddressBook ABAddressBookCreateWithDatabaseDirectory + 725 AddressBook ABAddressBookCreateWithOptionsAndPolicy + 1446 AddressBook ABAddressBookCreateWithOptions + 867 ICQ +[AddressBookManager newAddressBook] ...16 Graphics... GSEventRunModal + 13617 UIKit UIApplicationMain + 113418 ICQ main (main.mm:23)19 libdyld.dylibstart + 0

+ Можно смотреть стек главного потока – очень высока вероятность, что там будет видна причина проблемы.

− Приложение останавливается. Пользователь вынужден начинать все с начала.

Page 10: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Как работать с результатами

Page 11: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Анализ стека в крэшлоге

Thread 0:0 libsyste...semaphore_wait_trap + 81 libxpc.d... xpc_connection_send_message_with_repl...2 Security securityd_message_with_reply_sync + 703 Security securityd_send_sync_and_do + 464 Security __SecItemAdd_block_invoke + 1665 Security SecOSStatusWith + 146 Security SecItemAdd + 3387 ICQ -[KeychainItemWrapper writeToKeychain] 8 ICQ -[MRAuthenticationManager setKeychainV...9 ICQ -[MRAuthenticationManager setPasscode:]...

Операции не место на главном потоке – выносим в фоновый поток

Page 12: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Анализ стекав крэшлоге

Thread 0:0 libsystem... semaphore_wait_trap + 81 AudioToolbox playerasync_Invalidate + 2282 AVFoundation -[AVPlayer dealloc] + 2803 AVFoundation -[AVPlayerLayer dealloc] + 1844 Foundatio... NSKVODeallocate + 885 AVFoundation __destroy_helper_block_339 + 246 libsystem... _Block_release + 1527 libdispat... _dispatch_client_callout + 128 libdispat... _dispatch_main_queue_callback_4CF

Thread 30:0 libsystem... mach_msg_trap + 81 AudioToolbox ASClient_AudioSessionSetActiveW...2 AudioToolbox AudioSessionSetActiveWithFlags + 1123 libAVFAud... -[AVAudioSession setActive:withOp...4 ICQ __48-[SoundManager deactivateAudioSession...

Нашего кода нет в главном потоке. Возможно, он ожидает завершения нашей работы в другом потоке

Page 13: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Профилирование

Page 14: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

https://www.raywenderlich.com/97886/instruments-tutorial-with-swift-getting-started

Page 15: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Что здесь происходит?Процессор ничем не занят, но UI висит

Загрузка процессора при блокировках

Page 16: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Запись ждущих потоков

Page 17: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Запись ждущих потоков

Page 18: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Поток ждет на семафоре

Page 19: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Нельзя просто так измерить время операции

1

2

3

3

4

5

Page 20: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Результаты на проекте ICQ

Page 21: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Пример блокировки. CoreData

Thread 0:0 libsqlite3.dylib 0x0000000194391454 sqlite3_value_text + 13068...4 libsqlite3.dylib 0x000000019437f368 sqlite3_step + 5245 CoreData 0x00000001824e47e8 _execute + 1206 CoreData 0x00000001824e4420 -[NSSQLiteConnection execute] + 2108...15 CoreData 0x00000001824eac5c -[NSPersistentStoreCoordinator executeRequest...16 CoreData 0x00000001824e96e0 -[NSManagedObjectContext executeFetchRequest...17 ICQ 0x00000001001a37f4 __69+[OBJCIM_Profile nicknameForConferenceParticipantWithUid:profilePid:]_block_invoke463 (objcimprofile.mm:1011)

Page 22: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Пример блокировки. CoreData

Thread 0:

0 libsystem_kernel... 0x01968e4e48 semaphore_wait_trap + 8

1 libdispatch.dylib 0x01967c2ee0 _dispatch_barrier_sync_f_slow + 516

2 CoreData 0x0184f0ccb4 _perform + 176

3 CoreData 0x0184e5e9b4 -[NSPersistentStoreCoo...newValuesFor...

4 CoreData 0x0184e5dfd4 _PFFaultHandlerLookupRow + 348

5 CoreData 0x0184e5da48 _PF_FulfillDeferredFault + 248

6 CoreData 0x0184e5d874 _sharedIMPL_pvfk_core + 80

7 ICQ 0x01002e6ad4 __66+[MCChatConversationPresenter...

Page 23: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Пример блокировки. UserDefaults synchronize

Thread 0:

0 libsystem_kernel.dylib 0x00000001968e4e48 semaphore_wait_trap + 8

1 CoreFoundation 0x0000000185120518 -[CFPrefsPlistSource synchronize] + 32

2 CoreFoundation 0x0000000185141398 -[CFPrefsSearchListSource alreadylock...

3 CoreFoundation 0x000000018514041c +[CFPrefsSearchListSource withSearchListForIde...

4 CoreFoundation 0x00000001851d0520 _CFPreferencesAppSynchronizeWithContainer + 8

5 Foundation 0x0000000185fd8db0 -[NSUserDefaults(NSUserDefaults) synchronize] + 32

Page 24: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Пример блокировки. Масштабирование картинки

Thread 0:

0 CoreGraphics 0x00000001859ad04c argb32_sample_argb32 + 788

1 CoreGraphics 0x00000001859a2a18 RGBA32_image + 1896

2 libRIP.A.dylib 0x0000000185d3b1fc ripl_Mark + 28

3 libRIP.A.dylib 0x0000000185d3a5f4 RIPLayerBltImage + 924

4 libRIP.A.dylib 0x0000000185d3a088 ripc_RenderImage + 256

5 libRIP.A.dylib 0x0000000185d38b58 ripc_DrawImage + 684

6 CoreGraphics 0x000000018597ff5c CGContextDrawImage + 404

7 ICQ 0x00000001005854a4 -[UIImage(Crop) scaleImage:andCropCenter:]

8 ICQ 0x000000010031ec44 -[OBJCWIM_Profile uploadAvatar:forUid:livechat:completion:] (OBJCWIM_Profile.mm:1980)

Page 25: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Пример блокировки. Работа с KeyChain

Thread 0:0 libsystem_kernel.dylib 0x25c6cc74 semaphore_wait_trap + 81 libxpc.dylib 0x25d4394b xpc_connection_send_message_with_reply_sync + 1762 Security 0x2637b1df securityd_message_with_reply_sync + 1203 Security 0x2637b399 securityd_send_sync_and_do + 46...7 Security 0x2638a109 SecItemAuthDoQuery + 3708 Security 0x2638ac8b __SecItemDelete_block_invoke + 409 Security 0x263891f9 SecOSStatusWith + 1410 Security 0x2638ac1d SecItemDelete + 36211 ICQ 0x0093ce8b +[Flurry startupNetworkAndSendSession] + 24012 ICQ 0x0093ccf5 +[Flurry startSession:] + 1442

Page 26: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Подводные камни

Page 27: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

При сворачивании приложения оно “засыпает”

До сворачивания После активацииРабота в фоне

● В фоне легко попасть в промежуток, когда приложение выгружено

● При сворачивании и разворачивании выполняются тяжелые системные операции

Page 28: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Системные модули. Клавиатура

6 CoreFoundation __93-[CFPrefsSearchListSource handleReply:toRequestNewDataMessage...7 libxpc.dylib xpc_array_apply8 CoreFoundation -[CFPrefsSearchListSource handleReply:toRequestNewDataMessage:onC...9 CoreFoundation __66-[CFPrefsSearchListSource generationCountFromListOfSources:co...10 CoreFoundation _CFPrefsWithDaemonConnection11 CoreFoundation __66-[CFPrefsSearchListSource generationCountFromListOfSources:c...12 CoreFoundation CFPREFERENCES_IS_WAITING_FOR_CFPREFSD13 CoreFoundation -[CFPrefsSearchListSource generationCountFromListOfSources:count:]...20 CoreFoundation +[CFPrefsSearchListSource withSearchListForIdentifier:container:...21 CoreFoundation _CFPreferencesCopyAppValueWithContainerAndConfiguration22 TextInput -[TIPreferencesController valueForKey:]23 TextInput -[TIPreferencesController boolForKey:]24 UIKit -[UIKeyboardImpl initWithFrame:]

Page 29: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Системные модули. Клавиатура

5 dyld ImageLoaderMegaDylib::dlopenFromCache(ImageLoader::LinkContext const&...6 dyld dyld::dlopenFromCache(char const*, int, void**)7 dyld dlopen8 libdyld.dylib dlopen9 TextInput -[TIKeyboardLayoutFactory init]10 TextInput __48+[TIKeyboardLayoutFactory sharedKeyboardFactory]_block_invoke11 libdispatch.dylib _dispatch_client_callout12 libdispatch.dylib dispatch_once_f$VARIANT$mp13 TextInput +[TIKeyboardLayoutFactory sharedKeyboardFactory]14 UIKit UIKeyboardGetKBStarName

Page 30: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Системные модули. Клавиатура

0 libsystem_kernel.dylib semaphore_wait_trap1 libdispatch.dylib _dispatch_semaphore_wait_slow2 libxpc.dylib xpc_connection_send_message_with_reply_sync3 libsystem_config… libSC_send_message_with_reply_sync4 libsystem_config… nwi_state_copy5 AssistantServices -[AFNetworkAvailability _updateState]6 AssistantServices __36-[AFNetworkAvailability isAvailable]_block_invoke7 libdispatch.dylib _dispatch_client_callout8 libdispatch.dylib _dispatch_barrier_sync_f_invoke9 AssistantServices -[AFNetworkAvailability isAvailable]10 AssistantServices -[AFDictationConnection dictationIsAvailableForLanguage:]11 UIKit +[UIDictationController dictationIsFunctional]12 UIKit -[UIKeyboardLayoutStar stateForDictationKey:]

Page 31: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Системные модули. Клавиатура

0 libsystem_kernel.dylib __open

1 Foundation _NSReadBytesFromFileWithExtendedAttributes

2 Foundation -[NSString initWithContentsOfFile:encoding:error:]

3 Foundation +[NSString stringWithContentsOfFile:encoding:error:]

4 AppSupport -[CPBitmapStore version]

5 UIKit -[UIKeyboardCache init]

6 UIKit +[UIKeyboardCache sharedInstance]

Page 32: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Системные модули. Камера

0 libsystem_kernel.dylib semaphore_wait_trap1 libdispatch.dylib _dispatch_semaphore_wait_slow2 libxpc.dylib xpc_connection_send_message_with_reply_sync3 CoreFoundation __66-[CFPrefsSearchListSource generationCount...4 CoreFoundation _CFPrefsWithDaemonConnection5 CoreFoundation __66-[CFPrefsSearchListSource generationCount...6 CoreFoundation CFPREFERENCES_IS_WAITING_FOR_CFPREFSD...16 CoreFoundation _CFPreferencesGetAppBooleanValueWithContainer17 CameraKit -[CMKCameraView initWithFrame:spec:]18 PhotoLibrary -[PLImagePickerCameraView initWithFrame:spec:]19 PhotoLibrary -[PLUICameraViewController loadView]

Page 33: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Системные модули. Камера

0 libsystem_kernel.dylib __getdirentries641 libsystem_c.dylib _readdir_unlocked2 libsystem_c.dylib readdir3 CoreFoundation _CFIterateDirectory...12 Foundation -[NSBundle localizedStringForKey:value:table:]13 CameraKit CMKLocalizedFrameworkString14 CameraKit -[CMKModeDial _titleForMode:]15 CameraKit -[CMKModeDial reloadData]...20 PhotoLibrary -[PLUICameraViewController loadView]

Page 34: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Системные модули. Камера

13 ImageIO CGImageSourceCreateImageAtIndex14 UIKit ImageRefAtPath15 UIKit GetImageAtPath16 UIKit -[_UIPathLazyImageAsset imageWithTraitCollection:]17 UIKit +[UIImage imageNamed:inBundle:compatibleWithTraitCollection:]18 UIKit +[UIImage(UIImagePrivate) imageNamed:inBundle:]19 CameraKit -[CMKFlipButton _flipImage]20 CameraKit -[CMKFlipButton _commonCMKFlipButtonInitialization]21 CameraKit -[CMKFlipButton initWithFrame:]22 UIKit +[UIButton buttonWithType:]23 CameraKit -[CMKCameraView _createFlipButtonIfNecessary]24 CameraKit -[CMKCameraView initWithFrame:spec:]

Page 35: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Системные модули. Камера

7 libxpc.dylib xpc_connection_create 8 libxpc.dylib xpc_connection_create_mach_service 9 AudioToolbox SSClientIPC::ConnectToServer() 10 AudioToolbox SSClientIPC::SSClientIPC() 11 AudioToolbox ___ZN10TSingletonI11SSClientIPCE8InstanceEv_block_invoke 12 0x210f980d 13 0x2110b171 14 AudioToolbox InitializeSystemSoundClient() 15 AudioToolbox AudioServicesAddSystemSoundCompletion 16 CameraKit -[CMKCameraView _registerForSystemSound]

Page 36: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Внешние библиотеки. Facebook SDK

Thread 0:0 libsystem... semaphore_wait_trap + 81 Accounts -[ACAccountStore accountTypeWithAccountTypeIdentifier:] + 3162 ICQ -[FBSDKSystemAccountStoreAdapter accountType]3 ICQ -[FBSDKSystemAccountStoreAdapter accessTokenString] 4 ICQ -[FBSDKGraphRequestConnection processResultBody:error:metadata:] 5 ICQ __64-[FBSDKGraphRequestConnection completeWithResults:networkErr...6 CoreFound... __53-[__NSArrayM enumerateObjectsWithOptions:usingBlock:]_block_...7 CoreFound... -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] + 2308 ICQ -[FBSDKGraphRequestConnection completeWithResults:networkError:] ...13 ICQ -[FBSDKURLConnection connectionDidFinishLoading:]14 Foundati... __65-[NSURLConnectionInternal _withConnectionAndDelegate:onlyAct...15 Foundati... -[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive...

Page 37: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Внешние библиотеки. AppsFlyer

Thread 0:0 libsystem... semaphore_wait_trap1 libdispat… _dispatch_group_wait_slow2 CoreFound... CFPREFERENCES_IS_WAITING_FOR_CFPREFSD3 CoreFound... -[CFPrefsPlistSource synchronize]4 CoreFound... -[CFPrefsSearchListSource alreadylocked_requestNewData]5 CoreFound... __95+[CFPrefsSearchListSource withSearchListForIdent...6 CoreFound... normalizeQuintuplet7 CoreFound... +[CFPrefsSearchListSource withSearchListForIdentifie...9 CoreFound... _CFPreferencesAppSynchronizeWithContainer10 Foundation -[NSUserDefaults(NSUserDefaults) synchronize]11 ICQ -[AppsFlyerTracker getCounter:]

Page 38: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Внешние библиотеки. Flurry

Thread 0:0 libsystem... lstat + 81 Foundation _NSStandardizePathUsingCache + 20682 Foundation -[NSString(NSPathUtilities) _stringByStandardizingPathUsingCache:] + 1283 Foundation _NSExpandTildeInPath + 1044 Foundation -[NSString(NSPathUtilities) stringByExpandingTildeInPath] + 1085 Foundation NSSearchPathForDirectoriesInDomains + 2966 ICQ +[FlurryUtil filePathDirectory] + 647 ICQ -[FlurryGlobalVariableStorage getPersistentFilePath:] + 608 ICQ -[FlurryGlobalVariableStorage initPersistentMap] + 409 ICQ +[Flurry startSession:] + 640

Page 39: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

WorkaroundsКостыли

Page 40: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Остановка и запуск

До сворачивания После активацииРабота в фоне

Важно остановиться как можно раньше при сворачивании и стартануть как можно позже при активации

Стоп Старт

Page 41: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Пропуск промежутка

Стоп Старт UI thread

Page 42: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Swizzled

Перехват и пропуск

Стоп Старт UI thread

Page 43: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

Значение временного лимита

1 секунда 3 секунды Выключен

Page 44: Оптимизация UI потока / Дмитрий Куркин (Mail.Ru)

На позитивной ноте

• Мы оперативно понимаем, что вызывает торможение на главном потоке

• Это настолько удобно, что хочется так же на остальных потоках

https://github.com/maxgordeev/MRWatchdog