Skip to content

Commit

Permalink
Basic benchmarking (#319)
Browse files Browse the repository at this point in the history
* Rename, created project

* Basic framework works

* Create 99bottles.draco

* Update LexerBenchmarks.cs

* Added parser tests

* Basic e2e benchmarking

* Namespace sync

* Cleanup

* PR comment

* Update SyntaxBenchmarks.cs
  • Loading branch information
LPeter1997 authored Sep 19, 2023
1 parent a420137 commit 92ae046
Show file tree
Hide file tree
Showing 28 changed files with 299 additions and 23 deletions.
25 changes: 25 additions & 0 deletions src/Draco.Compiler.Benchmarks/Draco.Compiler.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>

<!-- Copy benchmark inputs -->
<ItemGroup>
<Content Include="benchmarks\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Draco.Compiler\Draco.Compiler.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.8" />
<PackageReference Include="Basic.Reference.Assemblies.Net70" Version="1.4.1" />
</ItemGroup>

</Project>
36 changes: 36 additions & 0 deletions src/Draco.Compiler.Benchmarks/E2eBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using BenchmarkDotNet.Attributes;
using Draco.Compiler.Api;
using Draco.Compiler.Api.Syntax;

namespace Draco.Compiler.Benchmarks;

public class E2eBenchmarks : FolderBenchmarkBase
{
private MemoryStream peStream = null!;

public E2eBenchmarks()
: base("e2e")
{
}

[IterationSetup]
public void Setup()
{
this.peStream = new();
}

[Benchmark]
public EmitResult Compile()
{
var syntaxTree = SyntaxTree.Parse(this.Input.Code, Path.GetFullPath(this.Input.Path));
var compilation = Compilation.Create(
syntaxTrees: ImmutableArray.Create(syntaxTree),
metadataReferences: Basic.Reference.Assemblies.Net70.ReferenceInfos.All
.Select(r => MetadataReference.FromPeStream(new MemoryStream(r.ImageBytes)))
.ToImmutableArray());
return compilation.Emit(peStream: this.peStream);
}
}
23 changes: 23 additions & 0 deletions src/Draco.Compiler.Benchmarks/FolderBenchmarkBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BenchmarkDotNet.Attributes;

namespace Draco.Compiler.Benchmarks;

public abstract class FolderBenchmarkBase
{
[ParamsSource(nameof(GetSourcesFromFolder))]
public SourceCodeParameter Input { get; set; } = null!;

private readonly string path;

protected FolderBenchmarkBase(string path)
{
this.path = Path.Join("benchmarks", path);
}

public IEnumerable<SourceCodeParameter> GetSourcesFromFolder() => Directory
.GetFiles(this.path)
.Select(SourceCodeParameter.FromPath);
}
9 changes: 9 additions & 0 deletions src/Draco.Compiler.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using BenchmarkDotNet.Running;

namespace Draco.Compiler.Benchmarks;

internal class Program
{
internal static void Main(string[] args) =>
BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
}
10 changes: 10 additions & 0 deletions src/Draco.Compiler.Benchmarks/SourceCodeParameter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.IO;

namespace Draco.Compiler.Benchmarks;

public sealed record class SourceCodeParameter(string Path, string Code)
{
public static SourceCodeParameter FromPath(string path) => new(path, File.ReadAllText(path));

public override string ToString() => System.IO.Path.GetFileName(this.Path);
}
96 changes: 96 additions & 0 deletions src/Draco.Compiler.Benchmarks/SyntaxBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using Draco.Compiler.Api.Syntax;
using Draco.Compiler.Internal.Syntax;
using CompilationUnitSyntax = Draco.Compiler.Internal.Syntax.CompilationUnitSyntax;
using SyntaxToken = Draco.Compiler.Internal.Syntax.SyntaxToken;

namespace Draco.Compiler.Benchmarks;

public class SyntaxBenchmarks : FolderBenchmarkBase
{
private SyntaxToken[] tokens = null!;

private Lexer lexer = null!;
private Parser parser = null!;

public SyntaxBenchmarks()
: base("syntax")
{
}

[GlobalSetup]
public void GlobalSetup()
{
this.tokens = LexFromBenchmarkParameter(this.Input);
}

[IterationSetup(Target = nameof(Lex))]
public void LexSetup()
{
var sourceReader = SourceReader.From(this.Input.Code);
var syntaxDiagnostics = new SyntaxDiagnosticTable();
this.lexer = new Lexer(sourceReader, syntaxDiagnostics);
}

[IterationSetup(Target = nameof(Parse))]
public void ParseSetup()
{
var tokenSource = TokenSource.From(this.tokens.AsMemory());
var syntaxDiagnostics = new SyntaxDiagnosticTable();
this.parser = new Parser(tokenSource, syntaxDiagnostics);
}

[IterationSetup(Target = nameof(ParseWithStreamingLexer))]
public void ParseWithStreamingLexerSetup()
{
var syntaxDiagnostics = new SyntaxDiagnosticTable();

var sourceReader = SourceReader.From(this.Input.Code);
this.lexer = new Lexer(sourceReader, syntaxDiagnostics);

var tokenSource = TokenSource.From(this.lexer);
this.parser = new Parser(tokenSource, syntaxDiagnostics);
}

[Benchmark]
public int Lex()
{
var count = 0;
while (true)
{
var token = this.lexer.Lex();
++count;
if (token.Kind == TokenKind.EndOfInput) break;
}
return count;
}

[Benchmark]
public object Parse() =>
this.parser.ParseCompilationUnit();

[Benchmark]
public object ParseWithStreamingLexer() =>
this.parser.ParseCompilationUnit();

private static SyntaxToken[] LexFromBenchmarkParameter(SourceCodeParameter parameter)
{
var sourceReader = SourceReader.From(parameter.Code);
var syntaxDiagnostics = new SyntaxDiagnosticTable();
var lexer = new Lexer(sourceReader, syntaxDiagnostics);

var result = new List<SyntaxToken>();

while (true)
{
var token = lexer.Lex();
result.Add(token);

if (token.Kind == TokenKind.EndOfInput) break;
}

return result.ToArray();
}
}
29 changes: 29 additions & 0 deletions src/Draco.Compiler.Benchmarks/benchmarks/e2e/99bottles.draco
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import System.Console;

func bottles(n: int32): string =
if (n == 0) "no more bottles"
else if (n == 1) "1 bottle"
else "\{n} bottles";

func capitalize(s: string): string =
"\{s.Substring(0, 1).ToUpper()}\{s.Substring(1)}";

func main() {
var i = 99;
while (i > 0) {
WriteLine("""
\{capitalize(bottles(i))} of beer on the wall,
\{bottles(i)} of beer.
Take one down, pass it around,
\{bottles(i - 1)} of beer on the wall.

""");
i -= 1;
}
WriteLine("""
No more bottles of beer on the wall,
no more bottles of beer.
Go to the store, buy some more,
99 bottles of beer on the wall.
""");
}
5 changes: 5 additions & 0 deletions src/Draco.Compiler.Benchmarks/benchmarks/e2e/helloworld.draco
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import System.Console;

public func main() {
WriteLine("Hello, World!");
}
29 changes: 29 additions & 0 deletions src/Draco.Compiler.Benchmarks/benchmarks/syntax/99bottles.draco
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import System.Console;

func bottles(n: int32): string =
if (n == 0) "no more bottles"
else if (n == 1) "1 bottle"
else "\{n} bottles";

func capitalize(s: string): string =
"\{s.Substring(0, 1).ToUpper()}\{s.Substring(1)}";

func main() {
var i = 99;
while (i > 0) {
WriteLine("""
\{capitalize(bottles(i))} of beer on the wall,
\{bottles(i)} of beer.
Take one down, pass it around,
\{bottles(i - 1)} of beer on the wall.

""");
i -= 1;
}
WriteLine("""
No more bottles of beer on the wall,
no more bottles of beer.
Go to the store, buy some more,
99 bottles of beer on the wall.
""");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import System.Console;

public func main() {
WriteLine("Hello, World!");
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Draco.Fuzzer.Generators;
using Draco.Compiler.Fuzzer.Generators;

namespace Draco.Fuzzer.Components;
namespace Draco.Compiler.Fuzzer.Components;

/// <summary>
/// Utility base-class for component fuzzers.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
using Draco.Compiler.Api;
using Draco.Compiler.Api.Scripting;
using Draco.Compiler.Api.Syntax;
using Draco.Fuzzer.Generators;
using Draco.Compiler.Fuzzer.Generators;

namespace Draco.Fuzzer.Components;
namespace Draco.Compiler.Fuzzer.Components;

/// <summary>
/// Fuzzes the compiler end-to-end.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Draco.Fuzzer.Components;
namespace Draco.Compiler.Fuzzer.Components;

/// <summary>
/// Represents the fuzzer of a compiler component.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using Draco.Compiler.Api.Syntax;
using Draco.Compiler.Fuzzer.Generators;
using Draco.Compiler.Internal.Syntax;
using Draco.Fuzzer.Generators;

namespace Draco.Fuzzer.Components;
namespace Draco.Compiler.Fuzzer.Components;

/// <summary>
/// Fuzzes the lexer.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using System.Collections.Immutable;
using Draco.Compiler.Fuzzer.Generators;
using Draco.Compiler.Internal.Syntax;
using Draco.Fuzzer.Generators;

namespace Draco.Fuzzer.Components;
namespace Draco.Compiler.Fuzzer.Components;

/// <summary>
/// Fuzzes the parser.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Draco.Fuzzer;
namespace Draco.Compiler.Fuzzer;

/// <summary>
/// Represents an exception coming from a non-incremental change.
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Draco.Fuzzer.Generators;
namespace Draco.Compiler.Fuzzer.Generators;

/// <summary>
/// Character set constants.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Collections.Immutable;
using System.Globalization;

namespace Draco.Fuzzer.Generators;
namespace Draco.Compiler.Fuzzer.Generators;

/// <summary>
/// Utility functions for generation.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Draco.Fuzzer.Generators;
namespace Draco.Compiler.Fuzzer.Generators;

/// <summary>
/// Generates input for the fuzzer components.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Draco.Fuzzer.Generators;
namespace Draco.Compiler.Fuzzer.Generators;

/// <summary>
/// Settings for sequence generation.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Collections.Immutable;

namespace Draco.Fuzzer.Generators;
namespace Draco.Compiler.Fuzzer.Generators;

/// <summary>
/// An <see cref="IGenerator{T}"/> that generates a sequence based on another generator.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using SyntaxToken = Draco.Compiler.Internal.Syntax.SyntaxToken;
using SyntaxTrivia = Draco.Compiler.Internal.Syntax.SyntaxTrivia;

namespace Draco.Fuzzer.Generators;
namespace Draco.Compiler.Fuzzer.Generators;

/// <summary>
/// Generates a random valid token.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Draco.Compiler.Api.Syntax;
using SyntaxTrivia = Draco.Compiler.Internal.Syntax.SyntaxTrivia;

namespace Draco.Fuzzer.Generators;
namespace Draco.Compiler.Fuzzer.Generators;

/// <summary>
/// Generates a random valid syntax trivia.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Draco.Fuzzer;
namespace Draco.Compiler.Fuzzer;

/// <summary>
/// Represents an exception coming from an incremental change.
Expand Down
Loading

0 comments on commit 92ae046

Please sign in to comment.