Significantly reduced number of allocations

master
Inga 🏳‍🌈 7 years ago
parent 16bc5f2c98
commit 9423f1e34f
  1. 8
      README.md
  2. 4
      dotnet/WhiteRabbit.UnmanagedBridge/WhiteRabbit.UnmanagedBridge.cpp
  3. 2
      dotnet/WhiteRabbit.UnmanagedBridge/WhiteRabbit.UnmanagedBridge.h
  4. 6
      dotnet/WhiteRabbit.UnmanagedBridge/phraseset.cpp
  5. 2
      dotnet/WhiteRabbit.UnmanagedBridge/phraseset.h
  6. 18
      dotnet/WhiteRabbit/MD5Digest.cs
  7. 31
      dotnet/WhiteRabbit/PhraseSet.cs
  8. 5
      dotnet/WhiteRabbit/Program.cs
  9. 17
      dotnet/WhiteRabbit/StringsProcessor.cs
  10. 18
      dotnet/WhiteRabbit/Word.cs

@ -47,10 +47,10 @@ Number of words|Time to check all anagrams no longer than that|Time to solve "ea
---------------|----------------------------------------------|-------------------------|-----------------------------------|-------------------------|--------------------------------------------- ---------------|----------------------------------------------|-------------------------|-----------------------------------|-------------------------|---------------------------------------------
3|0.04s||||4560 3|0.04s||||4560
4|0.45s|||0.08s|7,431,984 4|0.45s|||0.08s|7,431,984
5|18s|0.25s|0.07s|0.5s|1,347,437,484 5|12s|0.16s|0.06s|0.32s|1,347,437,484
6|9.5 minutes|1.7s|0.3s|4.3s|58,405,904,844 6|6.5 minutes|1.25s|0.25s|3s|58,405,904,844
7|3.2 hours|10s|1.3s|28s|1,070,307,744,114 7|3.2 hours|7s|0.9s|19s|1,070,307,744,114
8|49 hours|37s|3.8s|1.9 minutes|10,893,594,396,594 8|49 hours|25s|2.6s|80s|10,893,594,396,594
9||2.5 minutes|13s|9.5 minutes|70,596,864,409,954 9||2.5 minutes|13s|9.5 minutes|70,596,864,409,954
10||5 minutes|21s|17.5 minutes|314,972,701,475,754 10||5 minutes|21s|17.5 minutes|314,972,701,475,754

@ -27,7 +27,7 @@ void WhiteRabbitUnmanagedBridge::MD5Unmanaged::ComputeMD5(unsigned __int32 * inp
#endif #endif
} }
void WhiteRabbitUnmanagedBridge::MD5Unmanaged::FillPhraseSet(__int64* bufferPointer, __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int permutationOffset, int numberOfCharacters, int numberOfWords) void WhiteRabbitUnmanagedBridge::MD5Unmanaged::FillPhraseSet(__int64* bufferPointer, __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfCharacters, int numberOfWords)
{ {
fillPhraseSet(bufferPointer, (unsigned __int64*)allWordsPointer, wordIndexes, permutationsPointer, permutationOffset, numberOfCharacters, numberOfWords); fillPhraseSet(bufferPointer, (unsigned __int64*)allWordsPointer, wordIndexes, permutationsPointer, numberOfCharacters, numberOfWords);
} }

@ -13,6 +13,6 @@ namespace WhiteRabbitUnmanagedBridge {
public: public:
literal int PhrasesPerSet = PHRASES_PER_SET; literal int PhrasesPerSet = PHRASES_PER_SET;
static void ComputeMD5(unsigned int* input); static void ComputeMD5(unsigned int* input);
static void FillPhraseSet(__int64* bufferPointer, __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int permutationOffset, int numberOfCharacters, int numberOfWords); static void FillPhraseSet(__int64* bufferPointer, __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfCharacters, int numberOfWords);
}; };
} }

@ -25,9 +25,9 @@
macro(15); macro(15);
#define INIT_WORD(phraseNumber) \ #define INIT_WORD(phraseNumber) \
auto permutation = permutationsPointer[permutationOffset + phraseNumber]; \ auto permutation = permutationsPointer[phraseNumber]; \
unsigned __int64 cumulativeWordOffset = 0; \ unsigned __int64 cumulativeWordOffset = 0; \
auto phrase = avx2buffer[phraseNumber]; auto phrase = _mm256_set1_epi32(0);
#define PROCESS_WORD(phraseNumber, wordNumber) \ #define PROCESS_WORD(phraseNumber, wordNumber) \
{ \ { \
@ -118,7 +118,7 @@
#define REPEAT_WORDS10(phraseNumber) REPEAT_WORDS(phraseNumber, REPEAT_WORDS_SIMPLE10) #define REPEAT_WORDS10(phraseNumber) REPEAT_WORDS(phraseNumber, REPEAT_WORDS_SIMPLE10)
void fillPhraseSet(__int64* bufferPointer, unsigned __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int permutationOffset, int numberOfCharacters, int numberOfWords) void fillPhraseSet(__int64* bufferPointer, unsigned __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfCharacters, int numberOfWords)
{ {
auto avx2buffer = (__m256i*)bufferPointer; auto avx2buffer = (__m256i*)bufferPointer;

@ -1,3 +1,3 @@
#pragma once #pragma once
void fillPhraseSet(__int64* bufferPointer, unsigned __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int permutationOffset, int numberOfCharacters, int numberOfWords); void fillPhraseSet(__int64* bufferPointer, unsigned __int64* allWordsPointer, __int32* wordIndexes, unsigned __int64* permutationsPointer, int numberOfCharacters, int numberOfWords);

@ -1,18 +0,0 @@
namespace WhiteRabbit
{
using System.Runtime.CompilerServices;
using WhiteRabbitUnmanagedBridge;
internal static class MD5Digest
{
// It only returns first component of MD5 hash
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Compute(PhraseSet input)
{
fixed (uint* inputBuffer = input.Buffer)
{
MD5Unmanaged.ComputeMD5(inputBuffer);
}
}
}
}

@ -2,17 +2,24 @@
{ {
using System.Diagnostics; using System.Diagnostics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using WhiteRabbitUnmanagedBridge;
// Anagram representation optimized for MD5 // Anagram representation optimized for MD5
internal struct PhraseSet internal struct PhraseSet
{ {
public uint[] Buffer; private uint[] Buffer;
public unsafe PhraseSet(Word[] allWords, int[] wordIndexes, ulong[] permutations, int permutationOffset, int numberOfCharacters) public int Length;
public PhraseSet(int length)
{ {
Debug.Assert(numberOfCharacters + wordIndexes.Length - 1 < 27); this.Length = length;
this.Buffer = new uint[8 * length];
}
this.Buffer = new uint[8 * Constants.PhrasesPerSet]; public unsafe void FillPhraseSet(Word[] allWords, int[] wordIndexes, ulong[] permutations, int permutationOffset, int numberOfCharacters)
{
Debug.Assert(numberOfCharacters + wordIndexes.Length - 1 < 27);
fixed (uint* bufferPointer = this.Buffer) fixed (uint* bufferPointer = this.Buffer)
{ {
@ -22,13 +29,27 @@
{ {
fixed (Word* allWordsPointer = allWords) fixed (Word* allWordsPointer = allWords)
{ {
WhiteRabbitUnmanagedBridge.MD5Unmanaged.FillPhraseSet((long*)bufferPointer, (long*)allWordsPointer, wordIndexesPointer, permutationsPointer, permutationOffset, numberOfCharacters, wordIndexes.Length); MD5Unmanaged.FillPhraseSet(
(long*)bufferPointer,
(long*)allWordsPointer,
wordIndexesPointer,
permutationsPointer + permutationOffset,
numberOfCharacters,
wordIndexes.Length);
} }
} }
} }
} }
} }
public unsafe void ComputeMD5()
{
fixed (uint* inputBuffer = this.Buffer)
{
MD5Unmanaged.ComputeMD5(inputBuffer);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public uint GetMD5(int number) public uint GetMD5(int number)
{ {

@ -80,14 +80,13 @@
processor.CheckPhrases(phraseSet => processor.CheckPhrases(phraseSet =>
{ {
MD5Digest.Compute(phraseSet); phraseSet.ComputeMD5();
for (var i = 0; i < Constants.PhrasesPerSet; i++) for (var i = 0; i < phraseSet.Length; i++)
{ {
Debug.Assert( Debug.Assert(
sourceChars == ToOrderedChars(ToString(phraseSet, i)), sourceChars == ToOrderedChars(ToString(phraseSet, i)),
$"StringsProcessor produced incorrect anagram: {ToString(phraseSet, i)}"); $"StringsProcessor produced incorrect anagram: {ToString(phraseSet, i)}");
if (Vector.EqualsAny(expectedHashesFirstComponents, new Vector<uint>(hashesFirstComponents[i])))
if (Vector.EqualsAny(expectedHashesFirstComponents, new Vector<uint>(phraseSet.GetMD5(i)))) if (Vector.EqualsAny(expectedHashesFirstComponents, new Vector<uint>(phraseSet.GetMD5(i))))
{ {
var phrase = ToString(phraseSet, i); var phrase = ToString(phraseSet, i);

@ -68,12 +68,17 @@
// converting sequences of vectors to the sequences of words... // converting sequences of vectors to the sequences of words...
Parallel.ForEach(sums, new ParallelOptions { MaxDegreeOfParallelism = Constants.NumberOfThreads }, sum => Parallel.ForEach(sums, new ParallelOptions { MaxDegreeOfParallelism = Constants.NumberOfThreads }, sum =>
{ {
var phraseSet = new PhraseSet(Constants.PhrasesPerSet);
var filter = ComputeFilter(sum); var filter = ComputeFilter(sum);
var wordsVariants = this.ConvertVectorsToWordIndexes(sum); var wordsVariants = this.ConvertVectorsToWordIndexes(sum);
foreach (var wordsArray in Flattener.Flatten(wordsVariants)) foreach (var wordsArray in Flattener.Flatten(wordsVariants))
{ {
foreach (var phraseSet in this.ConvertWordsToPhrases(wordsArray, filter)) //Console.WriteLine(new string(wordsArray.SelectMany(wordIndex => this.AllWords[wordIndex].Original).Select(b => (char)b).ToArray()));
var permutations = PrecomputedPermutationsGenerator.HamiltonianPermutations(wordsArray.Length, filter);
for (var i = 0; i < permutations.Length; i += Constants.PhrasesPerSet)
{ {
phraseSet.FillPhraseSet(this.AllWords, wordsArray, permutations, i, this.NumberOfCharacters);
action(phraseSet); action(phraseSet);
} }
} }
@ -128,15 +133,5 @@
return result; return result;
} }
private IEnumerable<PhraseSet> ConvertWordsToPhrases(int[] wordIndexes, uint filter)
{
var permutations = PrecomputedPermutationsGenerator.HamiltonianPermutations(wordIndexes.Length, filter);
var permutationsLength = permutations.Length;
for (var i = 0; i < permutationsLength; i += Constants.PhrasesPerSet)
{
yield return new PhraseSet(this.AllWords, wordIndexes, permutations, i, this.NumberOfCharacters);
}
}
} }
} }

@ -30,6 +30,24 @@
} }
} }
public unsafe byte[] Original
{
get
{
fixed (long* buffersPointer = this.Buffers)
{
var length = buffersPointer[127] / 4;
var result = new byte[length];
for (var i = 0; i < length; i++)
{
result[i] = ((byte*)buffersPointer)[i];
}
return result;
}
}
}
private static Word Empty { get; } = new Word(); private static Word Empty { get; } = new Word();
} }
} }

Loading…
Cancel
Save