-
Notifications
You must be signed in to change notification settings - Fork 483
[METRICS SDK] Fix hash collision in MetricAttributes #3322
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
[METRICS SDK] Fix hash collision in MetricAttributes #3322
Conversation
✅ Deploy Preview for opentelemetry-cpp-api-docs canceled.
|
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3322 +/- ##
==========================================
+ Coverage 89.52% 89.55% +0.03%
==========================================
Files 210 210
Lines 6526 6502 -24
==========================================
- Hits 5842 5822 -20
+ Misses 684 680 -4
🚀 New features to boost your workflow:
|
@@ -74,27 +74,6 @@ inline size_t GetHashForAttributeMap(const OrderedAttributeMap &attribute_map) | |||
return seed; | |||
} | |||
|
|||
// Calculate hash of keys and values of KeyValueIterable, filtered using callback. | |||
inline size_t GetHashForAttributeMap( |
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.
It is not expected to calculate hash on KeyValueIterable
by traversing it, because the order of the elements should not affect the hashing. MetricAttributes
need to be constructed from it before hash. So remove this function.
@ThomsonTan - Could you also include the benchmark results from before and after in the comments. A slight regression is acceptable, as it's a tradeoff for fixing collision. |
Here are the before/after benchmark result. It looks like that the wall time doubled while the CPU time reduced slightly.
./measurements_benchmark
2025-03-26T00:43:08+00:00
Running measurements_benchmark
Run on (16 X 2445.43 MHz CPU s)
CPU Caches:
L1 Data 32 KiB (x8)
L1 Instruction 32 KiB (x8)
L2 Unified 512 KiB (x8)
L3 Unified 32768 KiB (x1)
Load Average: 1.85, 3.23, 1.73
--------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------
BM_MeasurementsTest 2044809 ns 148990 ns 3856
measurements_benchmark
2025-03-26T00:44:26+00:00
Running measurements_benchmark
Run on (16 X 2445.43 MHz CPU s)
CPU Caches:
L1 Data 32 KiB (x8)
L1 Instruction 32 KiB (x8)
L2 Unified 512 KiB (x8)
L3 Unified 32768 KiB (x1)
Load Average: 1.02, 2.64, 1.65
--------------------------------------------------------------
Benchmark Time CPU Iterations
--------------------------------------------------------------
BM_MeasurementsTest 4287068 ns 95297 ns 1000 |
@lalitb it seems the major perf gap is from the below original code. It doesn't sort the incoming Aggregation *GetOrSetDefault(const opentelemetry::common::KeyValueIterable &attributes,
const AttributesProcessor *attributes_processor,
std::function<std::unique_ptr<Aggregation>()> aggregation_callback,
size_t hash)
{
auto it = hash_map_.find(hash);
if (it != hash_map_.end())
{
return it->second.second.get();
} |
private: | ||
std::unordered_map<size_t, std::pair<MetricAttributes, std::unique_ptr<Aggregation>>> hash_map_; | ||
std::unordered_map<MetricAttributes, std::unique_ptr<Aggregation>, CustomHash> hash_map_; |
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.
can we store MetricAttributes as a pointer? it's going to be a lot copying on rehashing...
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.
Do you mean make the key as std::shared_ptr<MetricAttributes>
, it may work with a more complicated custom hash. But I think MetricsAttributes
should be created and moved into the std::unordered_map
, so copying and rehashing should be in rare.
I remember the the exporting process does make a copy of MetricsAttributes
, but there is an optimization for the common scenario. @lalitb any thoughts on this?
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.
I believe we are already avoiding deep copy with std::move while inserting the MetricsAttributes, also during rehashing, the hashmp will move(not copy) the MetricAttributes objects to their new locations. In general, I do see options for optimization at other places, but we can visit it separate to the PR.
sdk/include/opentelemetry/sdk/metrics/state/filtered_ordered_attribute_map.h
Outdated
Show resolved
Hide resolved
Found no issues on this patch (LGTM), but I don't know the metric aggregation code well enough to approve. |
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.
LGTM. Thanks @ThomsonTan
sdk/include/opentelemetry/sdk/metrics/state/attributes_hashmap.h
Outdated
Show resolved
Hide resolved
@lalitb @ThomsonTan Assuming CI is clean, ok to merge ? |
Yes, it is Ok to merge it if CI is clean again. |
Fixes #3060
Changes
attributes_hashmap_benchmark shows flat result before and after this change.
For significant contributions please make sure you have completed the following items:
CHANGELOG.md
updated for non-trivial changes