Skip to content

Commit 41b6359

Browse files
test: use correct file name sorting
1 parent 2147072 commit 41b6359

8 files changed

Lines changed: 33 additions & 30 deletions

tests/profiling/collector/pprof_utils.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,17 @@ def parse_newest_profile(
285285
return profile
286286

287287

288+
def get_internal_metadata_files(filename_prefix: str) -> list[str]:
289+
"""Internal metadata files with the given prefix (which includes the pid), oldest upload first.
290+
291+
Files are named <filename_prefix>.<counter>.internal_metadata.json without
292+
padding, so a lexicographic sort would place upload 10 before upload 2.
293+
"""
294+
files = glob.glob(filename_prefix + ".*.internal_metadata.json")
295+
files.sort(key=lambda f: int(f.rsplit(".", 3)[-3]))
296+
return files
297+
298+
288299
def get_sample_type_index(profile: pprof_pb2.Profile, value_type: str) -> int:
289300
return next(
290301
i for i, sample_type in enumerate(profile.sample_type) if profile.string_table[sample_type.type] == value_type

tests/profiling/collector/test_asyncio_task_count.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
def test_asyncio_task_count_present():
1212
"""asyncio_task_count is present and positive when asyncio tasks are active."""
1313
import asyncio
14-
import glob
1514
import json
1615
import os
1716
import time
1817

1918
from ddtrace.profiling import profiler
2019
from ddtrace.trace import tracer
20+
from tests.profiling.collector import pprof_utils
2121

2222
async def worker():
2323
await asyncio.sleep(0.5)
@@ -38,7 +38,7 @@ async def main():
3838
p.stop()
3939

4040
output_filename = os.environ["DD_PROFILING_OUTPUT_PPROF"] + "." + str(os.getpid())
41-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"))
41+
files = pprof_utils.get_internal_metadata_files(output_filename)
4242
assert files, "Expected at least one internal_metadata.json file"
4343

4444
found_positive = False
@@ -68,13 +68,13 @@ def test_asyncio_task_count_survives_run_teardown():
6868
loop was live, so the uploaded profile reported asyncio_task_count: 0 when it should have been the peak.
6969
"""
7070
import asyncio
71-
import glob
7271
import json
7372
import os
7473
import time
7574

7675
from ddtrace.profiling import profiler
7776
from ddtrace.trace import tracer
77+
from tests.profiling.collector import pprof_utils
7878

7979
NUM_WORKERS = 10
8080
EXPECTED_PEAK = NUM_WORKERS + 1
@@ -98,7 +98,7 @@ async def main():
9898
p.stop()
9999

100100
output_filename = os.environ["DD_PROFILING_OUTPUT_PPROF"] + "." + str(os.getpid())
101-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"))
101+
files = pprof_utils.get_internal_metadata_files(output_filename)
102102
assert files, "Expected internal_metadata.json file"
103103

104104
peak = 0

tests/profiling/collector/test_copy_memory_stats.py

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,21 @@
1010
)
1111
def test_copy_memory_error_count_present():
1212
"""copy_memory_error_count is always emitted (even when 0) and is non-negative."""
13-
import glob
1413
import json
1514
import os
1615
import time
1716

1817
from ddtrace.profiling import profiler
1918
from ddtrace.trace import tracer
19+
from tests.profiling.collector import pprof_utils
2020

2121
p = profiler.Profiler(tracer=tracer)
2222
p.start()
2323
time.sleep(3)
2424
p.stop()
2525

2626
output_filename = os.environ["DD_PROFILING_OUTPUT_PPROF"] + "." + str(os.getpid())
27-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"))
27+
files = pprof_utils.get_internal_metadata_files(output_filename)
2828
assert files, "Expected at least one internal_metadata.json file"
2929

3030
for f in files:
@@ -51,25 +51,21 @@ def test_copy_memory_error_count_present():
5151
)
5252
def test_fast_copy_memory_disabled():
5353
"""fast_copy_memory_enabled is False when _DD_PROFILING_STACK_FAST_COPY=false."""
54-
import glob
5554
import json
5655
import os
5756
import time
5857

5958
from ddtrace.profiling import profiler
6059
from ddtrace.trace import tracer
60+
from tests.profiling.collector import pprof_utils
6161

6262
p = profiler.Profiler(tracer=tracer)
6363
p.start()
6464
time.sleep(3)
6565
p.stop()
6666

67-
def upload_seq(path: str) -> int:
68-
# Uploads are numbered without padding, so sort numerically rather than lexicographically.
69-
return int(path[: -len(".internal_metadata.json")].rsplit(".", 1)[1])
70-
7167
output_filename = os.environ["DD_PROFILING_OUTPUT_PPROF"] + "." + str(os.getpid())
72-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"), key=upload_seq)
68+
files = pprof_utils.get_internal_metadata_files(output_filename)
7369
assert files, "Expected at least one internal_metadata.json file"
7470

7571
for i, f in enumerate(files):
@@ -95,7 +91,6 @@ def upload_seq(path: str) -> int:
9591
)
9692
def test_fast_copy_memory_enabled() -> None:
9793
"""Sampler runs on the syscall copy during warmup, then upgrades to safe_memcpy (PROF-14568)."""
98-
import glob
9994
import json
10095
import os
10196
import time
@@ -104,6 +99,7 @@ def test_fast_copy_memory_enabled() -> None:
10499
from ddtrace.internal.datadog.profiling.stack import _stack
105100
from ddtrace.profiling import profiler
106101
from ddtrace.trace import tracer
102+
from tests.profiling.collector import pprof_utils
107103

108104
_stack._set_fast_copy_warmup_seconds(1.0)
109105

@@ -134,12 +130,8 @@ def test_fast_copy_memory_enabled() -> None:
134130
time.sleep(2)
135131
p.stop()
136132

137-
def upload_seq(path: str) -> int:
138-
# Uploads are numbered without padding, so sort numerically rather than lexicographically.
139-
return int(path[: -len(".internal_metadata.json")].rsplit(".", 1)[1])
140-
141133
output_filename = os.environ["DD_PROFILING_OUTPUT_PPROF"] + "." + str(os.getpid())
142-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"), key=upload_seq)
134+
files = pprof_utils.get_internal_metadata_files(output_filename)
143135
assert files, "Expected at least one internal_metadata.json file"
144136

145137
# A window with no completed sampling cycle inherits the previous window's fast-copy

tests/profiling/collector/test_greenlet_count.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ def test_greenlet_count_present():
2626

2727
monkey.patch_all()
2828

29-
import glob
3029
import json
3130
import os
3231
import time
@@ -35,6 +34,7 @@ def test_greenlet_count_present():
3534

3635
from ddtrace.profiling import profiler
3736
from ddtrace.trace import tracer
37+
from tests.profiling.collector import pprof_utils
3838

3939
stop = False
4040

@@ -53,7 +53,7 @@ def worker():
5353
p.stop()
5454

5555
output_filename = os.environ["DD_PROFILING_OUTPUT_PPROF"] + "." + str(os.getpid())
56-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"))
56+
files = pprof_utils.get_internal_metadata_files(output_filename)
5757
assert files, "Expected at least one internal_metadata.json file"
5858

5959
found_positive = False

tests/profiling/collector/test_heap_tracker_count.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@
1111
)
1212
def test_heap_tracker_count_present():
1313
"""heap_tracker_count is present and non-zero when memory profiling is enabled."""
14-
import glob
1514
import json
1615
import os
1716
import time
1817

1918
from ddtrace.profiling import profiler
2019
from ddtrace.trace import tracer
20+
from tests.profiling.collector import pprof_utils
2121

2222
p = profiler.Profiler(tracer=tracer)
2323
p.start()
@@ -33,7 +33,7 @@ def test_heap_tracker_count_present():
3333
p.stop()
3434

3535
output_filename = os.environ["DD_PROFILING_OUTPUT_PPROF"] + "." + str(os.getpid())
36-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"))
36+
files = pprof_utils.get_internal_metadata_files(output_filename)
3737
assert files, "Expected at least one internal_metadata.json file"
3838

3939
for f in files:

tests/profiling/collector/test_internal_adaptive_sampling.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
)
1414
def test_internal_adaptive_sampling():
1515
import asyncio
16-
import glob
1716
import json
1817
import os
1918
import time
@@ -22,6 +21,7 @@ def test_internal_adaptive_sampling():
2221
from ddtrace import ext
2322
from ddtrace.profiling import profiler
2423
from ddtrace.trace import tracer
24+
from tests.profiling.collector import pprof_utils
2525

2626
sleep_time = 0.2
2727
loop_run_time = 4
@@ -52,7 +52,7 @@ async def hello():
5252
p.stop()
5353

5454
output_filename = os.environ["DD_PROFILING_OUTPUT_PPROF"] + "." + str(os.getpid())
55-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"))
55+
files = pprof_utils.get_internal_metadata_files(output_filename)
5656

5757
# With adaptive sampling enabled, the sampling interval can grow up to 1 second
5858
# (g_max_sampling_period_us). Since the upload interval is also 1 second, the

tests/profiling/collector/test_sample_count.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
)
1111
def test_sample_count():
1212
import asyncio
13-
import glob
1413
import json
1514
import os
1615
import time
@@ -19,6 +18,7 @@ def test_sample_count():
1918
from ddtrace import ext
2019
from ddtrace.profiling import profiler
2120
from ddtrace.trace import tracer
21+
from tests.profiling.collector import pprof_utils
2222

2323
sleep_time = 0.2
2424
loop_run_time = 2
@@ -49,7 +49,7 @@ async def hello():
4949
p.stop()
5050

5151
output_filename = os.environ["DD_PROFILING_OUTPUT_PPROF"] + "." + str(os.getpid())
52-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"))
52+
files = pprof_utils.get_internal_metadata_files(output_filename)
5353

5454
found_at_least_one_with_more_samples_than_sampling_events = False
5555
for i, f in enumerate(files):

tests/profiling/collector/test_thread_subsampling.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
)
2020
def test_thread_subsampling_cap_respected() -> None:
2121
"""With max_threads=1, at most 1 thread is sampled per cycle, even with many threads alive."""
22-
import glob
2322
import json
2423
import os
2524
import threading
2625
import time
2726

2827
from ddtrace.internal.datadog.profiling import ddup
2928
from ddtrace.profiling.collector import stack
29+
from tests.profiling.collector import pprof_utils
3030

3131
N_THREADS = 10
3232
max_threads = 1
@@ -59,7 +59,7 @@ def worker() -> None:
5959
ddup.upload()
6060

6161
output_filename = pprof_prefix + "." + str(os.getpid())
62-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"))
62+
files = pprof_utils.get_internal_metadata_files(output_filename)
6363
assert files, f"No internal metadata files found at {output_filename}.*"
6464

6565
for f in files:
@@ -93,14 +93,14 @@ def test_thread_subsampling_all_threads_sampled_without_cap() -> None:
9393
With N_THREADS additional threads running, sample_count should be
9494
significantly greater than sampling_event_count.
9595
"""
96-
import glob
9796
import json
9897
import os
9998
import threading
10099
import time
101100

102101
from ddtrace.internal.datadog.profiling import ddup
103102
from ddtrace.profiling.collector import stack
103+
from tests.profiling.collector import pprof_utils
104104

105105
N_THREADS = 10
106106

@@ -132,7 +132,7 @@ def worker() -> None:
132132
ddup.upload()
133133

134134
output_filename = pprof_prefix + "." + str(os.getpid())
135-
files = sorted(glob.glob(output_filename + ".*.internal_metadata.json"))
135+
files = pprof_utils.get_internal_metadata_files(output_filename)
136136
assert files, f"No internal metadata files found at {output_filename}.*"
137137

138138
total_events: int = 0

0 commit comments

Comments
 (0)