Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions Dashboard/Services/DatabaseService.FinOps.Recommendations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,11 @@ FROM collect.memory_stats AS ms
var sampleCount = memReader.IsDBNull(1) ? 0L : Convert.ToInt64(memReader.GetValue(1));
var physMb = memReader.IsDBNull(2) ? 0 : Convert.ToInt32(memReader.GetValue(2));

// Need at least ~1 day of samples (one per minute baseline) to trust the P95
if (physMb > 0 && sampleCount >= 500)
// Need a handful of samples to compute a meaningful P95 — single
// readings can be misleading, but ~16 samples is enough to smooth
// out a single-point anomaly without delaying the recommendation
// for hours after a fresh install.
if (physMb > 0 && sampleCount >= 16)
{
var memRatio = (decimal)p95Mb / physMb;
if (memRatio < 0.50m && physMb > 8192)
Expand Down Expand Up @@ -531,8 +534,8 @@ FROM collect.memory_stats AS ms
}
}

// Memory prescription: needs >= 4 GB physical and at least ~1 day of samples
if (physMb >= 4096 && physMb > 0 && memSampleCount >= 500)
// Memory prescription: needs >= 4 GB physical and a handful of samples
if (physMb >= 4096 && physMb > 0 && memSampleCount >= 16)
{
var memRatio = (decimal)p95Mb / physMb;
int targetMb = 0;
Expand Down
32 changes: 19 additions & 13 deletions Lite/Analysis/TestDataSeeder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -885,33 +885,39 @@ INSERT INTO wait_stats
}

/// <summary>
/// Seeds memory_stats with physical memory, buffer pool, and target memory values.
/// Seeds memory_stats with physical memory, buffer pool, and target memory values
/// across 16 collection points so 7-day P95 queries (used by FinOps memory
/// recommendations) have enough samples to fire.
/// </summary>
internal async Task SeedMemoryStatsAsync(double totalPhysicalMb, double bufferPoolMb, double targetMb)
{
using var readLock = _duckDb.AcquireReadLock();
using var connection = _duckDb.CreateConnection();
await connection.OpenAsync();

using var cmd = connection.CreateCommand();
cmd.CommandText = @"
for (var i = 0; i < 16; i++)
{
using var cmd = connection.CreateCommand();
cmd.CommandText = @"
INSERT INTO memory_stats
(collection_id, collection_time, server_id, server_name,
total_physical_memory_mb, available_physical_memory_mb,
target_server_memory_mb, total_server_memory_mb, buffer_pool_mb)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)";

cmd.Parameters.Add(new DuckDBParameter { Value = _nextId-- });
cmd.Parameters.Add(new DuckDBParameter { Value = TestPeriodEnd });
cmd.Parameters.Add(new DuckDBParameter { Value = TestServerId });
cmd.Parameters.Add(new DuckDBParameter { Value = TestServerName });
cmd.Parameters.Add(new DuckDBParameter { Value = totalPhysicalMb });
cmd.Parameters.Add(new DuckDBParameter { Value = totalPhysicalMb - bufferPoolMb }); // available = total - used
cmd.Parameters.Add(new DuckDBParameter { Value = targetMb });
cmd.Parameters.Add(new DuckDBParameter { Value = bufferPoolMb });
cmd.Parameters.Add(new DuckDBParameter { Value = bufferPoolMb });
var t = TestPeriodStart.AddMinutes(i * 15);
cmd.Parameters.Add(new DuckDBParameter { Value = _nextId-- });
cmd.Parameters.Add(new DuckDBParameter { Value = t });
cmd.Parameters.Add(new DuckDBParameter { Value = TestServerId });
cmd.Parameters.Add(new DuckDBParameter { Value = TestServerName });
cmd.Parameters.Add(new DuckDBParameter { Value = totalPhysicalMb });
cmd.Parameters.Add(new DuckDBParameter { Value = totalPhysicalMb - bufferPoolMb }); // available = total - used
cmd.Parameters.Add(new DuckDBParameter { Value = targetMb });
cmd.Parameters.Add(new DuckDBParameter { Value = bufferPoolMb });
cmd.Parameters.Add(new DuckDBParameter { Value = bufferPoolMb });

await cmd.ExecuteNonQueryAsync();
await cmd.ExecuteNonQueryAsync();
}
}

/// <summary>
Expand Down
11 changes: 7 additions & 4 deletions Lite/Services/LocalDataService.FinOps.Recommendations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,11 @@ FROM v_memory_stats
}
}

// Need at least ~1 day of samples (one per minute baseline) to trust the P95
if (sampleCount >= 500)
// Need a handful of samples to compute a meaningful P95 — single
// readings can be misleading, but ~16 samples is enough to smooth
// out a single-point anomaly without delaying the recommendation
// for hours after a fresh install.
if (sampleCount >= 16)
{
var memRatio = (decimal)p95Mb / util.PhysicalMemoryMb;
if (memRatio < 0.50m)
Expand Down Expand Up @@ -553,8 +556,8 @@ FROM v_memory_stats
}
}

// Memory prescription: needs >= 4 GB physical and at least ~1 day of samples
if (physMb >= 4096 && physMb > 0 && memSampleCount >= 500)
// Memory prescription: needs >= 4 GB physical and a handful of samples
if (physMb >= 4096 && physMb > 0 && memSampleCount >= 16)
{
var memRatio = (decimal)p95MemMb / physMb;
int targetMb = 0;
Expand Down
Loading