Skip to content
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

[WASM] How to read from SharedArrayBuffer? #46016

Closed
ivan-prodanov opened this issue Dec 13, 2020 · 3 comments
Closed

[WASM] How to read from SharedArrayBuffer? #46016

ivan-prodanov opened this issue Dec 13, 2020 · 3 comments

Comments

@ivan-prodanov
Copy link

ivan-prodanov commented Dec 13, 2020

Context: My react app is accessing a large dataset from a worker using a SharedArrayBuffer. I'd like to process the SharedArrayBuffer in C# with minimal overhead. I have a hard time converting the SharedArrayBuffer to a Span in C#.
Here's what I tried:

public static int TestSum(SharedArrayBuffer sharedArrayBuffer)
{
    Int32Array array = new Int32Array(sharedArrayBuffer);
    Span<int> nativeArray = array; // error                        
    
    int sum = 0;
    for (int i = 0; i < nativeArray.Length; i++)
    {
        sum += nativeArray[i];
    }

    return sum;
}

This unfortunately fails with "Object '...' is not a typed array" in js_typed_array_to_array.

Here's the function from dotnet.js:

js_typed_array_to_array : function (js_obj) {
	if (!!(js_obj.buffer instanceof ArrayBuffer && js_obj.BYTES_PER_ELEMENT)) 
	{
		var arrayType = js_obj[Symbol.for("wasm type")];
		var heapBytes = this.js_typedarray_to_heap(js_obj);
		var bufferArray = this.mono_typed_array_new(heapBytes.byteOffset, js_obj.length, js_obj.BYTES_PER_ELEMENT, arrayType);
		Module._free(heapBytes.byteOffset);
		return bufferArray;
	}
	else {
		throw new Error("Object '" + js_obj + "' is not a typed array");
	} 

I was able to workaround this by changing

if (!!(js_obj.buffer instanceof ArrayBuffer && js_obj.BYTES_PER_ELEMENT)) 

to

if (!!(js_obj.buffer instanceof (ArrayBuffer, SharedArrayBuffer) && js_obj.BYTES_PER_ELEMENT)) 

Now the code executes with no errors, however there's a copying operation being done in mono_typed_array_new. Doesn't that make the whole idea behind using a SharedArrayBuffer in order to avoid copying useless?

Is this the proper way to process a SharedArrayBuffer? Is there a way to process it without copying the data?

@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added area-System.Buffers untriaged New issue has not been triaged by the area owner labels Dec 13, 2020
@ghost
Copy link

ghost commented Dec 13, 2020

Tagging subscribers to this area: @tannergooding, @pgovind
See info in area-owners.md if you want to be subscribed.

Issue Details

Context: My app loads mono wasm in a worker thread. The worker thread is accessing large data from another thread using a SharedArrayBuffer. The worker thread where the mono wasm is loaded is supposed to pass the shared array buffer to the C# code.

I have a hard time converting the SharedArrayBuffer to a Span in the C# code, here's what I tried:

public static int TestArrSum(SharedArrayBuffer sharedArrayBuffer)
{
    Int32Array array = new Int32Array(sharedArrayBuffer);
    Span<int> nativeArray = array;                        
    
    int sum = 0;
    for (int i = 0; i < nativeArray.Length; i++)
    {
        sum += nativeArray[i];
    }

    return sum;
}

This unfortunately fails with "Object '...' is not a typed array" in s_typed_array_to_array. Here's the code of the function:

js_typed_array_to_array : function (js_obj) {
	if (!!(js_obj.buffer instanceof ArrayBuffer && js_obj.BYTES_PER_ELEMENT)) 
	{
		var arrayType = js_obj[Symbol.for("wasm type")];
		var heapBytes = this.js_typedarray_to_heap(js_obj);
		var bufferArray = this.mono_typed_array_new(heapBytes.byteOffset, js_obj.length, js_obj.BYTES_PER_ELEMENT, arrayType);
		Module._free(heapBytes.byteOffset);
		return bufferArray;
	}
	else {
		throw new Error("Object '" + js_obj + "' is not a typed array");
	} 

I was able to workaround this by changing the code in dotnet.js from

if (!!(js_obj.buffer instanceof ArrayBuffer && js_obj.BYTES_PER_ELEMENT)) 

to

if (!!(js_obj.buffer instanceof (ArrayBuffer, SharedArrayBuffer) && js_obj.BYTES_PER_ELEMENT)) 

Now the code executes with no errors, however there's a copying operation being done in (mono_typed_array_new) which makes the whole thing of using a SharedArrayBuffer useless.

How can we process a SharedArrayBuffer in C# without copying and interops on each byte?

Author: ivan-prodanov
Assignees: -
Labels:

area-System.Buffers, untriaged

Milestone: -

@lewing lewing added this to the 6.0.0 milestone Dec 13, 2020
@lewing lewing removed the untriaged New issue has not been triaged by the area owner label Dec 13, 2020
@lewing lewing modified the milestones: 6.0.0, Future Dec 13, 2020
@kjpou1
Copy link
Contributor

kjpou1 commented Jan 4, 2021

@ivan-prodanov this is still not possible as per the WebAssembly design open issue: WebAssembly/design#1162. This is also for shared array buffers.

You might be able to use the heap itself and design something that will fit your needs. There are issues with holding onto memory addresses and should not be done long term. Emscripten during memory allocation can issue warning about the memory buffer being released and no longer accessible. Error maybe encountered: Attempting to access detached ArrayBuffer in WASM after memory growth. detached ArrayBuffer and avoid copy

There is some old code here that attempts to use memory pointers. It is for strings but the concepts are the same:

https://github.com/kjpou1/Mono.Wasm.Samples/tree/master/WasmString

The Program.cs still interacts with javascript via memory pointers being passed back and forth. The Index.html file has the javascript routines. This is old code written against the mono repo and older version of bindings but the concepts are still the same.

Thank you for reporting the issue you ran into. We will take a look at it and get a fix out as soon as possible.

@kjpou1
Copy link
Contributor

kjpou1 commented Jan 6, 2021

I am going to close this as there is nothing we can do about this issue. Issue #46624 was opened to track the bug that was reported along with description.

@kjpou1 kjpou1 closed this as completed Jan 6, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Feb 5, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants