赞
踩
在这个部分,我们将对几种主要的跨平台语言进行比较,主要从执行效率、引入testcase前后app体积变化、运行内存峰值和运行内存的overhead这几个方面进行考察。
对比的平台在iOS、AndroidOS、HarmonyOS这三个平台上进行测试,由于不同平台的硬件设备无法做到一致,所以我们会在各平台选一款设备作为测试标准。
对比的语言在目前bilibili实际生产环境中使用到的语言,分别为Kotlin、JavaScript、Dart、C++、Swift。
关于测试集,考虑到真实研发场景在研发过程中其实多数在于Model的操作,又由于bilibili大多使用grpc作为通信协议,积累了较多的真实业务场景的protobuf文件, 所以我们会使用这些proto文件作为测试集,并以最常见的序列化&反序列化作为测试用例,分别在这几种语言上进行测试。在本文中选取了当前B站的较常使用的一组protobuf, .proto个数为237个, .proto体积为2.2MB的测试集。
1. 基于每个平台 X 每种测试语言的环境构造测试工程
拥有最基本的调用testcase的UI及统计能力。
防止testcase自身的依赖被strip,最基简单的对应的protobuf的序列化反序列化的调用。
部分语言的工程环境支持多平台,例如Flutter、Kotlin Multiplatform等我们会在多平台使用同一份测试工程。
2. testcase 构造
基于以下protoc插件生成对应语言代码,在这我们假设各个protoc compiler尽可能以最优的方式生成代码。
语言 | 编译器 | protoc compiler | 备注 |
---|---|---|---|
Kotlin | 1.9.23 | 基于streem/pbandk自研 | |
TypeScript | / | bufbuild/protobuf-es | 在只可运行JS runtime的环境中通过 webpack(mode=production)进行打包 |
Dart | 3.3.3 | protocolbuffers/protobuf | |
C++ | Apple clang version 15.0.0 (clang-1500.1.0.2.5) | protocolbuffers/protobuf |
我们自研了测试中的所有语言的testcase的protoc插件,通过这个插件我们可以生成每个proto文件对应的序列化反序列化的testcase,具体行为为遍历所有的Message, 并构造这个Message,后序列化成ByteArray后再反序列化回去。在各语言构造对应protobuf的序列化反序列化代码举例如下:
- // fission.proto 对应的 cpp 测试模块
- namespace bilibili_::account_::fission_::v1_::fission_::proto {
-
- template<typename Message>
- inline void TestMessage() {
- auto str = Message().SerializeAsString();
- auto msg = Message().ParseFromString(str);
- }
-
- inline void Test() {
- TestMessage<::bilibili::account::fission::v1::EntranceReq>();
- TestMessage<::bilibili::account::fission::v1::EntranceReply>();
- TestMessage<::bilibili::account::fission::v1::AnimateIcon>();
- TestMessage<::bilibili::account::fission::v1::WindowReq>();
- TestMessage<::bilibili::account::fission::v1::WindowReply>();
- TestMessage<::bilibili::account::fission::v1::PrivacyReq>();
- TestMessage<::bilibili::account::fission::v1::PrivacyReply>();
- }
- }
- // fission.proto 对应的 kotlin 测试模块
- @file:OptIn(ExperimentalSerializationApi::class)
-
- package bilibili_account_fission_v1_fission
-
- import kotlinx.serialization.*
- import kotlinx.serialization.protobuf.*
- import kotlinx.serialization.protobuf.ProtoBuf.*
- import com.bapis.bilibili.account.fission.v1.*
-
- fun doTest() {
- ProtoBuf.decodeFromByteArray<KEntranceReq>(ProtoBuf.encodeToByteArray(KEntranceReq()))
- ProtoBuf.decodeFromByteArray<KEntranceReply>(ProtoBuf.encodeToByteArray(KEntranceReply()))
- ProtoBuf.decodeFromByteArray<KAnimateIcon>(ProtoBuf.encodeToByteArray(KAnimateIcon()))
- ProtoBuf.decodeFromByteArray<KWindowReq>(ProtoBuf.encodeToByteArray(KWindowReq()))
- ProtoBuf.decodeFromByteArray<KWindowReply>(ProtoBuf.encodeToByteArray(KWindowReply()))
- ProtoBuf.decodeFromByteArray<KPrivacyReq>(ProtoBuf.encodeToByteArray(KPrivacyReq()))
- ProtoBuf.decodeFromByteArray<KPrivacyReply>(ProtoBuf.encodeToByteArray(KPrivacyReply()))
- }
- import Foundation
- import SwiftProtobuf
-
- fileprivate func testMessage<T:SwiftProtobuf.Message>(type: T.Type) {
- let message = T()
-
- do {
- let encoded = try message.serializedData()
- let decoded = try T(serializedData: encoded)
- } catch {
- print("Error: \(error)")
- }
- }
-
- func testBilibiliPmmsV1PmmsProto() {
- testMessage(type: Bilibili_Pmms_V1_GetPullMessagesReq.self)
- testMessage(type: Bilibili_Pmms_V1_GetPullMessagesResponse.self)
- testMessage(type: Bilibili_Pmms_V1_Position.self)
- testMessage(type: Bilibili_Pmms_V1_ControlParams.self)
- testMessage(type: Bilibili_Pmms_V1_Message.self)
- }
构造TestEntry入口,收集并调用刚才生成所有的TestCase代码。
3. 编译&链接&运行
在各个平台上Cpp上编译&链接参数分别为-Os -fvisibility=hidden -fvisibility-inlines-hidden -dead_strip
其他语言基本使用默认的Release编译方式
由于Dart runtime和Flutter engine绑定较深,所以我们直接使用flutter并使用Dart aot进行测试
由于Android平台并没有原生系统自带的JsRuntime,故我们在iOS中使用的是JavaScriptCore ,在Harmony中使用的是默认的ArkRuntime
由于精力有限我们并没有测试Flutter在鸿蒙的数据表现
4. 通过各个平台的Profile工具进行数据的人工收集
标
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/959134
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。