Skip to content

Documentation: Should have Addons documentation easily findable, should explain how to use a Typed Array in C++ that is given as a parameter #883

Description

@metabench

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.

Activity

  1. bnoordhuis commented on Feb 18, 2015

    @bnoordhuis
    Member

    -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.

  2. metabench commented on Feb 18, 2015

    @metabench
    Author

    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.

  3. vkurchatkin commented on Feb 18, 2015

    @vkurchatkin
    Contributor

    At least 2 things we can do to make documentation better:

    1. mention that using Nan is a good idea
    2. remove link to v8 documentation on @isaacs site, because it is 3 year old
  4. Qard commented on Feb 18, 2015

    @Qard
    Member

    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/

  5. mscdex commented on Feb 18, 2015

    @mscdex
    Contributor

    @Qard I've often used this link which seems to be updated fairly often (1/7/2015 as of this writing). It doesn't have the v8 version number anywhere that I could find though...

  6. thlorenz commented on Feb 19, 2015

    @thlorenz
    Contributor

    @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.

  7. metabench commented on Feb 19, 2015

    @metabench
    Author

    @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?

    Float32Array arr = args[0]->Float32ArrayValue();
    

    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.

  8. metabench commented on Feb 19, 2015

    @metabench
    Author

    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
    Information on the right: Further explanations of the code, and references are provided on the right. This may include information which strictly speaking is not part of the iojs project, yet is still useful in using it to make addons.

    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.

  9. bnoordhuis commented on Feb 19, 2015

    @bnoordhuis
    Member

    @metabench

    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 new char[...]).

  10. metabench commented on Feb 19, 2015

    @metabench
    Author

    @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?

  11. vkurchatkin commented on Feb 19, 2015

    @vkurchatkin
    Contributor

    @metabench you can use smalloc with Float type instead. This way you don't have to manage memory manually

  12. metabench commented on Feb 19, 2015

    @metabench
    Author

    @bnoordhuis I managed to read the values of the Float32Array with the following code:

    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] = 1.0f / i;
                    cout << "arr[i] " << data[i] << endl;
                }
            delete[] static_cast<float*>(data);
        }
    }
    
    delete[] static_cast<char*>(data);
    

    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?

  13. metabench commented on Feb 19, 2015

    @metabench
    Author

    @vkurchatkin would you provide a code sample please?

  14. vkurchatkin commented on Feb 19, 2015

    @vkurchatkin
    Contributor

    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

  15. metabench commented on Feb 19, 2015

    @metabench
    Author

    I now have a version that can modify a Float32Array. It's required removing a line from the @bnoordhuis example. Without that line removed,
    console.log('ta_test', ta_test);
    would not show anything (even an error). Now I have kept that line, it logs the modified Float32Array.I now use this code:

    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.

  16. 4 remaining items

  17. vkurchatkin commented on Feb 19, 2015

    @vkurchatkin
    Contributor

    Is delete[] reinterpret_cast<char*>(data); really necessary?

    It's necessary to have this SOMEWHERE, otherwise memory would leak.

  18. metabench commented on Feb 19, 2015

    @metabench
    Author

    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?

  19. metabench commented on Feb 19, 2015

    @metabench
    Author

    you can simply attach length property to the object

    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.

  20. rvagg commented on Feb 19, 2015

    @rvagg
    Member

    @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)

  21. trevnorris commented on Feb 19, 2015

    @trevnorris
    Contributor

    @metabench

    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.

    That's one common usage of 'smalloc'. By attaching a uint32 external data array to an object you can use that memory to track status by flags. Retrieving that information in C++ is fast, and faster still if you pull it out and store a pointer to it for future reference (though you have to be aware of when the object is no longer in scope and could be cleaned up by gc).

    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.

    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);
  22. metabench commented on Feb 19, 2015

    @metabench
    Author

    @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 delete[] reinterpret_cast<char*>(data);, and if I did not use it I would get FATAL ERROR: v8::ArrayBuffer::Externalize ArrayBuffer already externalized, which I found very little information about using Google.

  23. metabench commented on Feb 19, 2015

    @metabench
    Author

    @trevnorris, also do you know if smalloc would work with NAN?

  24. trevnorris commented on Feb 19, 2015

    @trevnorris
    Contributor

    @metabench Don't cleanup the memory yourself. GC will take care of it. And yes, it then becomes a usable uint32 external array.

  25. metabench commented on Feb 20, 2015

    @metabench
    Author

    @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?

  26. trevnorris commented on Feb 20, 2015

    @trevnorris
    Contributor

    @metabench Don't believe so.

  27. metabench commented on Feb 20, 2015

    @metabench
    Author

    @trevnorris how would I make the smalloc in iojs addon C++? I can't yet understand it from the source code unfortunately.

  28. thlorenz commented on Feb 20, 2015

    @thlorenz
    Contributor

    So the v8 doxygen docs have been updated.

    Here is the io.js 1.2 one documenting v8 4.1.0.14.
    If you want we could link to those from the addons documentation.
    We'll make sure to update with each io.js release (our build script was updated to make that easier).

  29. trevnorris commented on Feb 20, 2015

    @trevnorris
    Contributor

    @metabench Until #905 lands it can only be done from JS. When it does land look at test/addons/smalloc-alloc/binding.cc for an example of how to use it.

  30. added
    docIssues and PRs related to Node.js documentation.
    on Feb 22, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    docIssues and PRs related to Node.js documentation.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions