-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Add support for custom hardware counter names #2953
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
base: master
Are you sure you want to change the base?
Add support for custom hardware counter names #2953
Conversation
Fixes dotnet#1520 This PR adds the ability to specify custom hardware counter names by their ETW profile source names, giving developers flexibility to use CPU-specific counters that aren't covered by the HardwareCounter enum. Changes: - Add CustomCounter class to represent custom PMC counters with configurable profile source name, short display name, interval, and higher-is-better flag - Add CustomCountersAttribute for declarative counter specification - Add IConfig.GetCustomCounters() and ManualConfig.AddCustomCounters() methods - Update ImmutableConfig/ImmutableConfigBuilder to handle custom counters - Update PreciseMachineCounter to support both enum and custom counters - Update PmcStats to track custom counters separately - Update PmcMetricDescriptor to use ShortName for column display - Update EtwProfiler to collect both hardware and custom counters - Update HardwareCounters.Validate() and Sessions to handle custom counters - Fix ManualConfig.Add() to propagate custom counters during config merge Usage example: // Using attribute [CustomCounters("DCMiss", "ICMiss", "BranchMispredictions")] public class MyBenchmark { } // Using ManualConfig var config = ManualConfig.CreateEmpty() .AddCustomCounters( new CustomCounter("DCMiss", shortName: "L1D$Miss"), new CustomCounter("ICMiss", shortName: "L1I$Miss") ); Developers can discover available counters on their system using: TraceEventProfileSources.GetInfo().Keys
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.
Pull request overview
This PR adds support for custom hardware performance counter names, allowing developers to specify CPU-specific counters by their ETW profile source names that aren't covered by the built-in HardwareCounter enum. This addresses a real need for AMD-specific counters and other architecture-specific performance monitoring capabilities.
Key Changes:
- Introduced
CustomCounterclass andCustomCountersAttributefor declarative counter specification - Extended config infrastructure (
IConfig,ManualConfig,ImmutableConfig) to support custom counters alongside hardware counters - Updated ETW profiling infrastructure to collect and validate both built-in and custom performance counters
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/BenchmarkDotNet/Diagnosers/CustomCounter.cs | New class representing custom PMC counters with configurable profile source name, display name, interval, and directionality |
| src/BenchmarkDotNet/Attributes/CustomCountersAttribute.cs | New attribute for declaratively specifying custom counters on benchmark classes or assemblies |
| src/BenchmarkDotNet/Configs/IConfig.cs | Added GetCustomCounters() method to config interface |
| src/BenchmarkDotNet/Configs/ManualConfig.cs | Added customCounters collection and AddCustomCounters() method with config merging support |
| src/BenchmarkDotNet/Configs/ImmutableConfig.cs | Added custom counters storage and retrieval in immutable config |
| src/BenchmarkDotNet/Configs/ImmutableConfigBuilder.cs | Updated to handle custom counters during config building and diagnoser loading |
| src/BenchmarkDotNet/Configs/DefaultConfig.cs | Returns empty collection for custom counters in default config |
| src/BenchmarkDotNet/Configs/DebugConfig.cs | Returns empty collection for custom counters in debug config |
| src/BenchmarkDotNet/Diagnosers/PreciseMachineCounter.cs | Added custom counter support with new constructor and properties for short name and directionality |
| src/BenchmarkDotNet/Diagnosers/PmcStats.cs | Extended to track custom counters separately and merge them with hardware counters by profile source ID |
| src/BenchmarkDotNet/Diagnosers/PmcMetricDescriptor.cs | Updated to use ShortName and HigherIsBetter properties from PreciseMachineCounter |
| src/BenchmarkDotNet.Diagnostics.Windows/EtwProfiler.cs | Updated to collect both hardware and custom counters, building separate lists and concatenating them |
| src/BenchmarkDotNet.Diagnostics.Windows/HardwareCounters.cs | Added custom counter validation and FromCustomCounter factory method with interval handling |
| src/BenchmarkDotNet.Diagnostics.Windows/Sessions.cs | Updated to enable PMCProfile keywords when custom counters are present |
| tests/BenchmarkDotNet.Tests/Configs/CustomCounterTests.cs | Comprehensive test suite covering CustomCounter class, config operations, merging, and integration with hardware counters |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Consolidated null and whitespace validation into single IsNullOrWhiteSpace check as suggested in PR review. This reduces code redundancy while maintaining the same validation behavior.
As suggested in PR review, simplified the logic to always use customCounter.Interval directly. The CustomCounter constructor already sets DefaultInterval as the default value, so the conditional check was redundant and could incorrectly override explicitly-set intervals that happened to match DefaultInterval.
As suggested in PR review, added validation to detect and report collisions between hardware counters and custom counters that share the same ProfileSourceId. Previously, custom counters were silently dropped in case of collision, which could confuse users. Now an InvalidOperationException is thrown with details about the colliding counters.
Updated the comment in ImmutableConfigBuilder to reflect that the code now handles both [HardwareCounters] and [CustomCounters] attributes when dynamically loading the diagnoser.
Improved the error message to only show ellipsis when there are actually more than 20 available counters. Now displays '(and X more)' to indicate exactly how many counters were omitted from the list, providing clearer feedback to users.
Added ArgumentOutOfRangeException validation to reject zero or negative interval values in CustomCounter constructor. Non-positive intervals don't make sense for PMC sampling and could cause runtime errors in the ETW API. Updated tests to verify that zero and negative intervals are properly rejected.
Changed the foreach loop to use explicit .Where() filtering instead of implicit if-based filtering, as suggested in code review. This makes the filtering logic more explicit and aligns with functional programming style.
@dotnet-policy-service agree |
|
Please see prior art in #1438.
|
Fixes #1520
This PR adds the ability to specify custom hardware counter names by their ETW profile source names, giving developers flexibility to use CPU-specific counters that aren't covered by the HardwareCounter enum.
Changes:
Usage example:
// Using attribute
[CustomCounters("DCMiss", "ICMiss", "BranchMispredictions")] public class MyBenchmark { }
// Using ManualConfig
var config = ManualConfig.CreateEmpty()
.AddCustomCounters(
new CustomCounter("DCMiss", shortName: "L1D$Miss"),
new CustomCounter("ICMiss", shortName: "L1I$Miss")
);
Developers can discover available counters on their system using: TraceEventProfileSources.GetInfo().Keys
Note: This is an initial implementation that has not been
thoroughly tested across different CPU architectures or edge cases. Further review
and testing is recommended before merging to confirm correctness of the changes.
If you spot issues or have improvements in mind,
please feel free to push commits directly to this branch or open your own PR with the changes.