codecarbon 2.3.0__tar.gz → 2.3.2__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.
- {codecarbon-2.3.0 → codecarbon-2.3.2}/LICENSE +3 -2
- {codecarbon-2.3.0/codecarbon.egg-info → codecarbon-2.3.2}/PKG-INFO +19 -3
- {codecarbon-2.3.0 → codecarbon-2.3.2}/README.md +2 -1
- codecarbon-2.3.2/codecarbon/_version.py +1 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/cloud.py +0 -21
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/gpu.py +0 -22
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/util.py +15 -5
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/data/hardware/cpu_power.csv +2 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/emissions_tracker.py +4 -3
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/external/hardware.py +45 -14
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/external/scheduler.py +5 -4
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/prometheus/metric_definitions.py +13 -3
- codecarbon-2.3.2/codecarbon/prometheus/prometheus.py +75 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/viz/components.py +14 -9
- {codecarbon-2.3.0 → codecarbon-2.3.2/codecarbon.egg-info}/PKG-INFO +19 -3
- {codecarbon-2.3.0 → codecarbon-2.3.2}/setup.py +1 -1
- codecarbon-2.3.2/tests/test_ram.py +84 -0
- codecarbon-2.3.0/codecarbon/_version.py +0 -1
- codecarbon-2.3.0/codecarbon/prometheus/prometheus.py +0 -55
- codecarbon-2.3.0/tests/test_ram.py +0 -36
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/dependencies.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/domain/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/domain/emissions.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/domain/experiments.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/domain/organizations.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/domain/projects.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/domain/runs.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/domain/teams.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/domain/users.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/errors.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/routers/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/routers/authenticate.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/routers/emissions.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/routers/experiments.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/routers/organizations.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/routers/projects.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/routers/runs.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/routers/teams.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/routers/users.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/schemas.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/config.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/database/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/database/database.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/logger.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/container.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/main.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/setup.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/cli/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/cli/cli_utils.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/cli/main.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/api_client.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/co2_signal.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/config.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/cpu.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/emissions.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/measure.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/rapl.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/schemas.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/core/units.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/data/cloud/impact.csv +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/data/private_infra/2016/canada_energy_mix.json +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/data/private_infra/2016/usa_emissions.json +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/data/private_infra/carbon_intensity_per_source.json +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/data/private_infra/global_energy_mix.json +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/external/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/external/geography.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/external/logger.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/external/task.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/input.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/output.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/prometheus/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/viz/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/viz/assets/__init__.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/viz/assets/car_icon.png +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/viz/assets/house_icon.png +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/viz/assets/tv_icon.png +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/viz/carbonboard.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/viz/carbonboard_on_api.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/viz/data.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon.egg-info/SOURCES.txt +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon.egg-info/dependency_links.txt +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon.egg-info/entry_points.txt +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon.egg-info/requires.txt +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon.egg-info/top_level.txt +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/setup.cfg +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_api_call.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_cloud.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_co2_signal.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_config.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_core_util.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_cpu.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_emissions.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_emissions_tracker.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_emissions_tracker_constant.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_emissions_tracker_flush.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_energy.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_geography.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_gpu.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_logging_output.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_tracking_inference.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/test_viz_data.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/testdata.py +0 -0
- {codecarbon-2.3.0 → codecarbon-2.3.2}/tests/testutils.py +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (c)
|
|
3
|
+
Copyright (c) 2019 Mila, BCG Gamma, CometML, Haverford College
|
|
4
|
+
Copyright (c) 2023 Code Carbon NGO
|
|
4
5
|
|
|
5
6
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
7
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -18,4 +19,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
18
19
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
20
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
21
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
22
|
+
SOFTWARE.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: codecarbon
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.2
|
|
4
4
|
Author: Mila, DataForGood, BCG GAMMA, Comet.ml, Haverford College
|
|
5
5
|
Classifier: Natural Language :: English
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.7
|
|
@@ -11,9 +11,24 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
11
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
12
|
Requires-Python: >=3.7
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: arrow
|
|
16
|
+
Requires-Dist: pandas
|
|
17
|
+
Requires-Dist: pynvml
|
|
18
|
+
Requires-Dist: requests
|
|
19
|
+
Requires-Dist: psutil
|
|
20
|
+
Requires-Dist: py-cpuinfo
|
|
21
|
+
Requires-Dist: fuzzywuzzy
|
|
22
|
+
Requires-Dist: click
|
|
23
|
+
Requires-Dist: prometheus_client
|
|
14
24
|
Provides-Extra: viz
|
|
25
|
+
Requires-Dist: dash; extra == "viz"
|
|
26
|
+
Requires-Dist: dash_bootstrap_components<1.0.0; extra == "viz"
|
|
27
|
+
Requires-Dist: fire; extra == "viz"
|
|
15
28
|
Provides-Extra: dashboard
|
|
16
|
-
|
|
29
|
+
Requires-Dist: dash>=2.2.0; extra == "dashboard"
|
|
30
|
+
Requires-Dist: plotly>=5.6.0; extra == "dashboard"
|
|
31
|
+
Requires-Dist: dash_bootstrap_components; extra == "dashboard"
|
|
17
32
|
|
|
18
33
|

|
|
19
34
|
|
|
@@ -26,6 +41,7 @@ Estimate and track carbon emissions from your computer, quantify and analyze the
|
|
|
26
41
|
[](https://anaconda.org/conda-forge/codecarbon)
|
|
27
42
|
[](https://pypi.org/project/codecarbon/)
|
|
28
43
|
[](https://zenodo.org/badge/latestdoi/263364731)
|
|
44
|
+
[](https://pepy.tech/project/codecarbon)
|
|
29
45
|
|
|
30
46
|
|
|
31
47
|
- [About CodeCarbon 💡](#about-codecarbon-)
|
|
@@ -73,7 +89,7 @@ pip install codecarbon
|
|
|
73
89
|
```python
|
|
74
90
|
conda install -c conda-forge codecarbon
|
|
75
91
|
```
|
|
76
|
-
To see more installation options please refer to the documentation
|
|
92
|
+
To see more installation options please refer to the documentation: [**Installation**](https://mlco2.github.io/codecarbon/installation.html#)
|
|
77
93
|
|
|
78
94
|
## Start to estimate your impact 📏
|
|
79
95
|
|
|
@@ -9,6 +9,7 @@ Estimate and track carbon emissions from your computer, quantify and analyze the
|
|
|
9
9
|
[](https://anaconda.org/conda-forge/codecarbon)
|
|
10
10
|
[](https://pypi.org/project/codecarbon/)
|
|
11
11
|
[](https://zenodo.org/badge/latestdoi/263364731)
|
|
12
|
+
[](https://pepy.tech/project/codecarbon)
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
- [About CodeCarbon 💡](#about-codecarbon-)
|
|
@@ -56,7 +57,7 @@ pip install codecarbon
|
|
|
56
57
|
```python
|
|
57
58
|
conda install -c conda-forge codecarbon
|
|
58
59
|
```
|
|
59
|
-
To see more installation options please refer to the documentation
|
|
60
|
+
To see more installation options please refer to the documentation: [**Installation**](https://mlco2.github.io/codecarbon/installation.html#)
|
|
60
61
|
|
|
61
62
|
## Start to estimate your impact 📏
|
|
62
63
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.3.2"
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
# Copyright (C) 2020 [COMET-ML]
|
|
4
|
-
#
|
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
6
|
-
# software and associated documentation files (the "Software"), to deal in the Software
|
|
7
|
-
# without restriction, including without limitation the rights to use, copy, modify,
|
|
8
|
-
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to the following
|
|
10
|
-
# conditions:
|
|
11
|
-
#
|
|
12
|
-
# The above copyright notice and this permission notice shall be included in all copies
|
|
13
|
-
# or substantial portions of the Software.
|
|
14
|
-
#
|
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
16
|
-
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
17
|
-
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
18
|
-
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
19
|
-
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
20
|
-
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
-
|
|
22
1
|
from typing import Any, Dict, Optional
|
|
23
2
|
|
|
24
3
|
import requests
|
|
@@ -1,25 +1,3 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
# Copyright (C) 2020 [COMET-ML]
|
|
4
|
-
#
|
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
6
|
-
# software and associated documentation files (the "Software"), to deal in the Software
|
|
7
|
-
# without restriction, including without limitation the rights to use, copy, modify,
|
|
8
|
-
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to the following
|
|
10
|
-
# conditions:
|
|
11
|
-
#
|
|
12
|
-
# The above copyright notice and this permission notice shall be included in all copies
|
|
13
|
-
# or substantial portions of the Software.
|
|
14
|
-
#
|
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
16
|
-
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
|
17
|
-
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
18
|
-
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
|
19
|
-
# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
|
20
|
-
# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
-
|
|
22
|
-
|
|
23
1
|
from dataclasses import dataclass, field
|
|
24
2
|
|
|
25
3
|
import pynvml
|
|
@@ -11,6 +11,11 @@ import psutil
|
|
|
11
11
|
|
|
12
12
|
from codecarbon.external.logger import logger
|
|
13
13
|
|
|
14
|
+
SLURM_JOB_ID = os.environ.get(
|
|
15
|
+
"SLURM_JOB_ID", # default
|
|
16
|
+
os.environ.get("SLURM_JOBID"), # deprecated but may still be used
|
|
17
|
+
)
|
|
18
|
+
|
|
14
19
|
|
|
15
20
|
@contextmanager
|
|
16
21
|
def suppress(*exceptions):
|
|
@@ -75,16 +80,20 @@ def detect_cpu_model() -> str:
|
|
|
75
80
|
|
|
76
81
|
|
|
77
82
|
def count_cpus() -> int:
|
|
78
|
-
if
|
|
83
|
+
if SLURM_JOB_ID is None:
|
|
79
84
|
return psutil.cpu_count()
|
|
80
85
|
|
|
81
86
|
try:
|
|
87
|
+
logger.debug(
|
|
88
|
+
"SLURM environment detected for job {SLURM_JOB_ID}, running"
|
|
89
|
+
+ " `scontrol show job $SLURM_JOB_ID` to count SLURM-available cpus."
|
|
90
|
+
)
|
|
82
91
|
scontrol = subprocess.check_output(
|
|
83
|
-
["scontrol show job
|
|
92
|
+
[f"scontrol show job {SLURM_JOB_ID}"], shell=True
|
|
84
93
|
).decode()
|
|
85
94
|
except subprocess.CalledProcessError:
|
|
86
95
|
logger.warning(
|
|
87
|
-
"Error running `scontrol show job $
|
|
96
|
+
"Error running `scontrol show job $SLURM_JOB_ID` "
|
|
88
97
|
+ "to count SLURM-available cpus. Using the machine's cpu count."
|
|
89
98
|
)
|
|
90
99
|
return psutil.cpu_count()
|
|
@@ -93,17 +102,18 @@ def count_cpus() -> int:
|
|
|
93
102
|
|
|
94
103
|
if len(num_cpus_matches) == 0:
|
|
95
104
|
logger.warning(
|
|
96
|
-
"Could not find NumCPUs= after running `scontrol show job $
|
|
105
|
+
"Could not find NumCPUs= after running `scontrol show job $SLURM_JOB_ID` "
|
|
97
106
|
+ "to count SLURM-available cpus. Using the machine's cpu count."
|
|
98
107
|
)
|
|
99
108
|
return psutil.cpu_count()
|
|
100
109
|
|
|
101
110
|
if len(num_cpus_matches) > 1:
|
|
102
111
|
logger.warning(
|
|
103
|
-
"Unexpected output after running `scontrol show job $
|
|
112
|
+
"Unexpected output after running `scontrol show job $SLURM_JOB_ID` "
|
|
104
113
|
+ "to count SLURM-available cpus. Using the machine's cpu count."
|
|
105
114
|
)
|
|
106
115
|
return psutil.cpu_count()
|
|
107
116
|
|
|
108
117
|
num_cpus = num_cpus_matches[0].replace("NumCPUs=", "")
|
|
118
|
+
logger.debug(f"Detected {num_cpus} cpus available on SLURM.")
|
|
109
119
|
return int(num_cpus)
|
|
@@ -1991,8 +1991,10 @@ Intel Xeon E3-1285 v4,95
|
|
|
1991
1991
|
Intel Xeon E3-1285 v6,79
|
|
1992
1992
|
Intel Xeon E3-1290,95
|
|
1993
1993
|
Intel Xeon E3-1290 v2,87
|
|
1994
|
+
Intel Xeon E5-1603 v3,140
|
|
1994
1995
|
Intel Xeon E5-1620 v2,130
|
|
1995
1996
|
Intel Xeon E5-1650 v2,130
|
|
1997
|
+
Intel Xeon E5-1650 v4,140
|
|
1996
1998
|
Intel Xeon E5-1660 v2,130
|
|
1997
1999
|
Intel Xeon E5-2403 v2,80
|
|
1998
2000
|
Intel Xeon E5-2407 v2,80
|
|
@@ -433,7 +433,8 @@ class BaseEmissionsTracker(ABC):
|
|
|
433
433
|
:return: None
|
|
434
434
|
"""
|
|
435
435
|
# Stop scheduler as we do not want it to interfere with the task measurement
|
|
436
|
-
self._scheduler
|
|
436
|
+
if self._scheduler:
|
|
437
|
+
self._scheduler.stop()
|
|
437
438
|
|
|
438
439
|
if self._active_task:
|
|
439
440
|
logger.info("A task is already under measure")
|
|
@@ -457,11 +458,11 @@ class BaseEmissionsTracker(ABC):
|
|
|
457
458
|
)
|
|
458
459
|
self._active_task = task_name
|
|
459
460
|
|
|
460
|
-
def stop_task(self, task_name: str = None) ->
|
|
461
|
+
def stop_task(self, task_name: str = None) -> EmissionsData:
|
|
461
462
|
"""
|
|
462
463
|
Stop tracking a dedicated execution task. Delta energy is computed by task, to isolate its contribution to total
|
|
463
464
|
emissions.
|
|
464
|
-
:return:
|
|
465
|
+
:return: EmissionsData
|
|
465
466
|
"""
|
|
466
467
|
task_name = task_name if task_name else self._active_task
|
|
467
468
|
self._measure_power_and_energy()
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Encapsulates external dependencies to retrieve hardware metadata
|
|
3
3
|
"""
|
|
4
|
-
|
|
5
|
-
import os
|
|
6
4
|
import re
|
|
7
5
|
import subprocess
|
|
8
6
|
from abc import ABC, abstractmethod
|
|
@@ -14,7 +12,7 @@ import psutil
|
|
|
14
12
|
from codecarbon.core.cpu import IntelPowerGadget, IntelRAPL
|
|
15
13
|
from codecarbon.core.gpu import AllGPUDevices
|
|
16
14
|
from codecarbon.core.units import Energy, Power, Time
|
|
17
|
-
from codecarbon.core.util import detect_cpu_model
|
|
15
|
+
from codecarbon.core.util import SLURM_JOB_ID, detect_cpu_model
|
|
18
16
|
from codecarbon.external.logger import logger
|
|
19
17
|
|
|
20
18
|
# default W value for a CPU if no model is found in the ref csv
|
|
@@ -46,7 +44,7 @@ class BaseHardware(ABC):
|
|
|
46
44
|
)
|
|
47
45
|
return power, energy
|
|
48
46
|
|
|
49
|
-
def start(self) -> None:
|
|
47
|
+
def start(self) -> None: # noqa B027
|
|
50
48
|
pass
|
|
51
49
|
|
|
52
50
|
|
|
@@ -168,7 +166,7 @@ class CPU(BaseHardware):
|
|
|
168
166
|
|
|
169
167
|
power = 0
|
|
170
168
|
for metric, value in all_cpu_details.items():
|
|
171
|
-
# "^Processor Power_\d+\(Watt\)$" for
|
|
169
|
+
# "^Processor Power_\d+\(Watt\)$" for Intel Power Gadget
|
|
172
170
|
if re.match(r"^Processor Power", metric):
|
|
173
171
|
power += value
|
|
174
172
|
logger.debug(f"_get_power_from_cpus - MATCH {metric} : {value}")
|
|
@@ -238,6 +236,7 @@ class RAM(BaseHardware):
|
|
|
238
236
|
# 3 watts of power for every 8GB of DDR3 or DDR4 memory
|
|
239
237
|
# https://www.crucial.com/support/articles-faq-memory/how-much-power-does-memory-use
|
|
240
238
|
power_per_GB = 3 / 8 # W/GB
|
|
239
|
+
memory_size = None
|
|
241
240
|
|
|
242
241
|
def __init__(
|
|
243
242
|
self,
|
|
@@ -273,13 +272,29 @@ class RAM(BaseHardware):
|
|
|
273
272
|
|
|
274
273
|
def _read_slurm_scontrol(self):
|
|
275
274
|
try:
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
)
|
|
275
|
+
logger.debug(
|
|
276
|
+
"SLURM environment detected, running `scontrol show job $SLURM_JOB_ID`..."
|
|
277
|
+
)
|
|
278
|
+
return (
|
|
279
|
+
subprocess.check_output(
|
|
280
|
+
[f"scontrol show job {SLURM_JOB_ID}"], shell=True
|
|
281
|
+
)
|
|
282
|
+
.decode()
|
|
283
|
+
.strip()
|
|
284
|
+
)
|
|
279
285
|
except subprocess.CalledProcessError:
|
|
280
286
|
return
|
|
281
287
|
|
|
282
288
|
def _parse_scontrol_memory_GB(self, mem):
|
|
289
|
+
"""
|
|
290
|
+
Parse the memory string (B) returned by scontrol to a float (GB)
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
mem (str): Memory string (B) as `[amount][unit]` (e.g. `128G`)
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
float: Memory (GB)
|
|
297
|
+
"""
|
|
283
298
|
nb = int(mem[:-1])
|
|
284
299
|
unit = mem[-1]
|
|
285
300
|
if unit == "T":
|
|
@@ -292,16 +307,16 @@ class RAM(BaseHardware):
|
|
|
292
307
|
return nb / (1000**2)
|
|
293
308
|
|
|
294
309
|
def _parse_scontrol(self, scontrol_str):
|
|
295
|
-
mem_matches = re.findall(r"mem
|
|
310
|
+
mem_matches = re.findall(r"AllocTRES=.*?,mem=(\d+[A-Z])", scontrol_str)
|
|
296
311
|
if len(mem_matches) == 0:
|
|
297
312
|
logger.warning(
|
|
298
|
-
"Could not find mem= after running `scontrol show job $
|
|
313
|
+
"Could not find mem= after running `scontrol show job $SLURM_JOB_ID` "
|
|
299
314
|
+ "to count SLURM-available RAM. Using the machine's total RAM."
|
|
300
315
|
)
|
|
301
316
|
return psutil.virtual_memory().total / B_TO_GB
|
|
302
317
|
if len(mem_matches) > 1:
|
|
303
318
|
logger.warning(
|
|
304
|
-
"Unexpected output after running `scontrol show job $
|
|
319
|
+
"Unexpected output after running `scontrol show job $SLURM_JOB_ID` "
|
|
305
320
|
+ "to count SLURM-available RAM. Using the machine's total RAM."
|
|
306
321
|
)
|
|
307
322
|
return psutil.virtual_memory().total / B_TO_GB
|
|
@@ -310,17 +325,27 @@ class RAM(BaseHardware):
|
|
|
310
325
|
|
|
311
326
|
@property
|
|
312
327
|
def slurm_memory_GB(self):
|
|
328
|
+
"""
|
|
329
|
+
Property to compute the SLURM-available RAM in GigaBytes.
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
float: Memory allocated to the job (GB)
|
|
333
|
+
"""
|
|
334
|
+
# Prevent calling scontrol at each mesure
|
|
335
|
+
if self.memory_size:
|
|
336
|
+
return self.memory_size
|
|
313
337
|
scontrol_str = self._read_slurm_scontrol()
|
|
314
338
|
if scontrol_str is None:
|
|
315
339
|
logger.warning(
|
|
316
|
-
"Error running `scontrol show job $
|
|
340
|
+
"Error running `scontrol show job $SLURM_JOB_ID` "
|
|
317
341
|
+ "to retrieve SLURM-available RAM."
|
|
318
342
|
+ "Using the machine's total RAM."
|
|
319
343
|
)
|
|
320
344
|
return psutil.virtual_memory().total / B_TO_GB
|
|
321
345
|
mem = self._parse_scontrol(scontrol_str)
|
|
322
346
|
if isinstance(mem, str):
|
|
323
|
-
|
|
347
|
+
mem = self._parse_scontrol_memory_GB(mem)
|
|
348
|
+
self.memory_size = mem
|
|
324
349
|
return mem
|
|
325
350
|
|
|
326
351
|
@property
|
|
@@ -338,9 +363,15 @@ class RAM(BaseHardware):
|
|
|
338
363
|
|
|
339
364
|
@property
|
|
340
365
|
def machine_memory_GB(self):
|
|
366
|
+
"""
|
|
367
|
+
Property to compute the machine's total memory in bytes.
|
|
368
|
+
|
|
369
|
+
Returns:
|
|
370
|
+
float: Total RAM (GB)
|
|
371
|
+
"""
|
|
341
372
|
return (
|
|
342
373
|
self.slurm_memory_GB
|
|
343
|
-
if
|
|
374
|
+
if SLURM_JOB_ID
|
|
344
375
|
else psutil.virtual_memory().total / B_TO_GB
|
|
345
376
|
)
|
|
346
377
|
|
|
@@ -45,7 +45,8 @@ class PeriodicScheduler:
|
|
|
45
45
|
"""
|
|
46
46
|
Stop the scheduler.
|
|
47
47
|
"""
|
|
48
|
-
self.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
if not self._stopped:
|
|
49
|
+
self._lock.acquire()
|
|
50
|
+
self._stopped = True
|
|
51
|
+
self._timer.cancel()
|
|
52
|
+
self._lock.release()
|
|
@@ -32,50 +32,60 @@ labelnames = [
|
|
|
32
32
|
duration_gauge = Gauge(
|
|
33
33
|
"codecarbon_duration",
|
|
34
34
|
"Duration from last measure (s)",
|
|
35
|
+
["project_name"],
|
|
35
36
|
registry=registry,
|
|
36
37
|
)
|
|
37
38
|
emissions_gauge = Gauge(
|
|
38
39
|
"codecarbon_emissions",
|
|
39
40
|
"Emissions as CO₂-equivalents [CO₂eq] (kg)",
|
|
41
|
+
["project_name"],
|
|
40
42
|
registry=registry,
|
|
41
43
|
)
|
|
42
44
|
emissions_rate_gauge = Gauge(
|
|
43
45
|
"codecarbon_emissions_rate",
|
|
44
46
|
"Emissions divided per duration (Kg/s)",
|
|
47
|
+
["project_name"],
|
|
45
48
|
registry=registry,
|
|
46
49
|
)
|
|
47
50
|
cpu_power_gauge = Gauge(
|
|
48
51
|
"codecarbon_cpu_power",
|
|
49
52
|
"CPU power (W)",
|
|
53
|
+
["project_name"],
|
|
50
54
|
registry=registry,
|
|
51
55
|
)
|
|
52
56
|
gpu_power_gauge = Gauge(
|
|
53
57
|
"codecarbon_gpu_power",
|
|
54
58
|
"GPU power (W)",
|
|
59
|
+
["project_name"],
|
|
55
60
|
registry=registry,
|
|
56
61
|
)
|
|
57
62
|
ram_power_gauge = Gauge(
|
|
58
63
|
"codecarbon_ram_power",
|
|
59
64
|
"RAM power (W)",
|
|
65
|
+
["project_name"],
|
|
60
66
|
registry=registry,
|
|
61
67
|
)
|
|
62
68
|
cpu_energy_gauge = Gauge(
|
|
63
69
|
"codecarbon_cpu_energy",
|
|
64
|
-
"Energy used per CPU (
|
|
70
|
+
"Energy used per CPU (kWh)",
|
|
71
|
+
["project_name"],
|
|
65
72
|
registry=registry,
|
|
66
73
|
)
|
|
67
74
|
gpu_energy_gauge = Gauge(
|
|
68
75
|
"codecarbon_gpu_energy",
|
|
69
|
-
"Energy used per GPU (
|
|
76
|
+
"Energy used per GPU (kWh)",
|
|
77
|
+
["project_name"],
|
|
70
78
|
registry=registry,
|
|
71
79
|
)
|
|
72
80
|
ram_energy_gauge = Gauge(
|
|
73
81
|
"codecarbon_ram_energy",
|
|
74
|
-
"Energy used per RAM (
|
|
82
|
+
"Energy used per RAM (kWh)",
|
|
83
|
+
["project_name"],
|
|
75
84
|
registry=registry,
|
|
76
85
|
)
|
|
77
86
|
energy_consumed_gauge = Gauge(
|
|
78
87
|
"codecarbon_energy_consumed",
|
|
79
88
|
"Sum of cpu_energy, gpu_energy and ram_energy (kW)",
|
|
89
|
+
["project_name"],
|
|
80
90
|
registry=registry,
|
|
81
91
|
)
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
3
|
+
from prometheus_client import push_to_gateway
|
|
4
|
+
from prometheus_client.exposition import basic_auth_handler
|
|
5
|
+
|
|
6
|
+
from codecarbon.prometheus.metric_definitions import (
|
|
7
|
+
cpu_energy_gauge,
|
|
8
|
+
cpu_power_gauge,
|
|
9
|
+
duration_gauge,
|
|
10
|
+
emissions_gauge,
|
|
11
|
+
emissions_rate_gauge,
|
|
12
|
+
energy_consumed_gauge,
|
|
13
|
+
gpu_energy_gauge,
|
|
14
|
+
gpu_power_gauge,
|
|
15
|
+
ram_energy_gauge,
|
|
16
|
+
ram_power_gauge,
|
|
17
|
+
registry,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Prometheus:
|
|
22
|
+
def __init__(self, prometheus_url):
|
|
23
|
+
self.prometheus_url = prometheus_url
|
|
24
|
+
|
|
25
|
+
def _auth_handler(self, url, method, timeout, headers, data):
|
|
26
|
+
username = os.getenv("PROMETHEUS_USERNAME")
|
|
27
|
+
password = os.getenv("PROMETHEUS_PASSWORD")
|
|
28
|
+
return basic_auth_handler(
|
|
29
|
+
url, method, timeout, headers, data, username, password
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
def add_emission(self, carbon_emission: dict):
|
|
33
|
+
"""
|
|
34
|
+
Send emissions data to push gateway
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
# Save the values of the metrics to the local registry
|
|
38
|
+
duration_gauge.labels(carbon_emission["project_name"]).set(
|
|
39
|
+
int(carbon_emission["duration"])
|
|
40
|
+
)
|
|
41
|
+
emissions_gauge.labels(carbon_emission["project_name"]).set(
|
|
42
|
+
carbon_emission["emissions"]
|
|
43
|
+
)
|
|
44
|
+
emissions_rate_gauge.labels(carbon_emission["project_name"]).set(
|
|
45
|
+
carbon_emission["emissions_rate"]
|
|
46
|
+
)
|
|
47
|
+
cpu_power_gauge.labels(carbon_emission["project_name"]).set(
|
|
48
|
+
carbon_emission["cpu_power"]
|
|
49
|
+
)
|
|
50
|
+
gpu_power_gauge.labels(carbon_emission["project_name"]).set(
|
|
51
|
+
carbon_emission["gpu_power"]
|
|
52
|
+
)
|
|
53
|
+
ram_power_gauge.labels(carbon_emission["project_name"]).set(
|
|
54
|
+
carbon_emission["ram_power"]
|
|
55
|
+
)
|
|
56
|
+
cpu_energy_gauge.labels(carbon_emission["project_name"]).set(
|
|
57
|
+
carbon_emission["cpu_energy"]
|
|
58
|
+
)
|
|
59
|
+
gpu_energy_gauge.labels(carbon_emission["project_name"]).set(
|
|
60
|
+
carbon_emission["gpu_energy"]
|
|
61
|
+
)
|
|
62
|
+
ram_energy_gauge.labels(carbon_emission["project_name"]).set(
|
|
63
|
+
carbon_emission["ram_energy"]
|
|
64
|
+
)
|
|
65
|
+
energy_consumed_gauge.labels(carbon_emission["project_name"]).set(
|
|
66
|
+
carbon_emission["energy_consumed"]
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# Send the new metric values
|
|
70
|
+
push_to_gateway(
|
|
71
|
+
self.prometheus_url,
|
|
72
|
+
job="codecarbon",
|
|
73
|
+
registry=registry,
|
|
74
|
+
handler=self._auth_handler,
|
|
75
|
+
)
|
|
@@ -29,15 +29,20 @@ class Components:
|
|
|
29
29
|
|
|
30
30
|
@staticmethod
|
|
31
31
|
def get_header():
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
return html.Div(
|
|
33
|
+
dbc.Container(
|
|
34
|
+
[
|
|
35
|
+
html.H1("Carbon Footprint", style={"textAlign": "center"}),
|
|
36
|
+
html.P(
|
|
37
|
+
"Measure Compute Emissions",
|
|
38
|
+
style={"textAlign": "center", "paddingLeft": "0.5%"},
|
|
39
|
+
className="lead",
|
|
40
|
+
),
|
|
41
|
+
],
|
|
42
|
+
fluid=True,
|
|
43
|
+
className="py-3",
|
|
44
|
+
),
|
|
45
|
+
className="p-3 mb-5 bg-light rounded-5",
|
|
41
46
|
)
|
|
42
47
|
|
|
43
48
|
@staticmethod
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: codecarbon
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.2
|
|
4
4
|
Author: Mila, DataForGood, BCG GAMMA, Comet.ml, Haverford College
|
|
5
5
|
Classifier: Natural Language :: English
|
|
6
6
|
Classifier: Programming Language :: Python :: 3.7
|
|
@@ -11,9 +11,24 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
11
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
12
|
Requires-Python: >=3.7
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: arrow
|
|
16
|
+
Requires-Dist: pandas
|
|
17
|
+
Requires-Dist: pynvml
|
|
18
|
+
Requires-Dist: requests
|
|
19
|
+
Requires-Dist: psutil
|
|
20
|
+
Requires-Dist: py-cpuinfo
|
|
21
|
+
Requires-Dist: fuzzywuzzy
|
|
22
|
+
Requires-Dist: click
|
|
23
|
+
Requires-Dist: prometheus_client
|
|
14
24
|
Provides-Extra: viz
|
|
25
|
+
Requires-Dist: dash; extra == "viz"
|
|
26
|
+
Requires-Dist: dash_bootstrap_components<1.0.0; extra == "viz"
|
|
27
|
+
Requires-Dist: fire; extra == "viz"
|
|
15
28
|
Provides-Extra: dashboard
|
|
16
|
-
|
|
29
|
+
Requires-Dist: dash>=2.2.0; extra == "dashboard"
|
|
30
|
+
Requires-Dist: plotly>=5.6.0; extra == "dashboard"
|
|
31
|
+
Requires-Dist: dash_bootstrap_components; extra == "dashboard"
|
|
17
32
|
|
|
18
33
|

|
|
19
34
|
|
|
@@ -26,6 +41,7 @@ Estimate and track carbon emissions from your computer, quantify and analyze the
|
|
|
26
41
|
[](https://anaconda.org/conda-forge/codecarbon)
|
|
27
42
|
[](https://pypi.org/project/codecarbon/)
|
|
28
43
|
[](https://zenodo.org/badge/latestdoi/263364731)
|
|
44
|
+
[](https://pepy.tech/project/codecarbon)
|
|
29
45
|
|
|
30
46
|
|
|
31
47
|
- [About CodeCarbon 💡](#about-codecarbon-)
|
|
@@ -73,7 +89,7 @@ pip install codecarbon
|
|
|
73
89
|
```python
|
|
74
90
|
conda install -c conda-forge codecarbon
|
|
75
91
|
```
|
|
76
|
-
To see more installation options please refer to the documentation
|
|
92
|
+
To see more installation options please refer to the documentation: [**Installation**](https://mlco2.github.io/codecarbon/installation.html#)
|
|
77
93
|
|
|
78
94
|
## Start to estimate your impact 📏
|
|
79
95
|
|
|
@@ -20,7 +20,7 @@ TEST_DEPENDENCIES = ["mock", "pytest", "responses", "tox", "numpy", "requests-mo
|
|
|
20
20
|
|
|
21
21
|
setuptools.setup(
|
|
22
22
|
name="codecarbon",
|
|
23
|
-
version="2.3.
|
|
23
|
+
version="2.3.2",
|
|
24
24
|
author="Mila, DataForGood, BCG GAMMA, Comet.ml, Haverford College",
|
|
25
25
|
long_description=long_description,
|
|
26
26
|
long_description_content_type="text/markdown",
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from textwrap import dedent
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from codecarbon.external.hardware import RAM
|
|
7
|
+
|
|
8
|
+
# TODO: need help: test multiprocess case
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestRAM(unittest.TestCase):
|
|
12
|
+
def test_ram_diff(self):
|
|
13
|
+
ram = RAM(tracking_mode="process")
|
|
14
|
+
|
|
15
|
+
for array_size in [
|
|
16
|
+
# (10, 10), # too small to be noticed
|
|
17
|
+
# (100, 100), # too small to be noticed
|
|
18
|
+
(1000, 1000), # ref for atol
|
|
19
|
+
(10, 1000, 1000),
|
|
20
|
+
(20, 1000, 1000),
|
|
21
|
+
(100, 1000, 1000),
|
|
22
|
+
(200, 1000, 1000),
|
|
23
|
+
(1000, 1000, 1000),
|
|
24
|
+
(2000, 1000, 1000),
|
|
25
|
+
]:
|
|
26
|
+
with self.subTest(array_size=array_size):
|
|
27
|
+
ref_W = ram.total_power().W
|
|
28
|
+
array = np.ones(array_size, dtype=np.int8)
|
|
29
|
+
new_W = ram.total_power().W
|
|
30
|
+
n_gb = array.nbytes / (1024**3)
|
|
31
|
+
n_gb_W = (new_W - ref_W) / ram.power_per_GB
|
|
32
|
+
is_close = np.isclose(n_gb, n_gb_W, atol=1e-3)
|
|
33
|
+
self.assertTrue(
|
|
34
|
+
is_close,
|
|
35
|
+
msg=f"{array_size}, {n_gb}, {n_gb_W}, {is_close}",
|
|
36
|
+
)
|
|
37
|
+
del array
|
|
38
|
+
|
|
39
|
+
def test_ram_slurm(self):
|
|
40
|
+
scontrol_str = dedent(
|
|
41
|
+
"""\
|
|
42
|
+
scontrol show job $SLURM_JOB_ID
|
|
43
|
+
JobId=XXXX JobName=gpu-jupyterhub
|
|
44
|
+
UserId=XXXX GroupId=XXXX MCS_label=N/A
|
|
45
|
+
Priority=255342 Nice=0 Account=puk@v100 QOS=qos_gpu-t3
|
|
46
|
+
JobState=RUNNING Reason=None Dependency=(null)
|
|
47
|
+
Requeue=1 Restarts=0 BatchFlag=1 Reboot=0 ExitCode=0:0
|
|
48
|
+
RunTime=00:33:42 TimeLimit=08:00:00 TimeMin=N/A
|
|
49
|
+
SubmitTime=2023-10-23T10:45:25 EligibleTime=2023-10-23T10:45:25
|
|
50
|
+
AccrueTime=2023-10-23T10:45:25
|
|
51
|
+
StartTime=2023-10-23T10:45:35 EndTime=2023-10-23T18:45:35 Deadline=N/A
|
|
52
|
+
SuspendTime=None SecsPreSuspend=0 LastSchedEval=2023-10-23T10:45:35 Scheduler=Main
|
|
53
|
+
Partition=gpu_p13 AllocNode:Sid=idrsrv12-ib0:500994
|
|
54
|
+
ReqNodeList=(null) ExcNodeList=(null)
|
|
55
|
+
NodeList=r13i5n0
|
|
56
|
+
BatchHost=r13i5n0
|
|
57
|
+
NumNodes=1 NumCPUs=64 NumTasks=1 CPUs/Task=32 ReqB:S:C:T=0:0:*:1
|
|
58
|
+
ReqTRES=cpu=32,mem=128G,node=1,billing=40,gres/gpu=4
|
|
59
|
+
AllocTRES=cpu=64,mem=128G,node=1,billing=40,gres/gpu=4
|
|
60
|
+
Socks/Node=* NtasksPerN:B:S:C=0:0:*:* CoreSpec=*
|
|
61
|
+
MinCPUsNode=32 MinMemoryCPU=4G MinTmpDiskNode=0
|
|
62
|
+
Features=v100-16g DelayBoot=00:00:00
|
|
63
|
+
OverSubscribe=OK Contiguous=0 Licenses=(null) Network=(null)
|
|
64
|
+
Command=(null)
|
|
65
|
+
WorkDir=/linkhome/rech/gendxh01/uei48xr
|
|
66
|
+
StdErr=/linkhome/rech/gendxh01/uei48xr/jupyterhub_slurm.err
|
|
67
|
+
StdIn=/dev/null
|
|
68
|
+
StdOut=/linkhome/rech/gendxh01/uei48xr/jupyterhub_slurm.out
|
|
69
|
+
Power=
|
|
70
|
+
TresPerNode=gres:gpu:4
|
|
71
|
+
"""
|
|
72
|
+
)
|
|
73
|
+
ram = RAM(tracking_mode="slurm")
|
|
74
|
+
ram_size = ram._parse_scontrol(scontrol_str)
|
|
75
|
+
self.assertEqual(ram_size, "128G")
|
|
76
|
+
scontrol_str = dedent(
|
|
77
|
+
"""\
|
|
78
|
+
ReqTRES=cpu=32,mem=134G,node=1,billing=40,gres/gpu=4
|
|
79
|
+
AllocTRES=cpu=64,mem=42K,node=1,billing=40,gres/gpu=4
|
|
80
|
+
"""
|
|
81
|
+
)
|
|
82
|
+
ram = RAM(tracking_mode="slurm")
|
|
83
|
+
ram_size = ram._parse_scontrol(scontrol_str)
|
|
84
|
+
self.assertEqual(ram_size, "42K")
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.3.0"
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
from prometheus_client import push_to_gateway
|
|
4
|
-
from prometheus_client.exposition import basic_auth_handler
|
|
5
|
-
|
|
6
|
-
from codecarbon.prometheus.metric_definitions import (
|
|
7
|
-
cpu_energy_gauge,
|
|
8
|
-
cpu_power_gauge,
|
|
9
|
-
duration_gauge,
|
|
10
|
-
emissions_gauge,
|
|
11
|
-
emissions_rate_gauge,
|
|
12
|
-
energy_consumed_gauge,
|
|
13
|
-
gpu_energy_gauge,
|
|
14
|
-
gpu_power_gauge,
|
|
15
|
-
ram_energy_gauge,
|
|
16
|
-
ram_power_gauge,
|
|
17
|
-
registry,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class Prometheus:
|
|
22
|
-
def __init__(self, prometheus_url):
|
|
23
|
-
self.prometheus_url = prometheus_url
|
|
24
|
-
|
|
25
|
-
def _auth_handler(self, url, method, timeout, headers, data):
|
|
26
|
-
username = os.getenv("PROMETHEUS_USERNAME")
|
|
27
|
-
password = os.getenv("PROMETHEUS_PASSWORD")
|
|
28
|
-
return basic_auth_handler(
|
|
29
|
-
url, method, timeout, headers, data, username, password
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
def add_emission(self, carbon_emission: dict):
|
|
33
|
-
"""
|
|
34
|
-
Send emissions data to push gateway
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
# Save the values of the metrics to the local registry
|
|
38
|
-
duration_gauge.set(int(carbon_emission["duration"]))
|
|
39
|
-
emissions_gauge.set(carbon_emission["emissions"])
|
|
40
|
-
emissions_rate_gauge.set(carbon_emission["emissions_rate"])
|
|
41
|
-
cpu_power_gauge.set(carbon_emission["cpu_power"])
|
|
42
|
-
gpu_power_gauge.set(carbon_emission["gpu_power"])
|
|
43
|
-
ram_power_gauge.set(carbon_emission["ram_power"])
|
|
44
|
-
cpu_energy_gauge.set(carbon_emission["cpu_energy"])
|
|
45
|
-
gpu_energy_gauge.set(carbon_emission["gpu_energy"])
|
|
46
|
-
ram_energy_gauge.set(carbon_emission["ram_energy"])
|
|
47
|
-
energy_consumed_gauge.set(carbon_emission["energy_consumed"])
|
|
48
|
-
|
|
49
|
-
# Send the new metric values
|
|
50
|
-
push_to_gateway(
|
|
51
|
-
self.prometheus_url,
|
|
52
|
-
job="codecarbon",
|
|
53
|
-
registry=registry,
|
|
54
|
-
handler=self._auth_handler,
|
|
55
|
-
)
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import unittest
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
|
|
5
|
-
from codecarbon.external.hardware import RAM
|
|
6
|
-
|
|
7
|
-
# TODO: need help: test multiprocess case
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class TestRAM(unittest.TestCase):
|
|
11
|
-
def test_ram_diff(self):
|
|
12
|
-
ram = RAM(tracking_mode="process")
|
|
13
|
-
|
|
14
|
-
for array_size in [
|
|
15
|
-
# (10, 10), # too small to be noticed
|
|
16
|
-
# (100, 100), # too small to be noticed
|
|
17
|
-
(1000, 1000), # ref for atol
|
|
18
|
-
(10, 1000, 1000),
|
|
19
|
-
(20, 1000, 1000),
|
|
20
|
-
(100, 1000, 1000),
|
|
21
|
-
(200, 1000, 1000),
|
|
22
|
-
(1000, 1000, 1000),
|
|
23
|
-
(2000, 1000, 1000),
|
|
24
|
-
]:
|
|
25
|
-
with self.subTest(array_size=array_size):
|
|
26
|
-
ref_W = ram.total_power().W
|
|
27
|
-
array = np.ones(array_size, dtype=np.int8)
|
|
28
|
-
new_W = ram.total_power().W
|
|
29
|
-
n_gb = array.nbytes / (1024**3)
|
|
30
|
-
n_gb_W = (new_W - ref_W) / ram.power_per_GB
|
|
31
|
-
is_close = np.isclose(n_gb, n_gb_W, atol=1e-3)
|
|
32
|
-
self.assertTrue(
|
|
33
|
-
is_close,
|
|
34
|
-
msg=f"{array_size}, {n_gb}, {n_gb_W}, {is_close}",
|
|
35
|
-
)
|
|
36
|
-
del array
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codecarbon-2.3.0 → codecarbon-2.3.2}/carbonserver/carbonserver/api/routers/organizations.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/data/private_infra/2016/canada_energy_mix.json
RENAMED
|
File without changes
|
|
File without changes
|
{codecarbon-2.3.0 → codecarbon-2.3.2}/codecarbon/data/private_infra/carbon_intensity_per_source.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|