This may seems silly, but maybe you could try writing larger buffers. If 
you write buffers of legnth 1, you'll cross the C++/JS border way more 
often than if you write buffers of length, say 16 or 32.
I'm not sure it will improve things, but it seems it's worth a try.

On Wednesday, 17 July 2013 23:33:34 UTC+2, Mihai Ene wrote:
>
> Hello fellow noders,
>
> This is a long post, jump to the end to see the final questions, but a 
> context is provided for the curious.
>
> *Introductory part*: I have some beaglebone black devices running Node 
> (0.8 atm, planning to upgrade for the streams api). *The OS is Angstrom 
> GNU/Linux v2012.12 running on a 3.8.13 kernel using device trees. I need to 
> send data to a device via bit banging. Ideally, the baud rate should be 
> somewhere between 60000 and 120000*.
>
> In order to benchmark the speed before writing the actual code, I wrote a 
> test suite. Via micro-optimizations, I got close to an acceptable speed 
> (approx 60kHz measured with an oscilloscope). Here is the path:
>
> *[1.] Classic beaglebone code, from the example*
>
>> var b = require('bonescript');
>>
>> var ledPin = "P8_10";
>>
>> b.pinMode(ledPin, b.OUTPUT);
>>
>> b.digitalWrite(ledPin, b.LOW);
>>
>> var fn = function(state) {
>>
>>     b.digitalWrite(ledPin, state);
>>
>> };
>>
>> var state = b.LOW;
>>
>> var getOppositeState = function() {
>>
>>     return state = state == b.LOW ? b.HIGH : b.LOW;
>>
>> };
>>
>> while(1 == 1) {
>>
>>     fn(getOppositeState());
>>
>> }
>>
>> With this function, the frequency measured by the oscilloscope was 
> fluctuating between 0.9-1.3 kHz. So about 1100 bits per second (screenshot: 
> http://cs.mene.ro/oscilloscope/NewFile1.bmp). This was too slow. I ended 
> up looking through the beaglebone scripts, noticing that it was doing some 
> validations and ended up writing to the pin's file. That's why I switch 
> from the beaglebone scripts to pure Node FS calls:
>
> *[2.] Classic FS calls*
>
>> var fs = require('fs');
>>
>> var pin = {
>>
>>     "name": "TIMER6",
>>
>>     "gpio": 68
>>
>> };
>>
>> var gpioFile = '/sys/class/gpio/gpio' + pin.gpio + '/value';
>>
>> var fn = function() {
>>
>>     fs.writeFile(gpioFile, '' + 0, null, function() {
>>
>>         fs.writeFile(gpioFile, '' + 1, null, fn.bind(null));
>>
>>     });
>>
>> };
>>
>> fn();
>>
>> With this new approach, the oscilloscope measured the frequency aroung 
> 650Hz, so 50% slower. Something was wrong (screenshot: 
> http://cs.mene.ro/oscilloscope/NewFile3.bmp). The problem was I was 
> waiting for the callback. Switching from the async fs.writeFile to the 
> fs.writeFileSync proved to be efficient, the frequency increased to about 
> 3.6kHz (screenshot: http://cs.mene.ro/oscilloscope/NewFile4.bmp), but 
> this is still too slow. I decided to optimize a bit more, and since I am 
> writing to the same file every time:
>
> *[3.] FS calls with one descriptor*
>
>> var fs = require('fs');
>>
>> var gpioFile = '/sys/class/gpio/gpio68/value';
>>
>> var fd = fs.openSync(gpioFile, 'a');
>>
>> while(1 == 1) {
>>
>>     fs.writeSync(fd, '1');
>>
>>     fs.writeSync(fd, '0');
>>
>> }
>>
>> Without requesting the file descriptor on each write, things really 
> improved. I was now changing the pin at a rate of 12kHz (screenshot: 
> http://cs.mene.ro/oscilloscope/NewFile5.bmp). But this is too slow to 
> write an image, so I decided to hack the NodeJS core.
>
> Node's FS functions are meant to be used by regular NodeJS users. The core 
> expects users to make mistakes, and over-validates everything they send to 
> it. After validating the buffer and creating a wrapper for the callback, 
> the FS finally calls process.binding('fs').write(fd, buffer, offset, 
> length, position, wrapper); (yes, this is a copy+paste from the node 
> source code)
> So i decided to go straight to the binding and write to it:
>
> *[4.] process.binding('fs') calls*
>
>> var fs = require('fs');
>>
>> var binding = process.binding('fs');
>>
>> var b0 = new Buffer('0', 0);
>>
>> var b1 = new Buffer('1', 0);
>>
>> var gpioFile = '/sys/class/gpio/gpio68/value';
>>
>> var fd = fs.openSync(gpioFile, 'a');
>>
>> while(1 == 1) {
>>
>>     binding.write(fd, b0, 0, 1, 0);
>>
>>     binding.write(fd, b1, 0, 1, 0);
>>
>> }
>>
>> The oscilloscope is now registering 57-62kHz. Yay! So after several 
> micro-optimizations, I got close to the target values. I am not sure why 
> process.binding should not be called directly by Node users (I assume this 
> has something to do with validating stuff before calling), but this made 
> things considerably faster (about 5 times faster).
>
> At the moment, I am at the minimum acceptable baud rate. I can write a 
> screen in about 2 seconds using Node and a 50+ kHz bit rate. But I know it 
> can be faster, since I also tested a partially optimized C application 
> which does the same benchmark at about 160kHz, so almost 3x faster than 
> Node.
>
> In order to simulate an SPI protocol with Node (eg: piping an image stream 
> from a TCP socket to a screen on the embedded device), a higher 
> pullup/pulldown frequency would be preferable.
>
> Q1. Is there any way to optimize the calls from [4.] onward? For example, 
> can I use malloc from process.binding('smalloc') to jump the buffer 
> validation/creation other low-lever functions to make this faster?
> Q2. Is there any way to use /dev/mem for gpio  (mmap bindings) in Node?
> Q3. The OS and the GC keep interrupting the Node application, and that 
> leads to noticeable fluctuations in the data flow (55kHz-62kHz), any 
> suggestions to stabilize the flow would also be very welcomed
>
>
>

-- 
-- 
Job Board: http://jobs.nodejs.org/
Posting guidelines: 
https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

--- 
You received this message because you are subscribed to the Google Groups 
"nodejs" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to