-
Notifications
You must be signed in to change notification settings - Fork 870
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
Data classes for exponential histogram prototype (#3550) #3637
Data classes for exponential histogram prototype (#3550) #3637
Conversation
|
...trics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleExponentialHistogramBuckets.java
Outdated
Show resolved
Hide resolved
sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleExponentialHistogramData.java
Outdated
Show resolved
Hide resolved
...ics/src/main/java/io/opentelemetry/sdk/metrics/data/DoubleExponentialHistogramPointData.java
Outdated
Show resolved
Hide resolved
One question I have for @anuraaga and @jkwatson (and @jamesmoessis). Given the cost of exponential histogram generation, would it make more sense for the "data" package to be an interface-only experience and we defer actual storage for an implementation? Specifically, the state of the art seems to be dynamic linked-list or bucket-expansion style classes. I think copying the data out of these representations into the data model may be expensive, looking to see if we can throw ourselves a bone by sticking to interfaces specifically. |
Seems totally reasonable to me. |
Also @jamesmoessis Take a look at metrics-testing, where we have "assertions" that help make it easy to write unit tests. Not required in this PR, but definitely have come in handy. |
Codecov Report
@@ Coverage Diff @@
## main #3637 +/- ##
===========================================
+ Coverage 0 88.66% +88.66%
- Complexity 0 3698 +3698
===========================================
Files 0 446 +446
Lines 0 11641 +11641
Branches 0 1115 +1115
===========================================
+ Hits 0 10322 +10322
- Misses 0 937 +937
- Partials 0 382 +382
Continue to review full report at Codecov.
|
I agree, and it's why I've backed off implementing any real logic in this PR. I could probably move it to a pure interface. Is something like this what you are imagining?
Which implementations are you referring to here? I would love to have a look and see the best ways of implementing. |
Exactly. The requirements I imagine for usefulness are:
Not suggesting anything but (1) for this specific PR.
To a lesser extent, you can look at DDSketch , which may share similarities in storage, but not usage. |
Also @jmacd added more links to prototypes, test code and codegen for constants here: open-telemetry/oteps#179 |
@jsuereth thanks for the explanations. I've changed the abstract classes here to pure interfaces like you suggested. Essentially, a bunch of getters that map directly to the OTLP definitions. I've left bucket mapping/indexing out because I believe these details are slightly more contentious and could be figured out in the implementations.
Are you envisioning the implementations of these interfaces to be a mutable representation, to avoid copying? |
sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/ExponentialHistogramPointData.java
Outdated
Show resolved
Hide resolved
I'd like to leave that possibility open to use, yeah. For initial version feel free to copy-data and just get it working (assuming @jkwatson @anuraaga are on board with that). Using interfaces, hopefully keeps your options open for how to optimise later. |
* | ||
* @return the bucket counts. | ||
*/ | ||
List<Long> getBucketCounts(); |
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 we think we need Long
level numbers for the bucket counts? That's a lot of recordings for a single bucket.
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.
In the NrSketch implementation there is a backing array that uses variable-width counts backing array that uses variable-width counts.
See also OTel-Go: open-telemetry/opentelemetry-go#2261
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.
Looking at the details here, I think exposing List<Long>
may be... overkill for Java. (@anuraaga will prove me wrong with some fun optimisation around List
), but from every example @jmacd lists, I think we want to have the flexibilty to use a primitive array and keep the primitives. That implies exposing a long getBucketCountAt(int idx)
vs. an actual list (which is what the Go SDK + NR impl are doing).
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 would make sense to use something similar to the WindowedCounterArray
backed by the MultiTypeCounterArray
from the NrSketch that @jmacd mentioned.
I can replace List<Long> getBucketCounts()
with long getBucketCountAt(int idx)
. Though, it does raise the question in my mind of how the entire collection of counts would be gathered easily. I can't see that in the Go SDK. Am I incorrectly assuming that it's a necessary method to have for aggregation/exporting?
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.
Ok, I've changed this to long getBucketCountAt(int index)
and updated relevant javadocs.
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.
By the way, I expect marshaling to look like
int size = 0;
for (int i = 0; i < getNumBuckets(); i++) {
size += CodedOutputStream.computeUint32SizeNoTag(getBucketCountAt(i));
}
writeTag(fieldNumber, size)
for (int i = 0; i < getNumBuckets(); i++) {
writeUint32NoTag(getBucketCountAt(i);
}
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.
By the way, just curious if any consideration was given to a sparse array given this comment in the proto
This field is expected to have many buckets,
// especially zeros, so uint64 has been selected to ensure
// varint encoding.
repeated fixed32 bucket_indexes;
repeated fixed64 bucket_counts;
No need to write out zeros
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.
@anuraaga @jsuereth @jkwatson I've made a few changes:
I've removed the List<Long>
and replaced it with these three methods with the aim of being flexible for implementations.
long getBucketCountAt(int index)
int getNumBuckets()
int getStartIndex()
@anuraaga so your for loop would look like
for (int i = getStartIndex(); i < getNumBuckets(); i++) {
size += CodedOutputStream.computeUint32SizeNoTag(getBucketCountAt(i));
}
EDIT: going to move back to List<Long>
as per below conversation.
sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/data/ExponentialHistogramPointData.java
Outdated
Show resolved
Hide resolved
* @param index signed int corresponding to the relevant bucket. | ||
* @return the number of measurements in the bucket. | ||
*/ | ||
long getBucketCountAt(int index); |
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.
Oh - I think we need the number of buckets (the upper limit of index
) to be able to actually iterate 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.
Probably needs to be the upper_limit_index - lower_limit_index
since the index can be negative and doesn't always start from 0. It might be easier to implement or expose an Iterable, I would like to hear your thoughts on that.
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.
As mentioned above, I've added getNumBuckets()
and getStartIndex()
to solve for 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.
Thanks for iterating on this - I'm sorry for the back and forth, but this complexity of the indexes makes me prefer the iterable a lot then. Can we go back to List<Long>
? Sorry about that.
We'll just cast to an internal hypothetical LongList
that stores and allows iterating on long[]
in the exporters so it's still efficient.
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.
LongList
is neat, that sounds good to me. I'll make the changes tomorrow.
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.
Thanks @jamesmoessis - let me go ahead and merge this as if anything comes up we can easily follow up
sdk.metrics.data
.New to OTel contribution so any constructive feedback is welcomed.