The benchmarks various LINQ and PLINQ methods for analyzing potentially fraudulent transactions in different dataset sizes.
Date Added (UTC):
14 May 2024 @ 05:40
Date Updated (UTC):14 May 2024 @ 05:40
.NET Version(s): Tag(s):
Added By:
A dedicated executive technical architect who is focused on expanding organizations technology capabilities.
Benchmark Results:
Benchmark Code:
Originally imported from :
https://gist.github.com/admir-live/0d6cb706acdea72b9cc0e9303cb4a9aeon 14 May 2024 @ 05:40 (UTC) .
The original benchmark may have changed.
https://gist.github.com/admir-live/0d6cb706acdea72b9cc0e9303cb4a9ae
The original benchmark may have changed.
using System.Security.Cryptography;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Running;
public class Transaction
{
public decimal Amount { get; }
public TimeSpan TransactionTime { get; }
public Transaction(decimal amount, TimeSpan transactionTime)
{
Amount = amount;
TransactionTime = transactionTime;
}
}
public class TransactionFactory
{
private const int MaxTransactionAmount = 20000;
private const int MinutesInADay = 1440;
private readonly RandomNumberGenerator _randomNumberGenerator = RandomNumberGenerator.Create();
public List<Transaction> CreateTransactions(int count)
{
List<Transaction> transactions = new List<Transaction>();
for (int i = 0; i < count; i++)
{
decimal amount = GenerateRandomAmount();
double minutes = GenerateRandomMinutes();
transactions.Add(new Transaction(amount, TimeSpan.FromMinutes(minutes)));
}
return transactions;
}
private decimal GenerateRandomAmount()
{
return (decimal)(NextDouble(_randomNumberGenerator) * MaxTransactionAmount);
}
private double GenerateRandomMinutes()
{
return NextDouble(_randomNumberGenerator) * MinutesInADay;
}
private static double NextDouble(RandomNumberGenerator rng)
{
byte[] buffer = new byte[8];
rng.GetBytes(buffer);
ulong ulongValue = BitConverter.ToUInt64(buffer, 0) / (1UL << 11);
return (double)ulongValue / (1UL << 53);
}
}
public class TransactionAnalysisBenchmark
{
private const int SmallNumberOfTransactions = 1000;
private const int LargeNumberOfTransactions = 1000000;
private const decimal FraudulentAmountThreshold = 10000;
private List<Transaction> smallTransactionList;
private List<Transaction> largeTransactionList;
[GlobalSetup]
public void PrepareTransactionData()
{
TransactionFactory transactionFactory = new TransactionFactory();
smallTransactionList = transactionFactory.CreateTransactions(SmallNumberOfTransactions);
largeTransactionList = transactionFactory.CreateTransactions(LargeNumberOfTransactions);
}
[Benchmark]
public List<Transaction> PerformLinqQueryOnSmallTransactions()
{
return smallTransactionList
.Where(IsTransactionPotentiallyFraudulent)
.ToList();
}
[Benchmark]
public List<Transaction> PerformLinqQueryOnLargeTransactions()
{
return largeTransactionList
.Where(IsTransactionPotentiallyFraudulent)
.ToList();
}
[Benchmark]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsSingleCore()
{
return smallTransactionList.AsParallel()
.WithDegreeOfParallelism(1)
.Where(IsTransactionPotentiallyFraudulent)
.ToList();
}
[Benchmark]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsMaxCore()
{
return smallTransactionList.AsParallel()
.WithDegreeOfParallelism(Environment.ProcessorCount)
.Where(IsTransactionPotentiallyFraudulent)
.ToList();
}
[Benchmark]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsSingleCore()
{
return largeTransactionList.AsParallel()
.WithDegreeOfParallelism(1)
.Where(IsTransactionPotentiallyFraudulent)
.ToList();
}
[Benchmark]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsMaxCore()
{
return largeTransactionList.AsParallel()
.WithDegreeOfParallelism(Environment.ProcessorCount)
.Where(IsTransactionPotentiallyFraudulent)
.ToList();
}
public static bool IsTransactionPotentiallyFraudulent(Transaction transaction)
{
return transaction is { Amount: > FraudulentAmountThreshold, TransactionTime.Hours: < 4 or 0x0 };
}
public static void Main(string[] args)
{
Summary summary = BenchmarkRunner.Run<TransactionAnalysisBenchmark>();
}
}
Powered by SharpLab
// .NET 8
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
public class Transaction
{
[CompilerGenerated]
private readonly decimal <Amount>k__BackingField;
[CompilerGenerated]
private readonly TimeSpan <TransactionTime>k__BackingField;
public decimal Amount
{
[CompilerGenerated]
get
{
return <Amount>k__BackingField;
}
}
public TimeSpan TransactionTime
{
[CompilerGenerated]
get
{
return <TransactionTime>k__BackingField;
}
}
public Transaction(decimal amount, TimeSpan transactionTime)
{
<Amount>k__BackingField = amount;
<TransactionTime>k__BackingField = transactionTime;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionFactory
{
private const int MaxTransactionAmount = 20000;
private const int MinutesInADay = 1440;
private readonly RandomNumberGenerator _randomNumberGenerator = RandomNumberGenerator.Create();
public List<Transaction> CreateTransactions(int count)
{
List<Transaction> list = new List<Transaction>();
int num = 0;
while (num < count)
{
decimal amount = GenerateRandomAmount();
double value = GenerateRandomMinutes();
list.Add(new Transaction(amount, TimeSpan.FromMinutes(value)));
num++;
}
return list;
}
private decimal GenerateRandomAmount()
{
return (decimal)(NextDouble(_randomNumberGenerator) * 20000.0);
}
private double GenerateRandomMinutes()
{
return NextDouble(_randomNumberGenerator) * 1440.0;
}
private static double NextDouble(RandomNumberGenerator rng)
{
byte[] array = new byte[8];
rng.GetBytes(array);
return (double)(BitConverter.ToUInt64(array, 0) / 2048uL) / 9007199254740992.0;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionAnalysisBenchmark
{
[CompilerGenerated]
private static class <>O
{
[Nullable(0)]
public static Func<Transaction, bool> <0>__IsTransactionPotentiallyFraudulent;
}
private const int SmallNumberOfTransactions = 1000;
private const int LargeNumberOfTransactions = 1000000;
[DecimalConstant(0, 0, 0u, 0u, 10000u)]
private static readonly decimal FraudulentAmountThreshold = 10000m;
private List<Transaction> smallTransactionList;
private List<Transaction> largeTransactionList;
[GlobalSetup]
public void PrepareTransactionData()
{
TransactionFactory transactionFactory = new TransactionFactory();
smallTransactionList = transactionFactory.CreateTransactions(1000);
largeTransactionList = transactionFactory.CreateTransactions(1000000);
}
[Benchmark(84, "_")]
public List<Transaction> PerformLinqQueryOnSmallTransactions()
{
return Enumerable.ToList(Enumerable.Where(smallTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(92, "_")]
public List<Transaction> PerformLinqQueryOnLargeTransactions()
{
return Enumerable.ToList(Enumerable.Where(largeTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(100, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(109, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(118, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(127, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
public static bool IsTransactionPotentiallyFraudulent(Transaction transaction)
{
if (transaction != null && transaction.Amount > 10000m)
{
return transaction.TransactionTime.Hours < 4;
}
return false;
}
public static void Main(string[] args)
{
BenchmarkRunner.Run<TransactionAnalysisBenchmark>(null, null);
}
}
// .NET 8
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
public class Transaction
{
[CompilerGenerated]
private readonly decimal <Amount>k__BackingField;
[CompilerGenerated]
private readonly TimeSpan <TransactionTime>k__BackingField;
public decimal Amount
{
[CompilerGenerated]
get
{
return <Amount>k__BackingField;
}
}
public TimeSpan TransactionTime
{
[CompilerGenerated]
get
{
return <TransactionTime>k__BackingField;
}
}
public Transaction(decimal amount, TimeSpan transactionTime)
{
<Amount>k__BackingField = amount;
<TransactionTime>k__BackingField = transactionTime;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionFactory
{
private const int MaxTransactionAmount = 20000;
private const int MinutesInADay = 1440;
private readonly RandomNumberGenerator _randomNumberGenerator = RandomNumberGenerator.Create();
public List<Transaction> CreateTransactions(int count)
{
List<Transaction> list = new List<Transaction>();
int num = 0;
while (num < count)
{
decimal amount = GenerateRandomAmount();
double value = GenerateRandomMinutes();
list.Add(new Transaction(amount, TimeSpan.FromMinutes(value)));
num++;
}
return list;
}
private decimal GenerateRandomAmount()
{
return (decimal)(NextDouble(_randomNumberGenerator) * 20000.0);
}
private double GenerateRandomMinutes()
{
return NextDouble(_randomNumberGenerator) * 1440.0;
}
private static double NextDouble(RandomNumberGenerator rng)
{
byte[] array = new byte[8];
rng.GetBytes(array);
return (double)(BitConverter.ToUInt64(array, 0) / 2048uL) / 9007199254740992.0;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionAnalysisBenchmark
{
[CompilerGenerated]
private static class <>O
{
[Nullable(0)]
public static Func<Transaction, bool> <0>__IsTransactionPotentiallyFraudulent;
}
private const int SmallNumberOfTransactions = 1000;
private const int LargeNumberOfTransactions = 1000000;
[DecimalConstant(0, 0, 0u, 0u, 10000u)]
private static readonly decimal FraudulentAmountThreshold = 10000m;
private List<Transaction> smallTransactionList;
private List<Transaction> largeTransactionList;
[GlobalSetup]
public void PrepareTransactionData()
{
TransactionFactory transactionFactory = new TransactionFactory();
smallTransactionList = transactionFactory.CreateTransactions(1000);
largeTransactionList = transactionFactory.CreateTransactions(1000000);
}
[Benchmark(84, "_")]
public List<Transaction> PerformLinqQueryOnSmallTransactions()
{
return Enumerable.ToList(Enumerable.Where(smallTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(92, "_")]
public List<Transaction> PerformLinqQueryOnLargeTransactions()
{
return Enumerable.ToList(Enumerable.Where(largeTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(100, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(109, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(118, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(127, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
public static bool IsTransactionPotentiallyFraudulent(Transaction transaction)
{
if (transaction != null && transaction.Amount > 10000m)
{
return transaction.TransactionTime.Hours < 4;
}
return false;
}
public static void Main(string[] args)
{
BenchmarkRunner.Run<TransactionAnalysisBenchmark>(null, null);
}
}
// .NET 8
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
public class Transaction
{
[CompilerGenerated]
private readonly decimal <Amount>k__BackingField;
[CompilerGenerated]
private readonly TimeSpan <TransactionTime>k__BackingField;
public decimal Amount
{
[CompilerGenerated]
get
{
return <Amount>k__BackingField;
}
}
public TimeSpan TransactionTime
{
[CompilerGenerated]
get
{
return <TransactionTime>k__BackingField;
}
}
public Transaction(decimal amount, TimeSpan transactionTime)
{
<Amount>k__BackingField = amount;
<TransactionTime>k__BackingField = transactionTime;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionFactory
{
private const int MaxTransactionAmount = 20000;
private const int MinutesInADay = 1440;
private readonly RandomNumberGenerator _randomNumberGenerator = RandomNumberGenerator.Create();
public List<Transaction> CreateTransactions(int count)
{
List<Transaction> list = new List<Transaction>();
int num = 0;
while (num < count)
{
decimal amount = GenerateRandomAmount();
double value = GenerateRandomMinutes();
list.Add(new Transaction(amount, TimeSpan.FromMinutes(value)));
num++;
}
return list;
}
private decimal GenerateRandomAmount()
{
return (decimal)(NextDouble(_randomNumberGenerator) * 20000.0);
}
private double GenerateRandomMinutes()
{
return NextDouble(_randomNumberGenerator) * 1440.0;
}
private static double NextDouble(RandomNumberGenerator rng)
{
byte[] array = new byte[8];
rng.GetBytes(array);
return (double)(BitConverter.ToUInt64(array, 0) / 2048uL) / 9007199254740992.0;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionAnalysisBenchmark
{
[CompilerGenerated]
private static class <>O
{
[Nullable(0)]
public static Func<Transaction, bool> <0>__IsTransactionPotentiallyFraudulent;
}
private const int SmallNumberOfTransactions = 1000;
private const int LargeNumberOfTransactions = 1000000;
[DecimalConstant(0, 0, 0u, 0u, 10000u)]
private static readonly decimal FraudulentAmountThreshold = 10000m;
private List<Transaction> smallTransactionList;
private List<Transaction> largeTransactionList;
[GlobalSetup]
public void PrepareTransactionData()
{
TransactionFactory transactionFactory = new TransactionFactory();
smallTransactionList = transactionFactory.CreateTransactions(1000);
largeTransactionList = transactionFactory.CreateTransactions(1000000);
}
[Benchmark(84, "_")]
public List<Transaction> PerformLinqQueryOnSmallTransactions()
{
return Enumerable.ToList(Enumerable.Where(smallTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(92, "_")]
public List<Transaction> PerformLinqQueryOnLargeTransactions()
{
return Enumerable.ToList(Enumerable.Where(largeTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(100, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(109, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(118, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(127, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
public static bool IsTransactionPotentiallyFraudulent(Transaction transaction)
{
if (transaction != null && transaction.Amount > 10000m)
{
return transaction.TransactionTime.Hours < 4;
}
return false;
}
public static void Main(string[] args)
{
BenchmarkRunner.Run<TransactionAnalysisBenchmark>(null, null);
}
}
// .NET 8
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
public class Transaction
{
[CompilerGenerated]
private readonly decimal <Amount>k__BackingField;
[CompilerGenerated]
private readonly TimeSpan <TransactionTime>k__BackingField;
public decimal Amount
{
[CompilerGenerated]
get
{
return <Amount>k__BackingField;
}
}
public TimeSpan TransactionTime
{
[CompilerGenerated]
get
{
return <TransactionTime>k__BackingField;
}
}
public Transaction(decimal amount, TimeSpan transactionTime)
{
<Amount>k__BackingField = amount;
<TransactionTime>k__BackingField = transactionTime;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionFactory
{
private const int MaxTransactionAmount = 20000;
private const int MinutesInADay = 1440;
private readonly RandomNumberGenerator _randomNumberGenerator = RandomNumberGenerator.Create();
public List<Transaction> CreateTransactions(int count)
{
List<Transaction> list = new List<Transaction>();
int num = 0;
while (num < count)
{
decimal amount = GenerateRandomAmount();
double value = GenerateRandomMinutes();
list.Add(new Transaction(amount, TimeSpan.FromMinutes(value)));
num++;
}
return list;
}
private decimal GenerateRandomAmount()
{
return (decimal)(NextDouble(_randomNumberGenerator) * 20000.0);
}
private double GenerateRandomMinutes()
{
return NextDouble(_randomNumberGenerator) * 1440.0;
}
private static double NextDouble(RandomNumberGenerator rng)
{
byte[] array = new byte[8];
rng.GetBytes(array);
return (double)(BitConverter.ToUInt64(array, 0) / 2048uL) / 9007199254740992.0;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionAnalysisBenchmark
{
[CompilerGenerated]
private static class <>O
{
[Nullable(0)]
public static Func<Transaction, bool> <0>__IsTransactionPotentiallyFraudulent;
}
private const int SmallNumberOfTransactions = 1000;
private const int LargeNumberOfTransactions = 1000000;
[DecimalConstant(0, 0, 0u, 0u, 10000u)]
private static readonly decimal FraudulentAmountThreshold = 10000m;
private List<Transaction> smallTransactionList;
private List<Transaction> largeTransactionList;
[GlobalSetup]
public void PrepareTransactionData()
{
TransactionFactory transactionFactory = new TransactionFactory();
smallTransactionList = transactionFactory.CreateTransactions(1000);
largeTransactionList = transactionFactory.CreateTransactions(1000000);
}
[Benchmark(84, "_")]
public List<Transaction> PerformLinqQueryOnSmallTransactions()
{
return Enumerable.ToList(Enumerable.Where(smallTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(92, "_")]
public List<Transaction> PerformLinqQueryOnLargeTransactions()
{
return Enumerable.ToList(Enumerable.Where(largeTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(100, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(109, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(118, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(127, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
public static bool IsTransactionPotentiallyFraudulent(Transaction transaction)
{
if (transaction != null && transaction.Amount > 10000m)
{
return transaction.TransactionTime.Hours < 4;
}
return false;
}
public static void Main(string[] args)
{
BenchmarkRunner.Run<TransactionAnalysisBenchmark>(null, null);
}
}
// .NET 8
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
public class Transaction
{
[CompilerGenerated]
private readonly decimal <Amount>k__BackingField;
[CompilerGenerated]
private readonly TimeSpan <TransactionTime>k__BackingField;
public decimal Amount
{
[CompilerGenerated]
get
{
return <Amount>k__BackingField;
}
}
public TimeSpan TransactionTime
{
[CompilerGenerated]
get
{
return <TransactionTime>k__BackingField;
}
}
public Transaction(decimal amount, TimeSpan transactionTime)
{
<Amount>k__BackingField = amount;
<TransactionTime>k__BackingField = transactionTime;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionFactory
{
private const int MaxTransactionAmount = 20000;
private const int MinutesInADay = 1440;
private readonly RandomNumberGenerator _randomNumberGenerator = RandomNumberGenerator.Create();
public List<Transaction> CreateTransactions(int count)
{
List<Transaction> list = new List<Transaction>();
int num = 0;
while (num < count)
{
decimal amount = GenerateRandomAmount();
double value = GenerateRandomMinutes();
list.Add(new Transaction(amount, TimeSpan.FromMinutes(value)));
num++;
}
return list;
}
private decimal GenerateRandomAmount()
{
return (decimal)(NextDouble(_randomNumberGenerator) * 20000.0);
}
private double GenerateRandomMinutes()
{
return NextDouble(_randomNumberGenerator) * 1440.0;
}
private static double NextDouble(RandomNumberGenerator rng)
{
byte[] array = new byte[8];
rng.GetBytes(array);
return (double)(BitConverter.ToUInt64(array, 0) / 2048uL) / 9007199254740992.0;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionAnalysisBenchmark
{
[CompilerGenerated]
private static class <>O
{
[Nullable(0)]
public static Func<Transaction, bool> <0>__IsTransactionPotentiallyFraudulent;
}
private const int SmallNumberOfTransactions = 1000;
private const int LargeNumberOfTransactions = 1000000;
[DecimalConstant(0, 0, 0u, 0u, 10000u)]
private static readonly decimal FraudulentAmountThreshold = 10000m;
private List<Transaction> smallTransactionList;
private List<Transaction> largeTransactionList;
[GlobalSetup]
public void PrepareTransactionData()
{
TransactionFactory transactionFactory = new TransactionFactory();
smallTransactionList = transactionFactory.CreateTransactions(1000);
largeTransactionList = transactionFactory.CreateTransactions(1000000);
}
[Benchmark(84, "_")]
public List<Transaction> PerformLinqQueryOnSmallTransactions()
{
return Enumerable.ToList(Enumerable.Where(smallTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(92, "_")]
public List<Transaction> PerformLinqQueryOnLargeTransactions()
{
return Enumerable.ToList(Enumerable.Where(largeTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(100, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(109, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(118, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(127, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
public static bool IsTransactionPotentiallyFraudulent(Transaction transaction)
{
if (transaction != null && transaction.Amount > 10000m)
{
return transaction.TransactionTime.Hours < 4;
}
return false;
}
public static void Main(string[] args)
{
BenchmarkRunner.Run<TransactionAnalysisBenchmark>(null, null);
}
}
// .NET 8
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
public class Transaction
{
[CompilerGenerated]
private readonly decimal <Amount>k__BackingField;
[CompilerGenerated]
private readonly TimeSpan <TransactionTime>k__BackingField;
public decimal Amount
{
[CompilerGenerated]
get
{
return <Amount>k__BackingField;
}
}
public TimeSpan TransactionTime
{
[CompilerGenerated]
get
{
return <TransactionTime>k__BackingField;
}
}
public Transaction(decimal amount, TimeSpan transactionTime)
{
<Amount>k__BackingField = amount;
<TransactionTime>k__BackingField = transactionTime;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionFactory
{
private const int MaxTransactionAmount = 20000;
private const int MinutesInADay = 1440;
private readonly RandomNumberGenerator _randomNumberGenerator = RandomNumberGenerator.Create();
public List<Transaction> CreateTransactions(int count)
{
List<Transaction> list = new List<Transaction>();
int num = 0;
while (num < count)
{
decimal amount = GenerateRandomAmount();
double value = GenerateRandomMinutes();
list.Add(new Transaction(amount, TimeSpan.FromMinutes(value)));
num++;
}
return list;
}
private decimal GenerateRandomAmount()
{
return (decimal)(NextDouble(_randomNumberGenerator) * 20000.0);
}
private double GenerateRandomMinutes()
{
return NextDouble(_randomNumberGenerator) * 1440.0;
}
private static double NextDouble(RandomNumberGenerator rng)
{
byte[] array = new byte[8];
rng.GetBytes(array);
return (double)(BitConverter.ToUInt64(array, 0) / 2048uL) / 9007199254740992.0;
}
}
[NullableContext(1)]
[Nullable(0)]
public class TransactionAnalysisBenchmark
{
[CompilerGenerated]
private static class <>O
{
[Nullable(0)]
public static Func<Transaction, bool> <0>__IsTransactionPotentiallyFraudulent;
}
private const int SmallNumberOfTransactions = 1000;
private const int LargeNumberOfTransactions = 1000000;
[DecimalConstant(0, 0, 0u, 0u, 10000u)]
private static readonly decimal FraudulentAmountThreshold = 10000m;
private List<Transaction> smallTransactionList;
private List<Transaction> largeTransactionList;
[GlobalSetup]
public void PrepareTransactionData()
{
TransactionFactory transactionFactory = new TransactionFactory();
smallTransactionList = transactionFactory.CreateTransactions(1000);
largeTransactionList = transactionFactory.CreateTransactions(1000000);
}
[Benchmark(84, "_")]
public List<Transaction> PerformLinqQueryOnSmallTransactions()
{
return Enumerable.ToList(Enumerable.Where(smallTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(92, "_")]
public List<Transaction> PerformLinqQueryOnLargeTransactions()
{
return Enumerable.ToList(Enumerable.Where(largeTransactionList, <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(100, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(109, "_")]
public List<Transaction> PerformPLinqQueryOnSmallTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(smallTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(118, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsSingleCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), 1), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
[Benchmark(127, "_")]
public List<Transaction> PerformPLinqQueryOnLargeTransactionsMaxCore()
{
return ParallelEnumerable.ToList(ParallelEnumerable.Where(ParallelEnumerable.WithDegreeOfParallelism(ParallelEnumerable.AsParallel(largeTransactionList), Environment.ProcessorCount), <>O.<0>__IsTransactionPotentiallyFraudulent ?? (<>O.<0>__IsTransactionPotentiallyFraudulent = new Func<Transaction, bool>(IsTransactionPotentiallyFraudulent))));
}
public static bool IsTransactionPotentiallyFraudulent(Transaction transaction)
{
if (transaction != null && transaction.Amount > 10000m)
{
return transaction.TransactionTime.Hours < 4;
}
return false;
}
public static void Main(string[] args)
{
BenchmarkRunner.Run<TransactionAnalysisBenchmark>(null, null);
}
}
Powered by SharpLab
// .NET 8
.method public hidebysig
instance class [System.Collections]System.Collections.Generic.List`1<class Transaction> PerformLinqQueryOnSmallTransactions () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 54 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2169
// Code size 44 (0x2c)
.maxstack 8
// sequence point: (line 87, col 9) to (line 89, col 23) in _
IL_0000: ldarg.0
IL_0001: ldfld class [System.Collections]System.Collections.Generic.List`1<class Transaction> TransactionAnalysisBenchmark::smallTransactionList
IL_0006: ldsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_000b: dup
IL_000c: brtrue.s IL_0021
IL_000e: pop
IL_000f: ldnull
IL_0010: ldftn bool TransactionAnalysisBenchmark::IsTransactionPotentiallyFraudulent(class Transaction)
IL_0016: newobj instance void class [System.Runtime]System.Func`2<class Transaction, bool>::.ctor(object, native int)
IL_001b: dup
IL_001c: stsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_0021: call class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0> [System.Linq]System.Linq.Enumerable::Where<class Transaction>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Runtime]System.Func`2<!!0, bool>)
IL_0026: call class [System.Collections]System.Collections.Generic.List`1<!!0> [System.Linq]System.Linq.Enumerable::ToList<class Transaction>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>)
IL_002b: ret
}
// .NET 8
.method public hidebysig
instance class [System.Collections]System.Collections.Generic.List`1<class Transaction> PerformLinqQueryOnLargeTransactions () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 5c 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2196
// Code size 44 (0x2c)
.maxstack 8
// sequence point: (line 95, col 9) to (line 97, col 23) in _
IL_0000: ldarg.0
IL_0001: ldfld class [System.Collections]System.Collections.Generic.List`1<class Transaction> TransactionAnalysisBenchmark::largeTransactionList
IL_0006: ldsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_000b: dup
IL_000c: brtrue.s IL_0021
IL_000e: pop
IL_000f: ldnull
IL_0010: ldftn bool TransactionAnalysisBenchmark::IsTransactionPotentiallyFraudulent(class Transaction)
IL_0016: newobj instance void class [System.Runtime]System.Func`2<class Transaction, bool>::.ctor(object, native int)
IL_001b: dup
IL_001c: stsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_0021: call class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0> [System.Linq]System.Linq.Enumerable::Where<class Transaction>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Runtime]System.Func`2<!!0, bool>)
IL_0026: call class [System.Collections]System.Collections.Generic.List`1<!!0> [System.Linq]System.Linq.Enumerable::ToList<class Transaction>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>)
IL_002b: ret
}
// .NET 8
.method public hidebysig
instance class [System.Collections]System.Collections.Generic.List`1<class Transaction> PerformPLinqQueryOnSmallTransactionsSingleCore () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 64 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x21c3
// Code size 55 (0x37)
.maxstack 8
// sequence point: (line 103, col 9) to (line 106, col 23) in _
IL_0000: ldarg.0
IL_0001: ldfld class [System.Collections]System.Collections.Generic.List`1<class Transaction> TransactionAnalysisBenchmark::smallTransactionList
IL_0006: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::AsParallel<class Transaction>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>)
IL_000b: ldc.i4.1
IL_000c: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::WithDegreeOfParallelism<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>, int32)
IL_0011: ldsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_0016: dup
IL_0017: brtrue.s IL_002c
IL_0019: pop
IL_001a: ldnull
IL_001b: ldftn bool TransactionAnalysisBenchmark::IsTransactionPotentiallyFraudulent(class Transaction)
IL_0021: newobj instance void class [System.Runtime]System.Func`2<class Transaction, bool>::.ctor(object, native int)
IL_0026: dup
IL_0027: stsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_002c: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::Where<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>, class [System.Runtime]System.Func`2<!!0, bool>)
IL_0031: call class [System.Collections]System.Collections.Generic.List`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::ToList<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>)
IL_0036: ret
}
// .NET 8
.method public hidebysig
instance class [System.Collections]System.Collections.Generic.List`1<class Transaction> PerformPLinqQueryOnSmallTransactionsMaxCore () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 6d 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x21fb
// Code size 59 (0x3b)
.maxstack 8
// sequence point: (line 112, col 9) to (line 115, col 23) in _
IL_0000: ldarg.0
IL_0001: ldfld class [System.Collections]System.Collections.Generic.List`1<class Transaction> TransactionAnalysisBenchmark::smallTransactionList
IL_0006: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::AsParallel<class Transaction>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>)
IL_000b: call int32 [System.Runtime]System.Environment::get_ProcessorCount()
IL_0010: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::WithDegreeOfParallelism<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>, int32)
IL_0015: ldsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_001a: dup
IL_001b: brtrue.s IL_0030
IL_001d: pop
IL_001e: ldnull
IL_001f: ldftn bool TransactionAnalysisBenchmark::IsTransactionPotentiallyFraudulent(class Transaction)
IL_0025: newobj instance void class [System.Runtime]System.Func`2<class Transaction, bool>::.ctor(object, native int)
IL_002a: dup
IL_002b: stsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_0030: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::Where<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>, class [System.Runtime]System.Func`2<!!0, bool>)
IL_0035: call class [System.Collections]System.Collections.Generic.List`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::ToList<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>)
IL_003a: ret
}
// .NET 8
.method public hidebysig
instance class [System.Collections]System.Collections.Generic.List`1<class Transaction> PerformPLinqQueryOnLargeTransactionsSingleCore () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 76 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x2237
// Code size 55 (0x37)
.maxstack 8
// sequence point: (line 121, col 9) to (line 124, col 23) in _
IL_0000: ldarg.0
IL_0001: ldfld class [System.Collections]System.Collections.Generic.List`1<class Transaction> TransactionAnalysisBenchmark::largeTransactionList
IL_0006: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::AsParallel<class Transaction>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>)
IL_000b: ldc.i4.1
IL_000c: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::WithDegreeOfParallelism<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>, int32)
IL_0011: ldsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_0016: dup
IL_0017: brtrue.s IL_002c
IL_0019: pop
IL_001a: ldnull
IL_001b: ldftn bool TransactionAnalysisBenchmark::IsTransactionPotentiallyFraudulent(class Transaction)
IL_0021: newobj instance void class [System.Runtime]System.Func`2<class Transaction, bool>::.ctor(object, native int)
IL_0026: dup
IL_0027: stsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_002c: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::Where<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>, class [System.Runtime]System.Func`2<!!0, bool>)
IL_0031: call class [System.Collections]System.Collections.Generic.List`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::ToList<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>)
IL_0036: ret
}
// .NET 8
.method public hidebysig
instance class [System.Collections]System.Collections.Generic.List`1<class Transaction> PerformPLinqQueryOnLargeTransactionsMaxCore () cil managed
{
.custom instance void [BenchmarkDotNet.Annotations]BenchmarkDotNet.Attributes.BenchmarkAttribute::.ctor(int32, string) = (
01 00 7f 00 00 00 01 5f 00 00
)
// Method begins at RVA 0x226f
// Code size 59 (0x3b)
.maxstack 8
// sequence point: (line 130, col 9) to (line 133, col 23) in _
IL_0000: ldarg.0
IL_0001: ldfld class [System.Collections]System.Collections.Generic.List`1<class Transaction> TransactionAnalysisBenchmark::largeTransactionList
IL_0006: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::AsParallel<class Transaction>(class [System.Runtime]System.Collections.Generic.IEnumerable`1<!!0>)
IL_000b: call int32 [System.Runtime]System.Environment::get_ProcessorCount()
IL_0010: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::WithDegreeOfParallelism<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>, int32)
IL_0015: ldsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_001a: dup
IL_001b: brtrue.s IL_0030
IL_001d: pop
IL_001e: ldnull
IL_001f: ldftn bool TransactionAnalysisBenchmark::IsTransactionPotentiallyFraudulent(class Transaction)
IL_0025: newobj instance void class [System.Runtime]System.Func`2<class Transaction, bool>::.ctor(object, native int)
IL_002a: dup
IL_002b: stsfld class [System.Runtime]System.Func`2<class Transaction, bool> TransactionAnalysisBenchmark/'<>O'::'<0>__IsTransactionPotentiallyFraudulent'
IL_0030: call class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::Where<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>, class [System.Runtime]System.Func`2<!!0, bool>)
IL_0035: call class [System.Collections]System.Collections.Generic.List`1<!!0> [System.Linq.Parallel]System.Linq.ParallelEnumerable::ToList<class Transaction>(class [System.Linq.Parallel]System.Linq.ParallelQuery`1<!!0>)
IL_003a: ret
}
Powered by SharpLab
|
Benchmark Description:
## Benchmark Description
This benchmark measures the performance of different LINQ and PLINQ methods for analyzing potentially fraudulent transactions across small and large datasets.
### Results Summary
- **Small Dataset (1000 transactions)**:
- **LINQ**: Baseline performance (100%).
- **PLINQ (Single Core)**: Approximately 27% slower than LINQ.
- **PLINQ (Max Cores)**: About 81% slower than LINQ due to overhead.
- **Large Dataset (1,000,000 transactions)**:
- **LINQ**: Baseline performance (100%).
- **PLINQ (Single Core)**: Around 47% slower than LINQ.
- **PLINQ (Max Cores)**: Approximately 56% faster than LINQ.
In summary, for small datasets, plain LINQ is the most efficient, while for large datasets, using PLINQ with maximum core utilization provides significant performance improvements.
The provided benchmark code is designed to measure the performance of querying a list of `Transaction` objects using LINQ and PLINQ (Parallel LINQ) under different conditions. It uses the BenchmarkDotNet library, a powerful tool for benchmarking .NET code. The benchmarks do not explicitly mention the .NET version, but given the use of BenchmarkDotNet and the code patterns, it's safe to assume it targets .NET Core 3.1 or .NET 5/6/7.
### General Setup
- **Transaction Class**: Represents a financial transaction with an amount and a time.
- **TransactionFactory Class**: Generates a list of `Transaction` objects with random amounts and times.
- **TransactionAnalysisBenchmark Class**: Contains benchmarks to analyze transactions for potential fraud.
### Benchmark Methods Rationale
1. **PerformLinqQueryOnSmallTransactions**: Measures the performance of filtering a small list (1,000 transactions) using LINQ to identify potentially fraudulent transactions. This benchmark tests LINQ's efficiency in handling relatively small datasets.
2. **PerformLinqQueryOnLargeTransactions**: Similar to the first, but for a large list (1,000,000 transactions). It tests LINQ's scalability and performance with significantly larger datasets.
3. **PerformPLinqQueryOnSmallTransactionsSingleCore**: Uses PLINQ with `WithDegreeOfParallelism(1)` on the small transaction list. This setup forces PLINQ to run in parallel but using only one core, essentially simulating a single-threaded environment. It's useful for comparing how PLINQ's overhead affects performance in a constrained parallel environment versus LINQ.
4. **PerformPLinqQueryOnSmallTransactionsMaxCore**: Applies PLINQ on the small transaction list with parallelism set to the maximum available cores. This benchmark tests how well PLINQ can utilize multiple cores for small datasets and whether the overhead of parallelization is justified for small data volumes.
5. **PerformPLinqQueryOnLargeTransactionsSingleCore**: Similar to the third benchmark but applied to the large dataset. It helps in understanding the impact of PLINQ's overhead in a single-core scenario for large datasets.
6. **PerformPLinqQueryOnLargeTransactionsMaxCore**: Uses PLINQ with full parallelism on the large dataset. This is the key benchmark for evaluating PLINQ's effectiveness and efficiency in utilizing multi-core processors for large-scale data processing tasks.
### What Each Benchmark Measures
- **LINQ vs. PLINQ Performance**: By comparing LINQ and PLINQ results, you can understand the overhead and benefits of parallel processing for different dataset sizes.
- **Effect of Dataset Size**: Comparing small vs. large dataset benchmarks helps in understanding how the size of the data affects performance and scalability.
- **Single-Core vs. Multi-Core Processing**: By adjusting the degree of parallelism in PLINQ queries, these benchmarks illustrate the impact of single-core processing versus leveraging multiple cores.
### Expected Insights
- **LINQ Performance**: For small datasets, LINQ is expected to perform well due to its simplicity and lower overhead.
- **PLINQ Overhead**: In single-core scenarios, PLINQ might not outperform LINQ significantly due to the overhead of parallelization.
- **PLINQ Scalability**: For large datasets and when utilizing multiple cores, PLINQ should demonstrate superior performance by efficiently distributing the workload across available cores.
- **Optimal Use Cases**: These benchmarks can help identify the threshold at which the overhead of parallelization is justified by the performance gains, guiding decisions on when to use LINQ vs. PLINQ based on dataset size and available system resources.
This benchmark suite is a comprehensive tool for understanding the performance characteristics of LINQ and PLINQ in various scenarios, aiding in making informed decisions for data processing tasks in .NET applications.