views:

603

answers:

7

I need to copy FAST a portion of an array into another, replacing it's old values.

  • No range checkings needed.
  • Number of items to copy: 16384
  • The array only contains integers

benchmark code: http://codebase.es/test/copytest.htm

This is my approach:

  var i = 0x4000>>5; // loops count
  var j = 0x4000;    // write start index
  var k = 0x8000;    // read start index
  while (i--) {      // loop unrolling
    dst[j++]=src[k++]; dst[j++]=src[k++];
    dst[j++]=src[k++]; dst[j++]=src[k++];    
    dst[j++]=src[k++]; dst[j++]=src[k++];
    dst[j++]=src[k++]; dst[j++]=src[k++];
    //8
    dst[j++]=src[k++]; dst[j++]=src[k++];
    dst[j++]=src[k++]; dst[j++]=src[k++];    
    dst[j++]=src[k++]; dst[j++]=src[k++];
    dst[j++]=src[k++]; dst[j++]=src[k++];
    //16
    dst[j++]=src[k++]; dst[j++]=src[k++];
    dst[j++]=src[k++]; dst[j++]=src[k++];    
    dst[j++]=src[k++]; dst[j++]=src[k++];
    dst[j++]=src[k++]; dst[j++]=src[k++];
    //24
    dst[j++]=src[k++]; dst[j++]=src[k++];
    dst[j++]=src[k++]; dst[j++]=src[k++];    
    dst[j++]=src[k++]; dst[j++]=src[k++];
    dst[j++]=src[k++]; dst[j++]=src[k++];
    //32
  }

can this be done faster?

+2  A: 

Im not sure your method is faster than this:

var i = 0x4000;     // loops count
var j = 0x4000;    // write start index
var k = 0x8000;    // read start index
while (i--) {      // loop unrolling
  dst[j++]=src[k++];
}
Cem Kalyoncu
It is (tested in chrome, FF3.5 and Opera)Have a look at:http://codebase.es/test/copytest.htm
Pedro Ladaria
A: 

I would consider the slice method:

var dst = src.slice(start,end)

The performance depends on the implementation of javascript engine, but presumably all the browsers have implemented as efficient as possible on their platform.

See more here

idrosid
He asks to replace contents of another array, not to form a new one.
Cem Kalyoncu
@cemkalyoncu: Then do `slice` and `splice`.
Gumbo
"Slice and splice" sounds like a TV direct-response product. "Tired of writing clumsy for loops? Try new Slice and Splice! It slices, it splices, it takes the pain out of array processing. Order now for only $19.95!"
Matthew Crumley
slice + splice is much slower. Look at copy 3:http://codebase.es/test/copytest.htm
Pedro Ladaria
A: 

An alternative worth benchmarking may be building a brand new dst array with just a few powerful primitives rather than performing the loop, i.e.:

dst = dst.slice(0, writestart).concat(
    src.slice(readstart, readstart+count),
    dst.slice(writestart+count));

How the performance of this approach compares to looping will no doubt vary with the array lengths and counts involved, as well as with the underlying Javascript engine -- guessing would not be very productive, which is why I suggest benchmarking instead;-).

Alex Martelli
this is around 10 times slower
Pedro Ladaria
Some internal functions which most probably written in C++ works slower than interpreting bunch of lines, strange. BTW I tested same code in C resulting 6-14ms of copy time (1000 x 0x4000 elements)
Cem Kalyoncu
modern browsers compile javascript into machine code. For example Chrome's V8 and FF's TraceMonkey.
Pedro Ladaria
+1  A: 

Try a combination with the build-in method slice and splice:

Array.prototype.splice.apply(dst, [j, i].concat(src.slice(k, k+i)));
Gumbo
Sorry. Your solution is around 50 times slower.
Pedro Ladaria
+1  A: 

You could keep unrolling the loop for even slighter increases in performance, but it seems like this is just about as fast as you're going to get it. As Gumbo stated in a comment, try using pre-increment instead of post-increment:

var i = 0x4000>>5 + 1; // loops count
var j = 0x4000 - 1;    // write start index
var k = 0x8000 - 1;    // read start index
while (--i) {      // loop unrolling
    dst[++j]=src[++k]; dst[++j]=src[++k];
    dst[++j]=src[++k]; dst[++j]=src[++k];    
    dst[++j]=src[++k]; dst[++j]=src[++k];
    dst[++j]=src[++k]; dst[++j]=src[++k];
    //8
    ...
Carson Myers
Why not for `i--` too?
Gumbo
Right, missed that
Carson Myers
A: 

You can create a completely unrolled version, eg via

function compileCopy(count, di, si) {
    var sb = new Array(count);
    di += count, si += count;
    while(count--) sb[count] = --di + ']=src[' + --si;
    return new Function('dst[' + sb.join('];dst[') + '];');
}

var copy = compileCopy(0x4000, 0x4000, 0x8000);

In Opera, it will be slightly faster than the looping version. In FF... not (there might even be some bug somewhere).

Christoph
But the start indexes are hardcoded into the "compiled" function. For each copy call you would need to "compile" it again.
Pedro Ladaria
your benchmark code has hardcoded indices as well
Christoph
but they could be function parameters without performance loss.
Pedro Ladaria
A: 

Sorry, one year later, but.. this is fastest in FF:

function copy4() {
  var i = 0x4000; // loops count
  var j = 0x4000; // write start index
  var k = 0x8000; // read start index

  var args = src.slice(k, k+i);
  args.unshift(i);
  args.unshift(j);
  Array.prototype.splice.apply(dst,args);
}
juanjis