mirror of
https://github.com/Thealexbarney/LibHac.git
synced 2024-11-14 10:49:41 +01:00
Add alignment options to StorageTester
This commit is contained in:
parent
27cc721b31
commit
c3cc7a69fb
3 changed files with 97 additions and 66 deletions
|
@ -1,7 +1,9 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
|
using LibHac.Util;
|
||||||
|
|
||||||
namespace LibHac.Tests.Fs;
|
namespace LibHac.Tests.Fs;
|
||||||
|
|
||||||
|
@ -12,6 +14,8 @@ public class StorageTester
|
||||||
private byte[][] _buffers;
|
private byte[][] _buffers;
|
||||||
private int _size;
|
private int _size;
|
||||||
|
|
||||||
|
private int[] _accessParamProbs;
|
||||||
|
|
||||||
private int[] _frequentAccessOffsets;
|
private int[] _frequentAccessOffsets;
|
||||||
private int _lastAccessEnd;
|
private int _lastAccessEnd;
|
||||||
private int _totalAccessCount;
|
private int _totalAccessCount;
|
||||||
|
@ -20,8 +24,7 @@ public class StorageTester
|
||||||
public class Configuration
|
public class Configuration
|
||||||
{
|
{
|
||||||
public Entry[] Entries { get; set; }
|
public Entry[] Entries { get; set; }
|
||||||
public int[] SizeClassProbs { get; set; }
|
public AccessParam[] AccessParams { get; set; }
|
||||||
public int[] SizeClassMaxSizes { get; set; }
|
|
||||||
public int[] TaskProbs { get; set; }
|
public int[] TaskProbs { get; set; }
|
||||||
public int[] AccessTypeProbs { get; set; }
|
public int[] AccessTypeProbs { get; set; }
|
||||||
public ulong RngSeed { get; set; }
|
public ulong RngSeed { get; set; }
|
||||||
|
@ -34,28 +37,34 @@ public class StorageTester
|
||||||
|
|
||||||
if (entries.Length < 2)
|
if (entries.Length < 2)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("At least 2 storage entries must be provided", nameof(config.Entries));
|
throw new ArgumentException("At least 2 storage entries must be provided", nameof(config));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entries.Select(x => x.BackingArray.Length).Distinct().Count() != 1)
|
if (entries.Select(x => x.BackingArray.Length).Distinct().Count() != 1)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("All storages must have the same size.", nameof(config.Entries));
|
throw new ArgumentException("All storages must have the same size.", nameof(config));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entries[0].BackingArray.Length == 0)
|
if (entries[0].BackingArray.Length == 0)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("The storage size must be greater than 0.", nameof(config.Entries));
|
throw new ArgumentException("The storage size must be greater than 0.", nameof(config));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.AccessParams.SelectMany<AccessParam, int>(x => [x.OffsetAlignment, x.SizeAlignment]).Any(x => x != 0 && !BitUtil.IsPowerOfTwo(x)))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("All alignments must be 0 or powers of 2.", nameof(config));
|
||||||
}
|
}
|
||||||
|
|
||||||
_config = config;
|
_config = config;
|
||||||
_random = new Random(config.RngSeed);
|
_random = new Random(config.RngSeed);
|
||||||
|
|
||||||
|
_accessParamProbs = config.AccessParams.Select(x => x.Prob).ToArray();
|
||||||
_backingArrays = entries.Select(x => x.BackingArray).ToArray();
|
_backingArrays = entries.Select(x => x.BackingArray).ToArray();
|
||||||
|
|
||||||
_buffers = new byte[entries.Length][];
|
_buffers = new byte[entries.Length][];
|
||||||
for (int i = 0; i < entries.Length; i++)
|
for (int i = 0; i < entries.Length; i++)
|
||||||
{
|
{
|
||||||
_buffers[i] = new byte[config.SizeClassMaxSizes[^1]];
|
_buffers[i] = new byte[config.AccessParams.Max(x => x.MaxSize)];
|
||||||
}
|
}
|
||||||
|
|
||||||
_size = entries[0].BackingArray.Length;
|
_size = entries[0].BackingArray.Length;
|
||||||
|
@ -64,48 +73,10 @@ public class StorageTester
|
||||||
_frequentAccessOffsets = new int[config.FrequentAccessBlockCount];
|
_frequentAccessOffsets = new int[config.FrequentAccessBlockCount];
|
||||||
for (int i = 0; i < _frequentAccessOffsets.Length; i++)
|
for (int i = 0; i < _frequentAccessOffsets.Length; i++)
|
||||||
{
|
{
|
||||||
_frequentAccessOffsets[i] = ChooseOffset(AccessType.Random);
|
_frequentAccessOffsets[i] = _random.Next(0, _size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//public StorageTester(ulong rngSeed, int frequentAccessBlockCount, params Entry[] entries)
|
|
||||||
//{
|
|
||||||
// if (entries.Length < 2)
|
|
||||||
// {
|
|
||||||
// throw new ArgumentException("At least 2 storage entries must be provided", nameof(entries));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (entries.Select(x => x.BackingArray.Length).Distinct().Count() != 1)
|
|
||||||
// {
|
|
||||||
// throw new ArgumentException("All storages must have the same size.", nameof(entries));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (entries[0].BackingArray.Length == 0)
|
|
||||||
// {
|
|
||||||
// throw new ArgumentException("The storage size must be greater than 0.", nameof(entries));
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _random = new Random(rngSeed);
|
|
||||||
|
|
||||||
// _entries = entries;
|
|
||||||
// _backingArrays = entries.Select(x => x.BackingArray).ToArray();
|
|
||||||
|
|
||||||
// _buffers = new byte[entries.Length][];
|
|
||||||
// for (int i = 0; i < entries.Length; i++)
|
|
||||||
// {
|
|
||||||
// _buffers[i] = new byte[SizeClassMaxSizes[^1]];
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _size = _entries[0].BackingArray.Length;
|
|
||||||
// _lastAccessEnd = 0;
|
|
||||||
|
|
||||||
// _frequentAccessOffsets = new int[frequentAccessBlockCount];
|
|
||||||
// for (int i = 0; i < _frequentAccessOffsets.Length; i++)
|
|
||||||
// {
|
|
||||||
// _frequentAccessOffsets[i] = ChooseOffset(AccessType.Random);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
public void Run(long accessCount)
|
public void Run(long accessCount)
|
||||||
{
|
{
|
||||||
long endCount = _totalAccessCount + accessCount;
|
long endCount = _totalAccessCount + accessCount;
|
||||||
|
@ -132,10 +103,11 @@ public class StorageTester
|
||||||
|
|
||||||
private void RunRead()
|
private void RunRead()
|
||||||
{
|
{
|
||||||
int sizeClass = ChooseSizeClass();
|
AccessParam accessParams = ChooseAccessRangeParams();
|
||||||
AccessType accessType = ChooseAccessType();
|
AccessType accessType = ChooseAccessType();
|
||||||
int offset = ChooseOffset(accessType);
|
|
||||||
int size = ChooseSize(offset, sizeClass);
|
int offset = ChooseOffset(accessType, accessParams);
|
||||||
|
int size = ChooseSize(offset, accessParams);
|
||||||
|
|
||||||
for (int i = 0; i < _config.Entries.Length; i++)
|
for (int i = 0; i < _config.Entries.Length; i++)
|
||||||
{
|
{
|
||||||
|
@ -147,14 +119,17 @@ public class StorageTester
|
||||||
{
|
{
|
||||||
throw new InvalidDataException($"Read: Offset {offset}; Size {size}");
|
throw new InvalidDataException($"Read: Offset {offset}; Size {size}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lastAccessEnd = offset + size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunWrite()
|
private void RunWrite()
|
||||||
{
|
{
|
||||||
int sizeClass = ChooseSizeClass();
|
AccessParam accessParams = ChooseAccessRangeParams();
|
||||||
AccessType accessType = ChooseAccessType();
|
AccessType accessType = ChooseAccessType();
|
||||||
int offset = ChooseOffset(accessType);
|
|
||||||
int size = ChooseSize(offset, sizeClass);
|
int offset = ChooseOffset(accessType, accessParams);
|
||||||
|
int size = ChooseSize(offset, accessParams);
|
||||||
|
|
||||||
Span<byte> buffer = _buffers[0].AsSpan(0, size);
|
Span<byte> buffer = _buffers[0].AsSpan(0, size);
|
||||||
_random.NextBytes(buffer);
|
_random.NextBytes(buffer);
|
||||||
|
@ -164,6 +139,8 @@ public class StorageTester
|
||||||
Entry entry = _config.Entries[i];
|
Entry entry = _config.Entries[i];
|
||||||
entry.Storage.Write(offset, buffer).ThrowIfFailure();
|
entry.Storage.Write(offset, buffer).ThrowIfFailure();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lastAccessEnd = offset + size;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RunFlush()
|
private void RunFlush()
|
||||||
|
@ -180,24 +157,36 @@ public class StorageTester
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task ChooseTask() => (Task)ChooseProb(_config.TaskProbs);
|
private Task ChooseTask() => (Task)ChooseProb(_config.TaskProbs);
|
||||||
private int ChooseSizeClass() => ChooseProb(_config.SizeClassProbs);
|
private AccessParam ChooseAccessRangeParams() => _config.AccessParams[ChooseProb(_accessParamProbs)];
|
||||||
private AccessType ChooseAccessType() => (AccessType)ChooseProb(_config.AccessTypeProbs);
|
private AccessType ChooseAccessType() => (AccessType)ChooseProb(_config.AccessTypeProbs);
|
||||||
|
|
||||||
private int ChooseOffset(AccessType type) => type switch
|
private int ChooseOffset(AccessType type, AccessParam accessParams)
|
||||||
|
{
|
||||||
|
int offset = type switch
|
||||||
{
|
{
|
||||||
AccessType.Random => _random.Next(0, _size),
|
AccessType.Random => _random.Next(0, _size),
|
||||||
AccessType.Sequential => _lastAccessEnd == _size ? 0 : _lastAccessEnd,
|
AccessType.Sequential => _lastAccessEnd == _size ? 0 : _lastAccessEnd,
|
||||||
AccessType.FrequentBlock => _frequentAccessOffsets[_random.Next(0, _frequentAccessOffsets.Length)],
|
AccessType.FrequentBlock => _frequentAccessOffsets[_random.Next(0, _frequentAccessOffsets.Length)],
|
||||||
_ => 0
|
_ => 0
|
||||||
};
|
};
|
||||||
|
return Align(offset, accessParams.OffsetAlignment);
|
||||||
|
}
|
||||||
|
|
||||||
private int ChooseSize(int offset, int sizeClass)
|
private int ChooseSize(int offset, AccessParam sizeRange)
|
||||||
{
|
{
|
||||||
int availableSize = Math.Max(0, _size - offset);
|
int availableSize = Math.Max(0, _size - offset);
|
||||||
int randSize = _random.Next(0, _config.SizeClassMaxSizes[sizeClass]);
|
int randSize = Align(_random.Next(sizeRange.MinSize, sizeRange.MaxSize), sizeRange.SizeAlignment);
|
||||||
return Math.Min(availableSize, randSize);
|
return Math.Min(availableSize, randSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int Align(int value, int alignment)
|
||||||
|
{
|
||||||
|
if (alignment == 0)
|
||||||
|
return value;
|
||||||
|
|
||||||
|
return Alignment.AlignDown(value, alignment);
|
||||||
|
}
|
||||||
|
|
||||||
private int ChooseProb(int[] weights)
|
private int ChooseProb(int[] weights)
|
||||||
{
|
{
|
||||||
int total = 0;
|
int total = 0;
|
||||||
|
@ -248,6 +237,38 @@ public class StorageTester
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly struct AccessParam
|
||||||
|
{
|
||||||
|
public readonly int Prob;
|
||||||
|
public readonly int MinSize;
|
||||||
|
public readonly int MaxSize;
|
||||||
|
public readonly int OffsetAlignment;
|
||||||
|
public readonly int SizeAlignment;
|
||||||
|
|
||||||
|
public AccessParam(int prob, int minSize, int maxSize, int offsetAlignment, int sizeAlignment)
|
||||||
|
{
|
||||||
|
Prob = prob;
|
||||||
|
MinSize = minSize;
|
||||||
|
MaxSize = maxSize;
|
||||||
|
OffsetAlignment = offsetAlignment;
|
||||||
|
SizeAlignment = sizeAlignment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessParam(int prob, int minSize, int maxSize)
|
||||||
|
{
|
||||||
|
Prob = prob;
|
||||||
|
MinSize = minSize;
|
||||||
|
MaxSize = maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessParam(int prob, int maxSize)
|
||||||
|
{
|
||||||
|
Prob = prob;
|
||||||
|
MinSize = 0;
|
||||||
|
MaxSize = maxSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum Task
|
private enum Task
|
||||||
{
|
{
|
||||||
Read = 0,
|
Read = 0,
|
||||||
|
|
|
@ -209,11 +209,16 @@ public class BufferedStorageTests
|
||||||
var memoryStorageEntry = new StorageTester.Entry(memoryStorage, memoryStorageArray);
|
var memoryStorageEntry = new StorageTester.Entry(memoryStorage, memoryStorageArray);
|
||||||
var bufferedStorageEntry = new StorageTester.Entry(bufferedStorage, bufferedStorageArray);
|
var bufferedStorageEntry = new StorageTester.Entry(bufferedStorage, bufferedStorageArray);
|
||||||
|
|
||||||
var testerConfig = new StorageTester.Configuration()
|
var accessParams = new StorageTester.AccessParam[config.SizeClassProbs.Length];
|
||||||
|
for (int i = 0; i < accessParams.Length; i++)
|
||||||
|
{
|
||||||
|
accessParams[i] = new StorageTester.AccessParam(config.SizeClassProbs[i], config.SizeClassMaxSizes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var testerConfig = new StorageTester.Configuration
|
||||||
{
|
{
|
||||||
Entries = [memoryStorageEntry, bufferedStorageEntry],
|
Entries = [memoryStorageEntry, bufferedStorageEntry],
|
||||||
SizeClassProbs = config.SizeClassProbs,
|
AccessParams = accessParams,
|
||||||
SizeClassMaxSizes = config.SizeClassMaxSizes,
|
|
||||||
TaskProbs = config.TaskProbs,
|
TaskProbs = config.TaskProbs,
|
||||||
AccessTypeProbs = config.AccessTypeProbs,
|
AccessTypeProbs = config.AccessTypeProbs,
|
||||||
RngSeed = config.RngSeed,
|
RngSeed = config.RngSeed,
|
||||||
|
|
|
@ -340,11 +340,16 @@ public class IndirectStorageTests : IClassFixture<IndirectStorageBuffers>
|
||||||
var memoryStorageEntry = new StorageTester.Entry(memoryStorage, expectedStorageArray);
|
var memoryStorageEntry = new StorageTester.Entry(memoryStorage, expectedStorageArray);
|
||||||
var indirectStorageEntry = new StorageTester.Entry(indirectStorage, expectedStorageArray);
|
var indirectStorageEntry = new StorageTester.Entry(indirectStorage, expectedStorageArray);
|
||||||
|
|
||||||
var testerConfig = new StorageTester.Configuration()
|
var accessParams = new StorageTester.AccessParam[accessConfig.SizeClassProbs.Length];
|
||||||
|
for (int i = 0; i < accessParams.Length; i++)
|
||||||
|
{
|
||||||
|
accessParams[i] = new StorageTester.AccessParam(accessConfig.SizeClassProbs[i], accessConfig.SizeClassMaxSizes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var testerConfig = new StorageTester.Configuration
|
||||||
{
|
{
|
||||||
Entries = [memoryStorageEntry, indirectStorageEntry],
|
Entries = [memoryStorageEntry, indirectStorageEntry],
|
||||||
SizeClassProbs = accessConfig.SizeClassProbs,
|
AccessParams = accessParams,
|
||||||
SizeClassMaxSizes = accessConfig.SizeClassMaxSizes,
|
|
||||||
TaskProbs = accessConfig.TaskProbs,
|
TaskProbs = accessConfig.TaskProbs,
|
||||||
AccessTypeProbs = accessConfig.AccessTypeProbs,
|
AccessTypeProbs = accessConfig.AccessTypeProbs,
|
||||||
RngSeed = accessConfig.RngSeed,
|
RngSeed = accessConfig.RngSeed,
|
||||||
|
|
Loading…
Reference in a new issue