Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1715 #2184

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft

Fix #1715 #2184

wants to merge 3 commits into from

Conversation

YegorStepanov
Copy link
Contributor

fix #1715

@AndreyAkinshin
Copy link
Member

I'm OK with removing quotes, but it's a breaking change that can cause problems for BenchmarkDotNet users who parse the output of Exporters. If we introduce this change, we should provide a way to rollback to the previous behavior.

@YegorStepanov
Copy link
Contributor Author

YegorStepanov commented Nov 1, 2022

Done.

Instead of extending SummaryStyle, I was thinking of adding an assembly attribute:

[assembly: RevertOldBehaviourForBenchmarkName]

The attribute seems more elegant for this.

@YegorStepanov
Copy link
Contributor Author

YegorStepanov commented Nov 1, 2022

[assembly: RevertOldBehaviourForBenchmarkName]

Option 1

it will work like this:

//BenchmarkConverter.cs
//type is benchmark type
BenchmarkRunInfo MethodsToBenchmarksWithFullConfig(Type type, ...)
{
    bool revertOldBehaviour = type.Assembly.GetCustomAttributes().OfType<RevertOldBehaviourForBenchmarkName>();
    var targets = GetTargets(..., revertOldBehaviour);
}
cons:
  • benchmarks can be defined in different assemblies.
  • hard to test it

[Edit]
It looks we can get all assemblies with AppDomain.CurrentDomain.GetAssemblies() and cache the result.
So, the option1 make sense too (to avoid polluting SummaryStyle).

Option 2

Instead, we can make SummaryStyle.OldBehaviorForBenchmarkName internal and only allow it to set via an assembly attribute.

cons
  • hard to test (we can simply remove RevertOldBehaviorTest)

Changelog

Maybe it makes sense to add a "breaking change" paragraph to the changelog?

Users will notice this breaking change when they break their CI or erase benchmark history (because the name is changed).

The BreakingChange.md will also be useful. I can help with it (also for few older version).

[Edit2]
There is BDN.IntegrationTests.ConfigPerAssembly project, so we can test the assembly attribute.

@AndreyAkinshin
Copy link
Member

  1. It would be better to use a more meaningful option name instead of oldBehaviorForBenchmarkName (you never know how many behavior generations we will have in the future). E.g., QuoteBenchmarkNamesWithSpecialChars.
  2. We need a flexible way to control this behavior. The approach with assembly attributes is not flexible enough, it can be inconvenient for some users. Meanwhile, I don't really want to extend the Config API (which is already quite extensive) with additional temporary properties.

I was thinking about an approach inspired by the .NET Runtime knobs. We can introduce string? IConfig.GetKnob(string key) that returns the value of the given knob (additionally, we can introduce extension methods like bool? IConfig.GetKnobBool(string key) which implements the bool parsing logic). The Knob can be specified via ManualConfig (e.g., ManualConfig.WithKnob(string key, string value)), an attribute ([Knob(string key, string value)]), or via environment variables (e.g., BDN_<KnobKey>).

@adamsitnik @YegorStepanov what do you think about such a design?

@YegorStepanov YegorStepanov marked this pull request as draft November 3, 2022 12:09
@YegorStepanov
Copy link
Contributor Author

I like it. Will be done.

Does it make sense to add the Knob class?

public class Knob
{
     public const string QuoteBenchmarkNamesWithSpecialChars = "...";
}

[Knob(Knob.QuoteBenchmarkNamesWithSpecialChars, true)]

@AndreyAkinshin
Copy link
Member

@YegorStepanov, I was thinking about something like this:

public abstract class Knob<T>
{
    public string Key { get; }
    public T DefaultValue { get; }

    protected Knob(string key, T defaultValue)
    {
        Key = key;
        DefaultValue = defaultValue;
    }

    protected abstract T Parse(string value);

    public T GetValue(IConfig config)
    {
        string value = config.GetKnobValue(Key) ?? Environment.GetEnvironmentVariable("BDN_" + Key);
        return Parse(value);
    }
}

public class BoolKnob : Knob<bool>
{
    public BoolKnob(string key, bool defaultValue) : base(key, defaultValue) { }

    protected override bool Parse(string value) =>
        value?.ToLowerInvariant() switch
        {
            "0" or "f" or "false" => false,
            "1" or "t" or "true" => true,
            _ => DefaultValue
        };
}

public class Knobs
{
    public const string QuoteBenchmarkNamesWithSpecialCharsKey = "QuoteBenchmarkNamesWithSpecialChars";

    public BoolKnob QuoteBenchmarkNamesWithSpecialChars = new (QuoteBenchmarkNamesWithSpecialCharsKey, false);
}

P.S. Let's wait for an opinion by @adamsitnik before we start to implement this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Description with spaces and MethodTitle quotes
2 participants