Skip to content

Instantly share code, notes, and snippets.

@FeepingCreature
Created September 24, 2021 02:00
Show Gist options
  • Save FeepingCreature/ff4c052eb4df70774bbb3446df30dd9d to your computer and use it in GitHub Desktop.
Save FeepingCreature/ff4c052eb4df70774bbb3446df30dd9d to your computer and use it in GitHub Desktop.
module bench;
import std;
import std.datetime.stopwatch : benchmark;
int test(alias skip)(ubyte[] trash)
{
int lenSum;
while (!trash.empty)
{
if (trash.front == '"')
{
trash.popFront;
auto start = trash.length;
skip(trash);
lenSum += start - trash.length;
}
if (trash.empty) break;
trash.popFront;
}
return lenSum;
}
void skipToQuoteBasic(ref ubyte[] data) {
import core.bitop : bsf;
enum step = `
while (!data.empty && data.front != '"' && %s) {
data.popFront;
}`;
if (data.length >= 16) {
// 16-align pointer
mixin(format!step(q{(cast(size_t) data.ptr) & 0xf}));
if (data.empty || data.front == '"') return;
align(16)
static struct AlignedVector
{
ubyte[16] data;
}
while (data.length >= 16) {
auto vector = *cast(AlignedVector*) data.ptr;
static immutable AlignedVector match = AlignedVector(cast(ubyte[16]) [
'"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"']);
uint test;
foreach (i; 0 .. 16)
{
test |= (vector.data[i] == match.data[i]) << i;
}
if (test == 0) {
// no characters match '"'
data = data.drop(16);
continue;
}
data = data.drop(bsf(test));
return;
}
}
mixin(format!step(q{true}));
}
void skipToQuoteFullBasic(ref ubyte[] data) {
while (!data.empty && data.front != '"') {
data.popFront;
}
}
void skipToQuoteAsm(ref ubyte[] data) {
import core.bitop : bsf;
enum step = `
while (!data.empty && data.front != '"' && %s) {
data.popFront;
}`;
if (data.length >= 16) {
// 16-align pointer
mixin(format!step(q{(cast(size_t) data.ptr) & 0xf}));
if (data.empty || data.front == '"') return;
align(16)
static struct AlignedVector
{
ubyte[16] data;
}
while (data.length >= 16) {
auto vector = cast(AlignedVector*) data.ptr;
static immutable AlignedVector match = AlignedVector(cast(ubyte[16]) [
'"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"']);
uint test;
asm {
mov RAX, vector;
movaps XMM0, [RAX];
movaps XMM1, [match];
pcmpeqb XMM0, XMM1;
pmovmskb EAX, XMM0;
mov test, EAX;
}
if (test != 0) {
data = data.drop(bsf(test));
return;
}
// no characters match '"'
data = data.drop(16);
continue;
}
}
mixin(format!step(q{true}));
}
void skipToQuoteUnalignedAsm(ref ubyte[] data) {
import core.bitop : bsf;
enum step = `
while (!data.empty && data.front != '"' && %s) {
data.popFront;
}`;
while (data.length >= 16) {
align(16)
static struct AlignedVector
{
ubyte[16] data;
}
auto vector = data.ptr;
static immutable AlignedVector match = AlignedVector(cast(ubyte[16]) [
'"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"', '"']);
int test = 0;
asm {
mov RAX, vector;
movups XMM0, [RAX];
movaps XMM1, [match];
pcmpeqb XMM0, XMM1;
pmovmskb EAX, XMM0;
mov test, EAX;
}
if (test != 0) {
data = data.drop(bsf(test));
return;
}
data = data.drop(16);
continue;
}
mixin(format!step(q{true}));
}
void main() {
ubyte[] trash = cast(ubyte[]) rndGen.take(32*1048576).array;
writefln!"Starting benchmark.";
int res1, res2, res3, res4;
auto r = benchmark!(
{ res1 = trash.test!skipToQuoteFullBasic; },
{ res2 = trash.test!skipToQuoteBasic; },
{ res3 = trash.test!skipToQuoteAsm; },
{ res4 = trash.test!skipToQuoteUnalignedAsm; },
)(16);
writefln!"[Full Basic ] %s in %s"(res1, r[0]);
writefln!"[Basic ] %s in %s"(res2, r[1]);
writefln!"[Asm ] %s in %s"(res3, r[2]);
writefln!"[UnalignedAsm] %s in %s"(res4, r[3]);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment