Skip to content

chore(perf): improve performance of creating telemetry metrics #12738

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

Merged
merged 52 commits into from
Apr 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
4945fee
chore(perf): improve performance of creating telemetry metrics
brettlangdon Mar 14, 2025
2a3d723
address feedback / linting issues
brettlangdon Mar 14, 2025
9b0eddf
add flushing benchmark scenarios
brettlangdon Mar 14, 2025
61b6018
optimize further
brettlangdon Mar 14, 2025
7cf62c7
update typing
brettlangdon Mar 14, 2025
90d49ba
fix tests
brettlangdon Mar 14, 2025
13718b1
fix appsec tests accessing private attributes
brettlangdon Mar 14, 2025
f721ba9
Merge branch 'main' into brettlangdon/refactor.telemetry_metrics
brettlangdon Mar 14, 2025
84e411a
improve benchmarks
brettlangdon Mar 14, 2025
68f68a8
improve cython code
brettlangdon Mar 14, 2025
88d0f06
fix linting
brettlangdon Mar 14, 2025
0c5d894
cdef v
brettlangdon Mar 14, 2025
18ad628
Merge remote-tracking branch 'origin/main' into brettlangdon/refactor…
brettlangdon Mar 17, 2025
8ca67cd
use flush instead as accessing data directly
brettlangdon Mar 17, 2025
cfb484b
improve performance of flush scenarios
brettlangdon Mar 18, 2025
5ecfca4
Merge remote-tracking branch 'origin/main' into brettlangdon/refactor…
brettlangdon Mar 20, 2025
b0de404
fix when callers use a class E(str, enum.Enum)
brettlangdon Mar 20, 2025
2aa954d
Merge branch 'main' into brettlangdon/refactor.telemetry_metrics
brettlangdon Mar 25, 2025
8db4e4b
fix asm telemetry assertions
brettlangdon Mar 25, 2025
909f509
Update tests/appsec/appsec/test_telemetry.py
brettlangdon Mar 25, 2025
6bdc64a
Update benchmarks/telemetry_add_metric/config.yaml
brettlangdon Mar 25, 2025
1887bee
Merge branch 'main' into brettlangdon/refactor.telemetry_metrics
brettlangdon Mar 26, 2025
bc74223
Merge branch 'main' into brettlangdon/refactor.telemetry_metrics
brettlangdon Mar 26, 2025
183aef3
Revert "Revert "chore(tracing): removes tracer._configure from produc…
mabdinur Mar 26, 2025
1a8cd03
update appsec telemetry metrics mocking
brettlangdon Mar 27, 2025
25365b2
Merge remote-tracking branch 'origin/main' into brettlangdon/refactor…
brettlangdon Mar 27, 2025
23157a2
Merge remote-tracking branch 'origin/main' into brettlangdon/refactor…
brettlangdon Mar 27, 2025
65beaf1
ensure flush interval is a float
brettlangdon Mar 27, 2025
9e853bc
fix assertions
brettlangdon Mar 27, 2025
e3c20b4
Merge remote-tracking branch 'origin/main' into brettlangdon/refactor…
brettlangdon Mar 28, 2025
01d9ce3
fix more asm test failures
brettlangdon Mar 28, 2025
25046c9
Merge branch 'main' into brettlangdon/refactor.telemetry_metrics
brettlangdon Mar 28, 2025
aa0745c
fix more asm assertion errors
brettlangdon Mar 28, 2025
6cddbd1
Merge remote-tracking branch 'origin/main' into brettlangdon/refactor…
brettlangdon Mar 28, 2025
31ca368
fix more iast tests
brettlangdon Mar 28, 2025
96b3c64
fix incorrect syntax
brettlangdon Mar 28, 2025
021f7a8
fix more asm failures
brettlangdon Mar 29, 2025
192b8ff
fix: Update test assertion for generate_metrics tags in telemetry test
brettlangdon Mar 29, 2025
872f511
remove extra gitignore
brettlangdon Mar 29, 2025
d8f58e9
test: Update telemetry test assertions for metric structure and tags
brettlangdon Mar 29, 2025
bfcc6c8
test: fix telemetry metric assertions in iast test suite
brettlangdon Mar 29, 2025
327b527
Merge branch 'main' into brettlangdon/refactor.telemetry_metrics
brettlangdon Mar 29, 2025
f186239
Merge branch 'main' into brettlangdon/refactor.telemetry_metrics
brettlangdon Apr 2, 2025
f41d335
Merge branch 'main' into brettlangdon/refactor.telemetry_metrics
brettlangdon Apr 3, 2025
7a7fc58
Merge branch 'main' into brettlangdon/refactor.telemetry_metrics
brettlangdon Apr 4, 2025
62e2488
Merge remote-tracking branch 'origin/main' into brettlangdon/refactor…
brettlangdon Apr 5, 2025
2f07922
refactor: update test assertions and tag formatting in appsec tests
brettlangdon Apr 5, 2025
de91007
refactor: improve test assertion formatting for readability
brettlangdon Apr 5, 2025
5814a21
test: add metric result flush to telemetry test case
brettlangdon Apr 5, 2025
c818cad
test: update telemetry metric error tag assertions
brettlangdon Apr 5, 2025
177aad6
Update ddtrace/internal/telemetry/metrics_namespaces.pyx
brettlangdon Apr 7, 2025
3f9249a
Merge branch 'main' into brettlangdon/refactor.telemetry_metrics
brettlangdon Apr 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ddtrace/internal/datadog/profiling/crashtracker/crashtracker_exe*
ddtrace/internal/_encoding.c
ddtrace/internal/_rand.c
ddtrace/internal/_tagset.c
ddtrace/internal/telemetry/metrics_namespaces.c
pygoat/*
*.so
*.dylib
Expand Down
86 changes: 60 additions & 26 deletions benchmarks/telemetry_add_metric/config.yaml
Original file line number Diff line number Diff line change
@@ -1,33 +1,67 @@
# The scenario expects specific names:
# - create-1-<type>-metric: {}
# - create-100-<type>-metrics: {}
# - increment-1-<type>-metric-100-times: {}
# - increment-100-<type>-metrics-100-times: {}
#
# The create/increment-<num> is assumed to be a static name, it is not parsed.
# The "100-times" is assumed as a static name, it is not parsed.


# Count metrics
create-1-count-metric: {}
create-100-count-metrics: {}
increment-1-count-metric-100-times: {}
increment-100-count-metrics-100-times: {}
1-count-metric-1-times: &count
metric_type: count
num_metrics: 1
per_metric: 1
1-count-metrics-100-times:
<<: *count
num_metrics: 1
per_metric: 100
100-count-metrics-100-times:
<<: *count
num_metrics: 100
per_metric: 100

# Gauge metrics
create-1-gauge-metric: {}
create-100-gauge-metrics: {}
increment-1-gauge-metric-100-times: {}
increment-100-gauge-metrics-100-times: {}
1-gauge-metric-1-times: &gauge
metric_type: gauge
num_metrics: 1
per_metric: 1
1-gauge-metrics-100-times:
<<: *gauge
num_metrics: 1
per_metric: 100
100-gauge-metrics-100-times:
<<: *gauge
num_metrics: 100
per_metric: 10

# Distribution metrics
create-1-distribution-metric: {}
create-100-distribution-metrics: {}
increment-1-distribution-metric-100-times: {}
increment-100-distribution-metrics-100-times: {}
1-distribution-metric-1-times: &distribution
metric_type: distribution
num_metrics: 1
per_metric: 1
1-distribution-metrics-100-times:
<<: *distribution
num_metrics: 1
per_metric: 100
100-distribution-metrics-100-times:
<<: *distribution
num_metrics: 100
per_metric: 10

# Rate metrics
create-1-rate-metric: {}
create-100-rate-metrics: {}
increment-1-rate-metric-100-times: {}
increment-100-rate-metrics-100-times: {}
1-rate-metric-1-times: &rate
metric_type: rate
num_metrics: 1
per_metric: 1
1-rate-metrics-100-times:
<<: *rate
num_metrics: 1
per_metric: 100
100-rate-metrics-100-times:
<<: *rate
num_metrics: 100
per_metric: 10

# Flush
flush-1-metric: &flush
metric_type: count # unused
per_metric: 1
num_metrics: 1
flush-100-metrics:
<<: *flush
num_metrics: 100
flush-1000-metrics:
<<: *flush
num_metrics: 1000
121 changes: 74 additions & 47 deletions benchmarks/telemetry_add_metric/scenario.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import time

from bm import Scenario

from ddtrace.internal.telemetry.constants import TELEMETRY_NAMESPACE
from ddtrace.internal.telemetry.metrics import CountMetric
from ddtrace.internal.telemetry.metrics import DistributionMetric
from ddtrace.internal.telemetry.metrics import GaugeMetric
from ddtrace.internal.telemetry.metrics import RateMetric
from ddtrace.internal.telemetry.metrics_namespaces import MetricNamespace


try:
from ddtrace.internal.telemetry.metrics_namespaces import MetricType

CountMetric = MetricType.COUNT
DistributionMetric = MetricType.DISTRIBUTION
GaugeMetric = MetricType.GAUGE
RateMetric = MetricType.RATE
except ImportError:
from ddtrace.internal.telemetry.metrics import CountMetric
from ddtrace.internal.telemetry.metrics import DistributionMetric
from ddtrace.internal.telemetry.metrics import GaugeMetric
from ddtrace.internal.telemetry.metrics import RateMetric


def add_count_metric(namespace: MetricNamespace, name: str):
namespace.add_metric(
CountMetric,
Expand Down Expand Up @@ -53,52 +65,67 @@ class TelemetryAddMetric(Scenario):
This scenario checks to see if there's an impact on sending metrics via instrumentation telemetry
"""

def run(self):
metric_type: str
num_metrics: int
per_metric: int

# Override `_pyperf` instead of `run` so we get better control over
# how we run/time the scenario. This way we can ignore the creation time
# of the MetricNamespace or other parts and only time the actual flush or
# metrics adding
def _pyperf(self, loops: int) -> float:
if self.name.startswith("flush-"):
return self.run_flush(loops)
return self.run_add_metric(loops)

def run_add_metric(self, loops: int) -> float:
add_metric = None
if "count-metric" in self.name:
if self.metric_type == "count":
add_metric = add_count_metric
elif "gauge-metric" in self.name:
elif self.metric_type == "gauge":
add_metric = add_gauge_metric
elif "distribution-metric" in self.name:
elif self.metric_type == "distribution":
add_metric = add_distribution_metric
elif "rate-metric" in self.name:
elif self.metric_type == "rate":
add_metric = add_rate_metric
else:
raise ValueError(f"Unknown scenario: {self.name}")

if "create-1-" in self.name:

def _(loops: int):
for _ in range(loops):
metricnamespace = MetricNamespace()
add_metric(metricnamespace, "metric")

elif "create-100-" in self.name:

def _(loops: int):
for _ in range(loops):
metricnamespace = MetricNamespace()
for i in range(100):
add_metric(metricnamespace, str(i))

elif "increment-1-" in self.name:

def _(loops: int):
for _ in range(loops):
metricnamespace = MetricNamespace()
for _ in range(100):
add_metric(metricnamespace, "metric")

elif "increment-100-" in self.name:

def _(loops: int):
for _ in range(loops):
metricnamespace = MetricNamespace()
for i in range(100):
for _ in range(100):
add_metric(metricnamespace, str(i))

else:
raise ValueError(f"Unknown scenario: {self.name}")

yield _
raise ValueError(f"Scenario {self.name} has an unknown metric type: {self.metric_type}")

total = 0
metric_names = [str(i) for i in range(self.num_metrics)]
for _ in range(loops):
metricnamespace = MetricNamespace()
st = time.perf_counter()
for m in metric_names:
for _ in range(self.per_metric):
add_metric(metricnamespace, m)

total += time.perf_counter() - st
return total

def run_flush(self, loops: int) -> float:
# Pool of metrics to use for adding
metrics = (
[(f"count-{i}", add_count_metric) for i in range(250)]
+ [(f"gauge-{i}", add_gauge_metric) for i in range(250)]
+ [(f"distribution-{i}", add_distribution_metric) for i in range(250)]
+ [(f"rate-{i}", add_rate_metric) for i in range(250)]
)
start = 0
end = len(metrics)
step = end // self.num_metrics
total = 0.0

# Pre-fill the dummy namespace with metrics
dummy_namespace = MetricNamespace()
for i in range(start, end, step):
metrics[i][1](dummy_namespace, metrics[i][0])

for _ in range(loops):
metricnamespace = MetricNamespace()
# Copy the dummy metrics to the new namespace, this saves time on adding metrics
metricnamespace._metrics_data = dummy_namespace._metrics_data.copy()
st = time.perf_counter()
metricnamespace.flush()
total += time.perf_counter() - st
return total
144 changes: 0 additions & 144 deletions ddtrace/internal/telemetry/metrics.py

This file was deleted.

Loading
Loading