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

Create a new SupportabilityMetrics class rather than using alpha Metrics #2353

Merged
merged 5 commits into from Feb 24, 2021

Conversation

jkwatson
Copy link
Contributor

No description provided.

private final boolean agentDebugEnabled;
private final Consumer<String> reporter;

private final ConcurrentMap<String, EnumMap<SpanKind, AtomicInteger>> suppressionCounters =
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's use LongAdder instead of atomic integer

return;
}
// note: there's definitely a race here, but since this is just debug information, I think
// we can live with the possibility that we might lose a count or two.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the race because of the usage of enummap? Looks like it's easy enough for us to define a class with a final field per kind to avoid the worry.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, due to the two phase lookup.

Copy link
Contributor

Choose a reason for hiding this comment

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

Since they're both compute if absent, it seems like it would be ok if the second map was also a concurrent map. But we can use a class instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we could also just create a single layer with a String key that concatenates the bits.

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'll play around with a class to hold a longadder for each kind, although that feels a bit wasteful since a given instrumentation almost always only creates a single kind of span.

Copy link
Contributor Author

@jkwatson jkwatson Feb 20, 2021

Choose a reason for hiding this comment

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

By the light of day, after some more thinking, I think you're right. The lack of concurrent safety on the EnumMap makes it worse than a race... the values might not even be visible across threads.

So, some possible solutions are:

  • a compound key class (or string concat) on a single concurrent map
  • a thread-safe class as the value of a single level map
  • 2 levels of concurrent map with LongAdders as the leaf

Since this is only doing anything if you turn on agent debug, it probably doesn't matter all that much which we choose, although it would be great if we could have an efficient solution that could be always on, even in production (maybe it only dumps out the metrics on demand or something, rather than every n seconds).

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've been doing some research, mostly about LongAdder. It looks like all of the heap memory used by a LongAdder is completely lazily initialized. So, having a few extra LongAdders around that are unused is actually very cheap. I'm thinking that choosing the 2nd option is probably the simplest and most efficient, both from a correctness and a memory perspective.

Copy link
Member

Choose a reason for hiding this comment

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

I think you could also use an EnumMap<SpanKind, ConcurrentHashMap<String, LongAdder>> prepopulated with empty maps for all 5 enum values - this way the enum map would effectively be read-only and could be set in the constructor.

But to be honest I prefer your option 2 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done. option 2 has been implemented.


public SupportabilityMetrics start() {
if (agentDebugEnabled) {
Executors.newScheduledThreadPool(1).scheduleAtFixedRate(this::report, 5, 5, TimeUnit.SECONDS);
Copy link
Member

Choose a reason for hiding this comment

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

Shouldn't we use a daemon thread for things like that? There's a DaemonThreadFactory in javaagent-tooling, with some minor changes it could be moved to instrumentation-api and used here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

easy enough to just inline one that sets daemon here. will do.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done

Copy link
Member

Choose a reason for hiding this comment

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

good catch 👍

return;
}
// note: there's definitely a race here, but since this is just debug information, I think
// we can live with the possibility that we might lose a count or two.
Copy link
Member

Choose a reason for hiding this comment

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

I think you could also use an EnumMap<SpanKind, ConcurrentHashMap<String, LongAdder>> prepopulated with empty maps for all 5 enum values - this way the enum map would effectively be read-only and could be set in the constructor.

But to be honest I prefer your option 2 😄

Copy link
Contributor

@anuraaga anuraaga left a comment

Choose a reason for hiding this comment

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

Cool

Copy link
Member

@trask trask left a comment

Choose a reason for hiding this comment

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

👍

@trask trask merged commit 57185f5 into open-telemetry:main Feb 24, 2021
@jkwatson jkwatson deleted the supportability branch February 24, 2021 20:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants