kineapps / flutter_archive

Flutter plugin for creating and extracting ZIP files.
https://pub.dev/packages/flutter_archive
BSD 3-Clause "New" or "Revised" License
59 stars 44 forks source link

Performance issues on very old iOS devices #1

Closed PDDStudio closed 2 years ago

PDDStudio commented 4 years ago

Hello,

I'm developing a flutter application which is doing some unzip operations. It's nothing special, basically just unzipping files and placing them on the desired location. The files that I'm unzipping are typically between 50-150MB (zipped) and 150-450MB (unzipped).

At first, I was implementing the unzipping logic in plain flutter using the archive package. During testing, I recognized that the library isn't able to extract larger zip files on low memory devices. It starts unzipping but doesn't check its memory consumption until the system decides to kill the application because it's using too much RAM.

This is where your package comes into play. I was looking around and found it quite new on pub.dev - so I gave it a try.

Once I replaced the components and started testing with your package, I was amazed that on Android everything runs smoothly and without any noticeable UI/input lags.

Then I started testing on iOS and recognized a few things.

Before going into details, here are some benchmarks I took:

Test Scenario & Benchmark

Target File: 145MB ZIP file (450MB once extracted)

The goal is to extract the archive using flutter_archive

iPad Air 2013

On the old iPad Air 2013, the unzip operation for the ZIP file took about 20mins. During this time the CPU was constantly at 100%. Avg. read speed: 1MB Chunks every 3-5 seconds Avg. write speed: 0.3MB/s

-> This results in very low memory consumption (which is very nice) but takes a way too long to unzip the archive.

iPad Air 3 (2019)

On the newer iPad Air 3, the unzip operation for the ZIP file took about 5mins. During this time the CPU was as well at 100% (constantly). Avg. read speed: ~ 4MB Chunks every 3-5 seconds Avg. write speed: ~ 2MB/s

-> Same results as with the iPad Air 2013 (regarding memory). But still took a way too long to unzip.

Issue

Once I evaluated the problems I mentioned above I started looking into the source code of your package. The Android implementation looks good to me. For the iOS implementation, it seems like you're using ZipFoundation.

Is there a way to somehow configure the read/write chunk size of the archives? AFAIK the library allows you to configure the chunk size which it uses to read/write data.

Could you by any chance check if it's possible to adjust the chunk size and add additional parameters to your implementation to be able to customize these things?

This would be really appreciated. If you need further information from my side, please let me know.

Regards!

kinex commented 4 years ago

Thanks for your detailed issue report and interesting benchmarks!

I assume you run those tests with a release build, right? 20 minutes or even 5 minutes sounds like a terrible long time.

In the plugin version 0.1.1 Android implementation was already using background threads, but iOS code had not been optimized yet. It was using UI thread for zipping/unzipping which is of course a very stupid thing to do (did not cause any remarkable issue in my own app though). But I fixed this in the version 0.1.2. Difficult to say without testing if this effects the zipping/unzipping duration though. Could you please test it again?

I can also add configuration options for the buffer sizes if needed, but it would require some bigger changes. Default buffer size used by ZipFoundation seems to be 16KB.

PDDStudio commented 4 years ago

Hello @kinex,

Thank you for the fast reply and the new release version. The benchmark was done with debug builds, but I can also redo the same tests with profile/release builds. I'll test version 0.1.2 now and will report back to you in the next few hours.

Thanks for your time & effort!

kinex commented 4 years ago

I would not be worried about performance issues in a debug build. It must be tested with release/profile build. It would be also quite surprising if the used library ZipFoundation is slow with the default parameters. Well, anything is of course possible. Let me know your new test results when you have one.

PDDStudio commented 4 years ago

Okay, so I finished my benchmarks with the new version 0.1.2.

I was using the same ZIP archive as before.

This time I tested it on 3 different devices:

I also did the benchmark with both build flavors - "debug" and "release".

iOS Background Processing

I can confirm that the new (background processing) implementation works now on iOS as well, without freezing the UI anymore. 👍

Benchmark Results (debug)

iPad Air 3 (2019)

Idle RAM Usage: 270 MB RAM Unzipping RAM Usage: 888 MB RAM (max) Unzip Time: 21 sec. (completed successfully)

Idle CPU Usage: 0% Unzipping CPU Usage: max. 100%

=> Memory & CPU usage is fine

iPad Air 2013

Idle RAM Usage: 284 MB RAM Unzipping RAM Usage: 650 MB (average) -> +700MB max Unzip Time: (Out of Memory Exception) 1min 8sec

The problem here is that the max RAM usage is "limited" to 700MB. The other 300MB is used by other resources/system processes. It seems like the zip library (?) is not taking care of the max RAM usage at all. It keeps consuming RAM until the system decides to kill the app with an OOM exception. (I try to attach screenshots showing the RAM usage spikes)

=> CPU usage is fine. RAM usage is a problem. The result seems not very reliable because sometimes it gets above the 700 MB "line" & crashes and sometimes it can keep its memory consumption below 700MB which results in a successful unzip operation.

iPhone 6S

Idle RAM Usage: 240MB RAM Unzipping RAM Usage: 870MB RAM (max) Unzip Time: 29 sec. (completed successfully)

Idle CPU Usage: 0% Unzipping CPU Usage: 100% (avg) / 110% (max)

=> Memory & CPU usage is fine

Benchmark Results (release)

iPad Air 3 (2019)

Idle RAM Usage: 255MB RAM Unzipping RAM Usage: 550-600MB RAM (avg) / 810MB RAM (max) Unzip Time: 24 sec. (completed successfully)

Idle CPU Usage: 0% Unzipping CPU Usage: 90% (avg) / 100% (max)

=> Memory & CPU usage is fine

iPad Air 2013

Idle RAM Usage: 202MB RAM Unzipping RAM Usage: 580MB RAM (avg) -> +700MB max Unzip Time: (Out of Memory Exception) 53sec.

=> The memory usage / OOM Exception here is caused by the same problem I mentioned above.

iPhone 6S

Idle RAM Usage: 150MB RAM Unzipping RAM Usage: 750MB RAM (max) Unzip Time: 32 sec. (completed successfully)

Idle CPU Usage: 0% Unzipping CPU Usage: 100% (max)

=> Memory & CPU usage is fine

Conclusion

On mid- to high-end devices, everything seems to be fine (though adjusting the chunk size would be a nice-to-have feature for increasing performance on devices that can handle bigger loads). The only real problem seems to be unzipping archives on low-end devices (e.g the iPad Air 2013 with only 1GB RAM).

The current situation for me is now basically the same as I had with the archive package.

Is this something you would further investigate? I don't know whether you can handle RAM usage on your side while still using the ZipFoundation library. Maybe creating an issue there might help?

Looking forward to your reply.

Best Regards

PDDStudio commented 4 years ago

For some reasons GitHub won't let me attach the screenshot. Hopefully this works:

kinex commented 4 years ago

Thanks for the new benchmarks!

There is probably not much I can do on the plugin side to reduce memory usage. Let me know if you have any ideas. One idea that came into my mind is trying to use a lower priority thread to see if it consumes less memory (would be slower though).

Maybe you could make some benchmarks using directly the ZipFoundation library and add a new issue in that repository if needed. I can always update to the latest available native library.

I will enhance the plugin API in a future update adding more configuration options etc.

emreesen27 commented 4 years ago

I have the same problem. A process that takes 5-6 seconds on Android takes minutes to ios.

!!! The problem is experienced in large pdfs.

kinex commented 4 years ago

I fixed the issue title as it was misleading.

As an additional note. please do not make any performance tests with debug builds. There is heavy logging in debug builds and code is not optimized. Only benchmark tests with release builds are useful.

kinex commented 4 years ago

@emreesen27 If it takes few seconds in Android and 3-4 minutes in iPhone 11 as you claim (using a release build) then something is badly wrong.

Please share a sample file to reproduce the issue if possible. Or at least list the file contents (file types and uncompressed/compressed sizes).

kinex commented 2 years ago

Closing this, please reopen if you find some serious performance issues with a release build.