grpc-swift icon indicating copy to clipboard operation
grpc-swift copied to clipboard

Reduce framework size

Open Banck opened this issue 3 years ago • 19 comments

Hello. We are using grpc in project, which has App Clip,so that’s why we care about the size of the application (there is limit of 10 mb of uncompressed app). grpc integration (via spm) increased uncompressed app size by about 6.5 mb. Maybe there are any solutions to reduce framework size? Thanks.

Banck avatar Dec 14 '21 19:12 Banck

Can I recommend stripping the app binary? Much of the size is likely to be symbols, and these can easily be removed by stripping them. Otherwise, you can try enabling -Osize optimizations. Beyond that, there are no ways to reduce binary size in SwiftPM.

Lukasa avatar Dec 15 '21 09:12 Lukasa

-0size doesn't help. It reduced app clip size from 9.4 mb to 9.3 mb) Would't like to use a proxy for the grpc in App Clip, but grpc integration increases size a lot(

Banck avatar Dec 16 '21 08:12 Banck

Tried switch from SPM to Cocoapods and AppClip uncompressed size increased from 9.4 mb to 11.5 mb 😨

If change use_frameworks! to use_modular_headers! uncompressed size will be 8.4 mb.

Banck avatar Dec 17 '21 05:12 Banck

Have you tried stripping the binary?

Lukasa avatar Jan 04 '22 09:01 Lukasa

Have you tried stripping the binary? I have bitcode, Strip linked product, Dead code Stripping enabled. I've tried enable Strip debug symbols during copy for main target and app clip target, but app size didn't change.

App clip size with bitcode, Strip linked product, Dead code Stripping enabled: App Thinning Size Report Supported variant descriptors: Universal

  1. Cocoapods with use_modular_headers! App size: 3,9 MB compressed, 8,9 MB uncompressed

  2. SPM image

a) [-O] App size: 4,3 MB compressed, 9,9 MB uncompressed

b) Swift compiler: [-Osize], Apple clang Optimization level: [-0s] App size: 4,3 MB compressed, 9,8 MB uncompressed

c) Swift compiler: [-Osize], Apple clang Optimization level: [-0z] App size: 4,3 MB compressed, 9,8 MB uncompressed

Don't know what can I do else to reduce grpc lib size

Banck avatar Jan 11 '22 06:01 Banck

Thanks @Banck. Can you run the analyze_code_size.py script from Swift against your app clip and provide the output here? The invocation is probably something like: analyze_code_size.py -categorize <path/to/your/binary>.

Lukasa avatar Jan 11 '22 09:01 Lukasa

Thanks @Banck. Can you run the analyze_code_size.py script from Swift against your app clip and provide the output here? The invocation is probably something like: analyze_code_size.py -categorize <path/to/your/binary>.

  1. Cocoapods Cocoapods.txt
  2. SPM SPM.txt

Banck avatar Jan 11 '22 16:01 Banck

Hah, sorry, can you remove the symbol stripping before you do this? That data is not all that useful without the symbols, as all we can tell is that we're using the code size mostly with code.

I also want to point out apple/swift-protobuf#1204.

Lukasa avatar Jan 11 '22 17:01 Lukasa

Hah, sorry, can you remove the symbol stripping before you do this? That data is not all that useful without the symbols, as all we can tell is that we're using the code size mostly with code.

I also want to point out apple/swift-protobuf#1204.

Disabled Bitcode and applied these settings: image

  1. Cocoapods: App size: 6,4 MB compressed, 24,1 MB uncompressed Cocoapods.txt

  2. SPM image

App size: 7 MB compressed, 26,3 MB uncompressed SPM.txt

let me know if I did something wrong or if something needs to be done additionally. Thank you

Banck avatar Jan 11 '22 18:01 Banck

I also want to point out apple/swift-protobuf#1204.

When I wrote the first message, I measured app size, then integrated grpc with 1 simple proto file, and measured again. The size difference was around 6.5 mb.

Banck avatar Jan 11 '22 18:01 Banck

Is it possible for you to compare with only the impact from swift-protobuf? I'd like to isolate how much is grpc-swift. Keep your .proto files the same, but don't generate the grpc sources, only the regular protobuf ones?

Lukasa avatar Jan 11 '22 18:01 Lukasa

Is it possible for you to compare with only the impact from swift-protobuf? I'd like to isolate how much is grpc-swift. Keep your .proto files the same, but don't generate the grpc sources, only the regular protobuf ones?

I measured app size with bitcode and stripping and integrated grpc via SPM: App size: 4,3 MB compressed, 9,9 MB uncompressed

Then removed all services, generated before and generated only models via comand: protoc *.proto --swift_out=../Common/Models/Network/GRPC

  1. Commented all my code related with services. Commented import GRPC in files: App size: 4,3 MB compressed, 9,8 MB uncompressed

  2. removed GRPC from spm a) added NIO, NIOHTTP2, Logging and protobuf: image

App size: 3,1 MB compressed, 7,1 MB uncompressed

b) added these libs:

image

App size: 3,3 MB compressed, 7,5 MB uncompressed

Banck avatar Jan 11 '22 19:01 Banck

And sure, only with SwiftProtobuf: App size: 2,1 MB compressed, 4,3 MB uncompressed

Banck avatar Jan 12 '22 04:01 Banck

Ok, so based on those numbers, the big code size contributor appears to be NIO. This is not necessarily a huge surprise to me: NIOPosix is a particularly large library. Can you clarify: is your project directly importing and depending on NIO, or on NIOCore?

Lukasa avatar Jan 12 '22 10:01 Lukasa

For my own future reference:

  • Protobuf only: 2.1 MB compressed, 4.3 MB uncompressed
  • Protobuf, NIO, NIOHTTP2, Logging: 3.1 MB compressed, 7.1 MB uncompressed
  • All extra libraries including grpc: 3.3 MB compressed, 7.5 MB uncompressed

This sure implies that NIO is the bulk of the weight. NIOCore should not be that heavy, but NIOPosix may well be.

Lukasa avatar Jan 12 '22 10:01 Lukasa

Yes, I do import NIO and import NIOCore in my services, because grpc returns EventLoopFuture and I working with it, which is part of swiftNIO.

Banck avatar Jan 12 '22 13:01 Banck

For my own future reference:

  • Protobuf only: 2.1 MB compressed, 4.3 MB uncompressed
  • Protobuf, NIO, NIOHTTP2, Logging: 3.1 MB compressed, 7.1 MB uncompressed
  • All extra libraries including grpc: 3.3 MB compressed, 7.5 MB uncompressed

This sure implies that NIO is the bulk of the weight. NIOCore should not be that heavy, but NIOPosix may well be.

7.5 mb - it's without grpc. Grpc with all dependecies(nio, protobuf): App size: 4,3 MB compressed, 9,8 MB uncompressed

Banck avatar Jan 12 '22 14:01 Banck

@Banck It's part of SwiftNIO, but we recently split the NIO module up into three modules: NIOCore, NIOEmbedded, and NIOPosix. This is because for iOS apps, NIOPosix is not really necessary, but it still costs code size.

Now, unfortunately grpc itself still requires NIOPosix. We don't really have great tools for making that functionality conditional at the moment, so it's extremely hard to remove.

Lukasa avatar Jan 12 '22 16:01 Lukasa

I've noticed, that through SPM I can install grpc without swift-nio-ssl, cause Package.swift contains:

let includeNIOSSL = ProcessInfo.processInfo.environment["GRPC_NO_NIO_SSL"] == nil
.package(
    url: "https://github.com/apple/swift-nio-ssl.git",
    from: "2.14.0"
  ),
  if: includeNIOSSL

And this allowed us to reduce the size of the application by 1.5 mb from App size: 4,8 MB compressed, 11,3 MB uncompressed to App size: 4 MB compressed, 9,8 MB uncompressed

If install grpc through cocoapods app size is App size: 4,2 MB compressed, 10 MB uncompressed

I just wonder how can install grpc through cocoapods also without swift-nio-ssl ?

Banck avatar Jun 16 '22 06:06 Banck