Skip to content

Instantly share code, notes, and snippets.

@carbonrobot
Created November 18, 2013 15:40
Show Gist options
  • Save carbonrobot/7529910 to your computer and use it in GitHub Desktop.
Save carbonrobot/7529910 to your computer and use it in GitHub Desktop.
Performance of Buffer.BlockCopy on multidimensional arrays
// Begin linqpad script
void Main()
{
var sourceIndex = 3;
var source = new double[5,1000];
for(int i = 0; i < source.GetLength(1); i++){
source[sourceIndex, i] = i + 1;
}
// for loop
Action<double[,]> func1 = (s) => {
var length = s.GetLength(1);
var target0 = new double[length];
var target1 = new double[length];
var target2 = new double[length];
var target3 = new double[length];
var target4 = new double[length];
for(int i = 0; i < length; i++){
target0[i] = s[0, i];
target1[i] = s[1, i];
target2[i] = s[2, i];
target3[i] = s[3, i];
target4[i] = s[4, i];
}
};
// block copy
Action<double[,]> func2 = (s) => {
var length = s.GetLength(1);
var size = sizeof(double);
var byteLength = size * length;
var target0 = new double[length];
var target1 = new double[length];
var target2 = new double[length];
var target3 = new double[length];
var target4 = new double[length];
Buffer.BlockCopy(source, byteLength * 0, target0, 0, byteLength);
Buffer.BlockCopy(source, byteLength * 1, target0, 0, byteLength);
Buffer.BlockCopy(source, byteLength * 2, target0, 0, byteLength);
Buffer.BlockCopy(source, byteLength * 3, target0, 0, byteLength);
Buffer.BlockCopy(source, byteLength * 4, target0, 0, byteLength);
};
Benchmark
.For(1000)
.Execute("For Loop", () => func1(source))
.Execute("Buffer ", () => func2(source))
.Report(4).Dump();
}
public static class Benchmark
{
public static BenchmarkActionScheduler For(int count)
{
Process.GetCurrentProcess().ProcessorAffinity = new IntPtr(1);
return new BenchmarkActionScheduler(count);
}
}
public class BenchmarkActionScheduler
: IBenchmarkActionScheduler
{
private readonly int count;
private readonly IDictionary<string, Action> actionDictionary =
new Dictionary<string, Action>();
private int actionIndex;
internal BenchmarkActionScheduler(int count)
{
this.count = count;
}
public IBenchmarkActionScheduler Execute(Action action)
{
return Execute((actionIndex++).ToString(), action);
}
public IBenchmarkActionScheduler Execute(string name, Action action)
{
actionDictionary.Add(name, action);
return this;
}
IEnumerable<Report> IBenchmarkActionScheduler.Report(int? digits)
{
var reportList = new List<Report>();
foreach (var action in actionDictionary)
{
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
var stopwatch = Stopwatch.StartNew();
var localAction = action;
Enumerable
.Range(0, count)
.Iterate(() => localAction.Value());
reportList
.Add(new Report(action.Key, stopwatch.ElapsedMilliseconds));
}
var maxTime = reportList.Max(x => x.Milliseconds);
foreach (var report in reportList)
{
var percentage = (report.Milliseconds * 100) / (double)maxTime;
if (digits.HasValue)
{
percentage = Math.Round(percentage, digits.Value);
}
report.Percentage = percentage;
report.TimesFaster = Math.Round((double)maxTime / (double)report.Milliseconds, digits.Value);
}
return reportList;
}
}
public interface IBenchmarkActionScheduler
{
IEnumerable<Report> Report(int? digits = null);
IBenchmarkActionScheduler Execute(Action action);
IBenchmarkActionScheduler Execute(string name, Action action);
}
public class Report
{
public Report(string operationName, long milliseconds)
{
OperationName = operationName;
Milliseconds = milliseconds;
}
public string OperationName { get; private set; }
public long Milliseconds { get; private set; }
public double Percentage { get; internal set; }
public double TimesFaster { get; internal set; }
}
public static class EnumerableExensions
{
public static void Iterate<T>(this IEnumerable<T> collection)
{
var enumerator = collection.GetEnumerator();
while (enumerator.MoveNext())
{
}
}
public static void Iterate<T>(this IEnumerable<T> collection, Action action)
{
var enumerator = collection.GetEnumerator();
while (enumerator.MoveNext())
{
action();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment