A question about the throughput of mojo(JS to C++, sync call)

465 views
Skip to first unread message

Guanru Lee

unread,
Jan 12, 2023, 3:19:29 AM1/12/23
to chromi...@chromium.org

Hello chromium-mojo folks!


I am working on a prototype to send some video frames from JS to native C++ through mojo but encountered a throughput problem, here is the situation:

  1. Get a MediaStreamVideoTrack from a webRtcConnection

  2. Fetch video frames through MediaStreamTrackProcessor from webRtcConnection

  3. Send the frames from JS to native C++ through mojo(3.2 MB per frame, sync call)

  4. Found native C++ only can receive 4~5 frames per second which means the throughput is about 12 ~ 16MB


Assuming I want to send 30 fps frames(3.2MB per frame) from JS to native C++, I would need 96 MB throughput but it seems the sync call doesn’t have the bigger enough throughput.


Here are some of my questions, it would be very helpful if I can get some suggestions from the team :)

  • I am not sure my testing result of throughput is correct. May I know what is the throughput of a mojo sync call to send data?

  • If it is a real limitation of sync call(JS to C++), do I have other options? For example I found Data Pipes but it seems only for C++, not sure I can use Data Pipes from JS to C++ and how?

  • How about using WebScoket as an IPC between JS and C++? I also found websocket.mojom but I'm not sure if it is appropriate and possible to communicate between JS and C++. 

 

Any help would be much appreciated!

Thanks.


K. Moon

unread,
Jan 12, 2023, 5:14:29 PM1/12/23
to Guanru Lee, chromi...@chromium.org
Is there a reason you need synchronous calls? That's going to require an IPC round trip, which is always going to be slow.

--
You received this message because you are subscribed to the Google Groups "chromium-mojo" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-moj...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-mojo/CAOvTs4syz0aGiyoHL6FCTjojSS%3D-fkSWCeyGFQZGAwvP01x17A%40mail.gmail.com.

Ken Rockot

unread,
Jan 12, 2023, 5:50:54 PM1/12/23
to Guanru Lee, chromi...@chromium.org
On Thu, Jan 12, 2023 at 12:19 AM 'Guanru Lee' via chromium-mojo <chromi...@chromium.org> wrote:

Hello chromium-mojo folks!


I am working on a prototype to send some video frames from JS to native C++ through mojo but encountered a throughput problem, here is the situation:

  1. Get a MediaStreamVideoTrack from a webRtcConnection

  2. Fetch video frames through MediaStreamTrackProcessor from webRtcConnection

  3. Send the frames from JS to native C++ through mojo(3.2 MB per frame, sync call)

  4. Found native C++ only can receive 4~5 frames per second which means the throughput is about 12 ~ 16MB


Assuming I want to send 30 fps frames(3.2MB per frame) from JS to native C++, I would need 96 MB throughput but it seems the sync call doesn’t have the bigger enough throughput.


Throughput is not related to whether a call is sync or async. Transferring this much data over normal Mojo IPC messages is strongly discouraged and will never perform well!


Here are some of my questions, it would be very helpful if I can get some suggestions from the team :)

  • I am not sure my testing result of throughput is correct. May I know what is the throughput of a mojo sync call to send data?


Every Mojo IPC today is ultimately doing some basic platform-specific I/O under the hood -- we send the data over a socket or named pipe or Mach port. Theoretical throughput is here ~= memory throughput: message data is copied into one buffer, and back out into some other buffer. In practice throughput is much less due to kernel buffering limitations and scheduling latency.

For example on Linux or Android today if you try to send 3 MB in a Mojo IPC, Mojo will completely fill the I/O buffers between the two processes with as much of that data as possible -- nowhere near the full 3 MB, probably more like 128 kB -- while the remainder be retained by the sender until there's more socket capacity. The receiver will eventually wake to read the first 128 kB, and then the kernel will eventually wake the sender again to have it send more data. This round-trip will repeat several more times until all of your outgoing data is flushed into the IPC transport.

  • If it is a real limitation of sync call(JS to C++), do I have other options? For example I found Data Pipes but it seems only for C++, not sure I can use Data Pipes from JS to C++ and how?


You can use data pipes in JS! Data pipes can be created by Mojo.createDataPipe(). You can send the consumer handle over a mojom method that takes a handle<data_pipe_consumer>, and you can call writeData() on the producer handle it to transfer large amounts of data to the consumer:

    // Create a data pipe with a 4 MB buffer and send the consumer to service
    let {producer, consumer} = Mojo.createDataPipe({elementNumBytes: 1, capacityNumBytes: 4 * 1024 * 1024});
    myService.addFrameStream(consumer);

    // This is very lightweight compared to sending the data directly through a Mojo interface
    let {result, numBytes} = producer.writeData(frameData);  // can be an ArrayBuffer, Uint8Array, etc etc

The result code meanings for writeData here are equivalent to the MojoWriteData C API, so you can detect e.g. when the buffer is full and you need to wait to submit more data.

  • How about using WebScoket as an IPC between JS and C++? I also found websocket.mojom but I'm not sure if it is appropriate and possible to communicate between JS and C++. 


WebSocket is implemented using Mojo IPC and data pipes. There's a ton of other support around WebSocket details though and I don't think this would be an appropriate use of the API.
 

 

Any help would be much appreciated!

Thanks.


Guanru Lee

unread,
Jan 12, 2023, 6:23:45 PM1/12/23
to Ken Rockot, chromi...@chromium.org
Thank you for the detailed and clear explanation, I will try Data pipes. Thanks!
Reply all
Reply to author
Forward
0 new messages