Skip to content
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

Add Counter and Histogram Aggregators #178

Merged
merged 34 commits into from
Jul 30, 2020

Conversation

ankit-bhargava
Copy link
Contributor

This PR builds out SDK support for the Counter and Histogram Aggregators which combine updates to metric instruments in meaningful values. Each aggregator stores exportable values in a vector format for ease of use further down the metrics data pipeline. All aggregators are derived from a base Aggregator abstract class which holds functions and data relevant to all aggregators. Additional data structures, such as a vector for histogram boundaries, are added on a case by case basis. Aggregators are dependent on the Metric Instruments API (pending approval in PR # 161) and will not compile without those files.

Also included are tests for each aggregator which validate the correctness of aggregation in both single-threaded and concurrent situations.

Note: We templated aggregators to support a wider array of scalar types. This templating prevents us from using out of line declarations as we normally would. As a result, we left all implementation code in the header file. If there are any suggestions to remedy this we will gladly make the change.

This PR is part of a series of PRs to add a full implementation of metrics API and SDK support.

@ankit-bhargava ankit-bhargava marked this pull request as ready for review July 16, 2020 03:17
@ankit-bhargava ankit-bhargava requested a review from a team July 16, 2020 03:17

#include <variant>
#include <vector>
#include <mutex>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit - is there a reason these are not alphabetically sorted? If not, I would suggest to sort them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the format tools seem to reorder these

Aggregator() = default;

/**
* Recieves a captured value from the instrument and applies it to the current aggregator value.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Recieves a captured value from the instrument and applies it to the current aggregator value.
* Receives a captured value from the instrument and applies it to the current aggregator value.

void update(T val) override
{
this->mu_.lock();
this->values_[0] += val; // atomic operation
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For int and long, is it possible to spin + CAS (compare and swap) to achieve better perf?
Not blocking this PR though.

if (this->kind_ == other.kind_)
{
this->mu_.lock();
this->values_[0] += other.values_[0]; // atomic operation afaik
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

curious, what does // atomic operation afaik mean?

HistogramAggregator(metrics_api::BoundInstrumentKind kind, std::vector<double> boundaries)
{
this->kind_ = kind;
boundaries_ = boundaries;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to validate if the boundaries is monotonic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a check which throws an invalid_argument exception if provided boundaries are not sorted

}
}

// Alternate implementation with binary search
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'll be helpful to put a comment on the design decision - e.g. why would we choose linear search vs. binary search.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Included some background on the topic above the update function -- let me know if this is not enough and I'll gladly add a more thorough explanation.


for (int i = 0; i < bucketCounts_.size(); i++)
{
bucketCounts_[i] += other.bucketCounts_[i];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who should be responsible of making sure the other.bucketCounts won't overflow? Do we in general want to check the buckets are the same before proceeding?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good suggestion. When you say " other.bucketCounts won't overflow," are you referring to a scenario in which adding the values together would exceed the capacity of the data type?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, if other.bucketCounts_.size() <= i.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two separate things:

  1. index overflow while accessing the bucketCounts_.
  2. value overflow while performing +=.

1 is more scary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I preempted the possibility of an index out of bounds issue by ensuring that the boundary vectors of both aggregators are identical.

For the value overflow, I can think of some hacky ways to do it, for example if abs(a)+abs(b) < 0 to indicate a wraparound. I could also subtract from a variable set to int_max. I feel like there has to be a native c++ tool/function which does this but I can't seem to find it...


/**
* Merges the values of two aggregators in a semantically accurate manner.
* A histogram aggregator can only be merged with another histogram aggregatos with the same boudnaries.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Theoretically we could merge a more accurate histogram into a less accurate one (e.g. merge [0, 1, 10, 100, 1000) into [0, 10, 1000). Probably not something we should cover here.

Copy link
Member

@reyang reyang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please find my comments.

@codecov
Copy link

codecov bot commented Jul 24, 2020

Codecov Report

Merging #178 into master will not change coverage.
The diff coverage is n/a.

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #178   +/-   ##
=======================================
  Coverage   93.75%   93.75%           
=======================================
  Files         104      104           
  Lines        3249     3249           
=======================================
  Hits         3046     3046           
  Misses        203      203           

@ankit-bhargava
Copy link
Contributor Author

ankit-bhargava commented Jul 24, 2020

Addressed comments and rebased. This has a dependency on PR #161 and should be ready to go once that PR has been merged.

@ankit-bhargava
Copy link
Contributor Author

Failing Bazel noexcept test although I was under the impression we were allowed to throw exceptions in SDK components? Unsure why the exporter proto CMake test is failing.

Copy link
Member

@reyang reyang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@reyang reyang added the pr:please-merge This PR is ready to be merged by a Maintainer (rebased, CI passed, has enough valid approvals, etc.) label Jul 28, 2020
@reyang
Copy link
Member

reyang commented Jul 29, 2020

@ankit-bhargava would you fix the CI/Format issue?

@ankit-bhargava
Copy link
Contributor Author

ankit-bhargava commented Jul 29, 2020

@reyang
Fixed all the formatting issues and rebased. Seeing two runtime_context files which should not be part of this PR and I'm not sure why they've been added and if they're necessary? Feel free to remove these and merge (or I can delete them).

@reyang reyang merged commit 41af3ac into open-telemetry:master Jul 30, 2020
ziqizh pushed a commit to ziqizh/opentelemetry-cpp that referenced this pull request Jul 31, 2020
ziqizh pushed a commit to ziqizh/opentelemetry-cpp that referenced this pull request Jul 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr:please-merge This PR is ready to be merged by a Maintainer (rebased, CI passed, has enough valid approvals, etc.)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants