Skip to content

Commit f52002d

Browse files
perf: add threading benchmark scenario (#2789)
* perf: add threading benchmark scenario * fix unused variable * use NoopWriter and simulate some work in the child spans * fix type hinting * fix missing type import * add to main docs * Add workflow to spelling list * Update benchmarks/threading/README.rst Co-authored-by: Gabriele N. Tornetta <[email protected]> Co-authored-by: Gabriele N. Tornetta <[email protected]>
1 parent 8f6388d commit f52002d

File tree

6 files changed

+89
-1
lines changed

6 files changed

+89
-1
lines changed

benchmarks/README.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,9 @@ Example::
6969

7070
scripts/perf-run-scenario span ddtrace==0.50.0 ddtrace==0.51.0 ./artifacts/
7171
scripts/perf-run-scenario span Datadog/dd-trace-py@master Datadog/dd-trace-py@my-feature ./artifacts/
72+
73+
74+
Scenarios
75+
^^^^^^^^^
76+
77+
.. include:: ../benchmarks/threading/README.rst

benchmarks/threading/README.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
threading
2+
~~~~~~~~~
3+
4+
This benchmark test is used to simulate the creation, encoding, and flushing of traces in threaded environments.
5+
6+
It uses a ``concurrent.futures.ThreadPool`` to manage the total number of workers.
7+
8+
The only modification to the tracing workflow that has been made is using a ``NoopWriter`` which does not start a
9+
background thread and drops traces on ``writer.write``. This means we skip encoding, queuing, and flushing payloads
10+
to the agent, but we will still use the span processors.

benchmarks/threading/config.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
1-thread: &baseline
2+
nthreads: 1
3+
ntraces: 1000
4+
nspans: 10
5+
10-threads:
6+
<<: *baseline
7+
nthreads: 10
8+
50-threads:
9+
<<: *baseline
10+
nthreads: 50
11+
100-threads:
12+
<<: *baseline
13+
nthreads: 100

benchmarks/threading/scenario.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import concurrent.futures
2+
import random
3+
from typing import Callable
4+
from typing import Generator
5+
from typing import List
6+
from typing import Optional
7+
8+
import bm
9+
10+
from ddtrace.internal.writer import TraceWriter
11+
from ddtrace.span import Span
12+
from ddtrace.tracer import Tracer
13+
14+
15+
class NoopWriter(TraceWriter):
16+
def recreate(self):
17+
# type: () -> TraceWriter
18+
return NoopWriter()
19+
20+
def stop(self, timeout=None):
21+
# type: (Optional[float]) -> None
22+
pass
23+
24+
def write(self, spans=None):
25+
# type: (Optional[List[Span]]) -> None
26+
pass
27+
28+
29+
@bm.register
30+
class Threading(bm.Scenario):
31+
nthreads = bm.var(type=int)
32+
ntraces = bm.var(type=int)
33+
nspans = bm.var(type=int)
34+
35+
def create_trace(self, tracer):
36+
# type: (Tracer) -> None
37+
with tracer.trace("root"):
38+
for _ in range(self.nspans - 1):
39+
with tracer.trace("child"):
40+
# Simulate work in each child
41+
random.random()
42+
43+
def run(self):
44+
# type: () -> Generator[Callable[[int], None], None, None]
45+
from ddtrace import tracer
46+
47+
# configure global tracer to drop traces rather
48+
tracer.configure(writer=NoopWriter())
49+
50+
def _(loops):
51+
# type: (int) -> None
52+
for _ in range(loops):
53+
with concurrent.futures.ThreadPoolExecutor(max_workers=self.nthreads) as executor:
54+
tasks = {executor.submit(self.create_trace, tracer) for i in range(self.ntraces)}
55+
for task in concurrent.futures.as_completed(tasks):
56+
task.result()
57+
58+
yield _

docs/spelling_wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,5 +145,6 @@ uvicorn
145145
versioned
146146
vertica
147147
whitelist
148+
workflow
148149
wsgi
149150
xfail

scripts/perf-build-push

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ shift
1111

1212
IMAGES=()
1313

14-
for SCENARIO in "encoder" "span" "tracer" "django_simple" "flask_simple"; do
14+
for SCENARIO in "encoder" "span" "tracer" "django_simple" "flask_simple" "threading"; do
1515
TAG="${REPOSITORY}/perf-${SCENARIO}"
1616
scripts/perf-build-scenario "${SCENARIO}" "${TAG}"
1717
IMAGE="${TAG}:latest"

0 commit comments

Comments
 (0)