Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expunged all references to GoodLinq #3488

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public static PlotlyChart ChartCountForGCMethod((string name, List<CPUInfo> gcsT
ChartInfo? chartInfo = null)
{
Layout.Layout layout = ChartingHelpers.ConstructLayout(title: title, fieldName: data.name, xAxis: xAxisAsGCNumber, chartInfo: chartInfo);
List<float> cost = data.gcsToCost.Select(gc => gc.Count);
List<int> gcNumber = data.gcsToCost.Select(gc => gc.GC.Number);
List<float> cost = data.gcsToCost.EagerSelect(gc => gc.Count);
List<int> gcNumber = data.gcsToCost.EagerSelect(gc => gc.GC.Number);

Scatter scatter = new Scatter
{
Expand All @@ -31,8 +31,8 @@ public static PlotlyChart ChartCountForGCMethodWithGCData((string name, List<CPU
ChartInfo? chartInfo = null)
{
Layout.Layout layout = ChartingHelpers.ConstructLayout(title: title, fieldName: "Inclusive Count", xAxis: xAxisAsGCNumber, chartInfo: chartInfo);
List<float> cost = data.gcsToCost.Select(gc => gc.Count);
List<int> gcNumber = data.gcsToCost.Select(gc => gc.GC.Number);
List<float> cost = data.gcsToCost.EagerSelect(gc => gc.Count);
List<int> gcNumber = data.gcsToCost.EagerSelect(gc => gc.GC.Number);

layout.yaxis2 = new Yaxis { title = other.name, side = "right", overlaying = "y" };

Expand Down Expand Up @@ -65,8 +65,8 @@ public static PlotlyChart ChartCountForGCMethods(IEnumerable<(string name, List<

foreach(var d in data)
{
List<float> cost = d.gcsToCost.Select(gc => gc.Count);
List<int> gcNumber = d.gcsToCost.Select(gc => gc.GC.Number);
List<float> cost = d.gcsToCost.EagerSelect(gc => gc.Count);
List<int> gcNumber = d.gcsToCost.EagerSelect(gc => gc.GC.Number);

Scatter scatter = new Scatter
{
Expand All @@ -93,8 +93,8 @@ public static PlotlyChart ChartCountForGCMethod(this CPUProcessData cpuProcessDa
string countType = isInclusiveCount ? "Inclusive Count" : "Exclusive Count";
Layout.Layout layout = ChartingHelpers.ConstructLayout(title: title, fieldName: countType, xAxis: xAxisAsGCNumber, chartInfo: chartInfo);
var data = cpuProcessData.GetPerGCMethodCost(methodName: methodName, caller: caller, isInclusiveCount : isInclusiveCount);
List<float> cost = data.Select(gc => gc.Count);
List<int> gcNumber = data.Select(gc => gc.GC.Number);
List<float> cost = data.EagerSelect(gc => gc.Count);
List<int> gcNumber = data.EagerSelect(gc => gc.GC.Number);

Scatter scatter = new Scatter
{
Expand All @@ -117,8 +117,8 @@ public static PlotlyChart ChartCountForGCMethod(this CPUProcessData cpuProcessDa
string countType = isInclusiveCount ? "Inclusive Count" : "Exclusive Count";
Layout.Layout layout = ChartingHelpers.ConstructLayout(title: title, fieldName: countType, xAxis: xAxisAsGCNumber, chartInfo: chartInfo);
var data = cpuProcessData.GetPerGCMethodCost(methodName: methodName, isInclusiveCount : isInclusiveCount);
List<float> cost = data.Select(gc => gc.Count);
List<int> gcNumber = data.Select(gc => gc.GC.Number);
List<float> cost = data.EagerSelect(gc => gc.Count);
List<int> gcNumber = data.EagerSelect(gc => gc.GC.Number);

Scatter scatter = new Scatter
{
Expand Down Expand Up @@ -146,8 +146,8 @@ public static PlotlyChart ChartCountForGCMethods(this CPUProcessData cpuProcessD
foreach (var methodName in methodNames)
{
var data = cpuProcessData.GetPerGCMethodCost(methodName: methodName, isInclusiveCount : isInclusiveCount);
List<float> cost = data.Select(gc => gc.Count);
List<int> gcNumber = data.Select(gc => gc.GC.Number);
List<float> cost = data.EagerSelect(gc => gc.Count);
List<int> gcNumber = data.EagerSelect(gc => gc.GC.Number);

Scatter scatter = new Scatter
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ public static class MarkPhaseAnalysis
public static PlotlyChart[] ChartStatisticsOfMarkPhaseByType(this GCProcessData processData, int generation, MarkRootType type)
{
int heapCount = processData.Stats.HeapCount;
var generationGCs = processData.GCs.Where(gc => gc.Generation == generation);
var generationGCs = processData.GCs.EagerWhere(gc => gc.Generation == generation);

var maxPromoted = generationGCs.Select(gc => (gc.Number, gc.PerHeapMarkTimes.Max(gc => gc.Value.MarkPromoted[(long)type])));
var minPromoted = generationGCs.Select(gc => (gc.Number, gc.PerHeapMarkTimes.Min(gc => gc.Value.MarkPromoted[(long)type])));
var avgPromoted = generationGCs.Select(gc => (gc.Number, gc.PerHeapMarkTimes.Sum(gc => gc.Value.MarkPromoted[(long)type]) / heapCount));
var maxPromoted = generationGCs.EagerSelect(gc => (gc.Number, gc.PerHeapMarkTimes.Max(gc => gc.Value.MarkPromoted[(long)type])));
var minPromoted = generationGCs.EagerSelect(gc => (gc.Number, gc.PerHeapMarkTimes.Min(gc => gc.Value.MarkPromoted[(long)type])));
var avgPromoted = generationGCs.EagerSelect(gc => (gc.Number, gc.PerHeapMarkTimes.EagerSum(gc => gc.Value.MarkPromoted[(long)type]) / heapCount));

var maxTime = generationGCs.Select(gc => (gc.Number, gc.PerHeapMarkTimes.Max(gc => gc.Value.MarkTimes[(long)type])));
var minTime = generationGCs.Select(gc => (gc.Number, gc.PerHeapMarkTimes.Min(gc => gc.Value.MarkTimes[(long)type])));
var avgTime = generationGCs.Select(gc => (gc.Number, gc.PerHeapMarkTimes.Sum(gc => gc.Value.MarkTimes[(long)type]) / heapCount));
var maxTime = generationGCs.EagerSelect(gc => (gc.Number, gc.PerHeapMarkTimes.Max(gc => gc.Value.MarkTimes[(long)type])));
var minTime = generationGCs.EagerSelect(gc => (gc.Number, gc.PerHeapMarkTimes.Min(gc => gc.Value.MarkTimes[(long)type])));
var avgTime = generationGCs.EagerSelect(gc => (gc.Number, gc.PerHeapMarkTimes.EagerSum(gc => gc.Value.MarkTimes[(long)type]) / heapCount));

var layoutPromoted = new Layout.Layout
{
Expand All @@ -28,26 +28,26 @@ public static PlotlyChart[] ChartStatisticsOfMarkPhaseByType(this GCProcessData

var scatterMaxPromoted = new Scatter
{
y = maxPromoted.Select(gc => gc.Item2),
x = maxPromoted.Select(gc => gc.Number),
y = maxPromoted.EagerSelect(gc => gc.Item2),
x = maxPromoted.EagerSelect(gc => gc.Number),
mode = "lines+markers",
name = $"Max Bytes",
showlegend = true,
};

var scatterMinPromoted = new Scatter
{
y = minPromoted.Select(gc => gc.Item2),
x = maxPromoted.Select(gc => gc.Number),
y = minPromoted.EagerSelect(gc => gc.Item2),
x = maxPromoted.EagerSelect(gc => gc.Number),
mode = "lines+markers",
name = $"Min Bytes",
showlegend = true,
};

var scatterAveragePromoted = new Scatter
{
y = avgPromoted.Select(gc => gc.Item2),
x = avgPromoted.Select(gc => gc.Number),
y = avgPromoted.EagerSelect(gc => gc.Item2),
x = avgPromoted.EagerSelect(gc => gc.Number),
mode = "lines+markers",
name = $"Avg Bytes",
showlegend = true,
Expand All @@ -63,26 +63,26 @@ public static PlotlyChart[] ChartStatisticsOfMarkPhaseByType(this GCProcessData

var scatterMaxTime = new Scatter
{
y = maxTime.Select(gc => gc.Item2),
x = maxTime.Select(gc => gc.Number),
y = maxTime.EagerSelect(gc => gc.Item2),
x = maxTime.EagerSelect(gc => gc.Number),
mode = "lines+markers",
name = $"Max Time (ms)",
showlegend = true,
};

var scatterMinTime = new Scatter
{
y = minTime.Select(gc => gc.Item2),
x = minTime.Select(gc => gc.Number),
y = minTime.EagerSelect(gc => gc.Item2),
x = minTime.EagerSelect(gc => gc.Number),
mode = "lines+markers",
name = $"Min Time (ms)",
showlegend = true,
};

var scatterAverageTime = new Scatter
{
y = avgTime.Select(gc => gc.Item2),
x = avgTime.Select(gc => gc.Number),
y = avgTime.EagerSelect(gc => gc.Item2),
x = avgTime.EagerSelect(gc => gc.Number),
mode = "lines+markers",
name = $"Avg Time (ms)",
showlegend = true,
Expand All @@ -98,11 +98,11 @@ public static PlotlyChart[] ChartStatisticsOfMarkPhaseByType(this GCProcessData
public static PlotlyChart ChartAverageMarkPhaseTimeByMarkType(this GCProcessData processData, int generation, IEnumerable<MarkRootType> types)
{
int heapCount = processData.Stats.HeapCount;
var generationGCs = processData.GCs.Where(gc => gc.Generation == generation);
var generationGCs = processData.GCs.EagerWhere(gc => gc.Generation == generation);

var layout = new Layout.Layout
{
title = $"Average Mark Promoted Bytes for Gen{generation}",
title = $"EagerAverage Mark Promoted Bytes for Gen{generation}",
mrsharm marked this conversation as resolved.
Show resolved Hide resolved
xaxis = new Xaxis { title = "GC #" },
yaxis = new Yaxis { title = "Bytes" },
showlegend = true,
Expand All @@ -112,11 +112,11 @@ public static PlotlyChart ChartAverageMarkPhaseTimeByMarkType(this GCProcessData

foreach (var type in types)
{
var avgPromoted = generationGCs.Select(gc => (gc.Number, gc.PerHeapMarkTimes.Sum(gc => gc.Value.MarkPromoted[(long)type]) / heapCount));
var avgPromoted = generationGCs.EagerSelect(gc => (gc.Number, gc.PerHeapMarkTimes.EagerSum(gc => gc.Value.MarkPromoted[(long)type]) / heapCount));
var scatterAverageTime = new Scatter
{
y = avgPromoted.Select(gc => gc.Item2),
x = avgPromoted.Select(gc => gc.Number),
y = avgPromoted.EagerSelect(gc => gc.Item2),
x = avgPromoted.EagerSelect(gc => gc.Number),
mode = "lines+markers",
name = $"Avg Time (ms) - {type}",
showlegend = true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ public CallTreeNodeBase GetCallTreeNode(string symbolName)
if (node.Name.Equals(unresolvedSymbolsNodeName, StringComparison.OrdinalIgnoreCase))
{
// Symbols haven't been resolved yet. Try to resolve them now.
EtlxNS.TraceModuleFile moduleFile = _traceLog.ModuleFiles.Where(m => m.Name.Equals(symbolParts[0], StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
EtlxNS.TraceModuleFile moduleFile = _traceLog.ModuleFiles.EagerWhere(m => m.Name.Equals(symbolParts[0], StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
if (moduleFile != null)
{
// Special handling for NGEN images.
Expand Down Expand Up @@ -384,7 +384,7 @@ public DataFrame GetCPUDataForGCMethods(IEnumerable<string> methods)

// Find the most primitive TraceEventStackSource
TraceEventStackSource asTraceEventStackSource = GetTraceEventStackSource(CallTree.StackSource);
var cpuEvents = asTraceEventStackSource.TraceLog.Events.Where(e => e is SampledProfileTraceData && e.ProcessID != 0);
var cpuEvents = asTraceEventStackSource.TraceLog.Events.EagerWhere(e => e is SampledProfileTraceData && e.ProcessID != 0);

if (asTraceEventStackSource == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,10 @@ public static DataFrame Compare(this CPUProcessData cpuData, IEnumerable<CPUProc
return null;
}

var gen0s = new HashSet<int>(gcProcessData.GCs.Where(gc => gc.Generation == 0).Select(gc => gc.Number));
var gen1s = new HashSet<int>(gcProcessData.GCs.Where(gc => gc.Generation == 1).Select(gc => gc.Number));
var bgcs = new HashSet<int>(gcProcessData.BGCs.Select(gc => gc.Number));
var gen2Blocking = new HashSet<int>(gcProcessData.Gen2Blocking.Select(gc => gc.Number));
var gen0s = new HashSet<int>(gcProcessData.GCs.EagerWhere(gc => gc.Generation == 0).EagerSelect(gc => gc.Number));
var gen1s = new HashSet<int>(gcProcessData.GCs.EagerWhere(gc => gc.Generation == 1).EagerSelect(gc => gc.Number));
var bgcs = new HashSet<int>(gcProcessData.BGCs.EagerSelect(gc => gc.Number));
var gen2Blocking = new HashSet<int>(gcProcessData.Gen2Blocking.EagerSelect(gc => gc.Number));

foreach(var majorPhase in phases)
{
Expand All @@ -204,7 +204,7 @@ public static DataFrame Compare(this CPUProcessData cpuData, IEnumerable<CPUProc
{
foreach(var gc in gcToData)
{
var count = gc.Value.Values.Sum(g => g.Sum(gc => gc.InclusiveCount));
var count = gc.Value.Values.EagerSum(g => g.EagerSum(gc => gc.InclusiveCount));

if (gen0s.Contains(gc.Key))
{
Expand Down
125 changes: 64 additions & 61 deletions src/benchmarks/gc/GC.Infrastructure/GC.Analysis.API/Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,70 @@
using System.Text;
using XPlot.Plotly;

namespace System.Linq
{
public static class Linq
{
public static List<R> EagerSelect<T, R>(this IEnumerable<T> data, Func<T, R> map)
{
List<R> result = new();
foreach (var d in data)
{
result.Add(map(d));
}

return result;
}

public static List<T> EagerWhere<T>(this IEnumerable<T> data, Func<T, bool> predicate)
{
List<T> result = new();
foreach (var d in data)
{
if (predicate(d))
{
result.Add(d);
}
}

return result;
}

public static double EagerSum<TSource>(this IEnumerable<TSource> data, Func<TSource, double> map)
{
double sum = 0;
if (data == null || data.Count() == 0)
{
return sum;
}

foreach(var sourceItem in data)
{
sum += (double)map(sourceItem);
}

return sum;
}

public static double EagerAverage<TSource>(this IEnumerable<TSource> data, Func<TSource, double> map)
{
int count = data.Count();
if (data == null || count == 0)
{
return double.NaN;
}

double sum = 0;
foreach(var sourceItem in data)
{
sum += (double)map(sourceItem);
}

return sum / count;
}
}
}
Comment on lines +36 to +69
Copy link
Member

@markples markples Nov 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The standard Linq methods are already eager for these two. These differ from Linq

  • in their handling of null (no exception)
  • Average() returning NaN instead of throwing. (though there are Linq overloads that takes enumerables of nullables, and if the enumerable has no nonnull values (empty enumerable is a degenerate case of this) returns null)
  • calling Count() rather than counting during the foreach - if the enumerable is a List this won't matter, but for others it could enumerate twice
  • Linq uses checked arithmetic


namespace GC.Analysis.API
{
public sealed class AxisInfo
Expand Down Expand Up @@ -88,67 +152,6 @@ internal static Layout.Layout ConstructLayout(string title,
}
}

public static class GoodLinq
{
public static List<R> Select<T, R>(this IEnumerable<T> data, Func<T, R> map)
{
List<R> result = new();
foreach (var d in data)
{
result.Add(map(d));
}

return result;
}

public static List<T> Where<T>(this IEnumerable<T> data, Func<T, bool> predicate)
{
List<T> result = new();
foreach (var d in data)
{
if (predicate(d))
{
result.Add(d);
}
}

return result;
}

public static double Sum<TSource>(this IEnumerable<TSource> data, Func<TSource, double> map)
{
double sum = 0;
if (data == null || data.Count() == 0)
{
return sum;
}

foreach(var sourceItem in data)
{
sum += (double)map(sourceItem);
}

return sum;
}

public static double Average<TSource>(this IEnumerable<TSource> data, Func<TSource, double> map)
{
int count = data.Count();
if (data == null || count == 0)
{
return double.NaN;
}

double sum = 0;
foreach(var sourceItem in data)
{
sum += (double)map(sourceItem);
}

return sum / count;
}
}

public static class ReflectionHelpers
{
public static List<double> GetDoubleValueFromFieldForCustomObjects(IEnumerable<object> customObjects, string fieldName)
Expand Down
Loading
Loading