-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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