diff --git a/scenarios/python_cpu_sleep_asyncio_3.12/Dockerfile b/scenarios/python_cpu_sleep_asyncio_3.12/Dockerfile new file mode 100644 index 0000000..0d1cfcb --- /dev/null +++ b/scenarios/python_cpu_sleep_asyncio_3.12/Dockerfile @@ -0,0 +1,15 @@ +ARG BASE_IMAGE="prof-python-3.12" +FROM $BASE_IMAGE + +WORKDIR /usr/src/app + +COPY ./scenarios/python_cpu_sleep_asyncio_3.12/ /usr/src/app + +RUN chmod 644 /usr/src/app/main.py +RUN pip install --no-cache-dir -r requirements.txt + +ENV EXECUTION_TIME_SEC=30 +ENV DD_PROFILING_MEMORY_ENABLED=false +ENV _DD_PROFILING_STACK_ADAPTIVE_SAMPLING_ENABLED=0 + +CMD ddtrace-run python main.py diff --git a/scenarios/python_cpu_sleep_asyncio_3.12/expected_profile.json b/scenarios/python_cpu_sleep_asyncio_3.12/expected_profile.json new file mode 100644 index 0000000..d07cccd --- /dev/null +++ b/scenarios/python_cpu_sleep_asyncio_3.12/expected_profile.json @@ -0,0 +1,97 @@ +{ + "test_name": "python_cpu_sleep_asyncio_3.12", + "scale_by_duration": true, + "stacks": [ + { + "profile-type": "cpu-time", + "stack-content": [ + { + "regular_expression": ".*", + "value": 667000000, + "error_margin": 25 + }, + { + "regular_expression": ".*cpu_burst.*", + "percent": 80, + "error_margin": 10 + }, + { + "regular_expression": ".*", + "percent": 25, + "error_margin": 15, + "labels": [ + { + "key": "thread name", + "values": [ + "MainThread" + ] + }, + { + "key": "task name", + "values": [ + "Task-2" + ] + } + ] + }, + { + "regular_expression": ".*", + "percent": 25, + "error_margin": 15, + "labels": [ + { + "key": "thread name", + "values": [ + "MainThread" + ] + }, + { + "key": "task name", + "values": [ + "Task-3" + ] + } + ] + }, + { + "regular_expression": ".*", + "percent": 25, + "error_margin": 15, + "labels": [ + { + "key": "thread name", + "values": [ + "MainThread" + ] + }, + { + "key": "task name", + "values": [ + "Task-4" + ] + } + ] + }, + { + "regular_expression": ".*", + "percent": 25, + "error_margin": 15, + "labels": [ + { + "key": "thread name", + "values": [ + "MainThread" + ] + }, + { + "key": "task name", + "values": [ + "Task-5" + ] + } + ] + } + ] + } + ] +} diff --git a/scenarios/python_cpu_sleep_asyncio_3.12/main.py b/scenarios/python_cpu_sleep_asyncio_3.12/main.py new file mode 100644 index 0000000..78363f2 --- /dev/null +++ b/scenarios/python_cpu_sleep_asyncio_3.12/main.py @@ -0,0 +1,37 @@ +import asyncio +import os +import time + + +def cpu_burst(target_seconds: float) -> int: + deadline = time.monotonic() + target_seconds + x = 0x1234 + while time.monotonic() < deadline: + x = (x * 48271) % 2147483647 + return x + + +async def slot(cpu_seconds: float, off_cpu: float, deadline: float) -> None: + while time.monotonic() < deadline: + await asyncio.sleep(off_cpu) + cpu_burst(cpu_seconds) + + +async def main() -> None: + execution_time_sec = float(os.environ.get("EXECUTION_TIME_SEC", "30")) + cpu_seconds = 0.01 + off_cpu = 0.05 + concurrency = 4 + stagger = 0.01 + + deadline = time.monotonic() + execution_time_sec + tasks: list[asyncio.Task[None]] = [] + for i in range(concurrency): + if i > 0: + await asyncio.sleep(stagger) + tasks.append(asyncio.create_task(slot(cpu_seconds, off_cpu, deadline))) + await asyncio.gather(*tasks) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/scenarios/python_cpu_sleep_asyncio_3.12/requirements.txt b/scenarios/python_cpu_sleep_asyncio_3.12/requirements.txt new file mode 100644 index 0000000..749bf29 --- /dev/null +++ b/scenarios/python_cpu_sleep_asyncio_3.12/requirements.txt @@ -0,0 +1 @@ +ddtrace