Hummer: Why Hummer?

Hummer: Why Hummer?

preface

In January of this year, we opened source Hummer, a lightweight cross-end technology framework that is widely used within Didi. In order to respond to the expectations of the community partners, we did a multi-dimensional comparison test on Hummer’s overall performance, so that we could have a deeper understanding of Hummer.

Before that, let’s briefly introduce several relatively mature cross-end frameworks in the industry at present:

  1. ReactNative. ReactNative is a mobile cross-end development framework based on the React ecosystem officially opened by Facebook in 2015. It aims to achieve the following goals in mobile development: “Learn once, Write Anywhere”, the number of stars on GitHub is 94K at present. Facebook officials have been focusing on its construction and maintenance, and the community is highly active.
  2. Weex. Weex is a mobile terminal cross-end development framework based on Vue ecology opened source by Alibaba in 2016. The goal is to achieve the following goals in mobile terminal development: “Write Once, Run Everywhere”, ali donated it to Apache Foundation at the end of 2016. Later, it almost stopped maintaining it for various reasons, and the open source community gradually became cold. Currently, the number of stars on GitHub is 14K.
  3. Flutter. Flutter is a new mobile cross-platform development framework that Google announced at I/O 2017. The most notable features of Flutter are the Skia rendering engine and rendering controls that replace the controls on both ends of the system, providing platform consistency and performance. At present, the number of Star on GitHub has reached 117K. It is a cross-side development project maintained by Google and the community is very active.

Hummer established its own positioning and direction from the very beginning. We aim to create a cross-end development framework with a smaller package size, higher overall performance, and more robust styling support. Like Hummer’s name, hummingbird has a small, light body, fast, powerful wings, and colorful appearance.

Smaller package volume

Hummer originated from didi’s internal converged cashier SDK. Its core business scenarios and Didi’s strict package volume standards require us to polish Hummer’s package volume to the extreme.

We also did in-depth research and exploration, including cutting JavaScriptCore engine and investigating other small SIZE JS engines, etc. Finally, we chose JavaScriptCore as the JS engine of iOS. QuickJS is the JS engine for Android.

JavaScriptCore is an Apple open source embedded JS engine used in WebKit. Here we’ll focus on QuickJS.

QuickJS is an embedded JS engine released by Bellard in 2019. With only a few C files, QuickJS is fully functional, supports the ES2020 specification, and has even better syntax support than V8. You might be interested in how well it performs and how stable is it? QuickJS benchmarks and Test262 test results show that the performance and stability of the engine is not poor, and it is generally above average among all JS engines. After a comprehensive evaluation, we chose QuickJS as Hummer’s default JS engine on Android.

When it comes to Android, a lot of people think that JavaScriptCore is not a V8 engine. V8 does exist in every Android system that has Chromium WebView built in, but V8 is too tightly tied to WebView, unlike iOS, where JavaScriptCore is packaged into a system library that can be called by all apps. As a direct result, to use V8, developers still have to package it by source code, which will seriously affect the size of the App package, so it was not considered.

In addition, we simplify the dependence on JS engine features for the ultimate package size experience, and implement a set of abstract JS engine interfaces to smooth out the implementation differences of various JS engines. After our extreme optimization, Hummer can even share the JS engine with other cross-end frameworks to handle complex business and technical scenarios without worrying too much about the additional cost and stress of package size.

The following is a comparison of the total size of Release packages generated by a pure App in the mode of single architecture (Android: Armeabi-V7A, iOS: ARM64) after being connected to each cross-end framework:

Test version

  • Hummer (Android) : ‘com. Didi. Hummer: Hummer: 0.3.18’
  • Hummer (iOS) : 0.2.3
  • ReactNative: ‘com. Facebook. React: react – native: 0.63.4’
  • Weex: ‘com. Taobao. Android: weex_sdk: 0.26.0’
  • Flutter: 1.22.6

The test code

Github.com/OrangeLab/h…

The test results

platform Native Hummer ReactNative Weex Flutter
Android 2.5 M 4.2 M 8.5 M 6.9 M 5.2 M
iOS 0.097 M 0.697 M 1.2 M 0.997 M 5.9 M

Higher overall performance

Hummer, as a cross-end solution based on a JS engine, is often noted for its overall performance. One of the first questions our partners often ask when selecting a product is, how does Hummer compare to the H5 in a native App or WebView? What are the performance advantages compared to other cross-end frameworks that already exist in the industry?

In order to better measure the overall performance of Hummer, we have established a set of quantitative indicators in addition to the subjective feelings of users.

On the mobile terminal, we generally measure the overall performance of an App by page rendering time, CPU, memory and frame rate. The following is a comprehensive performance comparison test for each cross-end frame based on these four indicators and using test cases in four different scenarios. Four tests are used for example:

  • Use case 1: Long list benchmark (Scroller). 500 row views in the list, each row containing 5 subviews, to test the performance of quickly sliding through the list.
  • Use case 2: Long List benchmarks. 1000 row views in the list, each row containing 5 subviews, to test the performance of quickly sliding the entire list.
  • Use case 3: Animation benchmark. 500 views, each doing one of 5 animations, to test the performance of all animations executed simultaneously.
  • Use case 4: Drag benchmark test. Tests the performance of dragging and dropping a view across the screen.

In the long List of scene test, we tested the two types of long List, one is a delegate with Scroller no reuse type long List view, how many how many view data source will be created, another is a delegate with a List of reusable long List view, no matter how many data sources, forever will only create a view in the range of the visible screen number, These views are reused during list scrolling to improve performance and reduce memory footprint.

Animation and drag and drop, both of which are rich interaction, have high performance requirements. Their performance can directly affect the user experience, so we use two use cases to test the performance of animation and drag and drop respectively.

For these four use cases, we have tested the performance of the above four indicators on Android and iOS devices respectively. Due to the differences of Android and iOS systems, the test methods are slightly different. Here is how we tested the four indicators on these two systems respectively:

The Android side:

  1. Page rendering time

On Android, you can run the AM command to directly start a page in the App, and then run the Logcat command to filter out the log containing the “Displayed” string to view the time it took to start a page, that is, the page rendering time. However, Hummer, ReactNative and Weex, three apps with cross-end frameworks, all display pages by remotely loading JS, which will affect the statistics of page rendering time. Therefore, all apps are started by loading local JS. ReactNative and Weex use progressive page rendering. After the first frame of the page has been started and rendered (i.e., after the “Displayed” log has been printed), the elements in the actual page have not been rendered. Therefore, for their page rendering time statistics, You need to calculate the page rendering time with the Displayed log and the page rendering completion callback. Where ReactNative page render completion callback is JS side componentDidMount method, Weex page render completion callback is native side onRenderSuccess method. 2. CPU and memory The Android terminal can directly detect the USAGE of CPU and memory by using the profile tool built-in in AndroidStudio, but only for the debug version of the application. In order to make the test data as accurate as possible, Both tests were performed using the Release version of the App, so we chose to examine CPU and memory data using Tencent’s PrefDog tool. Frame rates can also be measured using PrefDog, but we have found that in some scenarios, especially animation-related scenarios, the PrefDog test does not provide PrefDog with an accurate result, so we have ended up using the Android dumpsys gfxinfo command to measure frame rates. If dumpsys gfxinfo is enabled in Developer Options of the Android OS, you can run adb shell dumpsys gfxinfo on the CLI to print the latest 120 frames. The actual frame rate can be approximated by using the formula: FPS = actual frames /(actual frames + extra sync pulses) * 60, where “extra sync pulses” refers to the total number of frames exceeding 16.67ms in one frame within the 120 frames.

The iOS side:

  1. Page rendering time

IOS page rendering time does not distinguish between first-time and non-first-time, because iOS doesn’t necessarily make a cold startup even after killing the app, so there is no longer a distinction between first-time and non-first-time. IOS uses the App Launch in Instruments and logs to analyze the startup time. The formula is as follows: Startup time = Premain time + rendering time, where: Render time = render end timestamp – appdelegate. DidFinishLaunching begin timestamp. Since ReactNative and Weex adopt a progressive page rendering method, after the page is started and the first frame is rendered, the elements in the actual page are not really rendered. Therefore, for their page rendering time statistics, they need to calculate the page rendering time together with the startup time and the page rendering completion callback. Where ReactNative page render completion callback is JS side componentDidMount method, Weex page render completion callback is native side onRenderSuccess method. 2. CPU and memory The iOS server can use The Instruments to collect CPU and memory statistics. However, the Instruments is not friendly to exported statistics and it is difficult to calculate the average over a period of time. As a result, we have also chosen to examine CPU and memory data using the PrefDog tool. On iOS, we also do not use PrefDog to examine frame rates, for the same reason that on Android, animation Hitches from Instruments is used on iOS to analyze frame rates. According to WWDC: A frame that appears on the screen later than expected; Stutter rate: stutter time/total frame time; Lag time: the total amount of time the image frame is delayed to be displayed on the screen; The hitch rate can be divided into three categories: – <5 ms/s, sliding smoothly; – 5-10 ms/s, image frames will be discarded every few seconds, slight lag; – > 10 ms/s, image frames are frequently discarded and severely stuck;

Specific test conditions and results are as follows:

The test model

Android

  • System: Android 10
  • Model Number: Vivo X27 Pro-V1836A
  • Vivo ROM: Funtouch OS_10 PD1836_a_6.20.1

iOS

  • System: iOS 14.4
  • Model: iPhoneX

Test version

  • Hummer (Android) : ‘com. Didi. Hummer: Hummer: 0.3.18’
  • Hummer (iOS) : 0.2.3
  • Tenon: 1.2.1
  • Weex: ‘com. Taobao. Android: weex_sdk: 0.26.0’
  • ReactNative: ‘com. Facebook. React: react – native: 0.63.4’
  • Flutter: 1.22.6

Use case code

Github.com/OrangeLab/h…

Use case page

Home page Case 1 Use case 2 Use case 3 Use case 4

(Take the use case page of Native Project as an example)

The test results

On both Android and iOS, Hummer and Tenon’s overall performance is pretty close to native performance, which shows Hummer’s strength.

Android

Case 1 (Scroller) Native Hummer Tenon ReactNative Weex Flutter
Page rendering time (first, MS) 741 1835 2617 1664 2834 862
Page rendering time (not first, MS) 590 1560 2182 1508 2579 568
CPU(%) 7.53 10.72 10.69 11.7 10.11 9.94
Memory (M) 114.89 133.45 137.94 167.8 178.5 210.17
Frame rate (FPS) 58 50 51 47 49 31
Use case 2 (List) Native Hummer Tenon ReactNative Weex Flutter
Page rendering time (first, MS) 334 387 559 545 3477 535
Page rendering time (not first, MS) 170 215 335 368 3238 215
CPU(%) 4.07 4.85 6.85 14.43 5.08 10.44
Memory (M) 58.14 64.62 70.48 173.89 224.08 152.38
Frame rate (FPS) 60 60 60 58 60 59
Use Case 3 (animation) Native Hummer Tenon ReactNative Weex Flutter
Page rendering time (first, MS) 345 641 1044 778 1881 538
Page rendering time (not first, MS) 195 385 730 636 1394 224
CPU(%) 14.27 15.48 15.3 33.31 17.22 18.58
Memory (M) 86.9 88.97 102.53 118.75 102.56 172.28
Frame rate (FPS) 30 30 30 31 29 30
Use Case 4 (drag and drop) Native Hummer Tenon ReactNative Weex Flutter
Page rendering time (first, MS) 253 310 342 425 396 514
Page rendering time (not first, MS) 168 175 183 287 185 213
CPU(%) 3.03 5.19 6 7.51 5.96 6.94
Memory (M) 55.55 63.16 66.5 102.17 66.57 142.21
Frame rate (FPS) 60 60 59 60 60 60

iOS

Case 1 (Scroller) Native Hummer Tenon ReactNative Weex Flutter
Page rendering time (ms) 1727 1970 2249 2358 1694 806
CPU(%) 1.73 2 2 5.45 3.18 8.18
Memory (M) 116 149 156.27 177.27 144 125.18
Caton rate (ms/s) 1.667 1.667 1.668 1.678 1.668 0
Use case 2 (List) Native Hummer Tenon ReactNative Weex Flutter
Page rendering time (ms) 469 545 684 975 4141 608
CPU(%) 3.36 5.64 5.82 18.45 9.91 8.27
Memory (M) 9.36 21.18 23.55 88.36 91.55 91.82
Caton rate (ms/s) 0 0 4.16 7.59 3.419 2.902
Use Case 3 (animation) Native Hummer Tenon ReactNative Weex Flutter
Page rendering time (ms) 773 905 1131 1353 1535 655
CPU(%) 1.55 2 1.91 30.55 6.73 8.45
Memory (M) 6 13 17.27 26 56.73 81.73
Caton rate (ms/s) 0 0 0 0 0 0
Use Case 4 (drag and drop) Native Hummer Tenon ReactNative Weex Flutter
Page rendering time (ms) 539 563 578 922 545 708
CPU(%) 2 5.55 6.18 7.55 7.18 5
Memory (M) 5 10 12 14 16 54
Caton rate (ms/s) 0 0 0 0 0 0

More robust style support

Hummer already has excellent consistency at both ends if it’s just client-side development. However, full support for front-end styles can maximize the current large and complete front-end ecosystem to rapidly expand Hummer’s application scenarios and improve historical compatibility.

While ReactNative tries to maintain the design principles of Native features, it provides two different apis for certain features. Hummer insists on the design principle of keeping the consistency of both ends as far as possible, and adopts the style consistent with the Web ecology to ensure the consistency of both ends and realize the high compatibility of the front-end ecology.

Hummer currently uses Flexbox layout. In addition to other commonly used CSS styles, Hummer has a good alignment of the two ends. Here are some typical CSS styles for comparison:

Functional description CSS styles Hummer ReactNative Weex
The box model box-sizing border-box border-box border-box
layout position relative

absolute

fixed
relative

absolute
relative

absolute

fixed
The background color background-color support support support
The background image background-image support support support
Plain border & rounded corners border-style

border-color

border-width

border-radius
support support support
Single side border & rounded corners border-left-width

border-top-left-radius
support Only View components are supported The arc transition is not smooth
shadow shadow support Android and iOS are two sets of APIS and UI effects, respectively Android does not support
The stacked sequence z-index support support Does not support
Content of the overflow overflow support support Android does not support

In contrast to RN and Weex, Hummer has been designed with style priorities in mind, and has experimented extensively in this area. Hummer is currently in internal beta and will be released in a future release.

In addition to the usual CSS style comparisons, there are some more common property comparisons, such as:

Functional description Hummer ReactNative Weex
The rich text support support support
GIF figure support Android does not support it by default Android does not support it by default
Accessibility function support support Part of the support

Richer animation

In terms of animation implementation, Hummer uses an abstract animation API to enable developers to achieve a variety of complex animation effects with high consistency at both ends.

Here’s how we compare the animation performance of each cross-end frame:

Functional description attribute Hummer ReactNative Weex
Animation API Based on the animation support support support
The frame of animation support Does not support Does not support
The animation properties duration support support support
delay support support support
easing support support support
repeatCount support support Does not support
repeatMode Android support

The iOS development
Does not support Does not support
CSS style animation transition support Does not support support

Other aspects

Hummer in addition to the package size, performance, style and animation has not a small advantage, in other aspects also has good performance, the following we support the front-end ecology and the overall characteristics of the framework have also done a simple comparison, you can feel Hummer from multidimensional comparison performance.

Front-end ecological support

Hummer’s support for the front-end framework is friendly, currently supported to Vue3.0, and support for Act16 + is in full development.

Tenon ReactNative Weex
Vue3.0 support Does not support Does not support
React16+ In the support support Does not support

Overall frame characteristics

Hummer ReactNative Weex Flutter
Framework complexity Very light The heavier The lighter Very heavy
To fit the difficulty easy higher general higher
Applicable scenario Whole App or single page The whole App Single page The whole App
Community maturity Just started, under construction Mature, Facebook focus maintenance Donated to Apache and no longer maintained Mature, Google focus on maintenance

conclusion

In summary, although Hummer is a relatively young cross-end technology solution, its overall performance has been very competitive. If you are interested, you can try it on a small scale in your own project and evaluate the effect. If you have any problems in the process of use, please give us feedback through our official QQ communication group. At the same time, we also welcome you to actively give us issues and PRs on GitHub. We will follow up and deal with it as soon as possible.

Contact us

Hummer GitHub github.com/didi/Hummer Benchmark GitHub github.com/OrangeLab/h… QQ communication group: 851327307 wechat official account: Didi OrangeLab

The team members

Zhang Danfeng: Principal of Hummer, focusing on the overall technical construction and community maintenance of Hummer framework. Fan Yuandong: core member of Hummer, mainly responsible for the overall architecture design of Hummer framework. Shi Guangyuan: A core member of Hummer, mainly responsible for the iOS development of Hummer framework. Tang Jiacheng: Core member of Hummer, mainly responsible for the iOS development of Hummer framework. Duan Likang: A core member of Hummer, mainly responsible for the design and development of Tenon framework. Enze Cao: A core member of Hummer, responsible for the design and development of Tenon framework.

read

Didi Open Source Lightweight Cross-end Development Framework: Hummer