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
5 changes: 2 additions & 3 deletions Ical.Net.Benchmarks/ApplicationWorkflows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace Ical.Net.Benchmarks
{
Expand All @@ -17,8 +16,8 @@ public class ApplicationWorkflows

private static List<string> GetIcalStrings()
{
var currentDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var topLevelIcsPath = Path.GetFullPath(Path.Combine(currentDirectory, @"..\..\..\..\", @"Ical.Net.CoreUnitTests\Calendars"));
var testProjectDirectory = Runner.FindParentFolder("Ical.Net.Tests", Directory.GetCurrentDirectory());
var topLevelIcsPath = Path.GetFullPath(Path.Combine(testProjectDirectory, "Calendars"));
return Directory.EnumerateFiles(topLevelIcsPath, "*.ics", SearchOption.AllDirectories)
.Select(File.ReadAllText)
.Distinct(StringComparer.OrdinalIgnoreCase)
Expand Down
1 change: 1 addition & 0 deletions Ical.Net.Benchmarks/Ical.Net.Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<PropertyGroup>
<TargetFrameworks>net8.0;net6.0;netcoreapp3.1;net48</TargetFrameworks>
<OutputType>Exe</OutputType>
<LangVersion>latest</LangVersion>
</PropertyGroup>

<ItemGroup>
Expand Down
6 changes: 3 additions & 3 deletions Ical.Net.Benchmarks/OccurencePerfTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void MultipleEventsWithUntilOccurrencesEventsAsParallel()
.ToList();
}

private Calendar GetFourCalendarEventsWithUntilRule()
private static Calendar GetFourCalendarEventsWithUntilRule()
{
const string tzid = "America/New_York";
const int limit = 4;
Expand Down Expand Up @@ -99,13 +99,13 @@ public void MultipleEventsWithCountOccurrencesEventsAsParallel()
var calendar = GetFourCalendarEventsWithCountRule();
var searchStart = calendar.Events.First().DtStart.AddYears(-1);
var searchEnd = calendar.Events.Last().DtStart.AddYears(1).AddDays(10);
var eventOccurrences = calendar.Events
_ = calendar.Events
.AsParallel()
.SelectMany(e => e.GetOccurrences(searchStart, searchEnd))
.ToList();
}

private Calendar GetFourCalendarEventsWithCountRule()
private static Calendar GetFourCalendarEventsWithCountRule()
{
const string tzid = "America/New_York";
const int limit = 4;
Expand Down
191 changes: 186 additions & 5 deletions Ical.Net.Benchmarks/Runner.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,199 @@
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
using System.IO;

namespace Ical.Net.Benchmarks
{
public class Runner
{
private static void Main(string[] args)
{
#if DEBUG
BenchmarkSwitcher.FromAssembly(typeof(ApplicationWorkflows).Assembly).Run(args, new DebugInProcessConfig());
#else
#region * ApplicationWorkflows results *
/*
// * Summary *

BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4317/23H2/2023Update/SunValley3)
13th Gen Intel Core i7-13700K, 1 CPU, 24 logical and 16 physical cores
.NET SDK 8.0.403
[Host] : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX2

| Method | Mean | Error | StdDev |
|---------------------------------------------------------------- |---------:|---------:|---------:|
| SingleThreaded | 18.20 ms | 0.184 ms | 0.163 ms |
| ParallelUponDeserialize | 17.56 ms | 0.350 ms | 0.739 ms |
| ParallelUponGetOccurrences | 26.39 ms | 0.294 ms | 0.275 ms |
| ParallelDeserializeSequentialGatherEventsParallelGetOccurrences | 19.39 ms | 0.373 ms | 0.399 ms |

// * Hints *
Outliers
ApplicationWorkflows.SingleThreaded: Default -> 1 outlier was removed (18.95 ms)
ApplicationWorkflows.ParallelUponGetOccurrences: Default -> 1 outlier was detected (25.79 ms)

// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
1 ms : 1 Millisecond (0.001 sec)

// ***** BenchmarkRunner: End *****
*/
#endregion
BenchmarkRunner.Run(BenchmarkConverter.TypeToBenchmarks(typeof(ApplicationWorkflows)));

#region * OccurencePerfTests results *
/*
// * Summary *

BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4317/23H2/2023Update/SunValley3)
13th Gen Intel Core i7-13700K, 1 CPU, 24 logical and 16 physical cores
.NET SDK 8.0.403
[Host] : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX2

| Method | Mean | Error | StdDev |
|----------------------------------------------------------- |-----------:|---------:|---------:|
| MultipleEventsWithUntilOccurrencesSearchingByWholeCalendar | 175.2 us | 1.87 us | 1.66 us |
| MultipleEventsWithUntilOccurrences | 126.6 us | 1.43 us | 1.34 us |
| MultipleEventsWithUntilOccurrencesEventsAsParallel | NA | NA | NA |
| MultipleEventsWithCountOccurrencesSearchingByWholeCalendar | 1,672.7 us | 33.29 us | 31.14 us |
| MultipleEventsWithCountOccurrences | 1,066.6 us | 20.83 us | 30.53 us |
| MultipleEventsWithCountOccurrencesEventsAsParallel | NA | NA | NA |

Benchmarks with issues (System.AggregateException: One or more errors occurred. (Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.
OccurencePerfTests.MultipleEventsWithUntilOccurrencesEventsAsParallel: DefaultJob
OccurencePerfTests.MultipleEventsWithCountOccurrencesEventsAsParallel: DefaultJob

*/
#endregion
BenchmarkRunner.Run(BenchmarkConverter.TypeToBenchmarks(typeof(OccurencePerfTests)));

//BenchmarkRunnerCore.Run(BenchmarkConverter.TypeToBenchmarks(typeof(OccurencePerfTests)), t => InProcessToolchain.Instance);
//BenchmarkRunnerCore.Run(BenchmarkConverter.TypeToBenchmarks(typeof(CalDateTimePerfTests)), t => InProcessToolchain.Instance);
//BenchmarkRunnerCore.Run(BenchmarkConverter.TypeToBenchmarks(typeof(SerializationPerfTests)), t => InProcessToolchain.Instance);
//BenchmarkRunnerCore.Run(BenchmarkConverter.TypeToBenchmarks(typeof(ThroughputTests)), t => InProcessToolchain.Instance);
#region * CalDateTimePerfTests results *
/*
// * Summary *

BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4317/23H2/2023Update/SunValley3)
13th Gen Intel Core i7-13700K, 1 CPU, 24 logical and 16 physical cores
.NET SDK 8.0.403
[Host] : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX2

| Method | Mean | Error | StdDev |
|----------------------------- |----------:|---------:|---------:|
| EmptyTzid | 97.35 ns | 0.700 ns | 0.620 ns |
| SpecifiedTzid | 219.31 ns | 4.406 ns | 5.729 ns |
| UtcDateTime | 193.75 ns | 3.563 ns | 3.333 ns |
| EmptyTzidToTzid | 412.57 ns | 6.857 ns | 6.414 ns |
| SpecifiedTzidToDifferentTzid | 494.44 ns | 8.299 ns | 7.763 ns |
| UtcToDifferentTzid | 437.86 ns | 3.880 ns | 3.630 ns |

// * Hints *
Outliers
CalDateTimePerfTests.EmptyTzid: Default -> 1 outlier was removed (101.43 ns)
*/
#endregion
BenchmarkRunner.Run(BenchmarkConverter.TypeToBenchmarks(typeof(CalDateTimePerfTests)));

#region * SerializationPerfTests results *
/*
// * Summary *

BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4317/23H2/2023Update/SunValley3)
13th Gen Intel Core i7-13700K, 1 CPU, 24 logical and 16 physical cores
.NET SDK 8.0.403
[Host] : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX2


| Method | Mean | Error | StdDev |
|--------------------------- |---------:|---------:|---------:|
| Deserialize | 53.40 us | 0.456 us | 0.404 us |
| BenchmarkSerializeCalendar | 13.76 us | 0.266 us | 0.285 us |

// * Hints *
Outliers
SerializationPerfTests.Deserialize: Default -> 1 outlier was removed (54.96 us)

// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
1 us : 1 Microsecond (0.000001 sec)

// ***** BenchmarkRunner: End *****
*/
#endregion
BenchmarkRunner.Run(BenchmarkConverter.TypeToBenchmarks(typeof(SerializationPerfTests)));

#region * ThroughputTests results *
/*
// * Summary *

BenchmarkDotNet v0.14.0, Windows 11 (10.0.22631.4317/23H2/2023Update/SunValley3)
13th Gen Intel Core i7-13700K, 1 CPU, 24 logical and 16 physical cores
.NET SDK 8.0.403
[Host] : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX2
DefaultJob : .NET 8.0.10 (8.0.1024.46610), X64 RyuJIT AVX2


| Method | Mean | Error | StdDev |
|-------------------------------------- |---------:|----------:|----------:|
| DeserializeAndComputeUntilOccurrences | 2.178 ms | 0.0410 ms | 0.0403 ms |
| DeserializeAndComputeCountOccurrences | 2.116 ms | 0.0277 ms | 0.0245 ms |

// * Hints *
Outliers
ThroughputTests.DeserializeAndComputeCountOccurrences: Default -> 1 outlier was removed (2.20 ms)

// * Legends *
Mean : Arithmetic mean of all measurements
Error : Half of 99.9% confidence interval
StdDev : Standard deviation of all measurements
1 ms : 1 Millisecond (0.001 sec)

// ***** BenchmarkRunner: End *****
*/
#endregion
BenchmarkRunner.Run(BenchmarkConverter.TypeToBenchmarks(typeof(ThroughputTests)));
#endif
}

/// <summary>
/// Searches the parent directories of <paramref name="startPath"/> for
/// the first directory with name of <paramref name="directoryName"/>.
/// </summary>
/// <param name="directoryName">The name of the directory to search.</param>
/// <param name="startPath">The path where the search starts.</param>
/// <returns>The full path of the found folder.</returns>
/// <exception cref="DirectoryNotFoundException">
/// The <paramref name="startPath"/> does not exist, or the <paramref name="directoryName"/>
/// was not found in the parent directories.
/// </exception>
/// <exception cref="System.UnauthorizedAccessException">The caller does not have the required permission.</exception>
/// <exception cref="System.IO.PathTooLongException">The specified path, file name, or both exceed the system-defined maximum length.</exception>
public static string FindParentFolder(string directoryName, string startPath)
{
if (!Directory.Exists(startPath))
{
throw new DirectoryNotFoundException($"Start path '{startPath}' not found.");
}

var currentPath = startPath;
var rootReached = false;

while (!rootReached && !Directory.Exists(Path.Combine(currentPath, directoryName)))
{
currentPath = Directory.GetParent(currentPath)?.FullName;
rootReached = currentPath == null;
currentPath ??= Directory.GetDirectoryRoot(startPath);
}

var resultPath = Path.Combine(currentPath, directoryName);
if (!Directory.Exists(resultPath)) throw new DirectoryNotFoundException($"Folder '{directoryName}' not found in parent directories.");
return resultPath;
}
}
}
103 changes: 52 additions & 51 deletions Ical.Net.Benchmarks/SerializationPerfTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,57 +10,58 @@ namespace Ical.Net.Benchmarks
{
public class SerializationPerfTests
{
private const string SampleEvent = @"BEGIN:VCALENDAR
PRODID:-//Microsoft Corporation//Outlook 12.0 MIMEDIR//EN
VERSION:2.0
METHOD:PUBLISH
X-CALSTART:20090621T000000
X-CALEND:20090622T000000
X-WR-RELCALID:{0000002E-6380-7FD2-FED7-97EAE70D6611}
X-WR-CALNAME:Parse Error Calendar
BEGIN:VEVENT
ATTENDEE;[email protected];RSVP=TRUE:mailto:[email protected]
m
ATTENDEE;[email protected];RSVP=TRUE:mailto:[email protected]
ATTENDEE;CN=""4th Floor Meeting Room"";CUTYPE=RESOURCE;ROLE=NON-PARTICIPANT;R
SVP=TRUE:mailto:[email protected]
CLASS:PUBLIC
CREATED:20090621T201527Z
DESCRIPTION:\n
DTEND;VALUE=DATE:20090622
DTSTAMP:20090621T201612Z
DTSTART;VALUE=DATE:20090621
LAST-MODIFIED:20090621T201618Z
LOCATION:The Exceptionally Long Named Meeting Room Whose Name Wraps Over Se
veral Lines When Exported From Leading Calendar and Office Software App
lication Microsoft Office 2007
ORGANIZER;CN=""Event Organizer"":mailto:[email protected]
PRIORITY:5
SEQUENCE:0
SUMMARY;LANGUAGE=en-gb:Example Calendar Export that Blows Up DDay.iCal
TRANSP:TRANSPARENT
UID:040000008200E00074C5B7101A82E00800000000900AD080B5F2C901000000000000000
010000000B29680BF9E5DC246B5EDDE228038E71F
X-ALT-DESC;FMTTYPE=text/html:<!DOCTYPE HTML PUBLIC ""-//W3C//DTD HTML 3.2//E
N"">\n<HTML>\n<HEAD>\n<META NAME=""Generator"" CONTENT=""MS Exchange Server ve
rsion 08.00.0681.000"">\n<TITLE></TITLE>\n</HEAD>\n<BODY>\n<!-- Converted f
rom text/rtf format -->\n\n<P DIR=LTR><SPAN LANG=""en-gb""></SPAN></P>\n\n</
BODY>\n</HTML>
X-MICROSOFT-CDO-BUSYSTATUS:FREE
X-MICROSOFT-CDO-IMPORTANCE:1
X-MICROSOFT-DISALLOW-COUNTER:FALSE
X-MS-OLK-ALLOWEXTERNCHECK:TRUE
X-MS-OLK-APPTSEQTIME:20090621T201612Z
X-MS-OLK-AUTOFILLLOCATION:TRUE
X-MS-OLK-CONFTYPE:0
BEGIN:VALARM
TRIGGER:-PT1080M
ACTION:DISPLAY
DESCRIPTION:Reminder
END:VALARM
END:VEVENT
END:VCALENDAR
";
private const string SampleEvent = """
BEGIN:VCALENDAR
PRODID:-//Microsoft Corporation//Outlook 12.0 MIMEDIR//EN
VERSION:2.0
METHOD:PUBLISH
X-CALSTART:20090621T000000
X-CALEND:20090622T000000
X-WR-RELCALID:{0000002E-6380-7FD2-FED7-97EAE70D6611}
X-WR-CALNAME:Parse Error Calendar
BEGIN:VEVENT
ATTENDEE;[email protected];RSVP=TRUE:mailto:[email protected]
m
ATTENDEE;[email protected];RSVP=TRUE:mailto:[email protected]
ATTENDEE;CN="4th Floor Meeting Room";CUTYPE=RESOURCE;ROLE=NON-PARTICIPANT;R
SVP=TRUE:mailto:[email protected]
CLASS:PUBLIC
CREATED:20090621T201527Z
DESCRIPTION:\n
DTEND;VALUE=DATE:20090622
DTSTAMP:20090621T201612Z
DTSTART;VALUE=DATE:20090621
LAST-MODIFIED:20090621T201618Z
LOCATION:The Exceptionally Long Named Meeting Room Whose Name Wraps Over Se
veral Lines When Exported From Leading Calendar and Office Software App
lication Microsoft Office 2007
ORGANIZER;CN="Event Organizer":mailto:[email protected]
PRIORITY:5
SEQUENCE:0
SUMMARY;LANGUAGE=en-gb:Example Calendar Export that Blows Up DDay.iCal
TRANSP:TRANSPARENT
UID:040000008200E00074C5B7101A82E00800000000900AD080B5F2C901000000000000000
010000000B29680BF9E5DC246B5EDDE228038E71F
X-ALT-DESC;FMTTYPE=text/html:<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//E
N">\n<HTML>\n<HEAD>\n<META NAME="Generator" CONTENT="MS Exchange Server ve
rsion 08.00.0681.000">\n<TITLE></TITLE>\n</HEAD>\n<BODY>\n<!-- Converted f
rom text/rtf format -->\n\n<P DIR=LTR><SPAN LANG="en-gb"></SPAN></P>\n\n</
BODY>\n</HTML>
X-MICROSOFT-CDO-BUSYSTATUS:FREE
X-MICROSOFT-CDO-IMPORTANCE:1
X-MICROSOFT-DISALLOW-COUNTER:FALSE
X-MS-OLK-ALLOWEXTERNCHECK:TRUE
X-MS-OLK-APPTSEQTIME:20090621T201612Z
X-MS-OLK-AUTOFILLLOCATION:TRUE
X-MS-OLK-CONFTYPE:0
BEGIN:VALARM
TRIGGER:-PT1080M
ACTION:DISPLAY
DESCRIPTION:Reminder
END:VALARM
END:VEVENT
END:VCALENDAR
""";

[Benchmark]
public void Deserialize() => Calendar.Load(SampleEvent).Events.First();
Expand Down
Loading