-
Notifications
You must be signed in to change notification settings - Fork 30.2k
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
Documentation: Should have Addons documentation easily findable, should explain how to use a Typed Array in C++ that is given as a parameter #883
Comments
-0.5 from me for the reason that doc/api/addons.markdown is not a V8 primer. Interacting with typed arrays is not in any way specific to io.js. Adding a section on typed arrays would be incongruous because we don't explain how objects or object templates work either. |
I'm not asking for an explanation of how V8 works (although links to V8 documentation helps with that). More like a simple how-to, with some example code that shows use of a typed array within a C++ plugin. The addon documentation does have code that features objects and object templates, but I'm looking at this from the perspective of how to get something specific done using io.js rather than explaining V8. It would help myself and others get started with higher performance code that's usable within the io.js framework, enabling better plugins to be written. |
At least 2 things we can do to make documentation better:
|
Maybe swap the v8 docs link to point to v8-dox from @thlorenz? https://thlorenz.github.io/v8-dox/build/v8-3.25.30/html/ |
@Qard I can release a version that only shows public API. The one linked is for understanding v8 internals and pretty much includes everything. So quite daunting when getting started. We could then run an update script similar to this one regularly every time a new v8 version is used in io.js. |
@bnoordhuis Do you know how a Typed Array would be accessed from a V8 plugin? For me it's still mysterious after having looked further at the V8 documentation. The following code does not work - can you please advise on how it should be done?
I understand your concern about not having the io.js documentation cover things that are not strictly part of the io.js project. It occurred to me that a more interactive documentation page could help solve it. There would be a code sample on one side of the page, with mouse-overs that explain parts of the code in more detail, and present references to the V8 documentation. |
I'm interested in making some tutorial pages that explain in more detail about writing addons with C++, I'm a beginner at C++ but good at front-end development. Would anyone here be interested in helping me write such a tutorial? It will be different to the existing tutorials in that the screen will have 2 parts: Code on the left: User can click or mouse over certain parts of the code At first glance the tutorials would be quick to read through for advanced users, while beginners to the V8 and iojs addon system will have access to a lot more information. Also, what would people think about hosting such a tutorial on iojs, if it were to be done? If anyone wants to help make such a tutorial, it could be considered by more iojs stakeholders for inclusion on the iojs website once it's made. If I were to get help with the C++ (ie providing content for the tutorial) I would expect a fairly short turnaround in making the page(s) - maybe 3 days or so. |
if (args[0]->IsFloat32Array()) {
Local<Float32Array> array = args[0].As<Float32Array>();
for (size_t i = 0, n = array->Length(); i < n; i += 1)
array->Set(i, Number::New(array->GetIsolate(), 1.0f / i));
// or:
Local<ArrayBuffer> buffer = array->Buffer();
ArrayBuffer::Contents contents = buffer->Externalize();
float* data = static_cast<float*>(contents.Data());
for (size_t i = 0, n = array->Length(); i < n; i += 1)
data[i] = 1.0f / i;
// ...
delete[] reinterpret_cast<char*>(data);
} Note that when you externalize the ArrayBuffer, you're responsible for freeing it. Sadly, the externalization API is currently rather awkward in that it forces you to know about the implementation detail of how the memory is allocated (with |
@bnoordhuis Thanks, that's very interesting. I'll see what I can do with it. There is quite a lot that I don't understand at first glance. Of course that's got to do with the limitations of my knowledge rather than the quality of what you provided. What do you think about helping me to write a tutorial that explains this stuff? |
@metabench you can use |
@bnoordhuis I managed to read the values of the Float32Array with the following code:
would not compile, so I changed it to float*, is that correct? Also, are the two lines at the top of the function (isolate and handle scope) necessary? |
@vkurchatkin would you provide a code sample please? |
Create you array in js like this: var smalloc = require('smalloc');
var data = smalloc.alloc(100, smalloc.Types.Float); Then you can use data as a container. It doesn't have length property so you need to keep track of it. In C++: Local<Object> obj = args[0].As<Object>();
if (obj->HasIndexedPropertiesInExternalArrayData()) {
int length = obj->GetIndexedPropertiesExternalArrayDataLength();
float* data = static_cast<float*>(obj->GetIndexedPropertiesExternalArrayData())
} P.S. this also should work if data (in JS) is a typed array, but it is undocumented |
I now have a version that can modify a Float32Array. It's required removing a line from the @bnoordhuis example. Without that line removed, void ReadTypedArray(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = Isolate::GetCurrent();
HandleScope scope(isolate);
cout << "args.length " << (args.Length()) << endl;
if (args.Length() == 1) {
Local<Float32Array> array = args[0].As<Float32Array>();
Local<ArrayBuffer> buffer = array->Buffer();
ArrayBuffer::Contents contents = buffer->Externalize();
float* data = static_cast<float*>(contents.Data());
for (size_t i = 0, n = array->Length(); i < n; i += 1) {
data[i] = data[i] + 1;
}
//delete[] static_cast<float*>(data);
}
} If I still plan on using the Float32Array in JavaScript, is there still anything I need to do to clear up anything done within the addon? Also, I'm interested in the most efficient ways of doing this, so if anyone has any input on what is the fastest code to use then please let me know. |
Sorry, that should have been a reinterpret_cast. I'll update the example.
|
@vkurchatkin, smalloc definitely looks like a promising way of going about things. It would avoid having to use V8 typed arrays in the C++ part at all. It's rare that someone avoids answering a question yet still answers it very well! My goal is really to get high performance access to data structures within JavaScript and C++, I had assumed typed arrays would be the way to go about it because that's what I had been using in JavaScript. I have a question about it though - you say that it does not keep track of the length so that needs to be done separately. However, in the C++ code I see you use |
@bnoordhuis using reinterpret_cast still causes the TypedArray, which was given as a parameter within JavaScript, to be deleted (or harmed somehow, deleted may not be exactly what's going on). I use the following test code: var ta_test = new Float32Array(4);
ta_test[0] = 1;
ta_test[1] = 2;
ta_test[2] = 3;
ta_test[3] = 4;
addon.read_typed_array(ta_test)
console.log('ta_test', ta_test); Is |
What I mean is the length is not exposed to JS. Internally V8 keeps track of it. If you need to know length in JS, you can simply attach |
It's necessary to have this SOMEWHERE, otherwise memory would leak. |
That does sound difficult, in that it would need to know when the JavaScript part is done with it. I would prefer all memory management to be done in C++ and not have to use JavaScript to tell C++ when it's finished. How could that best be written in C++ to take place automatically? |
I suspect keeping track of the length as a separate property would be at least as efficient. I'd need to see some benchmarks that attaching the length property to the object would be the right way of doing it. It seems likely to be slower as it would be rearranging an object's structure. |
@thlorenz and I were just discussing today the need to update https://v8docs.nodesource.com/ to include V8 docs for the io.js version(s) |
That's one common usage of
I've benchmarked this ad nauseam. The constructor incurs a small (meaning, measurable in nanoseconds) overhead, but it doesn't have any effect afterwards. Just make sure you attach the object properties before attaching the memory. Like so: var smalloc = require('smalloc');
var foo = {};
foo.length = 16;
smalloc.alloc(16, foo, smalloc.Types.Uint32); |
@trevnorris It's very good to know that adding the length property does not get in the way of V8 optimizations. With that code sample you just provided, is foo then usable as an array of Uint32? I've been having trouble getting this to work with the much appreciated example from @bnoordhuis and my own research. I've realised that execution stops when it does |
@trevnorris, also do you know if smalloc would work with NAN? |
@metabench Don't cleanup the memory yourself. GC will take care of it. And yes, it then becomes a usable uint32 external array. |
@trevnorris I'm having success reading from input smalloc arrays using the code @vkurchatkin provided. I've also found using NAN convenient with casting to a type that's simple in C++. I've succeeded in returning normal JavaScript arrays using NAN. I'm now trying to return a smalloc object. I've looked at the smalloc source code and have noticed changes between node and iojs... do you think that's going to make a difference for making a smalloc object? |
@metabench Don't believe so. |
@trevnorris how would I make the smalloc in iojs addon C++? I can't yet understand it from the source code unfortunately. |
So the v8 doxygen docs have been updated. Here is the io.js 1.2 one documenting v8 |
@metabench Until #905 lands it can only be done from JS. When it does land look at |
I also posted an issue at nodejs/node-v0.x-archive#9247
It would be useful if writing of addons was shown at a much higher level within the documentation. I don't even know where it exists within the io.js documentation (or node either). I've used Google to find information on writing addons.
Specifically, I'd like to make use of a Float32Array that has been given to a C++ function in an addon. Advice on this would be appreciated, but it's worth having in the docs too.
The text was updated successfully, but these errors were encountered: