Platform Channel VS FFI (Foreign Function Interface) on Flutter on Linux

Introduction

Flutter, a cross-platform framework, There is a mechanism called Platform Channel for calling the Native function of each platform from the application. You can call Java / Kotlin on Android and Obj-C / Swift on iOS.

On the other hand, there is also a mechanism called dart: ffi for calling C / C ++ functions from the application. FFI is an abbreviation for Foreign Function Interface, which is a mechanism to call the C / C ++ language from Dart.

Now, Flutter on Linux runs (currently) as a GTK app. In other words, the process called by Platform Channel is also described in C / C ++ language (see here for details).

Therefore, the performance when processing large data in C / C ++ language I compared Method Channel, which is one of the Platform Channels, with FFI.

Conclusion

Under the conditions measured this time, if data conversion between Dart and C is required, There was no significant difference between Method Channel and FFI.

On the other hand, if you don't need data conversion, use asTypedList for FFI. You can reduce the number of data copies while accessing from both sides of Dart / C. Of course, the larger the data size, the greater the effect, and under the measurement conditions this time, the FFI was about 100 times faster.

At least if you need to exchange large amounts of data between Dart-C It seems better to consider whether FFI can be designed to reduce the number of copies.

environment

I experimented in the following environment. The operating platform of Flutter is linux.

$ grep 'model name' /proc/cpuinfo | uniq -c
      8 model name	: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
$ grep MemTotal /proc/meminfo 
MemTotal:       32752704 kB
$ uname -a
Linux chama 5.5.8 #1 SMP Sat Mar 7 22:29:22 JST 2020 x86_64 x86_64 x86_64 GNU/Linux
$ lsb_release -d
Description:	Ubuntu 18.04.5 LTS
$ flutter --version
Waiting for another flutter command to release the startup lock...
Flutter 1.24.0-8.0.pre.143 • channel master • https://github.com/flutter/flutter
Framework • revision e4d94f7ccd (2 hours ago) • 2020-11-07 12:15:22 +0100
Engine • revision 1e3ceb037f
Tools • Dart 2.12.0 (build 2.12.0-27.0.dev)

Measurement result

I measured the time to memset the buffer secured on the Dart side on the C / C ++ side and return it to the Dart side. The program used for the measurement is published on here. I have tried 4 types of implementation.

--Implementation 1. Method Channel --Implementation 2. FFI (convert data between Dart-C) --Implementation 3. FFI (Share buffer between Dart-C using asTypedList) --Implementation 4. FFI (holds buffer only in C format)

The measurement results of the four mounting methods are as follows. The horizontal axis is the size of the buffer to be memset, and the vertical axis is the time taken (1000 times average). You can see that Implementation 3 / Implementation 4 without data copy is significantly faster than Implementation 1 / Implementation 2 with data copy.

release.png

Each time when 8MB memset is done is as follows. For convenience, it is displayed in [us] units, but I think there is a measurement error at least in the last two digits.

Implementation time[us]
Implementation 1. Method Channel 23,182
Implementation 2. FFI (Dart-Convert data between C) 21,616
Implementation 3. FFI (asTypedListUsingDart-SharebufferbetweenC) 251
Implementation 4. FFI (Hold buffer only in C format) 261
[reference]Full C implementation 274

For reference, the result of debug version is as follows. Implementation 2 (FFI (with data conversion between Dart-C)) takes significantly longer than the release version. It is considered that the AOT of the data conversion process described in Dart is working. As you can see, it changes a few times lightly, so don't forget to use the release version when measuring performance with Flutter. (You can launch the release version with flutter run --release)

debug.png

At the end

The result was expected to some extent, but I'm glad that I was able to know the asTypedList by implementing it, and I could feel the effect of the release version on my skin.

In the result of the release version, the linearity is clearly and meaningfully broken at 512KB, but the reason is unknown (it is reproducible). I think it's unlikely that my implementation bug is happening in both MethodChannel and FFI, but ... I would like to find out the reason in my spare time.

I haven't tried it this time, but I think it is theoretically possible to exchange the buffer address secured by ffi with MethodChannel. I have already implemented related processing in MethodChannel, but some of them have to exchange large data. In such a case, I think there may be such a choice. (I think it's necessary to think about whether MethodChannel is really good because it will be cross-platform.)

Flutter on Linux Desktop is an alpha version, and dart: ffi is a beta version. Not to mention the performance, the implementation on the Platform side may change, such as GTK, so please forgive me.

reference

MethodChannel class - services library - Dart API dart:ffi library - Dart API Is it possible to get pointer of Uint8List instead of allocating then copy · Issue #31 · dart-lang/ffi

Recommended Posts

Platform Channel VS FFI (Foreign Function Interface) on Flutter on Linux
Flutter platform channels for Linux
Disable IPv6 on network interface on CentOS Linux 8