public static void ExecuteWorker(int[] LocalCalls, double[] LocalTimes, int currentLogCount) { try { // todo // implement a custom sorting which also keeps track of the sum. // this will take this from // o(2*nlogn + n) to o(2*nlogn) var stats = GatherStats(LocalCalls, LocalTimes, currentLogCount); lock (CurrentLogStats.sync) // Dump our current statistics into our static class which our drawing class uses { CurrentLogStats.stats = stats; } } catch (Exception e) { #if DEBUG ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed while calculating stats for profiler"); #else if (Settings.verboseLogging) { ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed while calculating stats for profiler"); } #endif } }
public static void ProfilePatch() { var patches = Harmony.GetAllPatchedMethods().ToList(); var filteredTranspilers = patches .Where(m => Harmony.GetPatchInfo(m).Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner) && !TranspilerMethodUtility.PatchedMeths.Contains(m))) .ToList(); TranspilerMethodUtility.PatchedMeths.AddRange(filteredTranspilers); foreach (var meth in filteredTranspilers) { try { Modbase.Harmony.Patch(meth, transpiler: TranspilerMethodUtility.TranspilerProfiler); } catch (Exception e) { #if DEBUG ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed to patch transpiler {Utility.GetSignature(meth, false)}"); #endif #if NDEBUG if (Settings.verboseLogging) { ThreadSafeLogger.ReportException(e, $"[Analyzer] Failed to patch transpiler {Utility.GetSignature(meth, false)}"); } #endif } } }
public static void ProfilePatch() { try { MethodTransplanting.PatchMethods(typeof(H_HarmonyPatches)); } catch (Exception e) { ThreadSafeLogger.ReportException(e, "Failed to patch HarmonyPatches"); } }
public static void ExecutePatch(CurrentInput mode, string strinput, Category cat) { try { var entry = cat == Category.Tick ? typeof(CustomProfilersTick) : typeof(CustomProfilersUpdate); List <MethodInfo> methods = null; var temp = mode switch { CurrentInput.Method => Utility.GetMethods(strinput), CurrentInput.Type => Utility.GetTypeMethods(AccessTools.TypeByName(strinput)), CurrentInput.MethodHarmony => Utility.GetMethodsPatching(strinput), CurrentInput.SubClasses => Utility.SubClassImplementationsOf(AccessTools.TypeByName(strinput), m => true), CurrentInput.TypeHarmony => Utility.GetMethodsPatchingType(AccessTools.TypeByName(strinput)), _ => null, }; if (temp is null) { if (mode == CurrentInput.InternalMethod) { Utility.PatchInternalMethod(strinput, cat); } else { Utility.PatchAssembly(strinput, cat); } return; } methods = temp.ToList(); if (methods.Count == 0) { Messages.Message($"Failed to find the method(s) represented by {strinput}", MessageTypeDefOf.CautionInput, false); return; } Messages.Message(methods.Count != 1 ? $"Patching {methods.Count} methods in the category {cat}" : $"Patching {Utility.GetSignature(methods[0])} in the category {cat}", MessageTypeDefOf.CautionInput, false); MethodTransplanting.UpdateMethods(entry, methods.ToList()); GUIController.Tab(cat).collapsed = false; var entryName = (cat == Category.Tick) ? "Custom Tick" : "Custom Update"; GUIController.SwapToEntry(entryName); } catch (Exception e) { ThreadSafeLogger.ReportException(e, $"Failed to process search bar input"); } }
private static void ReportException(Exception e, string message) { #if DEBUG ThreadSafeLogger.ReportException(e, $"[Analyzer] Patching error: {message}"); #endif #if NDEBUG if (!displayMessages) { return; } ThreadSafeLogger.ReportException(e, message); #endif }
public static void ProfilePatch() { var jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new[] { typeof(BuildableDef), typeof(StatDef), typeof(ThingDef) }); var pre = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAb)); var post = new HarmonyMethod(typeof(H_GetStatValue), nameof(Postfix)); Modbase.Harmony.Patch(jiff, pre, post); jiff = AccessTools.Method(typeof(StatExtension), nameof(StatExtension.GetStatValueAbstract), new[] { typeof(AbilityDef), typeof(StatDef), typeof(Pawn) }); pre = new HarmonyMethod(typeof(H_GetStatValue), nameof(PrefixAbility)); Modbase.Harmony.Patch(jiff, pre, post); jiff = AccessTools.Method(typeof(StatWorker), nameof(StatWorker.GetValue), new[] { typeof(StatRequest), typeof(bool) }); pre = new HarmonyMethod(typeof(H_GetStatValue), nameof(GetValueDetour)); Modbase.Harmony.Patch(jiff, pre); HarmonyMethod go = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPrefix)); HarmonyMethod biff = new HarmonyMethod(typeof(H_GetStatValue), nameof(PartPostfix)); foreach (Type allLeafSubclass in typeof(StatPart).AllSubclassesNonAbstract()) { try { MethodInfo mef = AccessTools.Method(allLeafSubclass, nameof(StatPart.TransformValue), new Type[] { typeof(StatRequest), typeof(float).MakeByRefType() }); if (mef.DeclaringType == allLeafSubclass) { HarmonyLib.Patches info = Harmony.GetPatchInfo(mef); bool F = true; if (info != null) { foreach (Patch infoPrefix in info.Prefixes) { if (infoPrefix.PatchMethod == go.method) { F = false; } } } if (F) { Modbase.Harmony.Patch(mef, go, biff); } } } catch (Exception e) { ThreadSafeLogger.ReportException(e, $"Failed to patch {allLeafSubclass} from {allLeafSubclass.Assembly.FullName} for profiling"); } } }
internal static void Prefix(string id) { try { if (Utility.IsNotAnalyzerPatch(id) is false) { return; } // Can't be sure that the JIT won't inline the constructor of harmony // so we need to manually trawl until we find a method which doesn't belong // to either dpa or harmony. (this prefix, and the harmony ctor) var frames = new StackTrace(false).GetFrames(); if (frames == null) { return; } var methods = frames.Select(Harmony.GetMethodFromStackframe).Select(m => m is MethodInfo mi ? Harmony.GetOriginalMethod(mi) ?? m : m); // find the first non harmony/dpa method in the stack trace and assoc the asm // that method is from with the stack trace foreach (var method in methods) { var asm = method.DeclaringType?.Assembly ?? method.ReflectedType?.Assembly; if (asm == null) { continue; } if (asm.FullName.Contains("Harmony") || asm == dpaAssembly) { continue; } // we snipe this in another way if (method.Name == "ApplyHarmonyPatches") { return; } StackTraceUtility.RegisterHarmonyId(id, asm); return; } } catch (Exception e) // lets be exceedingly careful. { ThreadSafeLogger.ReportException(e, "Failed to capture Harmony ctor"); } }
public static EntryFile ReadFile(FileInfo file) { var entryFile = new EntryFile(); try { using (var reader = new BinaryReader(file.OpenRead())) { entryFile.header = ReadHeader(reader); if (entryFile.header.MAGIC == -1) { return(null); } entryFile.times = new double[entryFile.header.entries]; entryFile.calls = new int[entryFile.header.entries]; if (entryFile.header.entryPerCall) { Array.Fill(entryFile.calls, 1); } for (int i = 0; i < entryFile.header.entries; i++) { entryFile.times[i] = reader.ReadDouble(); if (!entryFile.header.entryPerCall) { entryFile.calls[i] = reader.ReadInt32(); } } reader.Close(); reader.Dispose(); } } catch (Exception e) { ThreadSafeLogger.ReportException(e, "Failed while reading entry file from disk."); } return(entryFile); }
private static IEnumerable <CodeInstruction> Transpiler(MethodBase __originalMethod, IEnumerable <CodeInstruction> codeInstructions) { try { var instructions = codeInstructions.ToList(); for (int i = 0; i < instructions.Count; i++) { if (!Utility.ValidCallInstruction(instructions[i], i == 0 ? null : instructions[i - 1], out var meth, out var key)) { continue; } var index = MethodInfoCache.AddMethod(key, meth); var inst = MethodTransplanting.ReplaceMethodInstruction( instructions[i], key, GUIController.types[__originalMethod.DeclaringType + ":" + __originalMethod.Name + "-int"], index); instructions[i] = inst; } return(instructions); } catch (Exception e) { #if DEBUG ThreadSafeLogger.ReportException(e, $"Failed to patch the methods inside {Utility.GetSignature(__originalMethod, false)}"); #else if (Settings.verboseLogging) { ThreadSafeLogger.ReportException(e, $"Failed to patch the methods inside {Utility.GetSignature(__originalMethod, false)}"); } #endif return(codeInstructions); } }
public static void WriteFile(EntryFile file) { var fileName = FinalFileNameFor(file.header.methodName); try { using (var writer = new BinaryWriter(File.Open(fileName, FileMode.Create))) { writer.Write(file.header.MAGIC); writer.Write(file.header.scribingVer); writer.Write(file.header.methodName); writer.Write(file.header.name); writer.Write(file.header.entryPerCall); writer.Write(file.header.onlyEntriesWithValues); writer.Write(file.header.entries); writer.Write(file.header.targetEntries); // interleaved is faster by profiling, (even if less cache-efficient) for (var i = 0; i < file.header.entries; i++) { writer.Write(file.times[i]); if (!file.header.entryPerCall) { writer.Write(file.calls[i]); } } writer.Close(); writer.Dispose(); } } catch (Exception e) { ThreadSafeLogger.ReportException(e, $"Caught an exception when writing file to disk, if the file exists on disk, it should be deleted at {fileName}"); } changed = true; }
public static IEnumerable <MethodInfo> GetPatchMethods() { var patches = Harmony.GetAllPatchedMethods().ToList(); foreach (var patch in patches) { HarmonyLib.Patches p = null; try { p = Harmony.GetPatchInfo(patch); } catch (Exception e) { ThreadSafeLogger.ReportException(e, $"Failed to get patch info for {Utility.GetSignature(patch)}"); continue; } if (patch is MethodInfo info && p.Transpilers.Any(p => Utility.IsNotAnalyzerPatch(p.owner))) { yield return(info); } } }
internal static void UpdateMethod(Type type, MethodInfo meth) { if (patchedMeths.Contains(meth)) { #if DEBUG ThreadSafeLogger.Warning($"[Analyzer] Already patched method {meth.DeclaringType.FullName + ":" + meth.Name}"); #else if (Settings.verboseLogging) { ThreadSafeLogger.Warning($"[Analyzer] Already patched method {Utility.GetSignature(meth, false)}"); } #endif return; } patchedMeths.Add(meth); typeInfo.TryAdd(meth, type); Task.Factory.StartNew(delegate { try { Modbase.Harmony.Patch(meth, transpiler: transpiler); } catch (Exception e) { #if DEBUG ThreadSafeLogger.ReportException(e, $"Failed to patch the method {Utility.GetSignature(meth, false)}"); #else if (Settings.verboseLogging) { ThreadSafeLogger.ReportException(e, $"Failed to patch the method {Utility.GetSignature(meth, false)}"); } #endif } }); }