Mapsui icon indicating copy to clipboard operation
Mapsui copied to clipboard

Xamarin.iOS app freezes while navigating

Open bertt opened this issue 3 years ago • 23 comments

I've created a Xamarin.Forms app containing Mapsui map with 1 graphics layer. When testing the iOS version on IPhone a complete app freeze can happen while navigating the map.

I've made a project to reproduce, see project 'MemoryProvider' (branch bug/getfeaturesinview_not_called/) in the samples/Mapsui.Samples.MemoryProvider folder. Project under test is MemoryProvider.iOS. Note, in this branch HasFling is set to false.

Its not easy to reproduce, its just a matter of continuous pan and zoom action's while graphic layer is visible (layer has MaxVisible defined), normally within 50 map actions the freeze happens.

Some more observations:

  • just a map without the graphics layer: no freeze happens (so far);
  • settings like map.RotationLock and map.MyLocationEnabled don't influence the app freeze.

For completeness, an screenshot after freeze. Note the graphics on the right/bottom side stopped drawing.

image

bertt avatar Sep 04 '21 19:09 bertt

Could you try, what's happening if you use MapControl instead of MapView? Perhaps you have to remove some special things (like MyLocationLayer) but it would be interesting, if this chances something.

charlenni avatar Sep 04 '21 20:09 charlenni

Good suggestion, it still happens when changing mapsui:MapView to mapsui:MapControl in MainPage.xaml. But the freeze seems to occur less frequently.

bertt avatar Sep 04 '21 20:09 bertt

Crash log from phone:

Date/Time:           2021-09-05 09:52:52.5998 +0200
Launch Time:         2021-09-05 09:52:03.1987 +0200
OS Version:          iPhone OS 14.7.1 (18G82)
Release Type:        User
Baseband Version:    4.04.00
Report Version:      104

Exception Type:  EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note:  EXC_CORPSE_NOTIFY
Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d
Termination Description: SPRINGBOARD, <RBSTerminateContext| domain:10 code:0x8BADF00D explanation:scene-update watchdog transgression: application<com.mapsui.MemoryProvider>:59325 exhausted real (wall clock) time allowance of 10.00 seconds | ProcessVisibility: Background | ProcessState: Running | WatchdogEvent: scene-update | WatchdogVisibility: Background | WatchdogCPUStatistics: ( | "Elapsed total CPU time (seconds): 4.980 (user 4.980, system 0.000), 8% CPU", | "Elapsed application CPU time (seconds): 0.386, 1% CPU" | ) reportType:CrashLog maxTerminationResistance:Interactive>
Triggered by Thread:  0

Thread 0 name:  tid_103  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libsystem_kernel.dylib        	0x00000001aebdd908 0x1aebda000 + 14600
1   libsystem_kernel.dylib        	0x00000001aebdcd0c 0x1aebda000 + 11532
2   IOKit                         	0x000000018d3c9bb8 0x18d34e000 + 506808
3   IOKit                         	0x000000018d355c94 0x18d34e000 + 31892
4   IOGPU                         	0x00000001bd8279fc 0x1bd817000 + 68092
5   IOGPU                         	0x00000001bd821fd8 0x1bd817000 + 45016
6   IOGPU                         	0x00000001bd818a9c 0x1bd817000 + 6812
7   AGXMetalA11                   	0x00000001cc3cb298 0x1cc38c000 + 258712
8   AppleMetalGLRenderer          	0x00000001cb7c7364 0x1cb7c5000 + 9060
9   AppleMetalGLRenderer          	0x00000001cb7c7480 0x1cb7c5000 + 9344
10  AppleMetalGLRenderer          	0x00000001cb7d3138 0x1cb7c5000 + 57656
11  GLEngine                      	0x00000001b468ff44 0x1b4668000 + 163652
12  GLEngine                      	0x00000001b468feb0 0x1b4668000 + 163504
13  libSkiaSharp                  	0x000000010b3c87c8 0x10b114000 + 2836424
14  libSkiaSharp                  	0x000000010b2daf38 0x10b114000 + 1863480
15  libSkiaSharp                  	0x000000010b3460dc 0x10b114000 + 2302172
16  libSkiaSharp                  	0x000000010b307ce8 0x10b114000 + 2047208
17  libSkiaSharp                  	0x000000010b3459b4 0x10b114000 + 2300340
18  libSkiaSharp                  	0x000000010b2e0134 0x10b114000 + 1884468
19  libSkiaSharp                  	0x000000010b2ea1dc 0x10b114000 + 1925596
20  libSkiaSharp                  	0x000000010b2d1cf4 0x10b114000 + 1826036
21  libSkiaSharp                  	0x000000010b2d185c 0x10b114000 + 1824860
22  libSkiaSharp                  	0x000000010b2d2048 0x10b114000 + 1826888
23  libSkiaSharp                  	0x000000010b2f5824 0x10b114000 + 1972260
24  libSkiaSharp                  	0x000000010b38f17c 0x10b114000 + 2601340
25  MemoryProvider.iOS            	0x00000001096cf9dc 0x104cf4000 + 77445596
26  MemoryProvider.iOS            	0x0000000109559fe4 0x104cf4000 + 75915236
27  MemoryProvider.iOS            	0x00000001094e78c8 0x104cf4000 + 75446472
28  MemoryProvider.iOS            	0x00000001056d34a0 0x104cf4000 + 10351776
29  MemoryProvider.iOS            	0x000000010a234f30 0x104cf4000 + 89394992
30  MemoryProvider.iOS            	0x000000010a2ef5c4 0x104cf4000 + 90158532
31  MemoryProvider.iOS            	0x000000010a2f2e04 0x104cf4000 + 90172932
32  MemoryProvider.iOS            	0x0000000104dd5ce4 0x104cf4000 + 924900
33  MemoryProvider.iOS            	0x0000000104e11d28 0x104cf4000 + 1170728
34  GLKit                         	0x00000001b3349b20 0x1b332c000 + 121632
35  MemoryProvider.iOS            	0x0000000106713680 0x104cf4000 + 27391616
36  MemoryProvider.iOS            	0x0000000105cb5f90 0x104cf4000 + 16523152
37  MemoryProvider.iOS            	0x00000001094a9bf0 0x104cf4000 + 75193328
38  MemoryProvider.iOS            	0x00000001061d8824 0x104cf4000 + 21907492
39  MemoryProvider.iOS            	0x00000001056d34a0 0x104cf4000 + 10351776
40  MemoryProvider.iOS            	0x000000010a234f30 0x104cf4000 + 89394992
41  MemoryProvider.iOS            	0x000000010a2ef5c4 0x104cf4000 + 90158532
42  MemoryProvider.iOS            	0x000000010a2f2e04 0x104cf4000 + 90172932
43  MemoryProvider.iOS            	0x0000000104dc0374 0x104cf4000 + 836468
44  MemoryProvider.iOS            	0x0000000104dc5088 0x104cf4000 + 856200
45  Foundation                    	0x00000001840cdee8 0x183f69000 + 1461992
46  CoreFoundation                	0x0000000182d1a8a8 0x182c80000 + 633000
47  CoreFoundation                	0x0000000182d1a7a8 0x182c80000 + 632744
48  CoreFoundation                	0x0000000182d19afc 0x182c80000 + 629500
49  CoreFoundation                	0x0000000182d14018 0x182c80000 + 606232
50  CoreFoundation                	0x0000000182d137d0 0x182c80000 + 604112
51  GraphicsServices              	0x0000000199455570 0x199452000 + 13680
52  UIKitCore                     	0x00000001856402d0 0x184b10000 + 11731664
53  UIKitCore                     	0x000000018564584c 0x184b10000 + 11753548
54  MemoryProvider.iOS            	0x00000001068bea68 0x104cf4000 + 29141608
55  MemoryProvider.iOS            	0x0000000105fc5140 0x104cf4000 + 19730752
56  MemoryProvider.iOS            	0x0000000105fc4fc4 0x104cf4000 + 19730372
57  MemoryProvider.iOS            	0x0000000104e2ecc0 0x104cf4000 + 1289408
58  MemoryProvider.iOS            	0x00000001056d34a0 0x104cf4000 + 10351776
59  MemoryProvider.iOS            	0x000000010a234f30 0x104cf4000 + 89394992
60  MemoryProvider.iOS            	0x000000010a2ef5c4 0x104cf4000 + 90158532
61  MemoryProvider.iOS            	0x000000010a2f5878 0x104cf4000 + 90183800
62  MemoryProvider.iOS            	0x000000010a213488 0x104cf4000 + 89257096
63  MemoryProvider.iOS            	0x000000010a3fb8d0 0x104cf4000 + 91257040
64  MemoryProvider.iOS            	0x0000000104e2ebc8 0x104cf4000 + 1289160
65  libdyld.dylib                 	0x00000001829f2140 0x1829f1000 + 4416

Thread 0 crashed with ARM Thread State (64-bit):
    x0: 0x0000000000000000   x1: 0x0000000000000003   x2: 0x00000000000000b4   x3: 0x00000000000010bc
    x4: 0x000000000000aa07   x5: 0x0000000000000000   x6: 0x0000000000000000   x7: 0x0000000000000000
    x8: 0x00000000fffffbbf   x9: 0x0000000000000000  x10: 0x0000000000000010  x11: 0x0000000000000000
   x12: 0x0000000000001000  x13: 0x0000000000000000  x14: 0x0000000000000000  x15: 0x0000000000000048
   x16: 0xffffffffffffffe1  x17: 0x00000001bd81df1c  x18: 0x0000000000000000  x19: 0x0000000000000000
   x20: 0x0000000000000000  x21: 0x000000000000aa07  x22: 0x00000000000010bc  x23: 0x000000016b1058a8
   x24: 0x0000000000000003  x25: 0x00000000000000b4  x26: 0x0000000000000003  x27: 0x00000001d5327f98
   x28: 0x000000016b105828   fp: 0x000000016b105880   lr: 0x00000001aebdcd0c
    sp: 0x000000016b105830   pc: 0x00000001aebdd908 cpsr: 0x80000000
   esr: 0x56000080  Address size fault

bertt avatar Sep 05 '21 08:09 bertt

From console logs kernel fault messages:

IOReturn IOGPUDevice::new_resource(IOGPUNewResourceArgs *, struct IOGPUNewResourceReturnData *, IOByteCount, uint32_t *): PID 59429 likely leaking IOGPUResource (count=55000)
IOReturn IOGPUDevice::new_resource(IOGPUNewResourceArgs *, struct IOGPUNewResourceReturnData *, IOByteCount, uint32_t *): PID 59429 likely leaking IOGPUResource (count=56000)
IOReturn IOGPUDevice::new_resource(IOGPUNewResourceArgs *, struct IOGPUNewResourceReturnData *, IOByteCount, uint32_t *): PID 59429 likely leaking IOGPUResource (count=60000)

count=60000 is the last one recorded.

bertt avatar Sep 05 '21 08:09 bertt

If you set UseGPU=false for MapControl before it is created and test it again, the crash happens too?

charlenni avatar Sep 05 '21 09:09 charlenni

Do we have a memory problem? You create at each drawing process hundreds of Polygons. They are never reused. Perhaps a dictionary would be helpful to store the already created Polygons? I don't know, if SkiaSharp interface stores some pointers to such structures.

charlenni avatar Sep 05 '21 09:09 charlenni

In moment we refresh the MapControl each time we get a new position for the map, because this generates a refresh. Now think about what could happen when you move around the map. We get in the range of sub ms new refresh's. Each of them generates a new bunch of Polygons, only to through them away a few microseconds later.

charlenni avatar Sep 05 '21 09:09 charlenni

In moment we refresh the MapControl each time we get a new position for the map, because this generates a refresh. Now think about what could happen when you move around the map. We get in the range of sub ms new refresh's. Each of them generates a new bunch of Polygons, only to through them away a few microseconds later.

This is inefficient wrt performance but if there is no memory leak this should not crash the app.

pauldendulk avatar Sep 06 '21 07:09 pauldendulk

Perhaps we add some more logging of thing related to memory use. Perhaps:

Logger.Log(LogLevel.Debug, $"Memory after rasterizing layer {GC.GetTotalMemory(true):N0}");

And there may be a way to request memory or feature use in SkiaSharp.

pauldendulk avatar Sep 06 '21 07:09 pauldendulk

If you set UseGPU=false for MapControl before it is created and test it again, the crash happens too?

With UseGPU = false the crash does not occur. So it seems to be related to drawing a lot of graphics on SKGLView (GPU) and not with SKCanvasView (CPU). This SkiaSharp issue is quite related https://github.com/mono/SkiaSharp/issues/1683

bertt avatar Sep 06 '21 21:09 bertt

I tried to get some more informations, but didn't find anything except the issue of SkiaSharp you mentioned.

I assume, that this is a problem with the deprecated OpenGL on iOS. Perhaps we have to wait until SkiaSharp uses Metal as backend (perhaps in 2.88.x?). Until than, setting UseGPU=false on iOS should do the trick. But I don't have an idea about the performance loose.

charlenni avatar Sep 08 '21 08:09 charlenni

Maybe we can force UseGPU=false when building for iOS (so people don't have to know about the UseGPU flag when building for iOS).

#if __IOS__
UseGPU=false
#endif

About performance: in my case I didn't notice any performance loss when using UseGPU = false

bertt avatar Sep 08 '21 08:09 bertt

BTW did you test the same with the Mac version of Mapsui.Forms?

charlenni avatar Sep 08 '21 08:09 charlenni

BTW did you test the same with the Mac version of Mapsui.Forms?

No, so far only on IPhone

bertt avatar Sep 08 '21 08:09 bertt

I don't know, how much this reduces the performance and reaction on iOS. The smartphone's runtime could also be affected.

So it would be better, if this isn't a default change.

charlenni avatar Sep 08 '21 08:09 charlenni

This reply indicates that just drawing will eventually crash the app. I'd say we should always worse performance over crash. Also it will most users will be unaware of it and find out late after te release of their app. So often it will not be their conscious choice.

@Sebastian1989101 Are you using GPU on iOS? Encountered such a problem?

pauldendulk avatar Sep 10 '21 09:09 pauldendulk

A Minimal, Reproducible Example might helpt to get this resolved. This sample could be without Mapsui.

pauldendulk avatar Sep 10 '21 09:09 pauldendulk

Checks had to be:

  1. Do you get it with MapControl too?
  2. Do you get it with the native iOS MapControl too?
  3. Could you reproduce the problem with a SKGLView without Mapsui?

charlenni avatar Sep 10 '21 11:09 charlenni

Why?

  1. If it is a problem with MapView, then it could be a problem if removing/adding the layers
  2. If it is a problem with the MapControl of Forms, then it could be a problem with the Forms components of SkiaSharp
  3. The same as 2.

charlenni avatar Sep 10 '21 11:09 charlenni

@Sebastian1989101 Are you using GPU on iOS? Encountered such a problem?

@pauldendulk if UseGPU = true was always the default in Mapsui 2.0, then it was also set this way in my apps on iOS. But now, I did not encounter this bug yet even with ~13000 data points on the map seperated in ~150 layers. I only had lags when changing the layer collection but nothing else and I tested my apps on multiple devices before each release (iPhone 4S on iOS 9.0 as the oldest). However I just checked the logs for that specific app and there are 67 crashes with a pretty similar crash log to this one with ~52000 daily active users average over the last 30 days, that does not seems to be that impactful. But maybe I also trigger to few redraws from changes.

Sebastian1989101 avatar Sep 10 '21 12:09 Sebastian1989101

@Sebastian1989101 Okay thanks. That means it is not as serious as I feared. It could also depend on the kind of feature that is drawn. Bert's sample uses geometries, perhaps you use mainly points.

pauldendulk avatar Sep 10 '21 14:09 pauldendulk

@pauldendulk yes, most of my thinks are points. Only a few LineString's are used. However I can recreate the issue from the linked SkiaSharp issue with the memory. If I set UseGPU = false the app uses less memory and more consistant compared to UseGPU = true. I can't say much about the performance for the latest release tho because I still use my local modified version currently (because without the mass edits of the LayerCollection the loading is just too long on changes in this app).

Sebastian1989101 avatar Sep 10 '21 14:09 Sebastian1989101

If anyone feels like it we could create a minimal reproducible sample and post it in skiasharp.

pauldendulk avatar Sep 26 '21 08:09 pauldendulk

GPU does not work on all platforms. We tried to set sensible defaults (selecting individual platforms). If not the user can override it with MapControl.UseGPU = false;

pauldendulk avatar Jun 23 '23 20:06 pauldendulk