C# Runtime
Technical deep-dive on how the .polybench C# runtime project works
This page documents how the .polybench/runtime-env/csharp/ project is set up, how codegen works, and how execution is performed.
The C# runtime uses a .NET project. The generated benchmark code overwrites Program.cs. poly-bench writes global.json to pin the SDK version (e.g. 8.0.0 for net8.0). The target framework defaults to net8.0. The runtime crate is runtimes-csharp; templates come from poly-bench-project.
When you run poly-bench init --languages csharp, poly-bench:
.polybench/runtime-env/csharp/polybench.csproj with target framework from [csharp] target_framework (default net8.0)Program.cs with a minimal public static void Main() {} placeholderNuGet.config with the vs-impl feed (for roslyn-language-server and other .NET tools)No dotnet restore at init. Dependencies are restored when you run poly-bench build or when the executor runs dotnet build.
When you run poly-bench build or poly-bench install:
polybench.csproj if --force is used[csharp] dependencies to the csprojdotnet restore (skipped with --skip-install)The executor writes global.json at run time to pin the SDK version (e.g. 8.0.0 for net8.0). This ensures dotnet build uses the correct SDK even when multiple SDKs are installed.
global.json at run time to pin the SDK version, ensuring dotnet build uses the correct SDK when multiple SDKs are installed.Program.cs — Same pattern as Rust: codegen produces a complete program. The placeholder exists for a valid project structure before the first run.global.json at run time — The executor writes it when executing benchmarks. Pinning the SDK avoids "which SDK?" ambiguity when the user has .NET 6, 7, and 8 installed.polybench.toml if you have only .NET 6 or 7.dotnet tool install and restore can resolve them.UseAppHost: false — Reduces build output; the benchmark runs via dotnet run or by invoking the DLL directly.When you run poly-bench init --languages csharp or poly-bench build, the following is created in .polybench/runtime-env/csharp/:
| File | Source | Purpose |
|---|---|---|
polybench.csproj | templates.csharp_csproj() | Target framework (default net8.0), dependencies |
Program.cs | Placeholder | Overwritten by codegen at run time |
global.json | Written by executor | Pins SDK version (e.g. 8.0.0 for net8.0) |
NuGet.config | templates.csharp_nuget_config() | Adds vs-impl feed for roslyn-language-server |
The global.json ensures dotnet build uses the correct SDK. Override the target framework in polybench.toml: [csharp] target_framework = "net9.0".
When poly-bench run executes a benchmark, the C# runtime:
generate_csharp_source(spec, suite, for_check) in runtimes-csharp/src/codegen.rsProgram.cs with: fixture decoding, setup/init code, helper functions, and the benchmark loopProgram.cs (overwriting the placeholder)Generated files:
Program.cs — overwritten with full benchmark harness| Step | Command | Output |
|---|---|---|
| Precompile | dotnet build | Compiled assembly in bin/ |
| Run | dotnet run | Executes the compiled program |
The executor uses dotnet run which builds and runs. The global.json pin ensures the correct SDK is used.
Program.cs, run dotnet builddotnet run (or equivalent) with the benchmark name and iterationspolybench.toml if you have only .NET 6 or 7.net8.0. Override in polybench.toml if you have .NET 6 or 7 only.global.json to pin the SDK version. Ensures dotnet build uses the correct SDK.See Requirements — C# for user-facing setup and gotchas.