Skip to content

Commit

Permalink
Overhead improvement to agent feedback based sampling (#8265)
Browse files Browse the repository at this point in the history
* Small improvement to agent feedback sampling

Previously, I updated this code to be case-insensitive.

In doing so, I introduced a call to String.toLowerCase which had a negative impact on response time and allocation.

By switching to TreeMap, I can use String::compareToIgnoreCase which avoids the allocation and has a better average complexity than toLowerCase.

This change provides a 1-1.5% improvement in a span creation throughput stress tests.
  • Loading branch information
dougqh authored Jan 27, 2025
1 parent af5f441 commit 8c6ec67
Showing 1 changed file with 12 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import datadog.trace.api.sampling.SamplingMechanism;
import datadog.trace.common.writer.RemoteResponseListener;
import datadog.trace.core.CoreSpan;
import java.util.HashMap;
import java.util.Collections;
import java.util.Map;
import java.util.TreeMap;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -71,8 +72,8 @@ public void onResponse(
}

log.debug("Update service sampler rates: {} -> {}", endpoint, responseJson);
final Map<String, Map<String, RateSampler>> updatedEnvServiceRates =
new HashMap<>(newServiceRates.size() * 2);
final TreeMap<String, TreeMap<String, RateSampler>> updatedEnvServiceRates =
new TreeMap<>(String::compareToIgnoreCase);

RateSampler fallbackSampler = RateSamplersByEnvAndService.DEFAULT_SAMPLER;
for (final Map.Entry<String, Number> entry : newServiceRates.entrySet()) {
Expand All @@ -87,7 +88,7 @@ public void onResponse(
} else {
Map<String, RateSampler> serviceRates =
updatedEnvServiceRates.computeIfAbsent(
envAndService.lowerEnv, env -> new HashMap<>(newServiceRates.size() * 2));
envAndService.lowerEnv, env -> new TreeMap<>(String::compareToIgnoreCase));

serviceRates.computeIfAbsent(
envAndService.lowerService,
Expand All @@ -114,38 +115,34 @@ private static RateSampler createRateSampler(final double sampleRate) {
private static final class RateSamplersByEnvAndService {
private static final RateSampler DEFAULT_SAMPLER = createRateSampler(DEFAULT_RATE);

private final Map<String, Map<String, RateSampler>> envServiceRates;
private final Map<String, TreeMap<String, RateSampler>> envServiceRates;
private final RateSampler fallbackSampler;

RateSamplersByEnvAndService() {
this(new HashMap<>(0), DEFAULT_SAMPLER);
this(Collections.emptyMap(), DEFAULT_SAMPLER);
}

RateSamplersByEnvAndService(
Map<String, Map<String, RateSampler>> envServiceRates, RateSampler fallbackSampler) {
Map<String, TreeMap<String, RateSampler>> envServiceRates, RateSampler fallbackSampler) {
this.envServiceRates = envServiceRates;
this.fallbackSampler = fallbackSampler;
}

// used in tests only
RateSampler getSampler(EnvAndService envAndService) {
return getSamplerImpl(envAndService.lowerEnv, envAndService.lowerService);
return getSampler(envAndService.lowerEnv, envAndService.lowerService);
}

public RateSampler getSampler(String env, String service) {
return getSamplerImpl(env.toLowerCase(), service.toLowerCase());
}

private RateSampler getSamplerImpl(String lowerEnv, String lowerService) {
if (EnvAndService.isFallback(lowerEnv, lowerService)) {
if (EnvAndService.isFallback(env, service)) {
return fallbackSampler;
}

Map<String, RateSampler> serviceRates = envServiceRates.get(lowerEnv);
Map<String, RateSampler> serviceRates = envServiceRates.get(env);
if (serviceRates == null) {
return fallbackSampler;
}
RateSampler sampler = serviceRates.get(lowerService);
RateSampler sampler = serviceRates.get(service);
return null == sampler ? fallbackSampler : sampler;
}
}
Expand Down

0 comments on commit 8c6ec67

Please sign in to comment.