Skip to content

Instantly share code, notes, and snippets.

@MichalStrehovsky
Last active December 19, 2023 14:12
Show Gist options
  • Save MichalStrehovsky/2c7cb3d623c7f8901541914dab04238d to your computer and use it in GitHub Desktop.
Save MichalStrehovsky/2c7cb3d623c7f8901541914dab04238d to your computer and use it in GitHub Desktop.
v2 compat fix
using System.Collections.Generic;
using System;
using Mono.Cecil;
using Mono.Cecil.Rocks;
using System.Linq;
internal class Program
{
static void Main(string[] args)
{
var asm = AssemblyDefinition.ReadAssembly(@"C:\Temp\Albums\AlbumsNetCore\obj\Release\net7.0\win-x64\native\AlbumsNetCore.mstat");
var globalType = (TypeDefinition)asm.MainModule.LookupToken(0x02000001);
int versionMajor = asm.Name.Version.Major;
var types = globalType.Methods.First(x => x.Name == "Types");
var typeStats = GetTypes(versionMajor, types).ToList();
var typeSize = typeStats.Sum(x => x.Size);
var typesByModules = typeStats.GroupBy(x => x.Type.Scope).Select(x => new { x.Key.Name, Sum = x.Sum(x => x.Size) }).ToList();
Console.WriteLine($"// ********** Types Total Size {typeSize:n0}");
foreach (var m in typesByModules.OrderByDescending(x => x.Sum))
{
Console.WriteLine($"{m.Name,-40} {m.Sum,7:n0}");
}
Console.WriteLine($"// **********");
Console.WriteLine();
var methods = globalType.Methods.First(x => x.Name == "Methods");
var methodStats = GetMethods(versionMajor, methods).ToList();
var methodSize = methodStats.Sum(x => x.Size + x.GcInfoSize + x.EhInfoSize);
var methodsByModules = methodStats.GroupBy(x => x.Method.DeclaringType.Scope).Select(x => new { x.Key.Name, Sum = x.Sum(x => x.Size + x.GcInfoSize + x.EhInfoSize) }).ToList();
Console.WriteLine($"// ********** Methods Total Size {methodSize:n0}");
foreach (var m in methodsByModules.OrderByDescending(x => x.Sum))
{
Console.WriteLine($"{m.Name,-40} {m.Sum,7:n0}");
}
Console.WriteLine($"// **********");
Console.WriteLine();
string FindNamespace(TypeReference type)
{
var current = type;
while (true)
{
if (!String.IsNullOrEmpty(current.Namespace))
{
return current.Namespace;
}
if (current.DeclaringType == null)
{
return current.Name;
}
current = current.DeclaringType;
}
}
var methodsByNamespace = methodStats.Select(x => new TypeStats { Type = x.Method.DeclaringType, Size = x.Size + x.GcInfoSize + x.EhInfoSize }).Concat(typeStats).GroupBy(x => FindNamespace(x.Type)).Select(x => new { x.Key, Sum = x.Sum(x => x.Size) }).ToList();
Console.WriteLine($"// ********** Size By Namespace");
foreach (var m in methodsByNamespace.OrderByDescending(x => x.Sum))
{
Console.WriteLine($"{m.Key,-40} {m.Sum,7:n0}");
}
Console.WriteLine($"// **********");
Console.WriteLine();
var blobs = globalType.Methods.First(x => x.Name == "Blobs");
var blobStats = GetBlobs(blobs).ToList();
var blobSize = blobStats.Sum(x => x.Size);
Console.WriteLine($"// ********** Blobs Total Size {blobSize:n0}");
foreach (var m in blobStats.OrderByDescending(x => x.Size))
{
Console.WriteLine($"{m.Name,-40} {m.Size,7:n0}");
}
Console.WriteLine($"// **********");
}
public static IEnumerable<TypeStats> GetTypes(int formatVersion, MethodDefinition types)
{
int entrySize = formatVersion == 1 ? 2 : 3;
types.Body.SimplifyMacros();
var il = types.Body.Instructions;
for (int i = 0; i + entrySize < il.Count; i += entrySize)
{
var type = (TypeReference)il[i + 0].Operand;
var size = (int)il[i + 1].Operand;
yield return new TypeStats
{
Type = type,
Size = size
};
}
}
public static IEnumerable<MethodStats> GetMethods(int formatVersion, MethodDefinition methods)
{
int entrySize = formatVersion == 1 ? 4 : 5;
methods.Body.SimplifyMacros();
var il = methods.Body.Instructions;
for (int i = 0; i + entrySize < il.Count; i += entrySize)
{
var method = (MethodReference)il[i + 0].Operand;
var size = (int)il[i + 1].Operand;
var gcInfoSize = (int)il[i + 2].Operand;
var ehInfoSize = (int)il[i + 3].Operand;
yield return new MethodStats
{
Method = method,
Size = size,
GcInfoSize = gcInfoSize,
EhInfoSize = ehInfoSize
};
}
}
public static IEnumerable<BlobStats> GetBlobs(MethodDefinition blobs)
{
blobs.Body.SimplifyMacros();
var il = blobs.Body.Instructions;
for (int i = 0; i + 2 < il.Count; i += 2)
{
var name = (string)il[i + 0].Operand;
var size = (int)il[i + 1].Operand;
yield return new BlobStats
{
Name = name,
Size = size
};
}
}
}
public class TypeStats
{
public TypeReference Type { get; set; }
public int Size { get; set; }
}
public class MethodStats
{
public MethodReference Method { get; set; }
public int Size { get; set; }
public int GcInfoSize { get; set; }
public int EhInfoSize { get; set; }
}
public class BlobStats
{
public string Name { get; set; }
public int Size { get; set; }
}
@amcasey
Copy link

amcasey commented Feb 25, 2023

@MichalStrehovsky I think FindNamespace needs to unwrap array types too (chiefly for dictionary entry arrays).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment