vedro-profiling 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vedro_profiling-0.0.1/PKG-INFO +33 -0
- vedro_profiling-0.0.1/README.md +3 -0
- vedro_profiling-0.0.1/setup.cfg +18 -0
- vedro_profiling-0.0.1/setup.py +39 -0
- vedro_profiling-0.0.1/vedro_profiling/__init__.py +5 -0
- vedro_profiling-0.0.1/vedro_profiling/_vedro_profiling.py +136 -0
- vedro_profiling-0.0.1/vedro_profiling/py.typed +0 -0
- vedro_profiling-0.0.1/vedro_profiling.egg-info/PKG-INFO +33 -0
- vedro_profiling-0.0.1/vedro_profiling.egg-info/SOURCES.txt +11 -0
- vedro_profiling-0.0.1/vedro_profiling.egg-info/dependency_links.txt +1 -0
- vedro_profiling-0.0.1/vedro_profiling.egg-info/requires.txt +3 -0
- vedro_profiling-0.0.1/vedro_profiling.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vedro-profiling
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Vedro plugin for measuring docker resource usage.
|
|
5
|
+
Home-page: https://github.com/lolimpo/vedro-profiling
|
|
6
|
+
Author: Nikita Mikheev
|
|
7
|
+
Author-email: thelol1mpo@gmail.com
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: vedro<2.0.0,>=1.13.0
|
|
18
|
+
Requires-Dist: docker<8.0.0,>=7.0.0
|
|
19
|
+
Requires-Dist: matplotlib<4.0.0,>=3.10.0
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
30
|
+
|
|
31
|
+
# Vedro profiling
|
|
32
|
+
|
|
33
|
+
Vedro plugin for measuring docker resource usage of tests.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
[flake8]
|
|
2
|
+
exclude = venv,__pycache__
|
|
3
|
+
max_line_length = 99
|
|
4
|
+
statistics = true
|
|
5
|
+
|
|
6
|
+
[isort]
|
|
7
|
+
line_length = 99
|
|
8
|
+
multi_line_output = 3
|
|
9
|
+
include_trailing_comma = true
|
|
10
|
+
skip = venv,__pycache__
|
|
11
|
+
|
|
12
|
+
[mypy]
|
|
13
|
+
ignore_missing_imports = false
|
|
14
|
+
|
|
15
|
+
[egg_info]
|
|
16
|
+
tag_build =
|
|
17
|
+
tag_date = 0
|
|
18
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from setuptools import find_packages, setup
|
|
2
|
+
|
|
3
|
+
from vedro_profiling import version
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def find_required():
|
|
7
|
+
with open("requirements.txt") as f:
|
|
8
|
+
return f.read().splitlines()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def find_dev_required():
|
|
12
|
+
with open("requirements-dev.txt") as f:
|
|
13
|
+
return f.read().splitlines()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
setup(
|
|
17
|
+
name="vedro-profiling",
|
|
18
|
+
version=version,
|
|
19
|
+
description="Vedro plugin for measuring docker resource usage.",
|
|
20
|
+
long_description=open("README.md").read(),
|
|
21
|
+
long_description_content_type="text/markdown",
|
|
22
|
+
author="Nikita Mikheev",
|
|
23
|
+
author_email="thelol1mpo@gmail.com",
|
|
24
|
+
python_requires=">=3.10",
|
|
25
|
+
url="https://github.com/lolimpo/vedro-profiling",
|
|
26
|
+
license="Apache-2.0",
|
|
27
|
+
packages=find_packages(exclude=["tests", "tests.*"]),
|
|
28
|
+
package_data={"vedro_profiling": ["py.typed"]},
|
|
29
|
+
install_requires=find_required(),
|
|
30
|
+
tests_require=find_dev_required(),
|
|
31
|
+
classifiers=[
|
|
32
|
+
"License :: OSI Approved :: Apache Software License",
|
|
33
|
+
"Programming Language :: Python :: 3.10",
|
|
34
|
+
"Programming Language :: Python :: 3.11",
|
|
35
|
+
"Programming Language :: Python :: 3.12",
|
|
36
|
+
"Programming Language :: Python :: 3.13",
|
|
37
|
+
"Typing :: Typed"
|
|
38
|
+
]
|
|
39
|
+
)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import threading
|
|
3
|
+
import time
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
from typing import Any, DefaultDict, Optional, Type
|
|
6
|
+
|
|
7
|
+
import docker
|
|
8
|
+
from matplotlib import pyplot as plt
|
|
9
|
+
from vedro.core import Dispatcher, Plugin, PluginConfig
|
|
10
|
+
from vedro.events import ArgParsedEvent, ArgParseEvent, CleanupEvent, StartupEvent
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class VedroProfilingPlugin(Plugin):
|
|
14
|
+
"""
|
|
15
|
+
Adds docker profiling support to the Vedro framework.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, config: Type["VedroProfiling"]):
|
|
19
|
+
super().__init__(config)
|
|
20
|
+
self._poll_time: float = config.poll_time
|
|
21
|
+
self._enable_profiling: bool = config.enable_profiling
|
|
22
|
+
self._draw_plots: bool = config.draw_plots
|
|
23
|
+
self._stats: DefaultDict[str, Any] = defaultdict(lambda: {"CPU": [], "MEM": []})
|
|
24
|
+
|
|
25
|
+
self._client = docker.from_env()
|
|
26
|
+
self._running: bool = False
|
|
27
|
+
self._thread: Optional[threading.Thread] = None
|
|
28
|
+
|
|
29
|
+
def subscribe(self, dispatcher: Dispatcher) -> None:
|
|
30
|
+
dispatcher.listen(ArgParseEvent, self.on_arg_parse) \
|
|
31
|
+
.listen(ArgParsedEvent, self.on_arg_parsed) \
|
|
32
|
+
.listen(StartupEvent, self.on_startup) \
|
|
33
|
+
.listen(CleanupEvent, self.on_cleanup)
|
|
34
|
+
|
|
35
|
+
def on_arg_parse(self, event: ArgParseEvent) -> None:
|
|
36
|
+
group = event.arg_parser.add_argument_group("VedroProfiling")
|
|
37
|
+
group.add_argument(
|
|
38
|
+
"--enable-profiling",
|
|
39
|
+
action="store_true",
|
|
40
|
+
default=self._enable_profiling,
|
|
41
|
+
help="Enable recording of containers stats during scenario execution"
|
|
42
|
+
)
|
|
43
|
+
group.add_argument(
|
|
44
|
+
"--draw-plots",
|
|
45
|
+
action="store_true",
|
|
46
|
+
default=self._draw_plots,
|
|
47
|
+
help="Draw CPU/MEM plots after test run"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def on_arg_parsed(self, event: ArgParsedEvent) -> None:
|
|
51
|
+
self._enable_profiling = event.args.enable_profiling
|
|
52
|
+
self._draw_plots = event.args.draw_plots
|
|
53
|
+
|
|
54
|
+
def _collect_stats(self) -> None:
|
|
55
|
+
containers = self._client.containers.list()
|
|
56
|
+
while self._running:
|
|
57
|
+
for container in containers:
|
|
58
|
+
stats = container.stats(decode=None, stream=False)
|
|
59
|
+
|
|
60
|
+
cpu_delta = (stats["cpu_stats"]["cpu_usage"]["total_usage"] -
|
|
61
|
+
stats["precpu_stats"]["cpu_usage"]["total_usage"])
|
|
62
|
+
system_delta = (stats["cpu_stats"]["system_cpu_usage"] -
|
|
63
|
+
stats["precpu_stats"]["system_cpu_usage"])
|
|
64
|
+
|
|
65
|
+
if system_delta > 0 and stats["cpu_stats"].get("online_cpus"):
|
|
66
|
+
cpu_percent = ((cpu_delta / system_delta) *
|
|
67
|
+
stats["cpu_stats"]["online_cpus"] * 100)
|
|
68
|
+
self._stats[container.name]["CPU"].append(cpu_percent)
|
|
69
|
+
|
|
70
|
+
mem = stats["memory_stats"]["usage"]
|
|
71
|
+
self._stats[container.name]["MEM"].append(mem / 1e6) # in MB
|
|
72
|
+
time.sleep(self._poll_time)
|
|
73
|
+
|
|
74
|
+
def on_startup(self, event: StartupEvent) -> None:
|
|
75
|
+
if not self._enable_profiling:
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
if not self._client.containers.list():
|
|
79
|
+
raise RuntimeError("No running containers found for profiling.")
|
|
80
|
+
|
|
81
|
+
self._running = True
|
|
82
|
+
self._thread = threading.Thread(target=self._collect_stats, daemon=True)
|
|
83
|
+
self._thread.start()
|
|
84
|
+
|
|
85
|
+
def _generate_plots(self) -> None:
|
|
86
|
+
for name, metrics in self._stats.items():
|
|
87
|
+
ticks = list(range(len(metrics["CPU"])))
|
|
88
|
+
|
|
89
|
+
# CPU plot
|
|
90
|
+
plt.figure()
|
|
91
|
+
plt.plot(ticks, metrics["CPU"], label="CPU (%)")
|
|
92
|
+
plt.xlabel("Tick")
|
|
93
|
+
plt.ylabel("CPU Usage (%)")
|
|
94
|
+
plt.title(f"{name} - CPU Usage")
|
|
95
|
+
plt.legend()
|
|
96
|
+
plt.tight_layout()
|
|
97
|
+
plt.savefig(f"{name}_cpu.png")
|
|
98
|
+
plt.close()
|
|
99
|
+
|
|
100
|
+
# Memory plot
|
|
101
|
+
plt.figure()
|
|
102
|
+
plt.plot(ticks, metrics["MEM"], label="Memory (MB)")
|
|
103
|
+
plt.xlabel("Tick")
|
|
104
|
+
plt.ylabel("Memory Usage (MB)")
|
|
105
|
+
plt.title(f"{name} - Memory Usage")
|
|
106
|
+
plt.legend()
|
|
107
|
+
plt.tight_layout()
|
|
108
|
+
plt.savefig(f"{name}_mem.png")
|
|
109
|
+
plt.close()
|
|
110
|
+
|
|
111
|
+
def on_cleanup(self, event: CleanupEvent) -> None:
|
|
112
|
+
if not self._enable_profiling:
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
self._running = False
|
|
116
|
+
if self._thread and self._thread.is_alive():
|
|
117
|
+
self._thread.join()
|
|
118
|
+
|
|
119
|
+
with open("./profiling.log", "w") as profiling_log:
|
|
120
|
+
json.dump(dict(self._stats), profiling_log, indent=2)
|
|
121
|
+
|
|
122
|
+
if self._draw_plots:
|
|
123
|
+
self._generate_plots()
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
class VedroProfiling(PluginConfig):
|
|
127
|
+
plugin = VedroProfilingPlugin
|
|
128
|
+
|
|
129
|
+
# Enable stats collection
|
|
130
|
+
enable_profiling: bool = False
|
|
131
|
+
|
|
132
|
+
# Enable plots drawing for given profile snapshot
|
|
133
|
+
draw_plots: bool = False
|
|
134
|
+
|
|
135
|
+
# Poll time for stats in seconds
|
|
136
|
+
poll_time: float = 1.0
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vedro-profiling
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Vedro plugin for measuring docker resource usage.
|
|
5
|
+
Home-page: https://github.com/lolimpo/vedro-profiling
|
|
6
|
+
Author: Nikita Mikheev
|
|
7
|
+
Author-email: thelol1mpo@gmail.com
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: vedro<2.0.0,>=1.13.0
|
|
18
|
+
Requires-Dist: docker<8.0.0,>=7.0.0
|
|
19
|
+
Requires-Dist: matplotlib<4.0.0,>=3.10.0
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: license
|
|
27
|
+
Dynamic: requires-dist
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
Dynamic: summary
|
|
30
|
+
|
|
31
|
+
# Vedro profiling
|
|
32
|
+
|
|
33
|
+
Vedro plugin for measuring docker resource usage of tests.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.cfg
|
|
3
|
+
setup.py
|
|
4
|
+
vedro_profiling/__init__.py
|
|
5
|
+
vedro_profiling/_vedro_profiling.py
|
|
6
|
+
vedro_profiling/py.typed
|
|
7
|
+
vedro_profiling.egg-info/PKG-INFO
|
|
8
|
+
vedro_profiling.egg-info/SOURCES.txt
|
|
9
|
+
vedro_profiling.egg-info/dependency_links.txt
|
|
10
|
+
vedro_profiling.egg-info/requires.txt
|
|
11
|
+
vedro_profiling.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
vedro_profiling
|