Skip to content

Commit

Permalink
Implement blacklist functionality
Browse files Browse the repository at this point in the history
- Added blacklist status to FunctionProfile
- Added PPTC Info file updater from v5518 and updated old updater logic to allow multiple update passes
- Added blacklist check to PPTC Cache loading
- Added marking functions as blacklisted if they do not yet exist at PPTC translation time
- Logger now shows how many functions were blacklisted when translating new functions to PPTC cache
  • Loading branch information
LotP1 committed Dec 14, 2024
1 parent d7a7936 commit ddd3e47
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 14 deletions.
54 changes: 50 additions & 4 deletions src/ARMeilleure/Translation/PTC/Ptc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Common;
using ARMeilleure.Memory;
using ARMeilleure.State;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
Expand Down Expand Up @@ -30,7 +31,7 @@ class Ptc : IPtcLoadState
private const string OuterHeaderMagicString = "PTCohd\0\0";
private const string InnerHeaderMagicString = "PTCihd\0\0";

private const uint InternalVersion = 6997; //! To be incremented manually for each change to the ARMeilleure project.
private const uint InternalVersion = 7007; //! To be incremented manually for each change to the ARMeilleure project.

private const string ActualDir = "0";
private const string BackupDir = "1";
Expand Down Expand Up @@ -185,6 +186,36 @@ private void ResetCarriersIfNeeded()
InitializeCarriers();
}

private bool ContainsBlacklistedFunctions()
{
List<ulong> blacklist = Profiler.GetBlacklistedFunctions();
bool containsBlacklistedFunctions = false;
_infosStream.Seek(0L, SeekOrigin.Begin);
bool foundBadFunction = false;

for (int index = 0; index < GetEntriesCount(); index++)
{
InfoEntry infoEntry = DeserializeStructure<InfoEntry>(_infosStream);
foreach (ulong address in blacklist)
{
if (infoEntry.Address == address)
{
containsBlacklistedFunctions = true;
Logger.Warning?.Print(LogClass.Ptc, "PPTC cache invalidated: Found blacklisted functions in PPTC cache");
foundBadFunction = true;
break;
}
}

if (foundBadFunction)
{
break;
}
}

return containsBlacklistedFunctions;
}

private void PreLoad()
{
string fileNameActual = $"{CachePathActual}.cache";
Expand Down Expand Up @@ -533,7 +564,7 @@ private unsafe void Save(string fileName)

public void LoadTranslations(Translator translator)
{
if (AreCarriersEmpty())
if (AreCarriersEmpty() || ContainsBlacklistedFunctions())
{
return;
}
Expand Down Expand Up @@ -836,10 +867,18 @@ void TranslateFuncs()
while (profiledFuncsToTranslate.TryDequeue(out var item))
{
ulong address = item.address;
ExecutionMode executionMode = item.funcProfile.Mode;
bool highCq = item.funcProfile.HighCq;

Debug.Assert(Profiler.IsAddressInStaticCodeRange(address));

TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq);
TranslatedFunction func = translator.Translate(address, executionMode, highCq);

if (func == null)
{
Profiler.UpdateEntry(address, executionMode, true, true);
continue;
}

bool isAddressUnique = translator.Functions.TryAdd(address, func.GuestSize, func);

Expand Down Expand Up @@ -886,7 +925,14 @@ void TranslateFuncs()

PtcStateChanged?.Invoke(PtcLoadingState.Loaded, _translateCount, _translateTotalCount);

Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism} in {sw.Elapsed.TotalSeconds} s");
if (_translateCount == _translateTotalCount)
{
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | Thread count: {degreeOfParallelism} in {sw.Elapsed.TotalSeconds} s");
}
else
{
Logger.Info?.Print(LogClass.Ptc, $"{_translateCount} of {_translateTotalCount} functions translated | {_translateTotalCount - _translateCount} function{(_translateTotalCount - _translateCount != 1 ? "s" : "")} blacklisted | Thread count: {degreeOfParallelism} in {sw.Elapsed.TotalSeconds} s");
}

Thread preSaveThread = new(PreSave)
{
Expand Down
86 changes: 76 additions & 10 deletions src/ARMeilleure/Translation/PTC/PtcProfiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ class PtcProfiler
{
private const string OuterHeaderMagicString = "Pohd\0\0\0\0";

private const uint InternalVersion = 5518; //! Not to be incremented manually for each change to the ARMeilleure project.
private const uint InternalVersion = 7007; //! Not to be incremented manually for each change to the ARMeilleure project.

private static readonly uint[] _migrateInternalVersions = {
1866,
5518,
};

private const int SaveInterval = 30; // Seconds.
Expand Down Expand Up @@ -74,20 +75,30 @@ public PtcProfiler(Ptc ptc)
Enabled = false;
}

public void AddEntry(ulong address, ExecutionMode mode, bool highCq)
public void AddEntry(ulong address, ExecutionMode mode, bool highCq, bool blacklist = false)
{
if (IsAddressInStaticCodeRange(address))
{
Debug.Assert(!highCq);

lock (_lock)
if (blacklist)
{
ProfiledFuncs.TryAdd(address, new FuncProfile(mode, highCq: false));
lock (_lock)
{
ProfiledFuncs[address] = new FuncProfile(mode, highCq: false, true);
}
}
else
{
lock (_lock)
{
ProfiledFuncs.TryAdd(address, new FuncProfile(mode, highCq: false, false));
}
}
}
}

public void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
public void UpdateEntry(ulong address, ExecutionMode mode, bool highCq, bool? blacklist = null)
{
if (IsAddressInStaticCodeRange(address))
{
Expand All @@ -97,7 +108,7 @@ public void UpdateEntry(ulong address, ExecutionMode mode, bool highCq)
{
Debug.Assert(ProfiledFuncs.ContainsKey(address));

ProfiledFuncs[address] = new FuncProfile(mode, highCq: true);
ProfiledFuncs[address] = new FuncProfile(mode, highCq: true, blacklist ?? ProfiledFuncs[address].Blacklist);
}
}
}
Expand All @@ -113,7 +124,7 @@ public bool IsAddressInStaticCodeRange(ulong address)

foreach (var profiledFunc in ProfiledFuncs)
{
if (!funcs.ContainsKey(profiledFunc.Key))
if (!funcs.ContainsKey(profiledFunc.Key) && !profiledFunc.Value.Blacklist)
{
profiledFuncsToTranslate.Enqueue((profiledFunc.Key, profiledFunc.Value));
}
Expand All @@ -128,6 +139,24 @@ public void ClearEntries()
ProfiledFuncs.TrimExcess();
}

public List<ulong> GetBlacklistedFunctions()
{
List<ulong> funcs = new List<ulong>();

foreach (var profiledFunc in ProfiledFuncs)
{
if (profiledFunc.Value.Blacklist)
{
if (!funcs.Contains(profiledFunc.Key))
{
funcs.Add(profiledFunc.Key);
}
}
}

return funcs;
}

public void PreLoad()
{
_lastHash = default;
Expand Down Expand Up @@ -218,13 +247,18 @@ private bool Load(string fileName, bool isBackup)
return false;
}

Func<ulong, FuncProfile, (ulong, FuncProfile)> migrateEntryFunc = null;

switch (outerHeader.InfoFileVersion)
{
case InternalVersion:
ProfiledFuncs = Deserialize(stream);
break;
case 1866:
ProfiledFuncs = Deserialize(stream, (address, profile) => (address + 0x500000UL, profile));
migrateEntryFunc = (address, profile) => (address + 0x500000UL, profile);
goto case 5518;
case 5518:
ProfiledFuncs = DeserializeAddBlacklist(stream, migrateEntryFunc);
break;
default:
Logger.Error?.Print(LogClass.Ptc, $"No migration path for {nameof(outerHeader.InfoFileVersion)} '{outerHeader.InfoFileVersion}'. Discarding cache.");
Expand Down Expand Up @@ -254,6 +288,16 @@ private static Dictionary<ulong, FuncProfile> Deserialize(Stream stream, Func<ul
return DeserializeDictionary<ulong, FuncProfile>(stream, DeserializeStructure<FuncProfile>);
}

private static Dictionary<ulong, FuncProfile> DeserializeAddBlacklist(Stream stream, Func<ulong, FuncProfile, (ulong, FuncProfile)> migrateEntryFunc = null)
{
if (migrateEntryFunc != null)
{
return DeserializeAndUpdateDictionary(stream, (Stream stream) => { return new FuncProfile(DeserializeStructure<FuncProfilePreBlacklist>(stream)); }, migrateEntryFunc);
}

return DeserializeDictionary<ulong, FuncProfile>(stream, (Stream stream) => { return new FuncProfile(DeserializeStructure<FuncProfilePreBlacklist>(stream)); });
}

private static ReadOnlySpan<byte> GetReadOnlySpan(MemoryStream memoryStream)
{
return new(memoryStream.GetBuffer(), (int)memoryStream.Position, (int)memoryStream.Length - (int)memoryStream.Position);
Expand Down Expand Up @@ -385,13 +429,35 @@ public bool IsHeaderValid()
}
}

[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)]
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 6*/)]
public struct FuncProfile
{
public ExecutionMode Mode;
public bool HighCq;
public bool Blacklist;

public FuncProfile(ExecutionMode mode, bool highCq, bool blacklist)
{
Mode = mode;
HighCq = highCq;
Blacklist = blacklist;
}

public FuncProfile(FuncProfilePreBlacklist fp)
{
Mode = fp.Mode;
HighCq = fp.HighCq;
Blacklist = false;
}
}

[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 5*/)]
public struct FuncProfilePreBlacklist
{
public ExecutionMode Mode;
public bool HighCq;

public FuncProfile(ExecutionMode mode, bool highCq)
public FuncProfilePreBlacklist(ExecutionMode mode, bool highCq)
{
Mode = mode;
HighCq = highCq;
Expand Down
10 changes: 10 additions & 0 deletions src/ARMeilleure/Translation/Translator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,11 @@ internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool hi

ControlFlowGraph cfg = EmitAndGetCFG(context, blocks, out Range funcRange, out Counter<uint> counter);

if (cfg == null)
{
return null;
}

ulong funcSize = funcRange.End - funcRange.Start;

Logger.EndPass(PassName.Translation, cfg);
Expand Down Expand Up @@ -407,6 +412,11 @@ private static ControlFlowGraph EmitAndGetCFG(
if (opCode.Instruction.Emitter != null)
{
opCode.Instruction.Emitter(context);
if (opCode.Instruction.Name == InstName.Und && blkIndex == 0)
{
range = new Range(rangeStart, rangeEnd);
return null;
}
}
else
{
Expand Down

0 comments on commit ddd3e47

Please sign in to comment.