-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Sending data to an isolate locks the main thread for some time #31960
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Currently there is almost 0 data sharing between isolates. The data is sent by copying - which means you need to copy the whole 100MB between isolates. Dart VM has support for external typed data - it can be passed between isolates without copying, but APIs for allocating such typed data are not exposed to the Dart code. |
This reduces the jank of bringing up the license screen further. The remaining lost frame or two are caused by Dart itself, see: dart-lang/sdk#31954 dart-lang/sdk#31959 dart-lang/sdk#31960 Fixes flutter#5187
One thing we could do is mark the buffer as frozen as soon as it is sent, then copy it on a different thread, and on the main thread, if we ever try to edit a frozen buffer, then do the copy (maybe only copying one page, and using a page table to indirect accesses into the buffer, if we find that this is common). So long as we document that once you've sent a buffer, you should never mutate it again or you'll pay a high copy cost, that would be fine. Most buffers aren't likely to be edited anyway, they'll be obtained from data and then processed into other data. In any case, sending immutable data has the same problem. Change String data = ''.padLeft(toIsolateSize, '\0'); ...and the numbers are actually worse:
Notice the occasional ~80ms delays, and the increased round-trip time, even though the data is theoretically the same. It's probably twice as big since Dart uses UTF-16 strings. Halving the size of the data being sent brings the overall overhead down to the 8ms range on my device (still too high, you'd skip frames at 120Hz) and the round-trip time is still higher, ~200ms instead of ~120ms. Also the occasional 80ms delays becomes 36ms delays. In this example, though, the data is immutable so the overhead should be zero (mark the string as busy, send a pointer to another thread, have it copy the data, receive a control message back saying the copy is done, mark the string as no longer busy so it can be GC'ed, moved, or whatever). |
Under the hood VM uses one-byte storage for Latin1 strings (which LICENSE is) and two-byte storage for everything else that does not fit into Latin1.
Well, that's not that trivial. If string was allocated in young space you can't just pin it - young space in the current GC design must be fully evacuated by the GC, so you'll have to pause young space GCs until all pinned data is moved out which will introduce some jank. Though if large objects are allocated on it's own pages then things become easier because those we can certainly pin. |
This reduces the jank of bringing up the license screen further. The remaining lost frame or two are caused by Dart itself, see: dart-lang/sdk#31954 dart-lang/sdk#31959 dart-lang/sdk#31960 Fixes #5187
seems to be related to #31959 |
This reduces the jank of bringing up the license screen further. The remaining lost frame or two are caused by Dart itself, see: dart-lang/sdk#31954 dart-lang/sdk#31959 dart-lang/sdk#31960 Fixes flutter#5187
cc @mkustermann |
@lrhn should we consider surfacing APIs in Dart to allow allocation of external typed data supported by the VM in Dart code. |
@a-siva fwiw as a workaround you already can allocate external typed data through FFI - you can allocate memory and then use |
The following little flutter program creates an isolate, and times how long the main thread locks while sending a 100MB of zero bytes to an isolate. It does this by having a timer run continuously on the main thread, timing how long since it last ran, and printing any time that it took more than 5ms between invocations ("since last checkin"). If the main thread is never locked, this should never print anything. At the same time, in a Future-mediated loop on the main thread, it sends a 100MB ByteData buffer of zeros to the isolate, then awaits a response, and prints the total round-trip time.
The isolate merely runs a Future-mediated loop that waits for a message, then sends a single byte back.
For flutter, what matters is primarily that the total overhead of sending something to a thread is small (small single-digits of milliseconds at most, ideally microseconds). Total round-trip time is only of academic interest so long as it's not measured in minutes.
Here is some representative output for this script running on a Pixel XL 2. The total overhead for sending 100MB to another isolate appears to be in the double-digit millisecond range, which means that sending 100MB to another isolate guarantees that the application will miss a frame.
See also #31959, which is a much more serious problem with receiving data taking double-digit milliseconds.
The text was updated successfully, but these errors were encountered: