From 5457a81068b00791920c9253c33635248dd9329e Mon Sep 17 00:00:00 2001 From: Alex Barney Date: Fri, 1 Feb 2019 16:15:28 -0600 Subject: [PATCH] Improve rom file table read/write performance --- .../IO/RomFs/HierarchicalRomFileTable.cs | 14 ++++ src/LibHac/IO/RomFs/RomFsDictionary.cs | 78 +++++++++---------- src/LibHac/IO/RomFs/RomFsEntries.cs | 32 ++------ 3 files changed, 56 insertions(+), 68 deletions(-) diff --git a/src/LibHac/IO/RomFs/HierarchicalRomFileTable.cs b/src/LibHac/IO/RomFs/HierarchicalRomFileTable.cs index d5a50065..fc160f3e 100644 --- a/src/LibHac/IO/RomFs/HierarchicalRomFileTable.cs +++ b/src/LibHac/IO/RomFs/HierarchicalRomFileTable.cs @@ -308,5 +308,19 @@ namespace LibHac.IO.RomFs return DirectoryTable.ContainsKey(ref key) || FileTable.ContainsKey(ref key); } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + private struct DirectoryRomEntry + { + public int NextSibling; + public FindPosition Pos; + } + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + private struct FileRomEntry + { + public int NextSibling; + public RomFileInfo Info; + } } } diff --git a/src/LibHac/IO/RomFs/RomFsDictionary.cs b/src/LibHac/IO/RomFs/RomFsDictionary.cs index d9f43035..cc6e75d8 100644 --- a/src/LibHac/IO/RomFs/RomFsDictionary.cs +++ b/src/LibHac/IO/RomFs/RomFsDictionary.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.IO; using System.Runtime.InteropServices; namespace LibHac.IO.RomFs @@ -47,7 +46,7 @@ namespace LibHac.IO.RomFs if (i >= 0) { - GetEntryInternal(i, out RomFsEntry entry); + ref RomFsEntry entry = ref GetEntryReference(i); value = new RomKeyValuePair { Key = key, Value = entry.Value, Offset = i }; return true; @@ -67,7 +66,9 @@ namespace LibHac.IO.RomFs value = new RomKeyValuePair(); - GetEntryInternal(offset, out RomFsEntry entry, out value.Key.Name); + ref RomFsEntry entry = ref GetEntryReference(offset, out Span name); + + value.Key.Name = name; value.Value = entry.Value; value.Key.Parent = entry.Parent; return true; @@ -78,9 +79,8 @@ namespace LibHac.IO.RomFs int i = FindEntry(ref key); if (i < 0) return false; - GetEntryInternal(i, out RomFsEntry entry); + ref RomFsEntry entry = ref GetEntryReference(i); entry.Value = value; - SetEntryInternal(i, ref entry); return true; } @@ -99,13 +99,14 @@ namespace LibHac.IO.RomFs int bucket = (int)(hashCode % Buckets.Length); int newOffset = FindOffsetForInsert(ref key); - var entry = new RomFsEntry(); + ref RomFsEntry entry = ref GetEntryReference(newOffset, out Span name, key.Name.Length); + entry.Next = Buckets[bucket]; entry.Parent = key.Parent; entry.KeyLength = key.Name.Length; entry.Value = value; - SetEntryInternal(newOffset, ref entry, ref key.Name); + key.Name.CopyTo(name); Buckets[bucket] = newOffset; _count++; @@ -135,7 +136,7 @@ namespace LibHac.IO.RomFs while (i != -1) { - GetEntryInternal(i, out RomFsEntry entry, out ReadOnlySpan name); + ref RomFsEntry entry = ref GetEntryReference(i, out Span name); if (key.Parent == entry.Parent && key.Name.SequenceEqual(name)) { @@ -148,35 +149,6 @@ namespace LibHac.IO.RomFs return i; } - private void GetEntryInternal(int offset, out RomFsEntry outEntry) - { - outEntry = MemoryMarshal.Read>(Entries.AsSpan(offset)); - } - - private void GetEntryInternal(int offset, out RomFsEntry outEntry, out ReadOnlySpan entryName) - { - GetEntryInternal(offset, out outEntry); - - if (outEntry.KeyLength > 0x300) - { - throw new InvalidDataException("Rom entry name is too long."); - } - - entryName = Entries.AsSpan(offset + _sizeOfEntry, outEntry.KeyLength); - } - - private void SetEntryInternal(int offset, ref RomFsEntry entry) - { - MemoryMarshal.Write(Entries.AsSpan(offset), ref entry); - } - - private void SetEntryInternal(int offset, ref RomFsEntry entry, ref ReadOnlySpan entryName) - { - MemoryMarshal.Write(Entries.AsSpan(offset), ref entry); - - entryName.CopyTo(Entries.AsSpan(offset + _sizeOfEntry, entry.KeyLength)); - } - private void EnsureCapacityBytes(int value) { if (value < 0) throw new ArgumentOutOfRangeException(nameof(value)); @@ -229,14 +201,12 @@ namespace LibHac.IO.RomFs newBuckets.AsSpan().Fill(-1); List offsets = GetEntryOffsets(); - var key = new RomEntryKey(); for (int i = 0; i < offsets.Count; i++) { - ref RomFsEntry entry = ref GetEntryReference(offsets[i], out key.Name); - key.Parent = entry.Parent; + ref RomFsEntry entry = ref GetEntryReference(offsets[i], out Span name); - uint hashCode = key.GetRomHashCode(); + uint hashCode = RomEntryKey.GetRomHashCode(entry.Parent, name); int bucket = (int)(hashCode % newSize); entry.Next = newBuckets[bucket]; @@ -246,14 +216,27 @@ namespace LibHac.IO.RomFs Buckets = newBuckets; } - private ref RomFsEntry GetEntryReference(int offset, out ReadOnlySpan name) + private ref RomFsEntry GetEntryReference(int offset) { - ref RomFsEntry entry = ref MemoryMarshal.Cast>(Entries.AsSpan(offset))[0]; + return ref MemoryMarshal.Cast(Entries.AsSpan(offset))[0]; + } + + private ref RomFsEntry GetEntryReference(int offset, out Span name) + { + ref RomFsEntry entry = ref MemoryMarshal.Cast(Entries.AsSpan(offset))[0]; name = Entries.AsSpan(offset + _sizeOfEntry, entry.KeyLength); return ref entry; } + private ref RomFsEntry GetEntryReference(int offset, out Span name, int nameLength) + { + ref RomFsEntry entry = ref MemoryMarshal.Cast(Entries.AsSpan(offset))[0]; + + name = Entries.AsSpan(offset + _sizeOfEntry, nameLength); + return ref entry; + } + private List GetEntryOffsets() { var offsets = new List(_count); @@ -277,5 +260,14 @@ namespace LibHac.IO.RomFs } private int EstimateEntryTableSize(int count) => (_sizeOfEntry + 0x10) * count; // Estimate 0x10 bytes per name + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + private struct RomFsEntry + { + public int Parent; + public T Value; + public int Next; + public int KeyLength; + } } } diff --git a/src/LibHac/IO/RomFs/RomFsEntries.cs b/src/LibHac/IO/RomFs/RomFsEntries.cs index 06d49c4b..f026fad8 100644 --- a/src/LibHac/IO/RomFs/RomFsEntries.cs +++ b/src/LibHac/IO/RomFs/RomFsEntries.cs @@ -16,9 +16,14 @@ namespace LibHac.IO.RomFs public uint GetRomHashCode() { - uint hash = 123456789 ^ (uint)Parent; + return GetRomHashCode(Parent, Name); + } - foreach (byte c in Name) + public static uint GetRomHashCode(int parent, ReadOnlySpan name) + { + uint hash = 123456789 ^ (uint)parent; + + foreach (byte c in name) { hash = c ^ ((hash << 27) | (hash >> 5)); } @@ -34,22 +39,6 @@ namespace LibHac.IO.RomFs public T Value; } - [StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct RomFsEntry where T : unmanaged - { - public int Parent; - public T Value; - public int Next; - public int KeyLength; - } - - [StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct FileRomEntry - { - public int NextSibling; - public RomFileInfo Info; - } - [StructLayout(LayoutKind.Sequential)] public struct RomFileInfo { @@ -57,13 +46,6 @@ namespace LibHac.IO.RomFs public long Length; } - [StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct DirectoryRomEntry - { - public int NextSibling; - public FindPosition Pos; - } - [StructLayout(LayoutKind.Sequential)] public struct FindPosition {