-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Support for custom metrics reported in the Benchmarks #735
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
Conversation
…r selected benchmarks, not all
… rely on hardcoded folder hierarchy
…ed in a dedicated process
…ot as decimal separator (and it fails for cultures with ",")
…osoft.ML.Runtime.IHost and BenchmarkDotNet.Engines.IHost..
Thanks @adamsitnik , can you please associate this with the relevant issue? |
public int PriorityInCategory => 1; | ||
public UnitType UnitType => UnitType.Dimensionless; | ||
// enforce Neutral Language as "en-us" because the input data files use dot as decimal separator (and it fails for cultures with ",") | ||
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line of code is a bit surprising in a method that is supposed to return a data path. Maybe it would be better to do this in the Main
method, or a GlobalSetup
method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eerhardt I agree that I am breaking CQRS here. My only excuse is that I have named the method GetInvariantCultureDataPath
so people can expect that.
I was thinking about moving it to a [GlobalSetup]
method but I am afraid that people will don't follow this pattern in new benchmarks. By having it here I guarantee that whoever is going to use files will be using CultureInfo.InvariantCulture
for reading these files.
I also wonder how ML.NET samples deal with the culture info problem. Does anybody know?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[GlobalCleanup] | ||
public void ReportMetrics() | ||
{ | ||
foreach (var metric in GetMetrics()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Would it improve perf to set var metrics = GetMetrics();
right before the foreach loop and then write the condition as var metric in metrics
? Not sure...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@briancylui no, it would not.
Whenever you are not sure about something you can benchmark it with BenchmarkDotNet ;)
var foldeWithAutogeneratedExe = Path.GetDirectoryName(artifactsPaths.ExecutablePath); | ||
var folderWithNativeDependencies = Path.GetDirectoryName(typeof(ProjectGenerator).Assembly.Location); | ||
|
||
foreach(var nativeDependency in Directory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: missing space between foreach
and the succeeding (
for (int bi = 0; bi < batch.Length; bi++) | ||
{ | ||
batch[bi] = _example; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this for loop change elements of _batches[i]
or only elements of the local variable batch
? Not an expert so not sure whether batch
is a ref-type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is done on purpose, it's a Setup method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to merge after responding to PR comments - I don't have write access so can't hit merge unfortunately. Not an expert in Benchmark.NET, but this PR looks good to me! Thanks @adamsitnik
More reviewers are needed for this PR to be merged - my review doesn't count towards mergeability since I don't have write access. |
@briancylui @eerhardt thank you for your reviews! I don't have write access myself, so who could merge it? @shauheen there is no issue, but there was an email thread. Do you want me to create an issue for that? |
test OSX10.13 Debug |
test OSX10.13 Debug please |
# Conflicts: # build/Dependencies.props # test/Microsoft.ML.Benchmarks/KMeansAndLogisticRegressionBench.cs
This PR enables two things:
Why should we run every benchmark in a separate process?
Results when running all the benchmarks in the same process:
When running every benchmark in a dedicated process:
To run every benchmark in a standalone, dedicated process BenchmarkDotNet needs to be able to create, build and run new executable.
So far it was not possible out of the box due to MSBuild limitation. When
Microsoft.ML.Benchmarks
references native assembly and the auto-generated BenchmarkDotNet project referencesMicrosoft.ML.Benchmarks
the native dependencies are not copied to the output folder of the auto-generated project with benchmarks. This is why I had to implementProjectGenerator
which does that for us.@eerhardt we had a conversation about making it possible for BenchmarkDotNet to compile ML.NET stuff a long time ago and the blocker was the native dependency.
The other thing are custom metrics. BenchmarkDotNet does not support it out of the box, I had to implement it. How it works:
WithExtraMetrics
and implementIEnumerable<Metric> GetMetrics()
methodWithExtraMetrics
after running the benchmarks prints the custom metrics to console in child processExtraMetricColumn
parses the output in parent process.Sample results:
Other changes: so far the benchmarks were using
currentAssemblyLocation.Directory.Parent.Parent.Parent.Parent.FullName
to get the path to folder with input files. I believe it's better to reference them as links incsproj
and "copy to output directory if newer". This solution is cleaner and more futureproof./cc @eerhardt @danmosemsft @briancylui @KrzysztofCwalina