copy / v86

x86 PC emulator and x86-to-wasm JIT, running in the browser
https://copy.sh/v86/
BSD 2-Clause "Simplified" License
19.53k stars 1.35k forks source link

Feature Request - Linux - 9PFS over WebSockets #1072

Closed evonox closed 2 days ago

evonox commented 1 month ago

Is there any plan to implement downloading 9PFS chunks over WebSockets? If not, I offer I will make this little contribution. I need faster response time of the hosted Ubuntu.

copy commented 1 month ago

I'd accept a PR if it demonstrates performance benefits over loading with regular http requests.

You'll need decompression and the browser's gzip decompression is very fast. v86 has a zst decompressor in wasm (which runs in a worker, see https://github.com/copy/v86/blob/21f5b0581f94147aa40b1de504907c04255a2307/src/browser/starter.js#L610), but it's currently not used for 9pfs. A good starting point would be making zst decompression work for the 9pfs The zst decompression doesn't do streaming decompression right now. It takes 1-2ms per 1mb chunk, which could be hidden behind the download if it was done in chunks parallel to the download (see https://gist.github.com/jfsiii/034152ecfa908cf66178?permalink_comment_id=4217928#gistcomment-4217928)

evonox commented 1 month ago

As for the performance benefit, we will certainly save some overhead of TCP hand-shaking. WebSockets are permanent TCP connections. I am however afraid if we will not waste this latency savings using GZIP decompression in WebWorkers. I will use socket.io library for this feature as well as the clustered NodeJS server supporting multiple CPU cores. Possibly I am thinking of using Deno instead of NodeJS later on.

evonox commented 1 month ago

@copy I tried the websocket download of BIN files without any significant performance gain. Some performance gain is however visible when the whole image file-system is preloaded in the standard browser Cache API. I created a Service Worker that intercepts browser fetch events and saves the BIN files to the Cache API. This also reduces the required number of HTTP requests upon the server. In case of interest I will paste here the Service Worker code.

evonox commented 1 month ago

@copy I have also the idea, that we may not uncache the files from MemoryStorage immediately, but make them dirty and remove after some time in case of the user of the OS will request these files in short time again. What do you think? The problem is the Cache API still has some latency.

copy commented 1 month ago

@evonox That does sound reasonable, but keep in mind that OSes also try to minimise disk accesses by keeping filesystem data cached, so I wouldn't usually expect the same file to be downloaded twice in a short timespan.

In the case of 9pfs (which is technically a network filesystem), it might be a matter of configuring linux so that it is aware that it has exclusive access and doesn't need to reload files. I have looked into that a while ago, but can't remember the best configuration now (and it might have changed).

SuperMaxusa commented 1 month ago

This also reduces the required number of HTTP requests upon the server.

IIRC files should be already cached in browser' disk cache after first loading (in normal XHR HTTP behavior).

evonox commented 1 month ago

It is quite true, you can set the cache behavior in window.fetch function. I am not sure now, if the emulator is using window.fetch or the old XMLHttpRequest API. On the other hand I do not know if the cached files survive the browser session. The new Cache API powered by Service Workers survive browser sessions. This behavior is very critical for my use case.

evonox commented 1 month ago

As for the caching file system in Linux OS, you must compile kernel with fscache driver module, what was not my case. I recompiled the kernel with the this support but I am not still successful yet with it.

SuperMaxusa commented 1 month ago

I recompiled the kernel with the this support but I am not still successful yet with it.

Did you set a rootflags=trans=virtio,cache=fscache in kernel parameters or that not work? (see https://landley.net/kdocs/Documentation/filesystems/9p.txt)

I am not sure now, if the emulator is using window.fetch or the old XMLHttpRequest API.

According to source code, it's XMLHttpRequest: https://github.com/copy/v86/blob/5435c2f8c428b587ad78d37a649580a7cb75fed0/src/browser/filestorage.js#L103-L107 https://github.com/copy/v86/blob/5435c2f8c428b587ad78d37a649580a7cb75fed0/src/lib.js#L551-L555

On the other hand I do not know if the cached files survive the browser session.

Usually this should be controlled by server headers: https://web.dev/articles/http-cache#overview, https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#caching_static_assets. If take look on WebSocket implementation - yes, only the Cache API is option in this case.

copy commented 2 days ago

Let's close this issue, but feel free to propose any caching changes.