Skip to content

2.13 Benchmarking

Marjan Nikolovski edited this page Apr 9, 2021 · 1 revision

Purpose

In computing, a benchmark is the act of running a computer program, a set of programs, or other operations, in order to assess the relative performance of an object, normally by running a number of standard tests and trials against it.

Signals offers an implementation for the Benchmarking aspect out of the box:

  • Signals.Aspects.Benchmarking.Database

How to use

When we implement any type of process a benchmarking provider is automatically injected in the process context.

public class MyProcess : BusinessProcess<VoidResult>
{
    /// <summary>
    /// Authenticate process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Auth()
    {
        return Ok();
    }

    /// <summary>
    /// Validate process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Validate()
    {
        return Ok();
    }

    /// <summary>
    /// Handle process
    /// </summary>
    /// <returns></returns>
    public override VoidResult Handle()
    {
        // Starting a benchmarking epic
        Context.Benchmarker.StartEpic("my_epic");

        // starting checkpoint
        Context.Benchmarker.Bench("my_start_checkpoint", "my_description_1", new { MyPayload1 = 1 });

        // some task that needs to be benchmarked
        LongRunningTask1();

        // checkpoint for measuring @LongRunningTask1();
        Context.Benchmarker.Bench("my_long_running_checkpoint_1", "my_description_2", new { MyPayload2 = 2 });

        // some task that needs to be benchmarked
        LongRunningTask2();

        // checkpoint for measuring @LongRunningTask2();
        Context.Benchmarker.Bench("my_end_checkpoint", "my_description_3", new { MyPayload3 = 3 });

        // Ending and saving a benchmarking epic
        Context.Benchmarker.FlushEpic();

        return Ok();
    }
}

Other more manual way of using the benchmarker is through the IBenchmarker instance.

public void BenchmarkAction(Action myAction)
{
    Guid epicId = Guid.NewGuid();
    var benchmarkProvider = SystemBootstrapper.GetInstance<IBenchmarker>();

    // Starting a benchmarking epic
    benchmarkProvider.StartEpic(epicId, "my_epic");

    // starting checkpoint
    benchmarkProvider.Bench("my_start_checkpoint", epicId, "myAction", "my_description_1", new { MyPayload1 = 1 });

    // some task that needs to be benchmarked
    myAction.Invoke();

    // checkpoint for measuring @LongRunningTask2();
    benchmarkProvider.Bench("my_end_checkpoint", epicId, "myAction", "my_description_3", new { MyPayload2 = 2 });

    // Ending and saving a benchmarking epic
    Context.Benchmarker.FlushEpic(epicId);
}

Configuration

We configure the benchmarking aspect by using an instance of Signals.Aspects.Benchmarking.Configurations.IBenchmarkingConfiguration which we pass in the ApplicationBootstrapConfiguration instance (web or background) at startup.

Properties explanation

DatabaseBenchmarkingConfiguration

  • ConnectionString: Database connection string
  • TableName: Benchmark checkpoints table name. Default BenchmarkingEntry
  • IsEnabled: Is the aspect enabled. Default true

Examples

Using Signals.Aspects.Benchmarking.Database

services
    .AddSignals(config =>
    {
        config.BenchmarkingConfiguration = new DatabaseBenchmarkingConfiguration
        {
            ConnectionString = myConnectionString,
            TableName = "BenchmarkingEntry",
            IsEnabled = true
        }
    });

Extending benchmarking

  1. Install package Signals.Aspects.Benchmarking
  2. Create class with implementation of Signals.Aspects.Benchmarking.Configurations.IBenchmarkingConfiguration
/// <summary>
/// Benchmarking configuration contract
/// </summary>
public class MyBenchmarkingConfiguration : IBenchmarkingConfiguration
{
    /// <summary>
    /// Custom property
    /// </summary>
    public string MyProperty { get; set; }
}
  1. Create class with implementation of Signals.Aspects.Benchmarking.IBenchmarker
/// <summary>
/// Storage contract
/// </summary>
public class MyStorageProvider : IStorageProvider
{
    private MyBenchmarkingConfiguration _configuraiton;

    /// <summary>
    /// Hit benchmarking checkpoint
    /// </summary>
    /// <param name="checkpointName"></param>
    /// <param name="epicId"></param>
    /// <param name="processName"></param>
    /// <param name="callerProcessName"></param>
    /// <param name="description"></param>
    /// <param name="payload"></param>
    void Bench(
        string checkpointName,
        Guid epicId,
        string processName,
        string callerProcessName = null,
        string description = null,
        object payload = null);

    /// <summary>
    /// Persist epic data
    /// </summary>
    /// <param name="epicId"></param>
    void FlushEpic(Guid epicId);

    /// <summary>
    /// Get epic report data
    /// </summary>
    /// <param name="epicName"></param>
    /// <param name="afterDate"></param>
    /// <returns></returns>
    EpicsReport GetEpicReport(string epicName, DateTime afterDate);

    /// <summary>
    /// Mark epic as started
    /// </summary>
    /// <param name="epicId"></param>
    /// <param name="epicName"></param>
    void StartEpic(Guid epicId, string epicName);
}
  1. Use our implementation of IBenchmarkingConfiguration when configuring our application
public static IServiceProvider AddSignals(this IServiceCollection services)
{
    services
        .AddSignals(config =>
        {
            config.BenchmarkingConfiguration = new MyBenchmarkingConfiguration
            {
                MyProperty = "my_value"
            };
        });
}
Clone this wiki locally