-
-
Notifications
You must be signed in to change notification settings - Fork 978
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
Support a "category" attribute for selecting benchmarks #248
Comments
I like this feature, but I'm not sure how to implement it. I have two questions:
|
I'm fine with BenchmarkCategory. I don't have enough understanding of the details of BenchmarkDotNet to comment, but I know I'd personally be interested in using it for filtering, primarily... but it would be nice to know which category any benchmark is in for filtering post-run as well. ("Show me how all the text handling benchmarks have gone over time.") |
Ok, we could use it in Csv and Json exporters and ignore in the summary. |
+1 for this. One additional idea would be to have the BenchmarkSwitcher support categories as well. Once you start having lots of benchmarks the switcher quickly becomes very hard to work with, the switcher could first present the user with the list of categories, and after category selection, the benchmarks in that category. |
I have a related use case here that could be satisfied by the same feature, I'd like to run all benchmarks in an assembly and see the results in a single output. Concrete case: in Dapper I have a class w/ benchmarks for each ORM, this is because their setup is different and one monolithic class with tons of setup for no good reason is very inefficient, slow, and possibly full of side-effects. A small class is easy to add, maintain, etc. and keeps If we could run all of them (or a Like @roji mentions above, |
Hey @NickCraver. First of all, there is a workaround that you can use right now, here is an example: [DryJob]
public class A
{
[Benchmark]
public void A1() => Thread.Sleep(10);
[Benchmark]
public void A2() => Thread.Sleep(10);
}
[DryJob]
public class B
{
[Benchmark]
public void B1() => Thread.Sleep(10);
[Benchmark]
public void B2() => Thread.Sleep(10);
}
internal class Program
{
public static void Main(string[] args)
{
var benchmarks = new List<Benchmark>();
benchmarks.AddRange(BenchmarkConverter.TypeToBenchmarks(typeof(A)));
benchmarks.AddRange(BenchmarkConverter.TypeToBenchmarks(typeof(B)));
BenchmarkRunner.Run(benchmarks.Where(b => b.Target.Method.Name.Contains("1")).ToArray(), null);
}
} Such approach allows combining specific set of benchmark methods from different types in one summary table. My current suggestions:
IEnumerable<IFilter> GetFilters(); By default, it will return an empty enumerable which will mean that we want to run all the benchmarks. The interface will contain single method: public interface IFilter
{
bool Predicate(Benchmark benchmark);
} And it would be easy to implement public class CategoryFilter: IFilter
{
public CategoryFilter(params string[] categories)
} Since it's a part of
@NickCraver, will this be enough? Do you need any additional features here? @adamsitnik, @mattwarren, @jskeet, what do you think about the suggested API? |
This is based on BenchmarkDotNet (while preserving the legacy format with minor improvements as well - legacy runs much faster). See #666 for details. Not an ominus number at all. Note: this code will get a bit simpler with BenchmarkDotNet categories, see dotnet/BenchmarkDotNet#248 for details.
I had similar issues when I wanted to benchmark Array vs Span vs List. I think that if we add class ArrayBenchmarks
{
[Benchmark(Baseline = true, Category = "Indexers"]
public int IndexerArray() => array[0];
}
class SpanBenchmarks
{
[Benchmark(Category = "Indexers"]
public int IndexerSpan() => span[0];
} And then sample Benchmark Switcher output could be:
Another thing would be new overload But I am not sure how to differentiate whole group of benchmarks (for example CollectionsBenchmark category) vs specialized category (for example "IndexerBenchmarks") |
@adamsitnik, see original request by Jon Skeet:
The |
@AndreyAkinshin First, thanks for the workaround - that unblocked me in Dapper and it's much appreciated! I like the API ideas, I guess the big question is whether a benchmark is in 1 or many categories. I'd certainly say it's the latter, which would affect attribute names...or maybe not. What if it was: [BenchmarkCategory("dynamic","list")] via a params on the attribute? It wouldn't preclude a property on I also have use cases for the union descriptor in Dapper as well (e.g. run all dynamic classes, or list classes, or the combination, etc.) so +1 to that. Related: possibly built-in |
@NickCraver, I implemented all the features (you can try 0.10.6.186 from our nigtly feed FiltersSometimes you don't want to run all of your benchmarks. Predefined filters:
Usage examples: [Config(typeof(Config))]
public class IntroFilters
{
private class Config : ManualConfig
{
// We will benchmark ONLY method with names with names
// (which contains "A" OR "1") AND (have length < 3)
public Config()
{
// benchmark with names which contains "A" OR "1"
Add(new DisjunctionFilter(
new NameFilter(name => name.Contains("A")),
new NameFilter(name => name.Contains("1"))
));
// benchmark with names with length < 3
Add(new NameFilter(name => name.Length < 3));
}
}
[Benchmark] public void A1() => Thread.Sleep(10); // Will be benchmarked
[Benchmark] public void A2() => Thread.Sleep(10); // Will be benchmarked
[Benchmark] public void A3() => Thread.Sleep(10); // Will be benchmarked
[Benchmark] public void B1() => Thread.Sleep(10); // Will be benchmarked
[Benchmark] public void B2() => Thread.Sleep(10);
[Benchmark] public void B3() => Thread.Sleep(10);
[Benchmark] public void C1() => Thread.Sleep(10); // Will be benchmarked
[Benchmark] public void C2() => Thread.Sleep(10);
[Benchmark] public void C3() => Thread.Sleep(10);
[Benchmark] public void Aaa() => Thread.Sleep(10);
} [DryJob]
[CategoriesColumn]
[BenchmarkCategory("Aswesome")]
[AnyCategoriesFilter("A", "1")]
public class IntroCategories
{
[Benchmark]
[BenchmarkCategory("A", "1")]
public void A1() => Thread.Sleep(10); // Will be benchmarked
[Benchmark]
[BenchmarkCategory("A", "2")]
public void A2() => Thread.Sleep(10); // Will be benchmarked
[Benchmark]
[BenchmarkCategory("B", "1")]
public void B1() => Thread.Sleep(10); // Will be benchmarked
[Benchmark]
[BenchmarkCategory("B", "2")]
public void B2() => Thread.Sleep(10);
} Command line examples:
If you are using
|
It was release as part of |
This is based on BenchmarkDotNet (while preserving the legacy format with minor improvements as well - legacy runs much faster). See #666 for details. Not an ominus number at all. Note: this code will get a bit simpler with BenchmarkDotNet categories, see dotnet/BenchmarkDotNet#248 for details.
This is based on BenchmarkDotNet (while preserving the legacy format with minor improvements as well - legacy runs much faster). See #666 for details. Not an ominus number at all. Note: this code will get a bit simpler with BenchmarkDotNet categories, see dotnet/BenchmarkDotNet#248 for details.
In Noda Time, I've found it useful to be able to categorize benchmarks. For example, I have a "BCL" category, and a "Text" category. Categories can be applied to classes or methods. From the command line, you can include or exclude specific categories.
Would love to see this in BenchmarkDotNet.
The text was updated successfully, but these errors were encountered: