• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

orion-ecs / keen-eye / 20763214739

06 Jan 2026 09:50PM UTC coverage: 70.212% (-1.1%) from 71.324%
20763214739

push

github

tyevco
fix(ci): Correct placement of --max-parallel-test-modules option

The option was incorrectly placed after the -- separator (xUnit runner
options). It is a top-level dotnet test option and must be placed before
the -- separator.

This prevents test assemblies from running in parallel, which was
causing intermittent hangs due to ThreadPool contention.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

6646 of 9148 branches covered (72.65%)

Branch coverage included in aggregate %.

41510 of 59439 relevant lines covered (69.84%)

1.05 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.58
/src/KeenEyes.Debugging/MemoryTracker.cs
1
using KeenEyes.Capabilities;
2

3
namespace KeenEyes.Debugging;
4

5
/// <summary>
6
/// Tracks memory usage and provides detailed statistics about ECS memory consumption.
7
/// </summary>
8
/// <remarks>
9
/// <para>
10
/// The MemoryTracker provides convenient access to memory statistics
11
/// with additional formatting and reporting capabilities.
12
/// </para>
13
/// <para>
14
/// Memory estimates are approximations based on component sizes and entity counts. Actual
15
/// memory usage may vary due to internal data structures, padding, and CLR overhead.
16
/// </para>
17
/// </remarks>
18
/// <example>
19
/// <code>
20
/// var tracker = world.GetExtension&lt;MemoryTracker&gt;();
21
///
22
/// // Get overall memory stats
23
/// var stats = tracker.GetMemoryStats();
24
/// Console.WriteLine($"Total entities: {stats.EntitiesActive}");
25
/// Console.WriteLine($"Estimated bytes: {stats.EstimatedComponentBytes}");
26
///
27
/// // Print formatted report
28
/// Console.WriteLine(tracker.GetMemoryReport());
29
/// </code>
30
/// </example>
31
public sealed class MemoryTracker
32
{
33
    private readonly IStatisticsCapability statisticsCapability;
34

35
    /// <summary>
36
    /// Initializes a new instance of the <see cref="MemoryTracker"/> class.
37
    /// </summary>
38
    /// <param name="statisticsCapability">The statistics capability to use.</param>
39
    /// <exception cref="ArgumentNullException">Thrown when <paramref name="statisticsCapability"/> is null.</exception>
40
    public MemoryTracker(IStatisticsCapability statisticsCapability)
1✔
41
    {
42
        ArgumentNullException.ThrowIfNull(statisticsCapability);
1✔
43
        this.statisticsCapability = statisticsCapability;
1✔
44
    }
1✔
45

46
    /// <summary>
47
    /// Gets memory statistics for the world.
48
    /// </summary>
49
    /// <returns>Current memory statistics.</returns>
50
    public MemoryStats GetMemoryStats()
51
    {
52
        return statisticsCapability.GetMemoryStats();
1✔
53
    }
54

55
    /// <summary>
56
    /// Gets a formatted memory report as a string.
57
    /// </summary>
58
    /// <returns>A multi-line string containing formatted memory statistics.</returns>
59
    /// <remarks>
60
    /// This method is useful for logging or displaying memory information in a human-readable format.
61
    /// </remarks>
62
    public string GetMemoryReport()
63
    {
64
        var stats = GetMemoryStats();
1✔
65

66
        var report = new System.Text.StringBuilder();
1✔
67
        report.AppendLine("=== Memory Statistics ===");
1✔
68
        report.AppendLine($"Entities: {stats.EntitiesActive} active, {stats.EntitiesRecycled} recycled, {stats.EntitiesAllocated} total allocated");
1✔
69
        report.AppendLine($"Entity Recycling: {stats.EntityRecycleCount} reuses ({stats.RecycleEfficiency:F1}% efficiency)");
1✔
70
        report.AppendLine($"Archetypes: {stats.ArchetypeCount}");
1✔
71
        report.AppendLine($"Component Types: {stats.ComponentTypeCount}");
1✔
72
        report.AppendLine($"Systems: {stats.SystemCount}");
1✔
73
        report.AppendLine($"Estimated Component Memory: {FormatBytes(stats.EstimatedComponentBytes)}");
1✔
74
        report.AppendLine($"Query Cache: {stats.CachedQueryCount} queries, {stats.QueryCacheHitRate:F1}% hit rate");
1✔
75

76
        return report.ToString();
1✔
77
    }
78

79
    /// <summary>
80
    /// Gets detailed statistics for all archetypes in the world.
81
    /// </summary>
82
    /// <returns>A list of statistics for each archetype.</returns>
83
    /// <remarks>
84
    /// <para>
85
    /// Archetype statistics provide insight into how entities are distributed
86
    /// across different component combinations and the memory efficiency of each.
87
    /// </para>
88
    /// </remarks>
89
    public IReadOnlyList<ArchetypeStatistics> GetArchetypeStats()
90
    {
91
        return statisticsCapability.GetArchetypeStatistics();
1✔
92
    }
93

94
    /// <summary>
95
    /// Gets a formatted archetype report as a string.
96
    /// </summary>
97
    /// <returns>A multi-line string containing archetype statistics.</returns>
98
    /// <remarks>
99
    /// This method is useful for identifying fragmented archetypes or understanding
100
    /// the distribution of entities across component combinations.
101
    /// </remarks>
102
    public string GetArchetypeReport()
103
    {
104
        var archetypeStats = GetArchetypeStats();
1✔
105

106
        var report = new System.Text.StringBuilder();
1✔
107
        report.AppendLine("=== Archetype Statistics ===");
1✔
108
        report.AppendLine($"Total Archetypes: {archetypeStats.Count}");
1✔
109
        report.AppendLine();
1✔
110

111
        if (archetypeStats.Count == 0)
1✔
112
        {
113
            report.AppendLine("No archetypes in use.");
1✔
114
            return report.ToString();
1✔
115
        }
116

117
        // Sort by entity count descending
118
        var sorted = archetypeStats.OrderByDescending(s => s.EntityCount).ToList();
1✔
119

120
        report.AppendLine($"{"ID",-6} {"Entities",-10} {"Chunks",-8} {"Utilization",-12} {"Memory",-12} Components");
1✔
121
        report.AppendLine($"{new string('-', 6)} {new string('-', 10)} {new string('-', 8)} {new string('-', 12)} {new string('-', 12)} {new string('-', 30)}");
1✔
122

123
        foreach (var stat in sorted)
1✔
124
        {
125
            var components = string.Join(", ", stat.ComponentTypeNames);
1✔
126
            if (components.Length > 40)
1✔
127
            {
128
                components = components[..37] + "...";
×
129
            }
130

131
            report.AppendLine($"{stat.Id,-6} {stat.EntityCount,-10} {stat.ChunkCount,-8} {stat.UtilizationPercentage,10:F1}% {FormatBytes(stat.EstimatedMemoryBytes),-12} {components}");
1✔
132
        }
133

134
        return report.ToString();
1✔
135
    }
136

137
    private static string FormatBytes(long bytes)
138
    {
139
        if (bytes < 1024)
1✔
140
        {
141
            return $"{bytes} bytes";
1✔
142
        }
143

144
        if (bytes < 1024 * 1024)
1✔
145
        {
146
            return $"{bytes / 1024.0:F2} KB";
1✔
147
        }
148

149
        if (bytes < 1024 * 1024 * 1024)
×
150
        {
151
            return $"{bytes / (1024.0 * 1024):F2} MB";
×
152
        }
153

154
        return $"{bytes / (1024.0 * 1024 * 1024):F2} GB";
×
155
    }
156
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc