buffer: speed up base64 encoding by 20%
Remove a lot of branches from the inner loop. Speeds up buf.toString('base64') by about 20%. Before: $ time out/Release/node benchmark/buffer-base64-encode.js real 0m6.607s user 0m5.508s sys 0m1.088s After: $ time out/Release/node benchmark/buffer-base64-encode.js real 0m5.520s user 0m4.520s sys 0m0.992s
This commit is contained in:
parent
192192a09e
commit
a329729537
27
benchmark/buffer-base64-encode.js
Normal file
27
benchmark/buffer-base64-encode.js
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright Joyent, Inc. and other Node contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the
|
||||
// "Software"), to deal in the Software without restriction, including
|
||||
// without limitation the rights to use, copy, modify, merge, publish,
|
||||
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
// persons to whom the Software is furnished to do so, subject to the
|
||||
// following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
var N = 64*1024*1024
|
||||
var b = Buffer(N);
|
||||
var s = '';
|
||||
for (var i = 0; i < 256; ++i) s += String.fromCharCode(i);
|
||||
for (var i = 0; i < N; i += 256) b.write(s, i, 256, 'ascii');
|
||||
for (var i = 0; i < 32; ++i) b.toString('base64');
|
@ -276,9 +276,6 @@ Handle<Value> Buffer::Ucs2Slice(const Arguments &args) {
|
||||
return scope.Close(string);
|
||||
}
|
||||
|
||||
static const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
// supports regular and URL-safe base64
|
||||
static const int unbase64_table[] =
|
||||
@ -307,69 +304,65 @@ Handle<Value> Buffer::Base64Slice(const Arguments &args) {
|
||||
Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
|
||||
SLICE_ARGS(args[0], args[1])
|
||||
|
||||
int n = end - start;
|
||||
int out_len = (n + 2 - ((n + 2) % 3)) / 3 * 4;
|
||||
char *out = new char[out_len];
|
||||
unsigned slen = end - start;
|
||||
const char* src = parent->data_ + start;
|
||||
|
||||
uint8_t bitbuf[3];
|
||||
int i = start; // data() index
|
||||
int j = 0; // out index
|
||||
char c;
|
||||
bool b1_oob, b2_oob;
|
||||
unsigned dlen = (slen + 2 - ((slen + 2) % 3)) / 3 * 4;
|
||||
char* dst = new char[dlen];
|
||||
|
||||
while (i < end) {
|
||||
bitbuf[0] = parent->data_[i++];
|
||||
unsigned a;
|
||||
unsigned b;
|
||||
unsigned c;
|
||||
unsigned i;
|
||||
unsigned k;
|
||||
unsigned n;
|
||||
|
||||
if (i < end) {
|
||||
bitbuf[1] = parent->data_[i];
|
||||
b1_oob = false;
|
||||
} else {
|
||||
bitbuf[1] = 0;
|
||||
b1_oob = true;
|
||||
}
|
||||
i++;
|
||||
static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
if (i < end) {
|
||||
bitbuf[2] = parent->data_[i];
|
||||
b2_oob = false;
|
||||
} else {
|
||||
bitbuf[2] = 0;
|
||||
b2_oob = true;
|
||||
}
|
||||
i++;
|
||||
i = 0;
|
||||
k = 0;
|
||||
n = slen / 3 * 3;
|
||||
|
||||
while (i < n) {
|
||||
a = src[i + 0] & 0xff;
|
||||
b = src[i + 1] & 0xff;
|
||||
c = src[i + 2] & 0xff;
|
||||
|
||||
c = bitbuf[0] >> 2;
|
||||
assert(c < 64);
|
||||
out[j++] = base64_table[(int)c];
|
||||
assert(j < out_len);
|
||||
dst[k + 0] = table[a >> 2];
|
||||
dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
|
||||
dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)];
|
||||
dst[k + 3] = table[c & 0x3f];
|
||||
|
||||
c = ((bitbuf[0] & 0x03) << 4) | (bitbuf[1] >> 4);
|
||||
assert(c < 64);
|
||||
out[j++] = base64_table[(int)c];
|
||||
assert(j < out_len);
|
||||
|
||||
if (b1_oob) {
|
||||
out[j++] = '=';
|
||||
} else {
|
||||
c = ((bitbuf[1] & 0x0F) << 2) | (bitbuf[2] >> 6);
|
||||
assert(c < 64);
|
||||
out[j++] = base64_table[(int)c];
|
||||
}
|
||||
assert(j < out_len);
|
||||
|
||||
if (b2_oob) {
|
||||
out[j++] = '=';
|
||||
} else {
|
||||
c = bitbuf[2] & 0x3F;
|
||||
assert(c < 64);
|
||||
out[j++] = base64_table[(int)c];
|
||||
}
|
||||
assert(j <= out_len);
|
||||
i += 3;
|
||||
k += 4;
|
||||
}
|
||||
|
||||
Local<String> string = String::New(out, out_len);
|
||||
delete [] out;
|
||||
if (n != slen) {
|
||||
switch (slen - n) {
|
||||
case 1:
|
||||
a = src[i + 0] & 0xff;
|
||||
dst[k + 0] = table[a >> 2];
|
||||
dst[k + 1] = table[(a & 3) << 4];
|
||||
dst[k + 2] = '=';
|
||||
dst[k + 3] = '=';
|
||||
break;
|
||||
|
||||
case 2:
|
||||
a = src[i + 0] & 0xff;
|
||||
b = src[i + 1] & 0xff;
|
||||
dst[k + 0] = table[a >> 2];
|
||||
dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
|
||||
dst[k + 2] = table[(b & 0x0f) << 2];
|
||||
dst[k + 3] = '=';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Local<String> string = String::New(dst, dlen);
|
||||
delete [] dst;
|
||||
|
||||
return scope.Close(string);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user