Skip to content

Instantly share code, notes, and snippets.

@aarondandy
Forked from hyrmn/netcore linecount
Last active January 23, 2020 00:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save aarondandy/9d1b30a291c201c4d7edb432673df28a to your computer and use it in GitHub Desktop.
Save aarondandy/9d1b30a291c201c4d7edb432673df28a to your computer and use it in GitHub Desktop.
netcore 3.1. hardcoded to the location of a 1.6gb text file
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System;
using System.IO;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
namespace BensWordCounter
{
public class Program
{
public const string FilePath = @"C:\tools\hashcat-5.1.0\rockyou.txt";
public const int CorrectAnswer = 14344391;
private Stream FileStream;
private byte[] FileData;
static void Main(string[] args)
{
BenchmarkRunner.Run<Program>();
}
//[Params(4096, 8192, 32768)]
public int BufferSize = 32768;
[GlobalSetup]
public void GlobalSetup()
{
FileData = File.ReadAllBytes(FilePath);
}
[IterationSetup]
public void Setup()
{
FileStream = new MemoryStream(FileData);
}
[IterationCleanup]
public void Cleanup()
{
FileStream?.Dispose();
}
[Benchmark]
public int AaronsSimple()
{
int count = 0;
var buffer = new Span<char>(new char[BufferSize]);
using var reader = new StreamReader(FileStream, Encoding.UTF8, true, bufferSize: buffer.Length);
int readLength;
int sliceIndex;
while ((readLength = reader.Read(buffer)) != 0)
{
var slice = buffer.Slice(0, readLength);
while ((sliceIndex = slice.IndexOf('\n')) >= 0)
{
slice = slice.Slice(sliceIndex + 1);
count++;
}
}
if (count != CorrectAnswer) throw new InvalidOperationException();
return count;
}
[Benchmark(Baseline = true)]
public int AaronsRawBytes()
{
const byte target = (byte)'\n';
var buffer = new Span<byte>(new byte[BufferSize]);
int count = 0;
int readLength;
int sliceIndex;
while ((readLength = FileStream.Read(buffer)) != 0)
{
var slice = buffer.Slice(0, readLength);
while ((sliceIndex = slice.IndexOf(target)) >= 0)
{
slice = slice.Slice(sliceIndex + 1);
count++;
}
}
if (count != CorrectAnswer) throw new InvalidOperationException();
return count;
}
[Benchmark]
public int OtherBensMask()
{
const int slicesize = 32;
var count = 0;
Span<byte> buffer = stackalloc byte[BufferSize];
var mask = new Vector<byte>((byte)'\n');
int readLength;
while ((readLength = FileStream.Read(buffer)) != 0)
{
var slice = buffer.Slice(0, readLength);
while (slice.Length > 0)
{
var sub = slice.Slice(0, Math.Min(slice.Length, slicesize));
if (sub.Length == slicesize)
{
var vector = new Vector<byte>(sub);
var equal = Vector.Equals(vector, mask);
var negation = Vector.Negate(equal);
var subcount = Vector.Dot(negation, Vector<byte>.One);
count += subcount;
slice = slice.Slice(slicesize);
}
else
{
Span<byte> sub2 = stackalloc byte[slicesize];
sub.TryCopyTo(sub2);
var vector = new Vector<byte>(sub2);
var equal = Vector.Equals(vector, mask);
var negation = Vector.Negate(equal);
var subcount = Vector.Dot(negation, Vector<byte>.One);
count += subcount;
break;
}
}
}
if (count != CorrectAnswer) throw new InvalidOperationException();
return count;
}
[Benchmark]
public int AaronsMask()
{
const int vectorSize = 32;
const byte target = (byte)'\n';
var count = 0;
Span<byte> buffer = stackalloc byte[BufferSize];
var mask = new Vector<byte>(target);
int readLength;
while ((readLength = FileStream.Read(buffer)) != 0)
{
ReadOnlySpan<byte> bufferSlice = buffer.Slice(0, readLength);
while (bufferSlice.Length >= vectorSize)
{
count += AaronsMask_CounterThingy(new Vector<byte>(bufferSlice.Slice(0, vectorSize)), mask);
bufferSlice = bufferSlice.Slice(vectorSize);
}
if (bufferSlice.Length > 0)
{
Span<byte> leftovers = stackalloc byte[vectorSize];
bufferSlice.CopyTo(leftovers);
count += AaronsMask_CounterThingy(new Vector<byte>(leftovers), mask);
break;
}
}
if (count != CorrectAnswer) throw new InvalidOperationException();
return count;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int AaronsMask_CounterThingy(Vector<byte> sub, Vector<byte> mask) =>
Vector.Dot(Vector.Negate(Vector.Equals(sub, mask)), Vector<byte>.One);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment