Spaces:
Running
on
Zero
Running
on
Zero
Commit
·
deb7c43
1
Parent(s):
654d664
:wrench: remove codecarbon install, add slightly modified codecarbon pkg to repo
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- codecarbon/__init__.py +13 -0
- codecarbon/_version.py +1 -0
- codecarbon/cli/__init__.py +0 -0
- codecarbon/cli/cli_utils.py +110 -0
- codecarbon/cli/main.py +381 -0
- codecarbon/core/__init__.py +0 -0
- codecarbon/core/api_client.py +362 -0
- codecarbon/core/cloud.py +71 -0
- codecarbon/core/co2_signal.py +62 -0
- codecarbon/core/config.py +115 -0
- codecarbon/core/cpu.py +521 -0
- codecarbon/core/emissions.py +308 -0
- codecarbon/core/gpu.py +305 -0
- codecarbon/core/measure.py +97 -0
- codecarbon/core/powermetrics.py +200 -0
- codecarbon/core/rapl.py +58 -0
- codecarbon/core/resource_tracker.py +230 -0
- codecarbon/core/schemas.py +110 -0
- codecarbon/core/units.py +164 -0
- codecarbon/core/util.py +157 -0
- codecarbon/data/canada_provinces.geojson +0 -0
- codecarbon/data/cloud/impact.csv +41 -0
- codecarbon/data/hardware/cpu_dataset_builder/CPU_Create_Dataset.ipynb +1671 -0
- codecarbon/data/hardware/cpu_dataset_builder/README.md +15 -0
- codecarbon/data/hardware/cpu_dataset_builder/amd_cpu_desktop_dataset.csv +0 -0
- codecarbon/data/hardware/cpu_dataset_builder/amd_cpu_scrapper.py +120 -0
- codecarbon/data/hardware/cpu_dataset_builder/amd_cpu_server_dataset.csv +203 -0
- codecarbon/data/hardware/cpu_dataset_builder/intel_cpu_ark_dataset.csv +0 -0
- codecarbon/data/hardware/cpu_dataset_builder/intel_cpu_scrapper.py +284 -0
- codecarbon/data/hardware/cpu_dataset_builder/merge_scrapped_cpu_power.py +159 -0
- codecarbon/data/hardware/cpu_load_profiling/AMD_EPYC_8024P_8C/compare_cpu_load_and_RAPL-all_cores-AMD_EPYC_8024P_8-Core_Processor-2025-01-14-tasks.csv +1 -0
- codecarbon/data/hardware/cpu_load_profiling/AMD_EPYC_8024P_8C/compare_cpu_load_and_RAPL-all_cores-AMD_EPYC_8024P_8-Core_Processor-2025-01-14.csv +12 -0
- codecarbon/data/hardware/cpu_load_profiling/AMD_EPYC_8024P_8C/compare_cpu_load_and_RAPL-some_cores-AMD_EPYC_8024P_8-Core_Processor-2025-01-14-tasks.csv +1 -0
- codecarbon/data/hardware/cpu_load_profiling/AMD_EPYC_8024P_8C/compare_cpu_load_and_RAPL-some_cores-AMD_EPYC_8024P_8-Core_Processor-2025-01-14.csv +12 -0
- codecarbon/data/hardware/cpu_load_profiling/AMD_Threadripper/compare_cpu_load_and_RAPL-all_cores-AMD_Ryzen_Threadripper_1950X_16-Core_Processor-2025-01-14.csv +12 -0
- codecarbon/data/hardware/cpu_load_profiling/AMD_Threadripper/compare_cpu_load_and_RAPL-some_cores-AMD_Ryzen_Threadripper_1950X_16-Core_Processor-2025-01-14.csv +12 -0
- codecarbon/data/hardware/cpu_load_profiling/E3-1240/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14-tasks.csv +1 -0
- codecarbon/data/hardware/cpu_load_profiling/E3-1240/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14.csv +12 -0
- codecarbon/data/hardware/cpu_load_profiling/E3-1240/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14-tasks.csv +1 -0
- codecarbon/data/hardware/cpu_load_profiling/E3-1240/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14.csv +10 -0
- codecarbon/data/hardware/cpu_load_profiling/E5-1240/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14-tasks.csv +1 -0
- codecarbon/data/hardware/cpu_load_profiling/E5-1240/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14.csv +12 -0
- codecarbon/data/hardware/cpu_load_profiling/E5-1240/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14-tasks.csv +1 -0
- codecarbon/data/hardware/cpu_load_profiling/E5-1240/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14.csv +10 -0
- codecarbon/data/hardware/cpu_load_profiling/E5-2620/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E5-2620_v3_@_2.40GHz-2025-01-14-tasks.csv +1 -0
- codecarbon/data/hardware/cpu_load_profiling/E5-2620/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E5-2620_v3_@_2.40GHz-2025-01-14.csv +12 -0
- codecarbon/data/hardware/cpu_load_profiling/E5-2620/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E5-2620_v3_@_2.40GHz-2025-01-14-tasks.csv +1 -0
- codecarbon/data/hardware/cpu_load_profiling/E5-2620/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E5-2620_v3_@_2.40GHz-2025-01-14.csv +12 -0
- codecarbon/data/hardware/cpu_power.csv +0 -0
- codecarbon/data/private_infra/2016/canada_energy_mix.json +171 -0
codecarbon/__init__.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
The Carbon Tracker module. The following objects/decorators belong to the Public API
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from ._version import __version__ # noqa
|
| 6 |
+
from .emissions_tracker import (
|
| 7 |
+
EmissionsTracker,
|
| 8 |
+
OfflineEmissionsTracker,
|
| 9 |
+
track_emissions,
|
| 10 |
+
)
|
| 11 |
+
|
| 12 |
+
__all__ = ["EmissionsTracker", "OfflineEmissionsTracker", "track_emissions"]
|
| 13 |
+
__app_name__ = "codecarbon"
|
codecarbon/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
__version__ = "3.0.2"
|
codecarbon/cli/__init__.py
ADDED
|
File without changes
|
codecarbon/cli/cli_utils.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import configparser
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from typing import Optional
|
| 4 |
+
|
| 5 |
+
import typer
|
| 6 |
+
from rich.prompt import Confirm
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def get_config(path: Optional[Path] = None):
|
| 10 |
+
p = path or Path.cwd().resolve() / ".codecarbon.config"
|
| 11 |
+
|
| 12 |
+
if p.exists():
|
| 13 |
+
config = configparser.ConfigParser()
|
| 14 |
+
config.read(str(p))
|
| 15 |
+
if "codecarbon" in config.sections():
|
| 16 |
+
d = dict(config["codecarbon"])
|
| 17 |
+
return d
|
| 18 |
+
|
| 19 |
+
else:
|
| 20 |
+
raise FileNotFoundError(
|
| 21 |
+
"No .codecarbon.config file found in the current directory."
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def get_api_endpoint(path: Optional[Path] = None):
|
| 26 |
+
p = path or Path.cwd().resolve() / ".codecarbon.config"
|
| 27 |
+
if p.exists():
|
| 28 |
+
config = configparser.ConfigParser()
|
| 29 |
+
config.read(str(p))
|
| 30 |
+
if "codecarbon" in config.sections():
|
| 31 |
+
d = dict(config["codecarbon"])
|
| 32 |
+
if "api_endpoint" in d:
|
| 33 |
+
return d["api_endpoint"]
|
| 34 |
+
else:
|
| 35 |
+
with p.open("a") as f:
|
| 36 |
+
f.write("api_endpoint=https://api.codecarbon.io\n")
|
| 37 |
+
return "https://api.codecarbon.io"
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def get_existing_local_exp_id(path: Optional[Path] = None):
|
| 41 |
+
p = path or Path.cwd().resolve() / ".codecarbon.config"
|
| 42 |
+
if p.exists():
|
| 43 |
+
existing_path = p
|
| 44 |
+
else:
|
| 45 |
+
existing_path = Path("~/.codecarbon.config").expanduser()
|
| 46 |
+
return _get_local_exp_id(existing_path)
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
def _get_local_exp_id(p: Optional[Path] = None):
|
| 50 |
+
config = configparser.ConfigParser()
|
| 51 |
+
config.read(str(p))
|
| 52 |
+
if "codecarbon" in config.sections():
|
| 53 |
+
d = dict(config["codecarbon"])
|
| 54 |
+
if "experiment_id" in d:
|
| 55 |
+
return d["experiment_id"]
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def write_local_exp_id(exp_id, path: Optional[Path] = None):
|
| 59 |
+
p = path or Path.cwd().resolve() / ".codecarbon.config"
|
| 60 |
+
|
| 61 |
+
config = configparser.ConfigParser()
|
| 62 |
+
if p.exists():
|
| 63 |
+
config.read(str(p))
|
| 64 |
+
if "codecarbon" not in config.sections():
|
| 65 |
+
config.add_section("codecarbon")
|
| 66 |
+
|
| 67 |
+
config["codecarbon"]["experiment_id"] = exp_id
|
| 68 |
+
|
| 69 |
+
with p.open("w") as f:
|
| 70 |
+
config.write(f)
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def overwrite_local_config(config_name, value, path: Optional[Path] = None):
|
| 74 |
+
p = path or Path.cwd().resolve() / ".codecarbon.config"
|
| 75 |
+
|
| 76 |
+
config = configparser.ConfigParser()
|
| 77 |
+
if p.exists():
|
| 78 |
+
config.read(str(p))
|
| 79 |
+
if "codecarbon" not in config.sections():
|
| 80 |
+
config.add_section("codecarbon")
|
| 81 |
+
|
| 82 |
+
config["codecarbon"][config_name] = value
|
| 83 |
+
with p.open("w") as f:
|
| 84 |
+
config.write(f)
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def create_new_config_file():
|
| 88 |
+
typer.echo("Creating new config file")
|
| 89 |
+
file_path = typer.prompt(
|
| 90 |
+
"Where do you want to put your config file ?",
|
| 91 |
+
type=str,
|
| 92 |
+
default="~/.codecarbon.config",
|
| 93 |
+
)
|
| 94 |
+
if file_path[0] == "~":
|
| 95 |
+
file_path = Path.home() / file_path[2:]
|
| 96 |
+
else:
|
| 97 |
+
file_path = Path(file_path)
|
| 98 |
+
|
| 99 |
+
if not file_path.parent.exists():
|
| 100 |
+
create = Confirm.ask(
|
| 101 |
+
"Parent folder does not exist do you want to create it (and parents) ?"
|
| 102 |
+
)
|
| 103 |
+
if create:
|
| 104 |
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
| 105 |
+
|
| 106 |
+
file_path.touch()
|
| 107 |
+
with open(file_path, "w") as f:
|
| 108 |
+
f.write("[codecarbon]\n")
|
| 109 |
+
typer.echo(f"Config file created at {file_path}")
|
| 110 |
+
return file_path
|
codecarbon/cli/main.py
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import sys
|
| 3 |
+
import time
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
from typing import Optional
|
| 6 |
+
|
| 7 |
+
import questionary
|
| 8 |
+
import requests
|
| 9 |
+
import typer
|
| 10 |
+
from fief_client import Fief
|
| 11 |
+
from fief_client.integrations.cli import FiefAuth
|
| 12 |
+
from rich import print
|
| 13 |
+
from rich.prompt import Confirm
|
| 14 |
+
from typing_extensions import Annotated
|
| 15 |
+
|
| 16 |
+
from codecarbon import __app_name__, __version__
|
| 17 |
+
from codecarbon.cli.cli_utils import (
|
| 18 |
+
create_new_config_file,
|
| 19 |
+
get_api_endpoint,
|
| 20 |
+
get_config,
|
| 21 |
+
get_existing_local_exp_id,
|
| 22 |
+
overwrite_local_config,
|
| 23 |
+
)
|
| 24 |
+
from codecarbon.core.api_client import ApiClient, get_datetime_with_timezone
|
| 25 |
+
from codecarbon.core.schemas import ExperimentCreate, OrganizationCreate, ProjectCreate
|
| 26 |
+
from codecarbon.emissions_tracker import EmissionsTracker
|
| 27 |
+
|
| 28 |
+
AUTH_CLIENT_ID = os.environ.get(
|
| 29 |
+
"AUTH_CLIENT_ID",
|
| 30 |
+
"jsUPWIcUECQFE_ouanUuVhXx52TTjEVcVNNtNGeyAtU",
|
| 31 |
+
)
|
| 32 |
+
AUTH_SERVER_URL = os.environ.get(
|
| 33 |
+
"AUTH_SERVER_URL", "https://auth.codecarbon.io/codecarbon"
|
| 34 |
+
)
|
| 35 |
+
API_URL = os.environ.get("API_URL", "https://dashboard.codecarbon.io/api")
|
| 36 |
+
|
| 37 |
+
DEFAULT_PROJECT_ID = "e60afa92-17b7-4720-91a0-1ae91e409ba1"
|
| 38 |
+
DEFAULT_ORGANIzATION_ID = "e60afa92-17b7-4720-91a0-1ae91e409ba1"
|
| 39 |
+
|
| 40 |
+
codecarbon = typer.Typer(no_args_is_help=True)
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def _version_callback(value: bool) -> None:
|
| 44 |
+
if value:
|
| 45 |
+
print(f"{__app_name__} v{__version__}")
|
| 46 |
+
raise typer.Exit()
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
@codecarbon.callback()
|
| 50 |
+
def main(
|
| 51 |
+
version: Optional[bool] = typer.Option(
|
| 52 |
+
None,
|
| 53 |
+
"--version",
|
| 54 |
+
"-v",
|
| 55 |
+
help="Show the application's version and exit.",
|
| 56 |
+
callback=_version_callback,
|
| 57 |
+
is_eager=True,
|
| 58 |
+
),
|
| 59 |
+
) -> None:
|
| 60 |
+
return
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def show_config(path: Path = Path("./.codecarbon.config")) -> None:
|
| 64 |
+
d = get_config(path)
|
| 65 |
+
api_endpoint = get_api_endpoint(path)
|
| 66 |
+
api = ApiClient(endpoint_url=api_endpoint)
|
| 67 |
+
api.set_access_token(_get_access_token())
|
| 68 |
+
print("Current configuration : \n")
|
| 69 |
+
print("Config file content : ")
|
| 70 |
+
print(d)
|
| 71 |
+
try:
|
| 72 |
+
if "organization_id" not in d:
|
| 73 |
+
print(
|
| 74 |
+
"No organization_id in config, follow setup instruction to complete your configuration file!",
|
| 75 |
+
)
|
| 76 |
+
else:
|
| 77 |
+
org = api.get_organization(d["organization_id"])
|
| 78 |
+
|
| 79 |
+
if "project_id" not in d:
|
| 80 |
+
print(
|
| 81 |
+
"No project_id in config, follow setup instruction to complete your configuration file!",
|
| 82 |
+
)
|
| 83 |
+
else:
|
| 84 |
+
project = api.get_project(d["project_id"])
|
| 85 |
+
if "experiment_id" not in d:
|
| 86 |
+
print(
|
| 87 |
+
"No experiment_id in config, follow setup instruction to complete your configuration file!",
|
| 88 |
+
)
|
| 89 |
+
else:
|
| 90 |
+
experiment = api.get_experiment(d["experiment_id"])
|
| 91 |
+
print("\nExperiment :")
|
| 92 |
+
print(experiment)
|
| 93 |
+
print("\nProject :")
|
| 94 |
+
print(project)
|
| 95 |
+
print("\nOrganization :")
|
| 96 |
+
print(org)
|
| 97 |
+
except Exception as e:
|
| 98 |
+
raise ValueError(
|
| 99 |
+
f"Your configuration is invalid, please verify your configuration file at {path}. To start from scratch, run `codecarbon config` and overwrite your configuration file. (error: {e})"
|
| 100 |
+
)
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
def get_fief_auth():
|
| 104 |
+
fief = Fief(AUTH_SERVER_URL, AUTH_CLIENT_ID)
|
| 105 |
+
fief_auth = FiefAuth(fief, "./credentials.json")
|
| 106 |
+
return fief_auth
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def _get_access_token():
|
| 110 |
+
try:
|
| 111 |
+
access_token_info = get_fief_auth().access_token_info()
|
| 112 |
+
access_token = access_token_info["access_token"]
|
| 113 |
+
return access_token
|
| 114 |
+
except Exception as e:
|
| 115 |
+
raise ValueError(
|
| 116 |
+
f"Not able to retrieve the access token, please run `codecarbon login` first! (error: {e})"
|
| 117 |
+
)
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def _get_id_token():
|
| 121 |
+
id_token = get_fief_auth()._tokens["id_token"]
|
| 122 |
+
return id_token
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
@codecarbon.command(
|
| 126 |
+
"test-api", short_help="Make an authenticated GET request to an API endpoint"
|
| 127 |
+
)
|
| 128 |
+
def api_get():
|
| 129 |
+
"""
|
| 130 |
+
ex: test-api
|
| 131 |
+
"""
|
| 132 |
+
api = ApiClient(endpoint_url=API_URL) # TODO: get endpoint from config
|
| 133 |
+
api.set_access_token(_get_access_token())
|
| 134 |
+
organizations = api.get_list_organizations()
|
| 135 |
+
print(organizations)
|
| 136 |
+
|
| 137 |
+
|
| 138 |
+
@codecarbon.command("login", short_help="Login to CodeCarbon")
|
| 139 |
+
def login():
|
| 140 |
+
get_fief_auth().authorize()
|
| 141 |
+
api = ApiClient(endpoint_url=API_URL) # TODO: get endpoint from config
|
| 142 |
+
id_token = _get_id_token()
|
| 143 |
+
api.set_access_token(id_token)
|
| 144 |
+
api.check_auth()
|
| 145 |
+
|
| 146 |
+
|
| 147 |
+
def get_api_key(project_id: str):
|
| 148 |
+
req = requests.post(
|
| 149 |
+
f"{API_URL}/projects/{project_id}/api-tokens",
|
| 150 |
+
json={
|
| 151 |
+
"project_id": project_id,
|
| 152 |
+
"name": "api token",
|
| 153 |
+
"x_token": "???",
|
| 154 |
+
},
|
| 155 |
+
headers={"Authorization": f"Bearer {_get_access_token()}"},
|
| 156 |
+
)
|
| 157 |
+
api_key = req.json()["token"]
|
| 158 |
+
return api_key
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
@codecarbon.command("get-token", short_help="Get project token")
|
| 162 |
+
def get_token(project_id: str):
|
| 163 |
+
# api = ApiClient(endpoint_url=API_URL) # TODO: get endpoint from config
|
| 164 |
+
# api.set_access_token(_get_access_token())
|
| 165 |
+
token = get_api_key(project_id)
|
| 166 |
+
print("Your token: " + token)
|
| 167 |
+
print("Add it to the api_key field in your configuration file")
|
| 168 |
+
|
| 169 |
+
|
| 170 |
+
@codecarbon.command("config", short_help="Generate or show config")
|
| 171 |
+
def config():
|
| 172 |
+
"""
|
| 173 |
+
Initialize CodeCarbon, this will prompt you for configuration of Organisation/Team/Project/Experiment.
|
| 174 |
+
"""
|
| 175 |
+
|
| 176 |
+
print("Welcome to CodeCarbon configuration wizard")
|
| 177 |
+
home = Path.home()
|
| 178 |
+
global_path = (home / ".codecarbon.config").expanduser().resolve()
|
| 179 |
+
|
| 180 |
+
if global_path.exists():
|
| 181 |
+
print("Existing global config file found :")
|
| 182 |
+
show_config(global_path)
|
| 183 |
+
|
| 184 |
+
use_config = questionary_prompt(
|
| 185 |
+
"Use existing global ~/.codecarbon.config to configure or create a new file somewhere else ?",
|
| 186 |
+
["~/.codecarbon.config", "Create New Config"],
|
| 187 |
+
default="~/.codecarbon.config",
|
| 188 |
+
)
|
| 189 |
+
|
| 190 |
+
if use_config == "~/.codecarbon.config":
|
| 191 |
+
modify = Confirm.ask("Do you want to modify the existing config file ?")
|
| 192 |
+
if modify:
|
| 193 |
+
print(f"Modifying existing config file {global_path}:")
|
| 194 |
+
file_path = global_path
|
| 195 |
+
else:
|
| 196 |
+
print(f"Using already existing global config file {global_path}")
|
| 197 |
+
|
| 198 |
+
return
|
| 199 |
+
else:
|
| 200 |
+
file_path = create_new_config_file()
|
| 201 |
+
else:
|
| 202 |
+
file_path = create_new_config_file()
|
| 203 |
+
|
| 204 |
+
api_endpoint = get_api_endpoint(file_path)
|
| 205 |
+
api_endpoint = typer.prompt(
|
| 206 |
+
f"Current API endpoint is {api_endpoint}. Press enter to continue or input other url",
|
| 207 |
+
type=str,
|
| 208 |
+
default=api_endpoint,
|
| 209 |
+
)
|
| 210 |
+
overwrite_local_config("api_endpoint", api_endpoint, path=file_path)
|
| 211 |
+
api = ApiClient(endpoint_url=api_endpoint)
|
| 212 |
+
api.set_access_token(_get_access_token())
|
| 213 |
+
organizations = api.get_list_organizations()
|
| 214 |
+
org = questionary_prompt(
|
| 215 |
+
"Pick existing organization from list or Create new organization ?",
|
| 216 |
+
[org["name"] for org in organizations] + ["Create New Organization"],
|
| 217 |
+
default="Create New Organization",
|
| 218 |
+
)
|
| 219 |
+
|
| 220 |
+
if org == "Create New Organization":
|
| 221 |
+
org_name = typer.prompt("Organization name", default="Code Carbon user test")
|
| 222 |
+
org_description = typer.prompt(
|
| 223 |
+
"Organization description", default="Code Carbon user test"
|
| 224 |
+
)
|
| 225 |
+
|
| 226 |
+
organization_create = OrganizationCreate(
|
| 227 |
+
name=org_name,
|
| 228 |
+
description=org_description,
|
| 229 |
+
)
|
| 230 |
+
organization = api.create_organization(organization=organization_create)
|
| 231 |
+
if organization is None:
|
| 232 |
+
print("Error creating organization")
|
| 233 |
+
return
|
| 234 |
+
print(f"Created organization : {organization}")
|
| 235 |
+
else:
|
| 236 |
+
organization = [orga for orga in organizations if orga["name"] == org][0]
|
| 237 |
+
org_id = organization["id"]
|
| 238 |
+
overwrite_local_config("organization_id", org_id, path=file_path)
|
| 239 |
+
|
| 240 |
+
projects = api.list_projects_from_organization(org_id)
|
| 241 |
+
project_names = [project["name"] for project in projects] if projects else []
|
| 242 |
+
project = questionary_prompt(
|
| 243 |
+
"Pick existing project from list or Create new project ?",
|
| 244 |
+
project_names + ["Create New Project"],
|
| 245 |
+
default="Create New Project",
|
| 246 |
+
)
|
| 247 |
+
if project == "Create New Project":
|
| 248 |
+
project_name = typer.prompt("Project name", default="Code Carbon user test")
|
| 249 |
+
project_description = typer.prompt(
|
| 250 |
+
"Project description", default="Code Carbon user test"
|
| 251 |
+
)
|
| 252 |
+
project_create = ProjectCreate(
|
| 253 |
+
name=project_name,
|
| 254 |
+
description=project_description,
|
| 255 |
+
organization_id=org_id,
|
| 256 |
+
)
|
| 257 |
+
project = api.create_project(project=project_create)
|
| 258 |
+
print(f"Created project : {project}")
|
| 259 |
+
else:
|
| 260 |
+
project = [p for p in projects if p["name"] == project][0]
|
| 261 |
+
project_id = project["id"]
|
| 262 |
+
overwrite_local_config("project_id", project_id, path=file_path)
|
| 263 |
+
|
| 264 |
+
experiments = api.list_experiments_from_project(project_id)
|
| 265 |
+
experiments_names = (
|
| 266 |
+
[experiment["name"] for experiment in experiments] if experiments else []
|
| 267 |
+
)
|
| 268 |
+
|
| 269 |
+
experiment = questionary_prompt(
|
| 270 |
+
"Pick existing experiment from list or Create new experiment ?",
|
| 271 |
+
experiments_names + ["Create New Experiment"],
|
| 272 |
+
default="Create New Experiment",
|
| 273 |
+
)
|
| 274 |
+
if experiment == "Create New Experiment":
|
| 275 |
+
print("Creating new experiment")
|
| 276 |
+
exp_name = typer.prompt("Experiment name :", default="Code Carbon user test")
|
| 277 |
+
exp_description = typer.prompt(
|
| 278 |
+
"Experiment description :",
|
| 279 |
+
default="Code Carbon user test ",
|
| 280 |
+
)
|
| 281 |
+
|
| 282 |
+
exp_on_cloud = Confirm.ask("Is this experiment running on the cloud ?")
|
| 283 |
+
if exp_on_cloud is True:
|
| 284 |
+
cloud_provider = typer.prompt(
|
| 285 |
+
"Cloud provider (AWS, GCP, Azure, ...)", default="AWS"
|
| 286 |
+
)
|
| 287 |
+
cloud_region = typer.prompt(
|
| 288 |
+
"Cloud region (eu-west-1, us-east-1, ...)", default="eu-west-1"
|
| 289 |
+
)
|
| 290 |
+
else:
|
| 291 |
+
cloud_provider = None
|
| 292 |
+
cloud_region = None
|
| 293 |
+
country_name = typer.prompt("Country name :", default="Auto")
|
| 294 |
+
country_iso_code = typer.prompt("Country ISO code :", default="Auto")
|
| 295 |
+
region = typer.prompt("Region :", default="Auto")
|
| 296 |
+
if country_name == "Auto":
|
| 297 |
+
country_name = None
|
| 298 |
+
if country_iso_code == "Auto":
|
| 299 |
+
country_iso_code = None
|
| 300 |
+
if region == "Auto":
|
| 301 |
+
region = None
|
| 302 |
+
experiment_create = ExperimentCreate(
|
| 303 |
+
timestamp=get_datetime_with_timezone(),
|
| 304 |
+
name=exp_name,
|
| 305 |
+
description=exp_description,
|
| 306 |
+
on_cloud=exp_on_cloud,
|
| 307 |
+
project_id=project["id"],
|
| 308 |
+
country_name=country_name,
|
| 309 |
+
country_iso_code=country_iso_code,
|
| 310 |
+
region=region,
|
| 311 |
+
cloud_provider=cloud_provider,
|
| 312 |
+
cloud_region=cloud_region,
|
| 313 |
+
)
|
| 314 |
+
experiment = api.add_experiment(experiment=experiment_create)
|
| 315 |
+
|
| 316 |
+
else:
|
| 317 |
+
experiment = [e for e in experiments if e["name"] == experiment][0]
|
| 318 |
+
|
| 319 |
+
overwrite_local_config("experiment_id", experiment["id"], path=file_path)
|
| 320 |
+
api_key = get_api_key(project_id)
|
| 321 |
+
overwrite_local_config("api_key", api_key, path=file_path)
|
| 322 |
+
show_config(file_path)
|
| 323 |
+
print(
|
| 324 |
+
"Consult [link=https://mlco2.github.io/codecarbon/usage.html#configuration]configuration documentation[/link] for more configuration options"
|
| 325 |
+
)
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
@codecarbon.command("monitor", short_help="Monitor your machine's carbon emissions.")
|
| 329 |
+
def monitor(
|
| 330 |
+
measure_power_secs: Annotated[
|
| 331 |
+
int, typer.Argument(help="Interval between two measures.")
|
| 332 |
+
] = 10,
|
| 333 |
+
api_call_interval: Annotated[
|
| 334 |
+
int, typer.Argument(help="Number of measures between API calls.")
|
| 335 |
+
] = 30,
|
| 336 |
+
api: Annotated[
|
| 337 |
+
bool, typer.Option(help="Choose to call Code Carbon API or not")
|
| 338 |
+
] = True,
|
| 339 |
+
):
|
| 340 |
+
"""Monitor your machine's carbon emissions.
|
| 341 |
+
|
| 342 |
+
Args:
|
| 343 |
+
measure_power_secs (Annotated[int, typer.Argument, optional): Interval between two measures. Defaults to 10.
|
| 344 |
+
api_call_interval (Annotated[int, typer.Argument, optional): Number of measures before calling API. Defaults to 30.
|
| 345 |
+
api (Annotated[bool, typer.Option, optional): Choose to call Code Carbon API or not. Defaults to True.
|
| 346 |
+
"""
|
| 347 |
+
experiment_id = get_existing_local_exp_id()
|
| 348 |
+
if api:
|
| 349 |
+
if experiment_id is None:
|
| 350 |
+
print(
|
| 351 |
+
"ERROR: No experiment id, call 'codecarbon config' first.",
|
| 352 |
+
file=sys.stderr,
|
| 353 |
+
)
|
| 354 |
+
print("CodeCarbon is going in an infinite loop to monitor this machine.")
|
| 355 |
+
with EmissionsTracker(
|
| 356 |
+
measure_power_secs=measure_power_secs,
|
| 357 |
+
api_call_interval=api_call_interval,
|
| 358 |
+
save_to_api=api,
|
| 359 |
+
) as tracker:
|
| 360 |
+
# Infinite loop
|
| 361 |
+
while True:
|
| 362 |
+
if (
|
| 363 |
+
hasattr(tracker, "_another_instance_already_running")
|
| 364 |
+
and tracker._another_instance_already_running
|
| 365 |
+
):
|
| 366 |
+
print("Another instance of CodeCarbon is already running. Exiting.")
|
| 367 |
+
break
|
| 368 |
+
time.sleep(300)
|
| 369 |
+
|
| 370 |
+
|
| 371 |
+
def questionary_prompt(prompt, list_options, default):
|
| 372 |
+
value = questionary.select(
|
| 373 |
+
prompt,
|
| 374 |
+
list_options,
|
| 375 |
+
default,
|
| 376 |
+
).ask()
|
| 377 |
+
return value
|
| 378 |
+
|
| 379 |
+
|
| 380 |
+
if __name__ == "__main__":
|
| 381 |
+
codecarbon()
|
codecarbon/core/__init__.py
ADDED
|
File without changes
|
codecarbon/core/api_client.py
ADDED
|
@@ -0,0 +1,362 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
|
| 3 |
+
Based on https://kernelpanic.io/the-modern-way-to-call-apis-in-python
|
| 4 |
+
|
| 5 |
+
TODO : use async call to API
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
# from httpx import AsyncClient
|
| 9 |
+
import dataclasses
|
| 10 |
+
import json
|
| 11 |
+
from datetime import timedelta, tzinfo
|
| 12 |
+
|
| 13 |
+
import arrow
|
| 14 |
+
import requests
|
| 15 |
+
|
| 16 |
+
from codecarbon.core.schemas import (
|
| 17 |
+
EmissionCreate,
|
| 18 |
+
ExperimentCreate,
|
| 19 |
+
OrganizationCreate,
|
| 20 |
+
ProjectCreate,
|
| 21 |
+
RunCreate,
|
| 22 |
+
)
|
| 23 |
+
from codecarbon.external.logger import logger
|
| 24 |
+
|
| 25 |
+
# from codecarbon.output import EmissionsData
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def get_datetime_with_timezone():
|
| 29 |
+
timestamp = str(arrow.now().isoformat())
|
| 30 |
+
return timestamp
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
class ApiClient: # (AsyncClient)
|
| 34 |
+
"""
|
| 35 |
+
This class call the Code Carbon API
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
run_id = None
|
| 39 |
+
|
| 40 |
+
def __init__(
|
| 41 |
+
self,
|
| 42 |
+
endpoint_url="https://api.codecarbon.io",
|
| 43 |
+
experiment_id=None,
|
| 44 |
+
api_key=None,
|
| 45 |
+
access_token=None,
|
| 46 |
+
conf=None,
|
| 47 |
+
create_run_automatically=True,
|
| 48 |
+
):
|
| 49 |
+
"""
|
| 50 |
+
:endpoint_url: URL of the API endpoint
|
| 51 |
+
:experiment_id: ID of the experiment
|
| 52 |
+
:api_key: Code Carbon API_KEY
|
| 53 |
+
:access_token: Code Carbon API access token
|
| 54 |
+
:conf: Metadata of the experiment
|
| 55 |
+
:create_run_automatically: If False, do not create a run. To use API in read only mode.
|
| 56 |
+
"""
|
| 57 |
+
# super().__init__(base_url=endpoint_url) # (AsyncClient)
|
| 58 |
+
self.url = endpoint_url
|
| 59 |
+
self.experiment_id = experiment_id
|
| 60 |
+
self.api_key = api_key
|
| 61 |
+
self.conf = conf
|
| 62 |
+
self.access_token = access_token
|
| 63 |
+
if self.experiment_id is not None and create_run_automatically:
|
| 64 |
+
self._create_run(self.experiment_id)
|
| 65 |
+
|
| 66 |
+
def _get_headers(self):
|
| 67 |
+
headers = {"Content-Type": "application/json"}
|
| 68 |
+
if self.api_key:
|
| 69 |
+
# set the x-api-token header
|
| 70 |
+
headers["x-api-token"] = self.api_key
|
| 71 |
+
elif self.access_token:
|
| 72 |
+
headers["Authorization"] = f"Bearer {self.access_token}"
|
| 73 |
+
return headers
|
| 74 |
+
|
| 75 |
+
def set_access_token(self, token: str):
|
| 76 |
+
"""This method sets the access token to be used for the API.
|
| 77 |
+
Args:
|
| 78 |
+
token (str): access token to be used for the API
|
| 79 |
+
"""
|
| 80 |
+
self.access_token = token
|
| 81 |
+
|
| 82 |
+
def check_auth(self):
|
| 83 |
+
"""
|
| 84 |
+
Check API access to user account
|
| 85 |
+
"""
|
| 86 |
+
url = self.url + "/auth/check"
|
| 87 |
+
headers = self._get_headers()
|
| 88 |
+
r = requests.get(url=url, timeout=2, headers=headers)
|
| 89 |
+
if r.status_code != 200:
|
| 90 |
+
self._log_error(url, {}, r)
|
| 91 |
+
return None
|
| 92 |
+
return r.json()
|
| 93 |
+
|
| 94 |
+
def get_list_organizations(self):
|
| 95 |
+
"""
|
| 96 |
+
List all organizations
|
| 97 |
+
"""
|
| 98 |
+
url = self.url + "/organizations"
|
| 99 |
+
headers = self._get_headers()
|
| 100 |
+
r = requests.get(url=url, timeout=2, headers=headers)
|
| 101 |
+
if r.status_code != 200:
|
| 102 |
+
self._log_error(url, {}, r)
|
| 103 |
+
return None
|
| 104 |
+
return r.json()
|
| 105 |
+
|
| 106 |
+
def check_organization_exists(self, organization_name: str):
|
| 107 |
+
"""
|
| 108 |
+
Check if an organization exists
|
| 109 |
+
"""
|
| 110 |
+
organizations = self.get_list_organizations()
|
| 111 |
+
if organizations is None:
|
| 112 |
+
return False
|
| 113 |
+
for organization in organizations:
|
| 114 |
+
if organization["name"] == organization_name:
|
| 115 |
+
return organization
|
| 116 |
+
return False
|
| 117 |
+
|
| 118 |
+
def create_organization(self, organization: OrganizationCreate):
|
| 119 |
+
"""
|
| 120 |
+
Create an organization
|
| 121 |
+
"""
|
| 122 |
+
payload = dataclasses.asdict(organization)
|
| 123 |
+
url = self.url + "/organizations"
|
| 124 |
+
if organization := self.check_organization_exists(organization.name):
|
| 125 |
+
logger.warning(
|
| 126 |
+
f"Organization {organization['name']} already exists. Skipping creation."
|
| 127 |
+
)
|
| 128 |
+
return organization
|
| 129 |
+
else:
|
| 130 |
+
headers = self._get_headers()
|
| 131 |
+
r = requests.post(url=url, json=payload, timeout=2, headers=headers)
|
| 132 |
+
if r.status_code != 201:
|
| 133 |
+
self._log_error(url, payload, r)
|
| 134 |
+
return None
|
| 135 |
+
return r.json()
|
| 136 |
+
|
| 137 |
+
def get_organization(self, organization_id):
|
| 138 |
+
"""
|
| 139 |
+
Get an organization
|
| 140 |
+
"""
|
| 141 |
+
headers = self._get_headers()
|
| 142 |
+
url = self.url + "/organizations/" + organization_id
|
| 143 |
+
r = requests.get(url=url, timeout=2, headers=headers)
|
| 144 |
+
if r.status_code != 200:
|
| 145 |
+
self._log_error(url, {}, r)
|
| 146 |
+
return None
|
| 147 |
+
return r.json()
|
| 148 |
+
|
| 149 |
+
def update_organization(self, organization: OrganizationCreate):
|
| 150 |
+
"""
|
| 151 |
+
Update an organization
|
| 152 |
+
"""
|
| 153 |
+
payload = dataclasses.asdict(organization)
|
| 154 |
+
headers = self._get_headers()
|
| 155 |
+
url = self.url + "/organizations/" + organization.id
|
| 156 |
+
r = requests.patch(url=url, json=payload, timeout=2, headers=headers)
|
| 157 |
+
if r.status_code != 200:
|
| 158 |
+
self._log_error(url, payload, r)
|
| 159 |
+
return None
|
| 160 |
+
return r.json()
|
| 161 |
+
|
| 162 |
+
def list_projects_from_organization(self, organization_id):
|
| 163 |
+
"""
|
| 164 |
+
List all projects
|
| 165 |
+
"""
|
| 166 |
+
url = self.url + "/organizations/" + organization_id + "/projects"
|
| 167 |
+
headers = self._get_headers()
|
| 168 |
+
r = requests.get(url=url, timeout=2, headers=headers)
|
| 169 |
+
if r.status_code != 200:
|
| 170 |
+
self._log_error(url, {}, r)
|
| 171 |
+
return None
|
| 172 |
+
return r.json()
|
| 173 |
+
|
| 174 |
+
def create_project(self, project: ProjectCreate):
|
| 175 |
+
"""
|
| 176 |
+
Create a project
|
| 177 |
+
"""
|
| 178 |
+
payload = dataclasses.asdict(project)
|
| 179 |
+
url = self.url + "/projects"
|
| 180 |
+
headers = self._get_headers()
|
| 181 |
+
r = requests.post(url=url, json=payload, timeout=2, headers=headers)
|
| 182 |
+
if r.status_code != 201:
|
| 183 |
+
self._log_error(url, payload, r)
|
| 184 |
+
return None
|
| 185 |
+
return r.json()
|
| 186 |
+
|
| 187 |
+
def get_project(self, project_id):
|
| 188 |
+
"""
|
| 189 |
+
Get a project
|
| 190 |
+
"""
|
| 191 |
+
url = self.url + "/projects/" + project_id
|
| 192 |
+
headers = self._get_headers()
|
| 193 |
+
r = requests.get(url=url, timeout=2, headers=headers)
|
| 194 |
+
if r.status_code != 200:
|
| 195 |
+
self._log_error(url, {}, r)
|
| 196 |
+
return None
|
| 197 |
+
return r.json()
|
| 198 |
+
|
| 199 |
+
def add_emission(self, carbon_emission: dict):
|
| 200 |
+
assert self.experiment_id is not None
|
| 201 |
+
if self.run_id is None:
|
| 202 |
+
logger.warning(
|
| 203 |
+
"ApiClient.add_emission() need a run_id : the initial call may "
|
| 204 |
+
+ "have failed. Retrying..."
|
| 205 |
+
)
|
| 206 |
+
self._create_run(self.experiment_id)
|
| 207 |
+
if self.run_id is None:
|
| 208 |
+
logger.error(
|
| 209 |
+
"ApiClient.add_emission still no run_id, aborting for this time !"
|
| 210 |
+
)
|
| 211 |
+
return False
|
| 212 |
+
if carbon_emission["duration"] < 1:
|
| 213 |
+
logger.warning(
|
| 214 |
+
"ApiClient : emissions not sent because of a duration smaller than 1."
|
| 215 |
+
)
|
| 216 |
+
return False
|
| 217 |
+
emission = EmissionCreate(
|
| 218 |
+
timestamp=get_datetime_with_timezone(),
|
| 219 |
+
run_id=self.run_id,
|
| 220 |
+
duration=int(carbon_emission["duration"]),
|
| 221 |
+
emissions_sum=carbon_emission["emissions"],
|
| 222 |
+
emissions_rate=carbon_emission["emissions_rate"],
|
| 223 |
+
cpu_power=carbon_emission["cpu_power"],
|
| 224 |
+
gpu_power=carbon_emission["gpu_power"],
|
| 225 |
+
ram_power=carbon_emission["ram_power"],
|
| 226 |
+
cpu_energy=carbon_emission["cpu_energy"],
|
| 227 |
+
gpu_energy=carbon_emission["gpu_energy"],
|
| 228 |
+
ram_energy=carbon_emission["ram_energy"],
|
| 229 |
+
energy_consumed=carbon_emission["energy_consumed"],
|
| 230 |
+
)
|
| 231 |
+
try:
|
| 232 |
+
payload = dataclasses.asdict(emission)
|
| 233 |
+
url = self.url + "/emissions"
|
| 234 |
+
headers = self._get_headers()
|
| 235 |
+
r = requests.post(url=url, json=payload, timeout=2, headers=headers)
|
| 236 |
+
if r.status_code != 201:
|
| 237 |
+
self._log_error(url, payload, r)
|
| 238 |
+
return False
|
| 239 |
+
logger.debug(f"ApiClient - Successful upload emission {payload} to {url}")
|
| 240 |
+
except Exception as e:
|
| 241 |
+
logger.error(e, exc_info=True)
|
| 242 |
+
return False
|
| 243 |
+
return True
|
| 244 |
+
|
| 245 |
+
def _create_run(self, experiment_id: str):
|
| 246 |
+
"""
|
| 247 |
+
Create the experiment for project_id
|
| 248 |
+
"""
|
| 249 |
+
if self.experiment_id is None:
|
| 250 |
+
# TODO : raise an Exception ?
|
| 251 |
+
logger.error(
|
| 252 |
+
"ApiClient FATAL The ApiClient._create_run() needs an experiment_id !"
|
| 253 |
+
)
|
| 254 |
+
return None
|
| 255 |
+
try:
|
| 256 |
+
run = RunCreate(
|
| 257 |
+
timestamp=get_datetime_with_timezone(),
|
| 258 |
+
experiment_id=experiment_id,
|
| 259 |
+
os=self.conf.get("os"),
|
| 260 |
+
python_version=self.conf.get("python_version"),
|
| 261 |
+
codecarbon_version=self.conf.get("codecarbon_version"),
|
| 262 |
+
cpu_count=self.conf.get("cpu_count"),
|
| 263 |
+
cpu_model=self.conf.get("cpu_model"),
|
| 264 |
+
gpu_count=self.conf.get("gpu_count"),
|
| 265 |
+
gpu_model=self.conf.get("gpu_model"),
|
| 266 |
+
# Reduce precision for Privacy
|
| 267 |
+
longitude=round(self.conf.get("longitude", 0), 1),
|
| 268 |
+
latitude=round(self.conf.get("latitude", 0), 1),
|
| 269 |
+
region=self.conf.get("region"),
|
| 270 |
+
provider=self.conf.get("provider"),
|
| 271 |
+
ram_total_size=self.conf.get("ram_total_size"),
|
| 272 |
+
tracking_mode=self.conf.get("tracking_mode"),
|
| 273 |
+
)
|
| 274 |
+
payload = dataclasses.asdict(run)
|
| 275 |
+
url = self.url + "/runs"
|
| 276 |
+
headers = self._get_headers()
|
| 277 |
+
r = requests.post(url=url, json=payload, timeout=2, headers=headers)
|
| 278 |
+
if r.status_code != 201:
|
| 279 |
+
self._log_error(url, payload, r)
|
| 280 |
+
return None
|
| 281 |
+
self.run_id = r.json()["id"]
|
| 282 |
+
logger.info(
|
| 283 |
+
"ApiClient Successfully registered your run on the API.\n\n"
|
| 284 |
+
+ f"Run ID: {self.run_id}\n"
|
| 285 |
+
+ f"Experiment ID: {self.experiment_id}\n"
|
| 286 |
+
)
|
| 287 |
+
return self.run_id
|
| 288 |
+
except requests.exceptions.ConnectionError as e:
|
| 289 |
+
logger.error(
|
| 290 |
+
f"Failed to connect to API, please check the configuration. {e}",
|
| 291 |
+
exc_info=False,
|
| 292 |
+
)
|
| 293 |
+
except Exception as e:
|
| 294 |
+
logger.error(e, exc_info=True)
|
| 295 |
+
|
| 296 |
+
def list_experiments_from_project(self, project_id: str):
|
| 297 |
+
"""
|
| 298 |
+
List all experiments for a project
|
| 299 |
+
"""
|
| 300 |
+
url = self.url + "/projects/" + project_id + "/experiments"
|
| 301 |
+
headers = self._get_headers()
|
| 302 |
+
r = requests.get(url=url, timeout=2, headers=headers)
|
| 303 |
+
if r.status_code != 200:
|
| 304 |
+
self._log_error(url, {}, r)
|
| 305 |
+
return []
|
| 306 |
+
return r.json()
|
| 307 |
+
|
| 308 |
+
def set_experiment(self, experiment_id: str):
|
| 309 |
+
"""
|
| 310 |
+
Set the experiment id
|
| 311 |
+
"""
|
| 312 |
+
self.experiment_id = experiment_id
|
| 313 |
+
|
| 314 |
+
def add_experiment(self, experiment: ExperimentCreate):
|
| 315 |
+
"""
|
| 316 |
+
Create an experiment, used by the CLI, not the package.
|
| 317 |
+
::experiment:: The experiment to create.
|
| 318 |
+
"""
|
| 319 |
+
payload = dataclasses.asdict(experiment)
|
| 320 |
+
url = self.url + "/experiments"
|
| 321 |
+
headers = self._get_headers()
|
| 322 |
+
r = requests.post(url=url, json=payload, timeout=2, headers=headers)
|
| 323 |
+
if r.status_code != 201:
|
| 324 |
+
self._log_error(url, payload, r)
|
| 325 |
+
return None
|
| 326 |
+
return r.json()
|
| 327 |
+
|
| 328 |
+
def get_experiment(self, experiment_id):
|
| 329 |
+
"""
|
| 330 |
+
Get an experiment by id
|
| 331 |
+
"""
|
| 332 |
+
url = self.url + "/experiments/" + experiment_id
|
| 333 |
+
headers = self._get_headers()
|
| 334 |
+
r = requests.get(url=url, timeout=2, headers=headers)
|
| 335 |
+
if r.status_code != 200:
|
| 336 |
+
self._log_error(url, {}, r)
|
| 337 |
+
return None
|
| 338 |
+
return r.json()
|
| 339 |
+
|
| 340 |
+
def _log_error(self, url, payload, response):
|
| 341 |
+
if len(payload) > 0:
|
| 342 |
+
logger.error(
|
| 343 |
+
f"ApiClient Error when calling the API on {url} with : {json.dumps(payload)}"
|
| 344 |
+
)
|
| 345 |
+
else:
|
| 346 |
+
logger.error(f"ApiClient Error when calling the API on {url}")
|
| 347 |
+
logger.error(
|
| 348 |
+
f"ApiClient API return http code {response.status_code} and answer : {response.text}"
|
| 349 |
+
)
|
| 350 |
+
|
| 351 |
+
def close_experiment(self):
|
| 352 |
+
"""
|
| 353 |
+
Tell the API that the experiment has ended.
|
| 354 |
+
"""
|
| 355 |
+
|
| 356 |
+
|
| 357 |
+
class simple_utc(tzinfo):
|
| 358 |
+
def tzname(self, **kwargs):
|
| 359 |
+
return "UTC"
|
| 360 |
+
|
| 361 |
+
def utcoffset(self, dt):
|
| 362 |
+
return timedelta(0)
|
codecarbon/core/cloud.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any, Dict, Optional
|
| 2 |
+
|
| 3 |
+
import requests
|
| 4 |
+
|
| 5 |
+
from codecarbon.external.logger import logger
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def postprocess_gcp_cloud_metadata(cloud_metadata: Dict[str, Any]) -> Dict[str, Any]:
|
| 9 |
+
# Attributes contains custom metadata and also contains Kubernetes config,
|
| 10 |
+
# startup script and secrets, filter it out
|
| 11 |
+
if "attributes" in cloud_metadata:
|
| 12 |
+
del cloud_metadata["attributes"]
|
| 13 |
+
|
| 14 |
+
return cloud_metadata
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
CLOUD_METADATA_MAPPING: Dict[str, Dict[str, Any]] = {
|
| 18 |
+
"AWS": {
|
| 19 |
+
"url": "http://169.254.169.254/latest/dynamic/instance-identity/document",
|
| 20 |
+
"headers": {},
|
| 21 |
+
},
|
| 22 |
+
"Azure": {
|
| 23 |
+
"url": "http://169.254.169.254/metadata/instance?api-version=2019-08-15",
|
| 24 |
+
"headers": {"Metadata": "true"},
|
| 25 |
+
},
|
| 26 |
+
"GCP": {
|
| 27 |
+
"url": "http://169.254.169.254/computeMetadata/v1/instance/?recursive=true&alt=json", # noqa: E501
|
| 28 |
+
"headers": {"Metadata-Flavor": "Google"},
|
| 29 |
+
"postprocess_function": postprocess_gcp_cloud_metadata,
|
| 30 |
+
},
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def get_env_cloud_details(timeout: int = 1) -> Optional[Any]:
|
| 35 |
+
"""
|
| 36 |
+
>>> get_env_cloud_details()
|
| 37 |
+
{'provider': 'AWS',
|
| 38 |
+
'metadata': {'accountId': '26550917306',
|
| 39 |
+
'architecture': 'x86_64',
|
| 40 |
+
'availabilityZone': 'us-east-1b',
|
| 41 |
+
'billingProducts': None,
|
| 42 |
+
'devpayProductCodes': None,
|
| 43 |
+
'marketplaceProductCodes': None,
|
| 44 |
+
'imageId': 'ami-025ed45832b817a35',
|
| 45 |
+
'instanceId': 'i-7c3e81fed58d8f7f7',
|
| 46 |
+
'instanceType': 'g4dn.2xlarge',
|
| 47 |
+
'kernelId': None,
|
| 48 |
+
'pendingTime': '2020-01-23T20:44:53Z',
|
| 49 |
+
'privateIp': '172.156.72.143',
|
| 50 |
+
'ramdiskId': None,
|
| 51 |
+
'region': 'us-east-1',
|
| 52 |
+
'version': '2017-09-30'}}
|
| 53 |
+
"""
|
| 54 |
+
for provider in CLOUD_METADATA_MAPPING.keys():
|
| 55 |
+
try:
|
| 56 |
+
params = CLOUD_METADATA_MAPPING[provider]
|
| 57 |
+
response = requests.get(
|
| 58 |
+
params["url"], headers=params["headers"], timeout=timeout
|
| 59 |
+
)
|
| 60 |
+
response.raise_for_status()
|
| 61 |
+
response_data = response.json()
|
| 62 |
+
|
| 63 |
+
postprocess_function = params.get("postprocess_function")
|
| 64 |
+
if postprocess_function is not None:
|
| 65 |
+
response_data = postprocess_function(response_data)
|
| 66 |
+
|
| 67 |
+
return {"provider": provider, "metadata": response_data}
|
| 68 |
+
except requests.exceptions.RequestException:
|
| 69 |
+
logger.debug("Not running on %s", provider)
|
| 70 |
+
|
| 71 |
+
return None
|
codecarbon/core/co2_signal.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from typing import Any, Dict
|
| 2 |
+
|
| 3 |
+
import requests
|
| 4 |
+
|
| 5 |
+
from codecarbon.core.units import EmissionsPerKWh, Energy
|
| 6 |
+
from codecarbon.external.geography import GeoMetadata
|
| 7 |
+
|
| 8 |
+
URL: str = "https://api.co2signal.com/v1/latest"
|
| 9 |
+
CO2_SIGNAL_API_TIMEOUT: int = 30
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
def get_emissions(
|
| 13 |
+
energy: Energy, geo: GeoMetadata, co2_signal_api_token: str = ""
|
| 14 |
+
) -> float:
|
| 15 |
+
"""
|
| 16 |
+
Calculate the CO2 emissions based on energy consumption and geographic location.
|
| 17 |
+
|
| 18 |
+
This function retrieves the carbon intensity (in grams of CO2 per kWh) from the CO2
|
| 19 |
+
Signal API based on the geographic location provided. It then calculates the total
|
| 20 |
+
CO2 emissions for a given amount of energy consumption.
|
| 21 |
+
|
| 22 |
+
Args:
|
| 23 |
+
energy (Energy):
|
| 24 |
+
An object representing the energy consumption in kilowatt-hours (kWh).
|
| 25 |
+
geo (GeoMetadata):
|
| 26 |
+
Geographic metadata, including either latitude/longitude
|
| 27 |
+
or a country code.
|
| 28 |
+
co2_signal_api_token (str, optional):
|
| 29 |
+
The API token for authenticating with the CO2 Signal API (default is an empty string).
|
| 30 |
+
|
| 31 |
+
Returns:
|
| 32 |
+
float:
|
| 33 |
+
The total CO2 emissions in kilograms based on the provided energy consumption and
|
| 34 |
+
carbon intensity of the specified geographic location.
|
| 35 |
+
|
| 36 |
+
Raises:
|
| 37 |
+
CO2SignalAPIError:
|
| 38 |
+
If the CO2 Signal API request fails or returns an error.
|
| 39 |
+
"""
|
| 40 |
+
params: Dict[str, Any]
|
| 41 |
+
if geo.latitude:
|
| 42 |
+
params = {"lat": geo.latitude, "lon": geo.longitude}
|
| 43 |
+
else:
|
| 44 |
+
params = {"countryCode": geo.country_2letter_iso_code}
|
| 45 |
+
resp = requests.get(
|
| 46 |
+
URL,
|
| 47 |
+
params=params,
|
| 48 |
+
headers={"auth-token": co2_signal_api_token},
|
| 49 |
+
timeout=CO2_SIGNAL_API_TIMEOUT,
|
| 50 |
+
)
|
| 51 |
+
if resp.status_code != 200:
|
| 52 |
+
message = resp.json().get("error") or resp.json().get("message")
|
| 53 |
+
raise CO2SignalAPIError(message)
|
| 54 |
+
carbon_intensity_g_per_kWh = resp.json()["data"]["carbonIntensity"]
|
| 55 |
+
emissions_per_kWh: EmissionsPerKWh = EmissionsPerKWh.from_g_per_kWh(
|
| 56 |
+
carbon_intensity_g_per_kWh
|
| 57 |
+
)
|
| 58 |
+
return emissions_per_kWh.kgs_per_kWh * energy.kWh
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
class CO2SignalAPIError(Exception):
|
| 62 |
+
pass
|
codecarbon/core/config.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import configparser
|
| 2 |
+
import os
|
| 3 |
+
from pathlib import Path
|
| 4 |
+
from typing import List
|
| 5 |
+
|
| 6 |
+
from codecarbon.external.logger import logger
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
def clean_env_key(k: str) -> str:
|
| 10 |
+
"""
|
| 11 |
+
Clean up an environment variable key: remove starting
|
| 12 |
+
CODECARBON_ and to lower case.
|
| 13 |
+
|
| 14 |
+
eg: "CODECARBON_PROJECT_NAME" -> "project_name"
|
| 15 |
+
|
| 16 |
+
Args:
|
| 17 |
+
k (str): Environment variable key
|
| 18 |
+
|
| 19 |
+
Returns:
|
| 20 |
+
str: Cleaned str
|
| 21 |
+
"""
|
| 22 |
+
assert isinstance(k, str)
|
| 23 |
+
return k.lower().replace("codecarbon_", "", 1)
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
def parse_env_config() -> dict:
|
| 27 |
+
"""
|
| 28 |
+
Get all environment variables starting with "CODECARBON_" (also in lower caps)
|
| 29 |
+
mapped to their values in a dict
|
| 30 |
+
|
| 31 |
+
eg:
|
| 32 |
+
* "CODECARBON_PROJECT_NAME=DeepLearning" -> {"project_name": "DeepLearning"}
|
| 33 |
+
* "codecarbon_project_name=DeepLearning" -> {"project_name": "DeepLearning"}
|
| 34 |
+
|
| 35 |
+
Returns:
|
| 36 |
+
dict: existing relevant environment variables mapped into a dict
|
| 37 |
+
"""
|
| 38 |
+
return {
|
| 39 |
+
"codecarbon": {
|
| 40 |
+
clean_env_key(k): v
|
| 41 |
+
for k, v in os.environ.items()
|
| 42 |
+
if k.lower().startswith("codecarbon_")
|
| 43 |
+
}
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def parse_gpu_ids(gpu_ids_str: str) -> List[int]:
|
| 48 |
+
"""
|
| 49 |
+
Transforms the potential gpu_ids string into a list of int values
|
| 50 |
+
|
| 51 |
+
Args:
|
| 52 |
+
gpu_ids_str (str): The config file or environment variable value for `gpu_ids`
|
| 53 |
+
which is read as a string and should be parsed into a list of ints
|
| 54 |
+
|
| 55 |
+
Returns:
|
| 56 |
+
list[int]: The list of GPU ids available declared by the user.
|
| 57 |
+
Potentially empty.
|
| 58 |
+
"""
|
| 59 |
+
if not isinstance(gpu_ids_str, str):
|
| 60 |
+
return gpu_ids_str
|
| 61 |
+
|
| 62 |
+
gpu_ids_str = "".join(c for c in gpu_ids_str if (c.isalnum() or c == ","))
|
| 63 |
+
str_ids = [gpu_id for gpu_id in gpu_ids_str.split(",") if gpu_id]
|
| 64 |
+
return list(map(int, str_ids))
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def get_hierarchical_config():
|
| 68 |
+
"""
|
| 69 |
+
Get the user-defined codecarbon configuration ConfigParser dictionnary
|
| 70 |
+
(actually a configparser.SectionProxy instance).
|
| 71 |
+
|
| 72 |
+
```
|
| 73 |
+
>>> from codecarbon.core.config import get_hierarchical_config
|
| 74 |
+
>>> conf = get_hierarchical_config()
|
| 75 |
+
>>> print(conf)
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
`conf` works like a regular dict + methods getint(key) getfloat(key)
|
| 79 |
+
and getboolean(key) to automatically parse strings into those types.
|
| 80 |
+
|
| 81 |
+
All values (outputs of get(key)) are strings.
|
| 82 |
+
|
| 83 |
+
It looks for, and reads, a config file .codecarbon.config in the user's $HOME.
|
| 84 |
+
It then looks for, reads, and updates the previous configuration from a config
|
| 85 |
+
file .codecarbon.config in the current working directory (Path.cwd()).
|
| 86 |
+
Finally it updates the resulting config from any environment variable starting
|
| 87 |
+
with `CODECARBON_` (for instance if `CODECARBON_PROJECT_NAME` is `your-project`
|
| 88 |
+
then the resulting configuration key `project_name` will have value `your-project`)
|
| 89 |
+
|
| 90 |
+
Returns:
|
| 91 |
+
dict: The final configuration dict parsed from global,
|
| 92 |
+
local and environment configurations. **All values are strings**.
|
| 93 |
+
"""
|
| 94 |
+
|
| 95 |
+
config = configparser.ConfigParser()
|
| 96 |
+
|
| 97 |
+
cwd = Path.cwd()
|
| 98 |
+
home = Path.home()
|
| 99 |
+
global_path = str((home / ".codecarbon.config").expanduser().resolve())
|
| 100 |
+
local_path = str((cwd / ".codecarbon.config").expanduser().resolve())
|
| 101 |
+
if Path(global_path).exists():
|
| 102 |
+
logger.info(
|
| 103 |
+
f"Codecarbon is taking the configuration from global file: {global_path}"
|
| 104 |
+
)
|
| 105 |
+
if Path(local_path).exists():
|
| 106 |
+
logger.info(f"Some variables are overriden by the local file: {local_path}")
|
| 107 |
+
elif Path(local_path).exists():
|
| 108 |
+
logger.info(
|
| 109 |
+
f"Codecarbon is taking the configuration from the local file {local_path}"
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
config.read([global_path, local_path])
|
| 113 |
+
config.read_dict(parse_env_config())
|
| 114 |
+
|
| 115 |
+
return dict(config["codecarbon"])
|
codecarbon/core/cpu.py
ADDED
|
@@ -0,0 +1,521 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Implements tracking Intel CPU Power Consumption on Mac and Windows
|
| 3 |
+
using Intel Power Gadget
|
| 4 |
+
https://software.intel.com/content/www/us/en/develop/articles/intel-power-gadget.html
|
| 5 |
+
"""
|
| 6 |
+
|
| 7 |
+
import os
|
| 8 |
+
import re
|
| 9 |
+
import shutil
|
| 10 |
+
import subprocess
|
| 11 |
+
import sys
|
| 12 |
+
from typing import Dict, Optional, Tuple
|
| 13 |
+
|
| 14 |
+
import pandas as pd
|
| 15 |
+
import psutil
|
| 16 |
+
from rapidfuzz import fuzz, process, utils
|
| 17 |
+
|
| 18 |
+
from codecarbon.core.rapl import RAPLFile
|
| 19 |
+
from codecarbon.core.units import Time
|
| 20 |
+
from codecarbon.core.util import detect_cpu_model
|
| 21 |
+
from codecarbon.external.logger import logger
|
| 22 |
+
from codecarbon.input import DataSource
|
| 23 |
+
|
| 24 |
+
# default W value per core for a CPU if no model is found in the ref csv
|
| 25 |
+
DEFAULT_POWER_PER_CORE = 4
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def is_powergadget_available() -> bool:
|
| 29 |
+
"""
|
| 30 |
+
Checks if Intel Power Gadget is available on the system.
|
| 31 |
+
|
| 32 |
+
Returns:
|
| 33 |
+
bool: `True` if Intel Power Gadget is available, `False` otherwise.
|
| 34 |
+
"""
|
| 35 |
+
try:
|
| 36 |
+
IntelPowerGadget()
|
| 37 |
+
return True
|
| 38 |
+
except Exception as e:
|
| 39 |
+
logger.debug(
|
| 40 |
+
"Not using PowerGadget, an exception occurred while instantiating "
|
| 41 |
+
+ "IntelPowerGadget : %s",
|
| 42 |
+
e,
|
| 43 |
+
)
|
| 44 |
+
return False
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def is_rapl_available() -> bool:
|
| 48 |
+
"""
|
| 49 |
+
Checks if Intel RAPL is available on the system.
|
| 50 |
+
|
| 51 |
+
Returns:
|
| 52 |
+
bool: `True` if Intel RAPL is available, `False` otherwise.
|
| 53 |
+
"""
|
| 54 |
+
try:
|
| 55 |
+
IntelRAPL()
|
| 56 |
+
return True
|
| 57 |
+
except Exception as e:
|
| 58 |
+
logger.debug(
|
| 59 |
+
"Not using the RAPL interface, an exception occurred while instantiating "
|
| 60 |
+
+ "IntelRAPL : %s",
|
| 61 |
+
e,
|
| 62 |
+
)
|
| 63 |
+
return False
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def is_psutil_available():
|
| 67 |
+
try:
|
| 68 |
+
nice = psutil.cpu_times().nice
|
| 69 |
+
if nice > 0.0001:
|
| 70 |
+
return True
|
| 71 |
+
else:
|
| 72 |
+
logger.debug(
|
| 73 |
+
f"is_psutil_available() : psutil.cpu_times().nice is too small : {nice} !"
|
| 74 |
+
)
|
| 75 |
+
return False
|
| 76 |
+
except Exception as e:
|
| 77 |
+
logger.debug(
|
| 78 |
+
"Not using the psutil interface, an exception occurred while instantiating "
|
| 79 |
+
+ f"psutil.cpu_times : {e}",
|
| 80 |
+
)
|
| 81 |
+
return False
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
class IntelPowerGadget:
|
| 85 |
+
"""
|
| 86 |
+
A class to interface with Intel Power Gadget for monitoring CPU power consumption on Windows and (non-Apple Silicon) macOS.
|
| 87 |
+
|
| 88 |
+
This class provides methods to set up and execute Intel Power Gadget's command-line interface (CLI) to
|
| 89 |
+
log power consumption data over a specified duration and resolution. It also includes functionality to
|
| 90 |
+
read and process the logged data to extract CPU power details.
|
| 91 |
+
|
| 92 |
+
Methods:
|
| 93 |
+
start():
|
| 94 |
+
Placeholder method for starting the Intel Power Gadget monitoring.
|
| 95 |
+
|
| 96 |
+
get_cpu_details() -> Dict:
|
| 97 |
+
Fetches the CPU power details by reading the values from the logged CSV file.
|
| 98 |
+
|
| 99 |
+
"""
|
| 100 |
+
|
| 101 |
+
_osx_exec = "PowerLog"
|
| 102 |
+
_osx_exec_backup = "/Applications/Intel Power Gadget/PowerLog"
|
| 103 |
+
_windows_exec = "PowerLog3.0.exe"
|
| 104 |
+
|
| 105 |
+
def __init__(
|
| 106 |
+
self,
|
| 107 |
+
output_dir: str = ".",
|
| 108 |
+
duration=1,
|
| 109 |
+
resolution=100,
|
| 110 |
+
log_file_name="intel_power_gadget_log.csv",
|
| 111 |
+
):
|
| 112 |
+
self._log_file_path = os.path.join(output_dir, log_file_name)
|
| 113 |
+
self._system = sys.platform.lower()
|
| 114 |
+
self._duration = duration
|
| 115 |
+
self._resolution = resolution
|
| 116 |
+
self._windows_exec_backup = None
|
| 117 |
+
self._setup_cli()
|
| 118 |
+
|
| 119 |
+
def _setup_cli(self) -> None:
|
| 120 |
+
"""
|
| 121 |
+
Setup cli command to run Intel Power Gadget
|
| 122 |
+
"""
|
| 123 |
+
if self._system.startswith("win"):
|
| 124 |
+
self._get_windows_exec_backup()
|
| 125 |
+
if shutil.which(self._windows_exec):
|
| 126 |
+
self._cli = shutil.which(
|
| 127 |
+
self._windows_exec
|
| 128 |
+
) # Windows exec is a relative path
|
| 129 |
+
elif shutil.which(self._windows_exec_backup):
|
| 130 |
+
self._cli = self._windows_exec_backup
|
| 131 |
+
else:
|
| 132 |
+
raise FileNotFoundError(
|
| 133 |
+
f"Intel Power Gadget executable not found on {self._system}"
|
| 134 |
+
)
|
| 135 |
+
elif self._system.startswith("darwin"):
|
| 136 |
+
if shutil.which(self._osx_exec):
|
| 137 |
+
self._cli = self._osx_exec
|
| 138 |
+
elif shutil.which(self._osx_exec_backup):
|
| 139 |
+
self._cli = self._osx_exec_backup
|
| 140 |
+
else:
|
| 141 |
+
raise FileNotFoundError(
|
| 142 |
+
f"Intel Power Gadget executable not found on {self._system}"
|
| 143 |
+
)
|
| 144 |
+
else:
|
| 145 |
+
raise SystemError("Platform not supported by Intel Power Gadget")
|
| 146 |
+
|
| 147 |
+
def _get_windows_exec_backup(self) -> None:
|
| 148 |
+
"""
|
| 149 |
+
Find the windows executable for the current version of intel power gadget.
|
| 150 |
+
Example: "C:\\Program Files\\Intel\\Power Gadget 3.5\\PowerLog3.0.exe"
|
| 151 |
+
"""
|
| 152 |
+
parent_folder = "C:\\Program Files\\Intel\\"
|
| 153 |
+
|
| 154 |
+
# Get a list of all subdirectories in the parent folder
|
| 155 |
+
subfolders = [f.name for f in os.scandir(parent_folder) if f.is_dir()]
|
| 156 |
+
|
| 157 |
+
# Look for a folder that contains "Power Gadget" in its name
|
| 158 |
+
desired_folder = next(
|
| 159 |
+
(folder for folder in subfolders if "Power Gadget" in folder), None
|
| 160 |
+
)
|
| 161 |
+
if desired_folder:
|
| 162 |
+
self._windows_exec_backup = os.path.join(
|
| 163 |
+
parent_folder, desired_folder, self._windows_exec
|
| 164 |
+
)
|
| 165 |
+
else:
|
| 166 |
+
self._windows_exec_backup = None
|
| 167 |
+
|
| 168 |
+
def _log_values(self) -> None:
|
| 169 |
+
"""
|
| 170 |
+
Logs output from Intel Power Gadget command line to a file
|
| 171 |
+
"""
|
| 172 |
+
returncode = None
|
| 173 |
+
if self._system.startswith("win"):
|
| 174 |
+
returncode = subprocess.call(
|
| 175 |
+
[
|
| 176 |
+
self._cli,
|
| 177 |
+
"-duration",
|
| 178 |
+
str(self._duration),
|
| 179 |
+
"-resolution",
|
| 180 |
+
str(self._resolution),
|
| 181 |
+
"-file",
|
| 182 |
+
self._log_file_path,
|
| 183 |
+
],
|
| 184 |
+
shell=True,
|
| 185 |
+
stdout=subprocess.PIPE,
|
| 186 |
+
stderr=subprocess.PIPE,
|
| 187 |
+
)
|
| 188 |
+
elif self._system.startswith("darwin"):
|
| 189 |
+
returncode = subprocess.call(
|
| 190 |
+
f"'{self._cli}' -duration {self._duration} -resolution {self._resolution} -file {self._log_file_path} > /dev/null", # noqa: E501
|
| 191 |
+
shell=True,
|
| 192 |
+
)
|
| 193 |
+
else:
|
| 194 |
+
return None
|
| 195 |
+
|
| 196 |
+
if returncode != 0:
|
| 197 |
+
logger.warning(
|
| 198 |
+
"Returncode while logging power values using "
|
| 199 |
+
+ "Intel Power Gadget: %s",
|
| 200 |
+
returncode,
|
| 201 |
+
)
|
| 202 |
+
|
| 203 |
+
def get_cpu_details(self) -> Dict:
|
| 204 |
+
"""
|
| 205 |
+
Fetches the CPU Power Details by fetching values from a logged csv file
|
| 206 |
+
in _log_values function
|
| 207 |
+
"""
|
| 208 |
+
self._log_values()
|
| 209 |
+
cpu_details = {}
|
| 210 |
+
try:
|
| 211 |
+
cpu_data = pd.read_csv(self._log_file_path).dropna()
|
| 212 |
+
for col_name in cpu_data.columns:
|
| 213 |
+
if col_name in ["System Time", "Elapsed Time (sec)", "RDTSC"]:
|
| 214 |
+
continue
|
| 215 |
+
if "Cumulative" in col_name:
|
| 216 |
+
cpu_details[col_name] = cpu_data[col_name].iloc[-1]
|
| 217 |
+
else:
|
| 218 |
+
cpu_details[col_name] = cpu_data[col_name].mean()
|
| 219 |
+
except Exception as e:
|
| 220 |
+
logger.info(
|
| 221 |
+
f"Unable to read Intel Power Gadget logged file at {self._log_file_path}\n \
|
| 222 |
+
Exception occurred %s",
|
| 223 |
+
e,
|
| 224 |
+
exc_info=True,
|
| 225 |
+
)
|
| 226 |
+
return cpu_details
|
| 227 |
+
|
| 228 |
+
def start(self) -> None:
|
| 229 |
+
"""
|
| 230 |
+
Placeholder method for starting the Intel Power Gadget monitoring.
|
| 231 |
+
"""
|
| 232 |
+
# TODO: Read energy
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
class IntelRAPL:
|
| 236 |
+
"""
|
| 237 |
+
A class to interface Intel's Running Average Power Limit (RAPL) for monitoring CPU power consumption.
|
| 238 |
+
|
| 239 |
+
This class provides methods to set up and read energy consumption data from Intel RAPL files,
|
| 240 |
+
which are available on Linux systems.
|
| 241 |
+
It enables the measurement of CPU energy usage over time and provides methods to fetch
|
| 242 |
+
both dynamic and static CPU energy details.
|
| 243 |
+
|
| 244 |
+
Attributes:
|
| 245 |
+
_lin_rapl_dir (str): The directory path where Intel RAPL files are located.
|
| 246 |
+
_system (str): The platform of the running system, typically used to ensure compatibility.
|
| 247 |
+
_rapl_files (List[RAPLFile]): A list of RAPLFile objects representing the files to read energy data from.
|
| 248 |
+
_cpu_details (Dict): A dictionary storing the latest CPU energy details.
|
| 249 |
+
_last_mesure (int): Placeholder for storing the last measurement time.
|
| 250 |
+
|
| 251 |
+
Methods:
|
| 252 |
+
start():
|
| 253 |
+
Starts monitoring CPU energy consumption.
|
| 254 |
+
|
| 255 |
+
get_cpu_details(duration: Time) -> Dict:
|
| 256 |
+
Fetches the CPU energy deltas over a specified duration by reading values from RAPL files.
|
| 257 |
+
|
| 258 |
+
get_static_cpu_details() -> Dict:
|
| 259 |
+
Returns the CPU details without recalculating them.
|
| 260 |
+
|
| 261 |
+
"""
|
| 262 |
+
|
| 263 |
+
def __init__(self, rapl_dir="/sys/class/powercap/intel-rapl/subsystem"):
|
| 264 |
+
self._lin_rapl_dir = rapl_dir
|
| 265 |
+
self._system = sys.platform.lower()
|
| 266 |
+
self._rapl_files = []
|
| 267 |
+
self._setup_rapl()
|
| 268 |
+
self._cpu_details: Dict = {}
|
| 269 |
+
|
| 270 |
+
self._last_mesure = 0
|
| 271 |
+
|
| 272 |
+
def _is_platform_supported(self) -> bool:
|
| 273 |
+
return self._system.startswith("lin")
|
| 274 |
+
|
| 275 |
+
def _setup_rapl(self) -> None:
|
| 276 |
+
if self._is_platform_supported():
|
| 277 |
+
if os.path.exists(self._lin_rapl_dir):
|
| 278 |
+
self._fetch_rapl_files()
|
| 279 |
+
else:
|
| 280 |
+
raise FileNotFoundError(
|
| 281 |
+
f"Intel RAPL files not found at {self._lin_rapl_dir} "
|
| 282 |
+
+ f"on {self._system}"
|
| 283 |
+
)
|
| 284 |
+
else:
|
| 285 |
+
raise SystemError("Platform not supported by Intel RAPL Interface")
|
| 286 |
+
|
| 287 |
+
def _fetch_rapl_files(self) -> None:
|
| 288 |
+
"""
|
| 289 |
+
Fetches RAPL files from the RAPL directory
|
| 290 |
+
"""
|
| 291 |
+
|
| 292 |
+
# consider files like `intel-rapl:$i`
|
| 293 |
+
files = list(filter(lambda x: ":" in x, os.listdir(self._lin_rapl_dir)))
|
| 294 |
+
|
| 295 |
+
i = 0
|
| 296 |
+
for file in files:
|
| 297 |
+
path = os.path.join(self._lin_rapl_dir, file, "name")
|
| 298 |
+
with open(path) as f:
|
| 299 |
+
name = f.read().strip()
|
| 300 |
+
# Fake the name used by Power Gadget
|
| 301 |
+
# We ignore "core" in name as it seems to be included in "package" for Intel CPU.
|
| 302 |
+
# TODO: Use "dram" for memory power
|
| 303 |
+
if "package" in name:
|
| 304 |
+
name = f"Processor Energy Delta_{i}(kWh)"
|
| 305 |
+
i += 1
|
| 306 |
+
# RAPL file to take measurement from
|
| 307 |
+
rapl_file = os.path.join(self._lin_rapl_dir, file, "energy_uj")
|
| 308 |
+
# RAPL file containing maximum possible value of energy_uj above which it wraps
|
| 309 |
+
rapl_file_max = os.path.join(
|
| 310 |
+
self._lin_rapl_dir, file, "max_energy_range_uj"
|
| 311 |
+
)
|
| 312 |
+
try:
|
| 313 |
+
# Try to read the file to be sure we can
|
| 314 |
+
with open(rapl_file, "r") as f:
|
| 315 |
+
_ = float(f.read())
|
| 316 |
+
self._rapl_files.append(
|
| 317 |
+
RAPLFile(name=name, path=rapl_file, max_path=rapl_file_max)
|
| 318 |
+
)
|
| 319 |
+
logger.debug("We will read Intel RAPL files at %s", rapl_file)
|
| 320 |
+
except PermissionError as e:
|
| 321 |
+
raise PermissionError(
|
| 322 |
+
"PermissionError : Unable to read Intel RAPL files for CPU power, we will use a constant for your CPU power."
|
| 323 |
+
+ " Please view https://github.com/mlco2/codecarbon/issues/244"
|
| 324 |
+
+ " for workarounds : %s",
|
| 325 |
+
e,
|
| 326 |
+
) from e
|
| 327 |
+
|
| 328 |
+
def get_cpu_details(self, duration: Time) -> Dict:
|
| 329 |
+
"""
|
| 330 |
+
Fetches the CPU Energy Deltas by fetching values from RAPL files
|
| 331 |
+
"""
|
| 332 |
+
cpu_details = {}
|
| 333 |
+
try:
|
| 334 |
+
list(map(lambda rapl_file: rapl_file.delta(duration), self._rapl_files))
|
| 335 |
+
|
| 336 |
+
for rapl_file in self._rapl_files:
|
| 337 |
+
logger.debug(rapl_file)
|
| 338 |
+
cpu_details[rapl_file.name] = rapl_file.energy_delta.kWh
|
| 339 |
+
# We fake the name used by Power Gadget when using RAPL
|
| 340 |
+
if "Energy" in rapl_file.name:
|
| 341 |
+
cpu_details[rapl_file.name.replace("Energy", "Power")] = (
|
| 342 |
+
rapl_file.power.W
|
| 343 |
+
)
|
| 344 |
+
except Exception as e:
|
| 345 |
+
logger.info(
|
| 346 |
+
"Unable to read Intel RAPL files at %s\n \
|
| 347 |
+
Exception occurred %s",
|
| 348 |
+
self._rapl_files,
|
| 349 |
+
e,
|
| 350 |
+
exc_info=True,
|
| 351 |
+
)
|
| 352 |
+
self._cpu_details = cpu_details
|
| 353 |
+
logger.debug("get_cpu_details %s", self._cpu_details)
|
| 354 |
+
return cpu_details
|
| 355 |
+
|
| 356 |
+
def get_static_cpu_details(self) -> Dict:
|
| 357 |
+
"""
|
| 358 |
+
Return CPU details without computing them.
|
| 359 |
+
"""
|
| 360 |
+
return self._cpu_details
|
| 361 |
+
|
| 362 |
+
def start(self) -> None:
|
| 363 |
+
"""
|
| 364 |
+
Starts monitoring CPU energy consumption.
|
| 365 |
+
"""
|
| 366 |
+
for rapl_file in self._rapl_files:
|
| 367 |
+
rapl_file.start()
|
| 368 |
+
|
| 369 |
+
|
| 370 |
+
class TDP:
|
| 371 |
+
"""
|
| 372 |
+
Represents Thermal Design Power (TDP) for detecting and estimating
|
| 373 |
+
the power consumption of the CPU on a machine.
|
| 374 |
+
|
| 375 |
+
The class provides methods to identify the CPU model, match it with known TDP
|
| 376 |
+
values from a dataset, and return the corresponding power consumption in watts.
|
| 377 |
+
|
| 378 |
+
Attributes:
|
| 379 |
+
model (str): The detected CPU model name.
|
| 380 |
+
tdp (int): The TDP value of the detected CPU in watts.
|
| 381 |
+
|
| 382 |
+
Methods:
|
| 383 |
+
start():
|
| 384 |
+
Placeholder method to initiate TDP analysis.
|
| 385 |
+
|
| 386 |
+
"""
|
| 387 |
+
|
| 388 |
+
def __init__(self):
|
| 389 |
+
self.model, self.tdp = self._main()
|
| 390 |
+
|
| 391 |
+
@staticmethod
|
| 392 |
+
def _get_cpu_constant_power(match: str, cpu_power_df: pd.DataFrame) -> int:
|
| 393 |
+
"""Extract constant power from matched CPU"""
|
| 394 |
+
return float(cpu_power_df[cpu_power_df["Name"] == match]["TDP"].values[0])
|
| 395 |
+
|
| 396 |
+
def _get_cpu_power_from_registry(self, cpu_model_raw: str) -> Optional[int]:
|
| 397 |
+
cpu_power_df = DataSource().get_cpu_power_data()
|
| 398 |
+
cpu_matching = self._get_matching_cpu(cpu_model_raw, cpu_power_df)
|
| 399 |
+
if cpu_matching:
|
| 400 |
+
power = self._get_cpu_constant_power(cpu_matching, cpu_power_df)
|
| 401 |
+
return power
|
| 402 |
+
return None
|
| 403 |
+
|
| 404 |
+
def _get_matching_cpu(
|
| 405 |
+
self, model_raw: str, cpu_df: pd.DataFrame, greedy=False
|
| 406 |
+
) -> str:
|
| 407 |
+
"""
|
| 408 |
+
Get matching cpu name
|
| 409 |
+
|
| 410 |
+
:args:
|
| 411 |
+
model_raw (str): raw name of the cpu model detected on the machine
|
| 412 |
+
|
| 413 |
+
cpu_df (DataFrame): table containing cpu models along their tdp
|
| 414 |
+
|
| 415 |
+
greedy (default False): if multiple cpu models match with an equal
|
| 416 |
+
ratio of similarity, greedy (True) selects the first model,
|
| 417 |
+
following the order of the cpu list provided, while non-greedy
|
| 418 |
+
returns None.
|
| 419 |
+
|
| 420 |
+
:return: name of the matching cpu model
|
| 421 |
+
|
| 422 |
+
:notes:
|
| 423 |
+
Thanks to the greedy mode, even though the match could be a model
|
| 424 |
+
with a tdp very different from the actual tdp of current cpu, it
|
| 425 |
+
still enables the relative comparison of models emissions running
|
| 426 |
+
on the same machine.
|
| 427 |
+
|
| 428 |
+
THRESHOLD_DIRECT defines the similarity ratio value to consider
|
| 429 |
+
almost-exact matches.
|
| 430 |
+
|
| 431 |
+
THRESHOLD_TOKEN_SET defines the similarity ratio value to consider
|
| 432 |
+
token_set matches (for more detail see fuzz.token_set_ratio).
|
| 433 |
+
"""
|
| 434 |
+
THRESHOLD_DIRECT: int = 100
|
| 435 |
+
THRESHOLD_TOKEN_SET: int = 100
|
| 436 |
+
|
| 437 |
+
direct_match = process.extractOne(
|
| 438 |
+
model_raw,
|
| 439 |
+
cpu_df["Name"],
|
| 440 |
+
processor=lambda s: s.lower(),
|
| 441 |
+
scorer=fuzz.ratio,
|
| 442 |
+
score_cutoff=THRESHOLD_DIRECT,
|
| 443 |
+
)
|
| 444 |
+
|
| 445 |
+
if direct_match:
|
| 446 |
+
return direct_match[0]
|
| 447 |
+
|
| 448 |
+
model_raw = model_raw.replace("(R)", "")
|
| 449 |
+
start_cpu = model_raw.find(" CPU @ ")
|
| 450 |
+
if start_cpu > 0:
|
| 451 |
+
model_raw = model_raw[0:start_cpu]
|
| 452 |
+
model_raw = model_raw.replace(" CPU", "")
|
| 453 |
+
model_raw = re.sub(r" @\s*\d+\.\d+GHz", "", model_raw)
|
| 454 |
+
direct_match = process.extractOne(
|
| 455 |
+
model_raw,
|
| 456 |
+
cpu_df["Name"],
|
| 457 |
+
processor=lambda s: s.lower(),
|
| 458 |
+
scorer=fuzz.ratio,
|
| 459 |
+
score_cutoff=THRESHOLD_DIRECT,
|
| 460 |
+
)
|
| 461 |
+
|
| 462 |
+
if direct_match:
|
| 463 |
+
return direct_match[0]
|
| 464 |
+
indirect_matches = process.extract(
|
| 465 |
+
model_raw,
|
| 466 |
+
cpu_df["Name"],
|
| 467 |
+
processor=utils.default_process,
|
| 468 |
+
scorer=fuzz.token_set_ratio,
|
| 469 |
+
score_cutoff=THRESHOLD_TOKEN_SET,
|
| 470 |
+
)
|
| 471 |
+
|
| 472 |
+
if indirect_matches:
|
| 473 |
+
if (
|
| 474 |
+
greedy
|
| 475 |
+
or len(indirect_matches) == 1
|
| 476 |
+
or indirect_matches[0][1] != indirect_matches[1][1]
|
| 477 |
+
):
|
| 478 |
+
return indirect_matches[0][0]
|
| 479 |
+
|
| 480 |
+
return None
|
| 481 |
+
|
| 482 |
+
def _main(self) -> Tuple[str, int]:
|
| 483 |
+
"""
|
| 484 |
+
Get CPU power from constant mode
|
| 485 |
+
|
| 486 |
+
:return: model name (str), power in Watt (int)
|
| 487 |
+
"""
|
| 488 |
+
cpu_model_detected = detect_cpu_model()
|
| 489 |
+
|
| 490 |
+
if cpu_model_detected:
|
| 491 |
+
power = self._get_cpu_power_from_registry(cpu_model_detected)
|
| 492 |
+
|
| 493 |
+
if power:
|
| 494 |
+
logger.debug(
|
| 495 |
+
"CPU : We detect a %s with a TDP of %s W",
|
| 496 |
+
cpu_model_detected,
|
| 497 |
+
power,
|
| 498 |
+
)
|
| 499 |
+
return cpu_model_detected, power
|
| 500 |
+
logger.warning(
|
| 501 |
+
"We saw that you have a %s but we don't know it."
|
| 502 |
+
+ " Please contact us.",
|
| 503 |
+
cpu_model_detected,
|
| 504 |
+
)
|
| 505 |
+
if is_psutil_available():
|
| 506 |
+
# Count thread of the CPU
|
| 507 |
+
threads = psutil.cpu_count(logical=True)
|
| 508 |
+
estimated_tdp = threads * DEFAULT_POWER_PER_CORE
|
| 509 |
+
logger.warning(
|
| 510 |
+
f"We will use the default power consumption of {DEFAULT_POWER_PER_CORE} W per thread for your {threads} CPU, so {estimated_tdp}W."
|
| 511 |
+
)
|
| 512 |
+
return cpu_model_detected, estimated_tdp
|
| 513 |
+
return cpu_model_detected, None
|
| 514 |
+
logger.warning(
|
| 515 |
+
"We were unable to detect your CPU using the `cpuinfo` package."
|
| 516 |
+
+ " Resorting to a default power consumption."
|
| 517 |
+
)
|
| 518 |
+
return "Unknown", None
|
| 519 |
+
|
| 520 |
+
def start(self):
|
| 521 |
+
pass
|
codecarbon/core/emissions.py
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Provides functionality to compute emissions for cloud & private infra
|
| 3 |
+
based on impact & energy Usage package
|
| 4 |
+
|
| 5 |
+
https://github.com/mlco2/impact
|
| 6 |
+
https://github.com/responsibleproblemsolving/energy-usage
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
from typing import Dict, Optional
|
| 10 |
+
|
| 11 |
+
import pandas as pd
|
| 12 |
+
|
| 13 |
+
from codecarbon.core import co2_signal
|
| 14 |
+
from codecarbon.core.units import EmissionsPerKWh, Energy
|
| 15 |
+
from codecarbon.external.geography import CloudMetadata, GeoMetadata
|
| 16 |
+
from codecarbon.external.logger import logger
|
| 17 |
+
from codecarbon.input import DataSource, DataSourceException
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
class Emissions:
|
| 21 |
+
def __init__(
|
| 22 |
+
self, data_source: DataSource, co2_signal_api_token: Optional[str] = None
|
| 23 |
+
):
|
| 24 |
+
self._data_source = data_source
|
| 25 |
+
self._co2_signal_api_token = co2_signal_api_token
|
| 26 |
+
|
| 27 |
+
def get_cloud_emissions(
|
| 28 |
+
self, energy: Energy, cloud: CloudMetadata, geo: GeoMetadata = None
|
| 29 |
+
) -> float:
|
| 30 |
+
"""
|
| 31 |
+
Computes emissions for cloud infra
|
| 32 |
+
:param energy: Mean power consumption of the process (kWh)
|
| 33 |
+
:param cloud: Region of compute
|
| 34 |
+
:param geo: Instance of GeoMetadata to fallback if we don't find cloud carbon intensity
|
| 35 |
+
:return: CO2 emissions in kg
|
| 36 |
+
"""
|
| 37 |
+
|
| 38 |
+
df: pd.DataFrame = self._data_source.get_cloud_emissions_data()
|
| 39 |
+
try:
|
| 40 |
+
emissions_per_kWh: EmissionsPerKWh = EmissionsPerKWh.from_g_per_kWh(
|
| 41 |
+
df.loc[
|
| 42 |
+
(df["provider"] == cloud.provider) & (df["region"] == cloud.region)
|
| 43 |
+
]["impact"].item()
|
| 44 |
+
)
|
| 45 |
+
emissions = emissions_per_kWh.kgs_per_kWh * energy.kWh # kgs
|
| 46 |
+
except Exception as e:
|
| 47 |
+
logger.warning(
|
| 48 |
+
f"Cloud electricity carbon intensity for provider '{cloud.provider}' and region '{cloud.region}' not found, using country value instead. Error : {e}"
|
| 49 |
+
)
|
| 50 |
+
logger.warning(
|
| 51 |
+
"AWS and Azure do not provide any carbon intensity data. Only GCP does it."
|
| 52 |
+
)
|
| 53 |
+
if geo:
|
| 54 |
+
emissions = self.get_private_infra_emissions(
|
| 55 |
+
energy, geo
|
| 56 |
+
) # float: kg co2_eq
|
| 57 |
+
else:
|
| 58 |
+
carbon_intensity_per_source = (
|
| 59 |
+
DataSource().get_carbon_intensity_per_source_data()
|
| 60 |
+
)
|
| 61 |
+
emissions = (
|
| 62 |
+
EmissionsPerKWh.from_g_per_kWh(
|
| 63 |
+
carbon_intensity_per_source.get("world_average")
|
| 64 |
+
).kgs_per_kWh
|
| 65 |
+
* energy.kWh
|
| 66 |
+
) # kgs
|
| 67 |
+
return emissions
|
| 68 |
+
|
| 69 |
+
def get_cloud_country_name(self, cloud: CloudMetadata) -> str:
|
| 70 |
+
"""
|
| 71 |
+
Returns the Country Name where the cloud region is located
|
| 72 |
+
"""
|
| 73 |
+
df: pd.DataFrame = self._data_source.get_cloud_emissions_data()
|
| 74 |
+
flags = (df["provider"] == cloud.provider) & (df["region"] == cloud.region)
|
| 75 |
+
selected = df.loc[flags]
|
| 76 |
+
if not len(selected):
|
| 77 |
+
raise ValueError(
|
| 78 |
+
"Unable to find country name for "
|
| 79 |
+
f"cloud_provider={cloud.provider}, "
|
| 80 |
+
f"cloud_region={cloud.region}"
|
| 81 |
+
)
|
| 82 |
+
return selected["country_name"].item()
|
| 83 |
+
|
| 84 |
+
def get_cloud_country_iso_code(self, cloud: CloudMetadata) -> str:
|
| 85 |
+
"""
|
| 86 |
+
Returns the Country ISO Code where the cloud region is located
|
| 87 |
+
"""
|
| 88 |
+
df: pd.DataFrame = self._data_source.get_cloud_emissions_data()
|
| 89 |
+
flags = (df["provider"] == cloud.provider) & (df["region"] == cloud.region)
|
| 90 |
+
selected = df.loc[flags]
|
| 91 |
+
if not len(selected):
|
| 92 |
+
raise ValueError(
|
| 93 |
+
"Unable to find country ISO Code for "
|
| 94 |
+
f"cloud_provider={cloud.provider}, "
|
| 95 |
+
f"cloud_region={cloud.region}"
|
| 96 |
+
)
|
| 97 |
+
return selected["countryIsoCode"].item()
|
| 98 |
+
|
| 99 |
+
def get_cloud_geo_region(self, cloud: CloudMetadata) -> str:
|
| 100 |
+
"""
|
| 101 |
+
Returns the State/City where the cloud region is located
|
| 102 |
+
"""
|
| 103 |
+
df: pd.DataFrame = self._data_source.get_cloud_emissions_data()
|
| 104 |
+
flags = (df["provider"] == cloud.provider) & (df["region"] == cloud.region)
|
| 105 |
+
selected = df.loc[flags]
|
| 106 |
+
if not len(selected):
|
| 107 |
+
raise ValueError(
|
| 108 |
+
"Unable to find State/City name for "
|
| 109 |
+
f"cloud_provider={cloud.provider}, "
|
| 110 |
+
f"cloud_region={cloud.region}"
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
state = selected["state"].item()
|
| 114 |
+
if state is not None:
|
| 115 |
+
return state
|
| 116 |
+
city = selected["city"].item()
|
| 117 |
+
return city
|
| 118 |
+
|
| 119 |
+
def get_private_infra_emissions(self, energy: Energy, geo: GeoMetadata) -> float:
|
| 120 |
+
"""
|
| 121 |
+
Computes emissions for private infra
|
| 122 |
+
:param energy: Mean power consumption of the process (kWh)
|
| 123 |
+
:param geo: Country and region metadata
|
| 124 |
+
:return: CO2 emissions in kg
|
| 125 |
+
"""
|
| 126 |
+
if self._co2_signal_api_token:
|
| 127 |
+
try:
|
| 128 |
+
return co2_signal.get_emissions(energy, geo, self._co2_signal_api_token)
|
| 129 |
+
except Exception as e:
|
| 130 |
+
logger.error(
|
| 131 |
+
"co2_signal.get_emissions: "
|
| 132 |
+
+ str(e)
|
| 133 |
+
+ " >>> Using CodeCarbon's data."
|
| 134 |
+
)
|
| 135 |
+
|
| 136 |
+
compute_with_regional_data: bool = (geo.region is not None) and (
|
| 137 |
+
geo.country_iso_code.upper() in ["USA", "CAN"]
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
if compute_with_regional_data:
|
| 141 |
+
try:
|
| 142 |
+
return self.get_region_emissions(energy, geo)
|
| 143 |
+
except Exception as e:
|
| 144 |
+
logger.error(e, exc_info=True)
|
| 145 |
+
logger.warning(
|
| 146 |
+
"Regional emissions retrieval failed."
|
| 147 |
+
+ " Falling back on country emissions."
|
| 148 |
+
)
|
| 149 |
+
return self.get_country_emissions(energy, geo)
|
| 150 |
+
|
| 151 |
+
def get_region_emissions(self, energy: Energy, geo: GeoMetadata) -> float:
|
| 152 |
+
"""
|
| 153 |
+
Computes emissions for a region on private infra.
|
| 154 |
+
Given an quantity of power consumed, use regional data
|
| 155 |
+
on emissions per unit power consumed or the mix of energy sources.
|
| 156 |
+
https://github.com/responsibleproblemsolving/energy-usage#calculating-co2-emissions
|
| 157 |
+
:param energy: Mean power consumption of the process (kWh)
|
| 158 |
+
:param geo: Country and region metadata.
|
| 159 |
+
:return: CO2 emissions in kg
|
| 160 |
+
"""
|
| 161 |
+
try:
|
| 162 |
+
country_emissions_data = self._data_source.get_country_emissions_data(
|
| 163 |
+
geo.country_iso_code.lower()
|
| 164 |
+
)
|
| 165 |
+
|
| 166 |
+
if geo.region not in country_emissions_data:
|
| 167 |
+
# TODO: Deal with missing data, default to something
|
| 168 |
+
raise ValueError(
|
| 169 |
+
f"Region: {geo.region} not found for Country"
|
| 170 |
+
+ f" with ISO CODE : {geo.country_iso_code}"
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
emissions_per_kWh: EmissionsPerKWh = EmissionsPerKWh.from_lbs_per_mWh(
|
| 174 |
+
country_emissions_data[geo.region]["emissions"]
|
| 175 |
+
)
|
| 176 |
+
except DataSourceException:
|
| 177 |
+
# This country has regional data at the energy mix level,
|
| 178 |
+
# not the emissions level
|
| 179 |
+
country_energy_mix_data = self._data_source.get_country_energy_mix_data(
|
| 180 |
+
geo.country_iso_code.lower()
|
| 181 |
+
)
|
| 182 |
+
region_energy_mix_data = country_energy_mix_data[geo.region]
|
| 183 |
+
emissions_per_kWh = self._region_energy_mix_to_emissions_rate(
|
| 184 |
+
region_energy_mix_data
|
| 185 |
+
)
|
| 186 |
+
|
| 187 |
+
return emissions_per_kWh.kgs_per_kWh * energy.kWh # kgs
|
| 188 |
+
|
| 189 |
+
def get_country_emissions(self, energy: Energy, geo: GeoMetadata) -> float:
|
| 190 |
+
"""
|
| 191 |
+
Computes emissions for a country on private infra,
|
| 192 |
+
given a quantity of power consumed by
|
| 193 |
+
using data for the mix of energy sources of that country.
|
| 194 |
+
:param energy: Mean power consumption of the process (kWh)
|
| 195 |
+
:param geo: Country and region metadata
|
| 196 |
+
:return: CO2 emissions in kg
|
| 197 |
+
"""
|
| 198 |
+
energy_mix = self._data_source.get_global_energy_mix_data()
|
| 199 |
+
|
| 200 |
+
if geo.country_iso_code not in energy_mix:
|
| 201 |
+
logger.warning(
|
| 202 |
+
f"We do not have data for {geo.country_iso_code}, using world average."
|
| 203 |
+
)
|
| 204 |
+
carbon_intensity_per_source = (
|
| 205 |
+
DataSource().get_carbon_intensity_per_source_data()
|
| 206 |
+
)
|
| 207 |
+
return (
|
| 208 |
+
EmissionsPerKWh.from_g_per_kWh(
|
| 209 |
+
carbon_intensity_per_source.get("world_average")
|
| 210 |
+
).kgs_per_kWh
|
| 211 |
+
* energy.kWh
|
| 212 |
+
) # kgs
|
| 213 |
+
|
| 214 |
+
country_energy_mix: Dict = energy_mix[geo.country_iso_code]
|
| 215 |
+
emissions_per_kWh = self._global_energy_mix_to_emissions_rate(
|
| 216 |
+
country_energy_mix
|
| 217 |
+
)
|
| 218 |
+
logger.debug(
|
| 219 |
+
f"We apply an energy mix of {emissions_per_kWh.kgs_per_kWh * 1000:.0f}"
|
| 220 |
+
+ f" g.CO2eq/kWh for {geo.country_name}"
|
| 221 |
+
)
|
| 222 |
+
|
| 223 |
+
return emissions_per_kWh.kgs_per_kWh * energy.kWh # kgs
|
| 224 |
+
|
| 225 |
+
@staticmethod
|
| 226 |
+
def _global_energy_mix_to_emissions_rate(energy_mix: Dict) -> EmissionsPerKWh:
|
| 227 |
+
"""
|
| 228 |
+
Convert a mix of electricity sources into emissions per kWh.
|
| 229 |
+
:param energy_mix: A dictionary that breaks down the electricity produced into
|
| 230 |
+
energy sources, with a total value. Format will vary, but must have keys for "total_TWh"
|
| 231 |
+
:return: an EmissionsPerKwh object representing the average emissions rate
|
| 232 |
+
in Kgs.CO2 / kWh
|
| 233 |
+
"""
|
| 234 |
+
# If we have the chance to have the carbon intensity for this country
|
| 235 |
+
if energy_mix.get("carbon_intensity"):
|
| 236 |
+
return EmissionsPerKWh.from_g_per_kWh(energy_mix.get("carbon_intensity"))
|
| 237 |
+
|
| 238 |
+
# Else we compute it from the energy mix.
|
| 239 |
+
# Read carbon_intensity from the json data file.
|
| 240 |
+
carbon_intensity_per_source = (
|
| 241 |
+
DataSource().get_carbon_intensity_per_source_data()
|
| 242 |
+
)
|
| 243 |
+
carbon_intensity = 0
|
| 244 |
+
energy_sum = energy_mix["total_TWh"]
|
| 245 |
+
energy_sum_computed = 0
|
| 246 |
+
# Iterate through each source of energy in the country
|
| 247 |
+
for energy_type, energy_per_year in energy_mix.items():
|
| 248 |
+
if "_TWh" in energy_type:
|
| 249 |
+
# Compute the carbon intensity ratio of this source for this country
|
| 250 |
+
carbon_intensity_for_type = carbon_intensity_per_source.get(
|
| 251 |
+
energy_type[: -len("_TWh")]
|
| 252 |
+
)
|
| 253 |
+
if carbon_intensity_for_type: # to ignore "total_TWh"
|
| 254 |
+
carbon_intensity += (
|
| 255 |
+
energy_per_year / energy_sum
|
| 256 |
+
) * carbon_intensity_for_type
|
| 257 |
+
energy_sum_computed += energy_per_year
|
| 258 |
+
|
| 259 |
+
# Sanity check
|
| 260 |
+
if energy_sum_computed != energy_sum:
|
| 261 |
+
logger.error(
|
| 262 |
+
f"We find {energy_sum_computed} TWh instead of {energy_sum} TWh for {energy_mix.get('country_name')}, using world average."
|
| 263 |
+
)
|
| 264 |
+
return EmissionsPerKWh.from_g_per_kWh(
|
| 265 |
+
carbon_intensity_per_source.get("world_average")
|
| 266 |
+
)
|
| 267 |
+
|
| 268 |
+
return EmissionsPerKWh.from_g_per_kWh(carbon_intensity)
|
| 269 |
+
|
| 270 |
+
@staticmethod
|
| 271 |
+
def _region_energy_mix_to_emissions_rate(energy_mix: Dict) -> EmissionsPerKWh:
|
| 272 |
+
"""
|
| 273 |
+
Convert a mix of energy sources into emissions per kWh
|
| 274 |
+
https://github.com/responsibleproblemsolving/energy-usage#calculating-co2-emissions
|
| 275 |
+
:param energy_mix: A dictionary that breaks down the energy produced into
|
| 276 |
+
sources, with a total value. Format will vary, but must have keys for "coal"
|
| 277 |
+
"petroleum" and "naturalGas" and "total"
|
| 278 |
+
:return: an EmissionsPerKwh object representing the average emissions rate
|
| 279 |
+
"""
|
| 280 |
+
# source:
|
| 281 |
+
# https://github.com/responsibleproblemsolving/energy-usage#conversion-to-co2
|
| 282 |
+
emissions_by_source: Dict[str, EmissionsPerKWh] = {
|
| 283 |
+
"coal": EmissionsPerKWh.from_kgs_per_kWh(0.995725971),
|
| 284 |
+
"petroleum": EmissionsPerKWh.from_kgs_per_kWh(0.8166885263),
|
| 285 |
+
"naturalGas": EmissionsPerKWh.from_kgs_per_kWh(0.7438415916),
|
| 286 |
+
}
|
| 287 |
+
emissions_percentage: Dict[str, float] = {}
|
| 288 |
+
for energy_type in energy_mix.keys():
|
| 289 |
+
if energy_type not in ["total", "isoCode", "country_name"]:
|
| 290 |
+
emissions_percentage[energy_type] = (
|
| 291 |
+
energy_mix[energy_type] / energy_mix["total"]
|
| 292 |
+
)
|
| 293 |
+
# Weighted sum of emissions by % of contributions
|
| 294 |
+
# `emissions_percentage`: coal: 0.5, petroleum: 0.25, naturalGas: 0.25
|
| 295 |
+
# `emission_value`: coal: 0.995725971, petroleum: 0.8166885263, naturalGas: 0.7438415916 # noqa: E501
|
| 296 |
+
# `emissions_per_kWh`: (0.5 * 0.995725971) + (0.25 * 0.8166885263) * (0.25 * 0.7438415916) # noqa: E501
|
| 297 |
+
# >> 0.5358309 kg/kWh
|
| 298 |
+
emissions_per_kWh = EmissionsPerKWh.from_kgs_per_kWh(
|
| 299 |
+
sum(
|
| 300 |
+
[
|
| 301 |
+
emissions_percentage[source]
|
| 302 |
+
* value.kgs_per_kWh # % (0.x) # kgs / kWh
|
| 303 |
+
for source, value in emissions_by_source.items()
|
| 304 |
+
]
|
| 305 |
+
)
|
| 306 |
+
)
|
| 307 |
+
|
| 308 |
+
return emissions_per_kWh
|
codecarbon/core/gpu.py
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass, field
|
| 2 |
+
from typing import Any, Dict, List, Union
|
| 3 |
+
|
| 4 |
+
import pynvml
|
| 5 |
+
|
| 6 |
+
from codecarbon.core.units import Energy, Power, Time
|
| 7 |
+
from codecarbon.external.logger import logger
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@dataclass
|
| 11 |
+
class GPUDevice:
|
| 12 |
+
"""
|
| 13 |
+
Represents a GPU device with associated energy and power metrics.
|
| 14 |
+
|
| 15 |
+
Attributes:
|
| 16 |
+
handle (any): An identifier for the GPU device.
|
| 17 |
+
gpu_index (int): The index of the GPU device in the system.
|
| 18 |
+
energy_delta (Energy): The amount of energy consumed by the GPU device
|
| 19 |
+
since the last measurement, expressed in kilowatt-hours (kWh).
|
| 20 |
+
Defaults to an initial value of 0 kWh.
|
| 21 |
+
power (Power): The current power consumption of the GPU device,
|
| 22 |
+
measured in watts (W). Defaults to an initial value of 0 W.
|
| 23 |
+
last_energy (Energy): The last recorded energy reading for the GPU
|
| 24 |
+
device, expressed in kilowatt-hours (kWh). This is used to
|
| 25 |
+
calculate `energy_delta`. Defaults to an initial value of 0 kWh.
|
| 26 |
+
"""
|
| 27 |
+
|
| 28 |
+
handle: any
|
| 29 |
+
gpu_index: int
|
| 30 |
+
# Energy consumed in kWh
|
| 31 |
+
energy_delta: Energy = field(default_factory=lambda: Energy(0))
|
| 32 |
+
# Power based on reading
|
| 33 |
+
power: Power = field(default_factory=lambda: Power(0))
|
| 34 |
+
# Last energy reading in kWh
|
| 35 |
+
last_energy: Energy = field(default_factory=lambda: Energy(0))
|
| 36 |
+
|
| 37 |
+
def start(self) -> None:
|
| 38 |
+
self.last_energy = self._get_energy_kwh()
|
| 39 |
+
|
| 40 |
+
def __post_init__(self) -> None:
|
| 41 |
+
self.last_energy = self._get_energy_kwh()
|
| 42 |
+
self._init_static_details()
|
| 43 |
+
|
| 44 |
+
def _get_energy_kwh(self) -> Energy:
|
| 45 |
+
total_energy_consumption = self._get_total_energy_consumption()
|
| 46 |
+
if total_energy_consumption is None:
|
| 47 |
+
return self.last_energy
|
| 48 |
+
return Energy.from_millijoules(total_energy_consumption)
|
| 49 |
+
|
| 50 |
+
def delta(self, duration: Time) -> dict:
|
| 51 |
+
"""
|
| 52 |
+
Compute the energy/power used since last call.
|
| 53 |
+
"""
|
| 54 |
+
new_last_energy = energy = self._get_energy_kwh()
|
| 55 |
+
self.power = self.power.from_energies_and_delay(
|
| 56 |
+
energy, self.last_energy, duration
|
| 57 |
+
)
|
| 58 |
+
self.energy_delta = energy - self.last_energy
|
| 59 |
+
self.last_energy = new_last_energy
|
| 60 |
+
return {
|
| 61 |
+
"name": self._gpu_name,
|
| 62 |
+
"uuid": self._uuid,
|
| 63 |
+
"delta_energy_consumption": self.energy_delta,
|
| 64 |
+
"power_usage": self.power,
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
def get_static_details(self) -> Dict[str, Any]:
|
| 68 |
+
return {
|
| 69 |
+
"name": self._gpu_name,
|
| 70 |
+
"uuid": self._uuid,
|
| 71 |
+
"total_memory": self._total_memory,
|
| 72 |
+
"power_limit": self._power_limit,
|
| 73 |
+
"gpu_index": self.gpu_index,
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
def _init_static_details(self) -> None:
|
| 77 |
+
self._gpu_name = self._get_gpu_name()
|
| 78 |
+
self._uuid = self._get_uuid()
|
| 79 |
+
self._power_limit = self._get_power_limit()
|
| 80 |
+
# Get the memory
|
| 81 |
+
memory = self._get_memory_info()
|
| 82 |
+
self._total_memory = memory.total
|
| 83 |
+
|
| 84 |
+
def get_gpu_details(self) -> Dict[str, Any]:
|
| 85 |
+
# Memory
|
| 86 |
+
memory = self._get_memory_info()
|
| 87 |
+
|
| 88 |
+
device_details = {
|
| 89 |
+
"name": self._gpu_name,
|
| 90 |
+
"uuid": self._uuid,
|
| 91 |
+
"free_memory": memory.free,
|
| 92 |
+
"total_memory": memory.total,
|
| 93 |
+
"used_memory": memory.used,
|
| 94 |
+
"temperature": self._get_temperature(),
|
| 95 |
+
"power_usage": self._get_power_usage(),
|
| 96 |
+
"power_limit": self._power_limit,
|
| 97 |
+
"total_energy_consumption": self._get_total_energy_consumption(),
|
| 98 |
+
"gpu_utilization": self._get_gpu_utilization(),
|
| 99 |
+
"compute_mode": self._get_compute_mode(),
|
| 100 |
+
"compute_processes": self._get_compute_processes(),
|
| 101 |
+
"graphics_processes": self._get_graphics_processes(),
|
| 102 |
+
}
|
| 103 |
+
return device_details
|
| 104 |
+
|
| 105 |
+
def _to_utf8(self, str_or_bytes) -> Any:
|
| 106 |
+
if hasattr(str_or_bytes, "decode"):
|
| 107 |
+
return str_or_bytes.decode("utf-8", errors="replace")
|
| 108 |
+
|
| 109 |
+
return str_or_bytes
|
| 110 |
+
|
| 111 |
+
def _get_total_energy_consumption(self) -> int:
|
| 112 |
+
"""Returns total energy consumption for this GPU in millijoules (mJ) since the driver was last reloaded
|
| 113 |
+
https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html#group__nvmlDeviceQueries_1g732ab899b5bd18ac4bfb93c02de4900a
|
| 114 |
+
"""
|
| 115 |
+
try:
|
| 116 |
+
return pynvml.nvmlDeviceGetTotalEnergyConsumption(self.handle)
|
| 117 |
+
except pynvml.NVMLError:
|
| 118 |
+
logger.warning(
|
| 119 |
+
"Failed to retrieve gpu total energy consumption", exc_info=True
|
| 120 |
+
)
|
| 121 |
+
return None
|
| 122 |
+
|
| 123 |
+
def _get_gpu_name(self) -> Any:
|
| 124 |
+
"""Returns the name of the GPU device
|
| 125 |
+
https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html#group__nvmlDeviceQueries_1ga5361803e044c6fdf3b08523fb6d1481
|
| 126 |
+
"""
|
| 127 |
+
try:
|
| 128 |
+
name = pynvml.nvmlDeviceGetName(self.handle)
|
| 129 |
+
return self._to_utf8(name)
|
| 130 |
+
except UnicodeDecodeError:
|
| 131 |
+
return "Unknown GPU"
|
| 132 |
+
|
| 133 |
+
def _get_uuid(self) -> Any:
|
| 134 |
+
"""Returns the globally unique GPU device UUID
|
| 135 |
+
https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html#group__nvmlDeviceQueries_1g72710fb20f30f0c2725ce31579832654
|
| 136 |
+
"""
|
| 137 |
+
uuid = pynvml.nvmlDeviceGetUUID(self.handle)
|
| 138 |
+
return self._to_utf8(uuid)
|
| 139 |
+
|
| 140 |
+
def _get_memory_info(self):
|
| 141 |
+
"""Returns memory info in bytes
|
| 142 |
+
https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html#group__nvmlDeviceQueries_1g2dfeb1db82aa1de91aa6edf941c85ca8
|
| 143 |
+
"""
|
| 144 |
+
return pynvml.nvmlDeviceGetMemoryInfo(self.handle)
|
| 145 |
+
|
| 146 |
+
def _get_temperature(self) -> int:
|
| 147 |
+
"""Returns degrees in the Celsius scale
|
| 148 |
+
https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html#group__nvmlDeviceQueries_1g92d1c5182a14dd4be7090e3c1480b121
|
| 149 |
+
"""
|
| 150 |
+
return pynvml.nvmlDeviceGetTemperature(self.handle, pynvml.NVML_TEMPERATURE_GPU)
|
| 151 |
+
|
| 152 |
+
def _get_power_usage(self) -> int:
|
| 153 |
+
"""Returns power usage in milliwatts
|
| 154 |
+
https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html#group__nvmlDeviceQueries_1g7ef7dff0ff14238d08a19ad7fb23fc87
|
| 155 |
+
"""
|
| 156 |
+
return pynvml.nvmlDeviceGetPowerUsage(self.handle)
|
| 157 |
+
|
| 158 |
+
def _get_power_limit(self) -> Union[int, None]:
|
| 159 |
+
"""Returns max power usage in milliwatts
|
| 160 |
+
https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html#group__nvmlDeviceQueries_1g263b5bf552d5ec7fcd29a088264d10ad
|
| 161 |
+
"""
|
| 162 |
+
try:
|
| 163 |
+
return pynvml.nvmlDeviceGetEnforcedPowerLimit(self.handle)
|
| 164 |
+
except Exception:
|
| 165 |
+
return None
|
| 166 |
+
|
| 167 |
+
def _get_gpu_utilization(self):
|
| 168 |
+
"""Returns the % of utilization of the kernels during the last sample
|
| 169 |
+
https://docs.nvidia.com/deploy/nvml-api/structnvmlUtilization__t.html#structnvmlUtilization__t
|
| 170 |
+
"""
|
| 171 |
+
return pynvml.nvmlDeviceGetUtilizationRates(self.handle).gpu
|
| 172 |
+
|
| 173 |
+
def _get_compute_mode(self) -> int:
|
| 174 |
+
"""Returns the compute mode of the GPU
|
| 175 |
+
https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceEnumvs.html#group__nvmlDeviceEnumvs_1gbed1b88f2e3ba39070d31d1db4340233
|
| 176 |
+
"""
|
| 177 |
+
return pynvml.nvmlDeviceGetComputeMode(self.handle)
|
| 178 |
+
|
| 179 |
+
def _get_compute_processes(self) -> List:
|
| 180 |
+
"""Returns the list of processes ids having a compute context on the
|
| 181 |
+
device with the memory used
|
| 182 |
+
https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html#group__nvmlDeviceQueries_1g46ceaea624d5c96e098e03c453419d68
|
| 183 |
+
"""
|
| 184 |
+
try:
|
| 185 |
+
processes = pynvml.nvmlDeviceGetComputeRunningProcesses(self.handle)
|
| 186 |
+
|
| 187 |
+
return [{"pid": p.pid, "used_memory": p.usedGpuMemory} for p in processes]
|
| 188 |
+
except pynvml.NVMLError:
|
| 189 |
+
return []
|
| 190 |
+
|
| 191 |
+
def _get_graphics_processes(self) -> List:
|
| 192 |
+
"""Returns the list of processes ids having a graphics context on the
|
| 193 |
+
device with the memory used
|
| 194 |
+
https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html#group__nvmlDeviceQueries_1g7eacf7fa7ba4f4485d166736bf31195e
|
| 195 |
+
"""
|
| 196 |
+
try:
|
| 197 |
+
processes = pynvml.nvmlDeviceGetGraphicsRunningProcesses(self.handle)
|
| 198 |
+
|
| 199 |
+
return [{"pid": p.pid, "used_memory": p.usedGpuMemory} for p in processes]
|
| 200 |
+
except pynvml.NVMLError:
|
| 201 |
+
return []
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
class AllGPUDevices:
|
| 205 |
+
def __init__(self) -> None:
|
| 206 |
+
if is_gpu_details_available():
|
| 207 |
+
logger.debug("GPU available. Starting setup")
|
| 208 |
+
self.device_count = pynvml.nvmlDeviceGetCount()
|
| 209 |
+
else:
|
| 210 |
+
logger.error("There is no GPU available")
|
| 211 |
+
self.device_count = 0
|
| 212 |
+
self.devices = []
|
| 213 |
+
for i in range(self.device_count):
|
| 214 |
+
handle = pynvml.nvmlDeviceGetHandleByIndex(i)
|
| 215 |
+
gpu_device = GPUDevice(handle=handle, gpu_index=i)
|
| 216 |
+
self.devices.append(gpu_device)
|
| 217 |
+
|
| 218 |
+
def get_gpu_static_info(self) -> List:
|
| 219 |
+
"""Get all GPUs static information.
|
| 220 |
+
>>> get_gpu_static_info()
|
| 221 |
+
[
|
| 222 |
+
{
|
| 223 |
+
"name": "Tesla V100-SXM2-16GB",
|
| 224 |
+
"uuid": "GPU-4e817856-1fb8-192a-7ab7-0e0e4476c184",
|
| 225 |
+
"total_memory": 16945512448,
|
| 226 |
+
"power_limit": 300000,
|
| 227 |
+
"gpu_index": 0,
|
| 228 |
+
}
|
| 229 |
+
]
|
| 230 |
+
"""
|
| 231 |
+
try:
|
| 232 |
+
devices_static_info = []
|
| 233 |
+
for i in range(self.device_count):
|
| 234 |
+
gpu_device = self.devices[i]
|
| 235 |
+
devices_static_info.append(gpu_device.get_static_details())
|
| 236 |
+
return devices_static_info
|
| 237 |
+
|
| 238 |
+
except pynvml.NVMLError:
|
| 239 |
+
logger.warning("Failed to retrieve gpu static info", exc_info=True)
|
| 240 |
+
return []
|
| 241 |
+
|
| 242 |
+
def get_gpu_details(self) -> List:
|
| 243 |
+
"""Get all GPUs instantaneous metrics
|
| 244 |
+
>>> get_gpu_details()
|
| 245 |
+
[
|
| 246 |
+
{
|
| 247 |
+
"name": "Tesla V100-SXM2-16GB",
|
| 248 |
+
"uuid": "GPU-4e817856-1fb8-192a-7ab7-0e0e4476c184",
|
| 249 |
+
"free_memory": 16945381376,
|
| 250 |
+
"total_memory": 16945512448,
|
| 251 |
+
"used_memory": 131072,
|
| 252 |
+
"temperature": 28,
|
| 253 |
+
"total_energy_consumption":2000,
|
| 254 |
+
"power_usage": 42159,
|
| 255 |
+
"power_limit": 300000,
|
| 256 |
+
"gpu_utilization": 0,
|
| 257 |
+
"compute_mode": 0,
|
| 258 |
+
"compute_processes": [],
|
| 259 |
+
"graphics_processes": [],
|
| 260 |
+
}
|
| 261 |
+
]
|
| 262 |
+
"""
|
| 263 |
+
try:
|
| 264 |
+
devices_info = []
|
| 265 |
+
for i in range(self.device_count):
|
| 266 |
+
gpu_device: GPUDevice = self.devices[i]
|
| 267 |
+
devices_info.append(gpu_device.get_gpu_details())
|
| 268 |
+
return devices_info
|
| 269 |
+
|
| 270 |
+
except pynvml.NVMLError:
|
| 271 |
+
logger.warning("Failed to retrieve gpu information", exc_info=True)
|
| 272 |
+
return []
|
| 273 |
+
|
| 274 |
+
def get_delta(self, last_duration: Time) -> List:
|
| 275 |
+
"""Get difference since last time this function was called
|
| 276 |
+
>>> get_delta()
|
| 277 |
+
[
|
| 278 |
+
{
|
| 279 |
+
"name": "Tesla V100-SXM2-16GB",
|
| 280 |
+
"uuid": "GPU-4e817856-1fb8-192a-7ab7-0e0e4476c184",
|
| 281 |
+
"delta_energy_consumption":2000,
|
| 282 |
+
"power_usage": 42159,
|
| 283 |
+
}
|
| 284 |
+
]
|
| 285 |
+
"""
|
| 286 |
+
try:
|
| 287 |
+
devices_info = []
|
| 288 |
+
for i in range(self.device_count):
|
| 289 |
+
gpu_device: GPUDevice = self.devices[i]
|
| 290 |
+
devices_info.append(gpu_device.delta(last_duration))
|
| 291 |
+
return devices_info
|
| 292 |
+
|
| 293 |
+
except pynvml.NVMLError:
|
| 294 |
+
logger.warning("Failed to retrieve gpu information", exc_info=True)
|
| 295 |
+
return []
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
def is_gpu_details_available() -> bool:
|
| 299 |
+
"""Returns True if the GPU details are available."""
|
| 300 |
+
try:
|
| 301 |
+
pynvml.nvmlInit()
|
| 302 |
+
return True
|
| 303 |
+
|
| 304 |
+
except pynvml.NVMLError:
|
| 305 |
+
return False
|
codecarbon/core/measure.py
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from time import perf_counter
|
| 2 |
+
|
| 3 |
+
from codecarbon.external.hardware import CPU, GPU, RAM, AppleSiliconChip
|
| 4 |
+
from codecarbon.external.logger import logger
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class MeasurePowerEnergy:
|
| 8 |
+
"""
|
| 9 |
+
Measure power and energy consumption of a hardware component.
|
| 10 |
+
"""
|
| 11 |
+
|
| 12 |
+
_last_measured_time: int = 0
|
| 13 |
+
_hardware: list
|
| 14 |
+
_pue: float
|
| 15 |
+
_total_cpu_energy: float
|
| 16 |
+
_total_gpu_energy: float
|
| 17 |
+
_total_ram_energy: float
|
| 18 |
+
_total_energy: float
|
| 19 |
+
_cpu_power: float
|
| 20 |
+
_gpu_power: float
|
| 21 |
+
_ram_power: float
|
| 22 |
+
|
| 23 |
+
def __init__(self, hardware, pue):
|
| 24 |
+
"""
|
| 25 |
+
:param hardware: list of hardware components to measure
|
| 26 |
+
:param pue: Power Usage Effectiveness of the datacenter
|
| 27 |
+
"""
|
| 28 |
+
self._last_measured_time = perf_counter()
|
| 29 |
+
self._hardware = hardware
|
| 30 |
+
self._pue = pue
|
| 31 |
+
# TODO: Read initial energy values from hardware
|
| 32 |
+
self._total_cpu_energy = 0
|
| 33 |
+
self._total_gpu_energy = 0
|
| 34 |
+
self._total_ram_energy = 0
|
| 35 |
+
self._total_energy = 0
|
| 36 |
+
# Power cant't be read at init because we need time, so we set it to 0
|
| 37 |
+
self._cpu_power = 0
|
| 38 |
+
self._gpu_power = 0
|
| 39 |
+
self._ram_power = 0
|
| 40 |
+
|
| 41 |
+
def do_measure(self) -> None:
|
| 42 |
+
for hardware in self._hardware:
|
| 43 |
+
h_time = perf_counter()
|
| 44 |
+
# Compute last_duration again for more accuracy
|
| 45 |
+
last_duration = perf_counter() - self._last_measured_time
|
| 46 |
+
power, energy = hardware.measure_power_and_energy(
|
| 47 |
+
last_duration=last_duration
|
| 48 |
+
)
|
| 49 |
+
# Apply the PUE of the datacenter to the consumed energy
|
| 50 |
+
energy *= self._pue
|
| 51 |
+
self._total_energy += energy
|
| 52 |
+
if isinstance(hardware, CPU):
|
| 53 |
+
self._total_cpu_energy += energy
|
| 54 |
+
self._cpu_power = power
|
| 55 |
+
logger.info(
|
| 56 |
+
f"Energy consumed for all CPUs : {self._total_cpu_energy.kWh:.6f} kWh"
|
| 57 |
+
+ f". Total CPU Power : {self._cpu_power.W} W"
|
| 58 |
+
)
|
| 59 |
+
elif isinstance(hardware, GPU):
|
| 60 |
+
self._total_gpu_energy += energy
|
| 61 |
+
self._gpu_power = power
|
| 62 |
+
logger.info(
|
| 63 |
+
f"Energy consumed for all GPUs : {self._total_gpu_energy.kWh:.6f} kWh"
|
| 64 |
+
+ f". Total GPU Power : {self._gpu_power.W} W"
|
| 65 |
+
)
|
| 66 |
+
elif isinstance(hardware, RAM):
|
| 67 |
+
self._total_ram_energy += energy
|
| 68 |
+
self._ram_power = power
|
| 69 |
+
logger.info(
|
| 70 |
+
f"Energy consumed for RAM : {self._total_ram_energy.kWh:.6f} kWh."
|
| 71 |
+
+ f"RAM Power : {self._ram_power.W} W"
|
| 72 |
+
)
|
| 73 |
+
elif isinstance(hardware, AppleSiliconChip):
|
| 74 |
+
if hardware.chip_part == "CPU":
|
| 75 |
+
self._total_cpu_energy += energy
|
| 76 |
+
self._cpu_power = power
|
| 77 |
+
logger.info(
|
| 78 |
+
f"Energy consumed for AppleSilicon CPU : {self._total_cpu_energy.kWh:.6f} kWh"
|
| 79 |
+
+ f".Apple Silicon CPU Power : {self._cpu_power.W} W"
|
| 80 |
+
)
|
| 81 |
+
elif hardware.chip_part == "GPU":
|
| 82 |
+
self._total_gpu_energy += energy
|
| 83 |
+
self._gpu_power = power
|
| 84 |
+
logger.info(
|
| 85 |
+
f"Energy consumed for AppleSilicon GPU : {self._total_gpu_energy.kWh:.6f} kWh"
|
| 86 |
+
+ f".Apple Silicon GPU Power : {self._gpu_power.W} W"
|
| 87 |
+
)
|
| 88 |
+
else:
|
| 89 |
+
logger.error(f"Unknown hardware type: {hardware} ({type(hardware)})")
|
| 90 |
+
h_time = perf_counter() - h_time
|
| 91 |
+
logger.debug(
|
| 92 |
+
f"{hardware.__class__.__name__} : {hardware.total_power().W:,.2f} "
|
| 93 |
+
+ f"W during {last_duration:,.2f} s [measurement time: {h_time:,.4f}]"
|
| 94 |
+
)
|
| 95 |
+
logger.info(
|
| 96 |
+
f"{self._total_energy.kWh:.6f} kWh of electricity used since the beginning."
|
| 97 |
+
)
|
codecarbon/core/powermetrics.py
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import re
|
| 3 |
+
import shutil
|
| 4 |
+
import subprocess
|
| 5 |
+
import sys
|
| 6 |
+
from typing import Dict
|
| 7 |
+
|
| 8 |
+
import numpy as np
|
| 9 |
+
|
| 10 |
+
from codecarbon.core.util import detect_cpu_model
|
| 11 |
+
from codecarbon.external.logger import logger
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def is_powermetrics_available() -> bool:
|
| 15 |
+
try:
|
| 16 |
+
ApplePowermetrics()
|
| 17 |
+
response = _has_powermetrics_sudo()
|
| 18 |
+
return response
|
| 19 |
+
except Exception as e:
|
| 20 |
+
logger.debug(
|
| 21 |
+
"Not using PowerMetrics, an exception occurred while instantiating"
|
| 22 |
+
+ f" Powermetrics : {e}",
|
| 23 |
+
)
|
| 24 |
+
return False
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
def _has_powermetrics_sudo() -> bool:
|
| 28 |
+
if shutil.which("sudo") is None:
|
| 29 |
+
logger.debug("sudo not available, we won't use Apple PowerMetrics.")
|
| 30 |
+
return False
|
| 31 |
+
if shutil.which("powermetrics") is None:
|
| 32 |
+
logger.info(
|
| 33 |
+
"Apple PowerMetrics not available. Please install it if you are using an Apple product."
|
| 34 |
+
)
|
| 35 |
+
return False
|
| 36 |
+
|
| 37 |
+
with subprocess.Popen(
|
| 38 |
+
[
|
| 39 |
+
"sudo",
|
| 40 |
+
"powermetrics",
|
| 41 |
+
"--samplers",
|
| 42 |
+
"cpu_power",
|
| 43 |
+
"-n",
|
| 44 |
+
"1",
|
| 45 |
+
"-i",
|
| 46 |
+
"1",
|
| 47 |
+
"-o",
|
| 48 |
+
"/dev/null",
|
| 49 |
+
],
|
| 50 |
+
stdout=subprocess.PIPE,
|
| 51 |
+
stderr=subprocess.PIPE,
|
| 52 |
+
text=True,
|
| 53 |
+
) as process:
|
| 54 |
+
_, stderr = process.communicate()
|
| 55 |
+
|
| 56 |
+
if re.search(r"[sudo].*password", stderr):
|
| 57 |
+
logger.debug(
|
| 58 |
+
"""Not using PowerMetrics, sudo password prompt detected.
|
| 59 |
+
If you want to enable Powermetrics please modify your sudoers file
|
| 60 |
+
as described in :
|
| 61 |
+
https://mlco2.github.io/codecarbon/methodology.html#power-usage
|
| 62 |
+
"""
|
| 63 |
+
)
|
| 64 |
+
return False
|
| 65 |
+
if process.returncode != 0:
|
| 66 |
+
raise Exception("Return code != 0")
|
| 67 |
+
|
| 68 |
+
return True
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
class ApplePowermetrics:
|
| 72 |
+
"""
|
| 73 |
+
A class to interact with and retrieve power metrics on Apple Silicon devices using
|
| 74 |
+
the `powermetrics` command-line tool.
|
| 75 |
+
|
| 76 |
+
Methods:
|
| 77 |
+
--------
|
| 78 |
+
__init__(output_dir: str = ".", n_points=10, interval=100, log_file_name="powermetrics_log.txt"):
|
| 79 |
+
Initializes the ApplePowermetrics instance, setting up the log file path, system info,
|
| 80 |
+
and other configurations.
|
| 81 |
+
|
| 82 |
+
get_details() -> Dict:
|
| 83 |
+
Parses the log file generated by `powermetrics` and returns a dictionary containing
|
| 84 |
+
the average CPU and GPU power consumption and energy deltas. If parsing fails, logs
|
| 85 |
+
the exception and returns an empty dictionary.
|
| 86 |
+
|
| 87 |
+
start() -> None:
|
| 88 |
+
Placeholder method for starting the energy reading process (to be implemented).
|
| 89 |
+
"""
|
| 90 |
+
|
| 91 |
+
_osx_silicon_exec = "powermetrics"
|
| 92 |
+
|
| 93 |
+
def __init__(
|
| 94 |
+
self,
|
| 95 |
+
output_dir: str = ".",
|
| 96 |
+
n_points=10,
|
| 97 |
+
interval=100,
|
| 98 |
+
log_file_name="powermetrics_log.txt",
|
| 99 |
+
):
|
| 100 |
+
self._log_file_path = os.path.join(output_dir, log_file_name)
|
| 101 |
+
self._system = sys.platform.lower()
|
| 102 |
+
self._n_points = n_points
|
| 103 |
+
self._interval = interval
|
| 104 |
+
self._setup_cli()
|
| 105 |
+
|
| 106 |
+
def _setup_cli(self) -> None:
|
| 107 |
+
"""
|
| 108 |
+
Setup cli command to run Powermetrics
|
| 109 |
+
"""
|
| 110 |
+
if self._system.startswith("darwin"):
|
| 111 |
+
cpu_model = detect_cpu_model()
|
| 112 |
+
if cpu_model.startswith("Apple"):
|
| 113 |
+
if shutil.which(self._osx_silicon_exec):
|
| 114 |
+
self._cli = self._osx_silicon_exec
|
| 115 |
+
else:
|
| 116 |
+
raise FileNotFoundError(
|
| 117 |
+
f"Powermetrics executable not found on {self._system}"
|
| 118 |
+
)
|
| 119 |
+
else:
|
| 120 |
+
raise SystemError("Platform not supported by Powermetrics")
|
| 121 |
+
|
| 122 |
+
def _log_values(self) -> None:
|
| 123 |
+
"""
|
| 124 |
+
Logs output from Powermetrics to a file
|
| 125 |
+
"""
|
| 126 |
+
returncode = None
|
| 127 |
+
|
| 128 |
+
if self._system.startswith("darwin"):
|
| 129 |
+
# Run the powermetrics command with sudo and capture its output
|
| 130 |
+
cmd = [
|
| 131 |
+
"sudo",
|
| 132 |
+
"powermetrics",
|
| 133 |
+
"-n",
|
| 134 |
+
str(self._n_points),
|
| 135 |
+
"",
|
| 136 |
+
"--samplers",
|
| 137 |
+
"cpu_power",
|
| 138 |
+
"--format",
|
| 139 |
+
"csv",
|
| 140 |
+
"-i",
|
| 141 |
+
str(self._interval),
|
| 142 |
+
"-o",
|
| 143 |
+
self._log_file_path,
|
| 144 |
+
]
|
| 145 |
+
returncode = subprocess.call(cmd, universal_newlines=True)
|
| 146 |
+
|
| 147 |
+
else:
|
| 148 |
+
return None
|
| 149 |
+
|
| 150 |
+
if returncode != 0:
|
| 151 |
+
logger.warning(
|
| 152 |
+
"Returncode while logging power values using "
|
| 153 |
+
+ f"Powermetrics: {returncode}"
|
| 154 |
+
)
|
| 155 |
+
return
|
| 156 |
+
|
| 157 |
+
def get_details(self) -> Dict:
|
| 158 |
+
"""
|
| 159 |
+
Fetches the CPU Power Details by fetching values from a logged csv file
|
| 160 |
+
in _log_values function
|
| 161 |
+
"""
|
| 162 |
+
self._log_values()
|
| 163 |
+
details = dict()
|
| 164 |
+
try:
|
| 165 |
+
with open(self._log_file_path) as f:
|
| 166 |
+
logfile = f.read()
|
| 167 |
+
cpu_pattern = r"CPU Power: (\d+) mW"
|
| 168 |
+
cpu_power_list = re.findall(cpu_pattern, logfile)
|
| 169 |
+
|
| 170 |
+
details["CPU Power"] = np.mean(
|
| 171 |
+
[float(power) / 1000 for power in cpu_power_list]
|
| 172 |
+
)
|
| 173 |
+
details["CPU Energy Delta"] = np.sum(
|
| 174 |
+
[
|
| 175 |
+
(self._interval / 1000) * (float(power) / 1000)
|
| 176 |
+
for power in cpu_power_list
|
| 177 |
+
]
|
| 178 |
+
)
|
| 179 |
+
gpu_pattern = r"GPU Power: (\d+) mW"
|
| 180 |
+
gpu_power_list = re.findall(gpu_pattern, logfile)
|
| 181 |
+
details["GPU Power"] = np.mean(
|
| 182 |
+
[float(power) / 1000 for power in gpu_power_list]
|
| 183 |
+
)
|
| 184 |
+
details["GPU Energy Delta"] = np.sum(
|
| 185 |
+
[
|
| 186 |
+
(self._interval / 1000) * (float(power) / 1000)
|
| 187 |
+
for power in gpu_power_list
|
| 188 |
+
]
|
| 189 |
+
)
|
| 190 |
+
except Exception as e:
|
| 191 |
+
logger.info(
|
| 192 |
+
f"Unable to read Powermetrics logged file at {self._log_file_path}\n \
|
| 193 |
+
Exception occurred {e}",
|
| 194 |
+
exc_info=True,
|
| 195 |
+
)
|
| 196 |
+
return details
|
| 197 |
+
|
| 198 |
+
def start(self) -> None:
|
| 199 |
+
# TODO: Read energy
|
| 200 |
+
pass
|
codecarbon/core/rapl.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass, field
|
| 2 |
+
|
| 3 |
+
from codecarbon.core.units import Energy, Power, Time
|
| 4 |
+
from codecarbon.external.logger import logger
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
@dataclass
|
| 8 |
+
class RAPLFile:
|
| 9 |
+
# RAPL device being measured
|
| 10 |
+
name: str
|
| 11 |
+
# Path to file containing RAPL reading
|
| 12 |
+
path: str
|
| 13 |
+
# Path to corresponding file containing maximum possible RAPL reading
|
| 14 |
+
max_path: str
|
| 15 |
+
# Energy consumed in kWh
|
| 16 |
+
energy_delta: Energy = field(default_factory=lambda: Energy(0))
|
| 17 |
+
# Power based on reading
|
| 18 |
+
power: Power = field(default_factory=lambda: Power(0))
|
| 19 |
+
# Last energy reading in kWh
|
| 20 |
+
last_energy: Energy = field(default_factory=lambda: Energy(0))
|
| 21 |
+
# Max value energy can hold before it wraps
|
| 22 |
+
max_energy_reading: Energy = field(default_factory=lambda: Energy(0))
|
| 23 |
+
|
| 24 |
+
def __post_init__(self):
|
| 25 |
+
self.last_energy = self._get_value()
|
| 26 |
+
with open(self.max_path, "r") as f:
|
| 27 |
+
max_micro_joules = float(f.read())
|
| 28 |
+
|
| 29 |
+
self.max_energy_reading = Energy.from_ujoules(max_micro_joules)
|
| 30 |
+
|
| 31 |
+
def _get_value(self) -> Energy:
|
| 32 |
+
"""
|
| 33 |
+
Reads the value in the file at the path
|
| 34 |
+
"""
|
| 35 |
+
with open(self.path, "r") as f:
|
| 36 |
+
micro_joules = float(f.read())
|
| 37 |
+
|
| 38 |
+
e = Energy.from_ujoules(micro_joules)
|
| 39 |
+
return e
|
| 40 |
+
|
| 41 |
+
def start(self) -> None:
|
| 42 |
+
self.last_energy = self._get_value()
|
| 43 |
+
|
| 44 |
+
def delta(self, duration: Time) -> None:
|
| 45 |
+
"""
|
| 46 |
+
Compute the energy used since last call.
|
| 47 |
+
"""
|
| 48 |
+
new_last_energy = energy = self._get_value()
|
| 49 |
+
if self.last_energy > energy:
|
| 50 |
+
logger.debug(
|
| 51 |
+
f"In RAPLFile : Current energy value ({energy}) is lower than previous value ({self.last_energy}). Assuming wrap-around! Source file : {self.path}"
|
| 52 |
+
)
|
| 53 |
+
energy = energy + self.max_energy_reading
|
| 54 |
+
self.power = self.power.from_energies_and_delay(
|
| 55 |
+
energy, self.last_energy, duration
|
| 56 |
+
)
|
| 57 |
+
self.energy_delta = energy - self.last_energy
|
| 58 |
+
self.last_energy = new_last_energy
|
codecarbon/core/resource_tracker.py
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from collections import Counter
|
| 2 |
+
from typing import List, Union
|
| 3 |
+
|
| 4 |
+
from codecarbon.core import cpu, gpu, powermetrics
|
| 5 |
+
from codecarbon.core.config import parse_gpu_ids
|
| 6 |
+
from codecarbon.core.util import detect_cpu_model, is_linux_os, is_mac_os, is_windows_os
|
| 7 |
+
from codecarbon.external.hardware import CPU, GPU, MODE_CPU_LOAD, AppleSiliconChip
|
| 8 |
+
from codecarbon.external.logger import logger
|
| 9 |
+
from codecarbon.external.ram import RAM
|
| 10 |
+
|
| 11 |
+
|
| 12 |
+
class ResourceTracker:
|
| 13 |
+
cpu_tracker = gpu_tracker = ram_tracker = "Unspecified"
|
| 14 |
+
|
| 15 |
+
def __init__(self, tracker):
|
| 16 |
+
self.tracker = tracker
|
| 17 |
+
|
| 18 |
+
def set_RAM_tracking(self):
|
| 19 |
+
logger.info("[setup] RAM Tracking...")
|
| 20 |
+
if self.tracker._force_ram_power is not None:
|
| 21 |
+
self.ram_tracker = (
|
| 22 |
+
f"User specified constant: {self.tracker._force_ram_power} Watts"
|
| 23 |
+
)
|
| 24 |
+
logger.info(
|
| 25 |
+
f"Using user-provided RAM power: {self.tracker._force_ram_power} Watts"
|
| 26 |
+
)
|
| 27 |
+
else:
|
| 28 |
+
self.ram_tracker = "RAM power estimation model"
|
| 29 |
+
ram = RAM(
|
| 30 |
+
tracking_mode=self.tracker._tracking_mode,
|
| 31 |
+
force_ram_power=self.tracker._force_ram_power,
|
| 32 |
+
)
|
| 33 |
+
self.tracker._conf["ram_total_size"] = ram.machine_memory_GB
|
| 34 |
+
self.tracker._hardware: List[Union[RAM, CPU, GPU, AppleSiliconChip]] = [ram]
|
| 35 |
+
|
| 36 |
+
def set_CPU_tracking(self):
|
| 37 |
+
logger.info("[setup] CPU Tracking...")
|
| 38 |
+
cpu_number = self.tracker._conf.get("cpu_physical_count")
|
| 39 |
+
tdp = cpu.TDP()
|
| 40 |
+
if self.tracker._force_cpu_power is not None:
|
| 41 |
+
logger.info(
|
| 42 |
+
f"Using user-provided CPU power: {self.tracker._force_cpu_power} Watts"
|
| 43 |
+
)
|
| 44 |
+
self.cpu_tracker = "User Input TDP constant"
|
| 45 |
+
max_power = self.tracker._force_cpu_power
|
| 46 |
+
else:
|
| 47 |
+
max_power = tdp.tdp * cpu_number if tdp.tdp is not None else None
|
| 48 |
+
if self.tracker._conf.get("force_mode_cpu_load", False) and (
|
| 49 |
+
tdp.tdp is not None or self.tracker._force_cpu_power is not None
|
| 50 |
+
):
|
| 51 |
+
if cpu.is_psutil_available():
|
| 52 |
+
# Register a CPU with MODE_CPU_LOAD
|
| 53 |
+
model = tdp.model
|
| 54 |
+
hardware_cpu = CPU.from_utils(
|
| 55 |
+
self.tracker._output_dir,
|
| 56 |
+
MODE_CPU_LOAD,
|
| 57 |
+
model,
|
| 58 |
+
max_power,
|
| 59 |
+
tracking_mode=self.tracker._tracking_mode,
|
| 60 |
+
)
|
| 61 |
+
self.cpu_tracker = MODE_CPU_LOAD
|
| 62 |
+
self.tracker._conf["cpu_model"] = hardware_cpu.get_model()
|
| 63 |
+
self.tracker._hardware.append(hardware_cpu)
|
| 64 |
+
return
|
| 65 |
+
else:
|
| 66 |
+
logger.warning(
|
| 67 |
+
"Force CPU load mode requested but psutil is not available."
|
| 68 |
+
)
|
| 69 |
+
if cpu.is_powergadget_available() and self.tracker._force_cpu_power is None:
|
| 70 |
+
logger.info("Tracking Intel CPU via Power Gadget")
|
| 71 |
+
self.cpu_tracker = "Power Gadget"
|
| 72 |
+
hardware_cpu = CPU.from_utils(
|
| 73 |
+
self.tracker._output_dir, "intel_power_gadget"
|
| 74 |
+
)
|
| 75 |
+
self.tracker._hardware.append(hardware_cpu)
|
| 76 |
+
self.tracker._conf["cpu_model"] = hardware_cpu.get_model()
|
| 77 |
+
elif cpu.is_rapl_available():
|
| 78 |
+
logger.info("Tracking Intel CPU via RAPL interface")
|
| 79 |
+
self.cpu_tracker = "RAPL"
|
| 80 |
+
hardware_cpu = CPU.from_utils(
|
| 81 |
+
output_dir=self.tracker._output_dir, mode="intel_rapl"
|
| 82 |
+
)
|
| 83 |
+
self.tracker._hardware.append(hardware_cpu)
|
| 84 |
+
self.tracker._conf["cpu_model"] = hardware_cpu.get_model()
|
| 85 |
+
if "AMD Ryzen Threadripper" in self.tracker._conf["cpu_model"]:
|
| 86 |
+
logger.warning(
|
| 87 |
+
"The RAPL energy and power reported is divided by 2 for all 'AMD Ryzen Threadripper' as it seems to give better results."
|
| 88 |
+
)
|
| 89 |
+
# change code to check if powermetrics needs to be installed or just sudo setup
|
| 90 |
+
elif (
|
| 91 |
+
powermetrics.is_powermetrics_available()
|
| 92 |
+
and self.tracker._force_cpu_power is None
|
| 93 |
+
):
|
| 94 |
+
logger.info("Tracking Apple CPU and GPU via PowerMetrics")
|
| 95 |
+
self.gpu_tracker = "PowerMetrics"
|
| 96 |
+
self.cpu_tracker = "PowerMetrics"
|
| 97 |
+
hardware_cpu = AppleSiliconChip.from_utils(
|
| 98 |
+
self.tracker._output_dir, chip_part="CPU"
|
| 99 |
+
)
|
| 100 |
+
self.tracker._hardware.append(hardware_cpu)
|
| 101 |
+
self.tracker._conf["cpu_model"] = hardware_cpu.get_model()
|
| 102 |
+
|
| 103 |
+
hardware_gpu = AppleSiliconChip.from_utils(
|
| 104 |
+
self.tracker._output_dir, chip_part="GPU"
|
| 105 |
+
)
|
| 106 |
+
self.tracker._hardware.append(hardware_gpu)
|
| 107 |
+
|
| 108 |
+
self.tracker._conf["gpu_model"] = hardware_gpu.get_model()
|
| 109 |
+
self.tracker._conf["gpu_count"] = 1
|
| 110 |
+
else:
|
| 111 |
+
# Explain what to install to increase accuracy
|
| 112 |
+
cpu_tracking_install_instructions = ""
|
| 113 |
+
if is_mac_os():
|
| 114 |
+
if (
|
| 115 |
+
"M1" in detect_cpu_model()
|
| 116 |
+
or "M2" in detect_cpu_model()
|
| 117 |
+
or "M3" in detect_cpu_model()
|
| 118 |
+
):
|
| 119 |
+
cpu_tracking_install_instructions = ""
|
| 120 |
+
cpu_tracking_install_instructions = "Mac OS and ARM processor detected: Please enable PowerMetrics sudo to measure CPU"
|
| 121 |
+
else:
|
| 122 |
+
cpu_tracking_install_instructions = "Mac OS detected: Please install Intel Power Gadget or enable PowerMetrics sudo to measure CPU"
|
| 123 |
+
elif is_windows_os():
|
| 124 |
+
cpu_tracking_install_instructions = "Windows OS detected: Please install Intel Power Gadget to measure CPU"
|
| 125 |
+
elif is_linux_os():
|
| 126 |
+
cpu_tracking_install_instructions = "Linux OS detected: Please ensure RAPL files exist at /sys/class/powercap/intel-rapl/subsystem to measure CPU"
|
| 127 |
+
logger.warning(
|
| 128 |
+
f"No CPU tracking mode found. Falling back on estimation based on TDP for CPU. \n {cpu_tracking_install_instructions}\n"
|
| 129 |
+
)
|
| 130 |
+
self.cpu_tracker = "TDP constant"
|
| 131 |
+
model = tdp.model
|
| 132 |
+
if (max_power is None) and self.tracker._force_cpu_power:
|
| 133 |
+
# We haven't been able to calculate CPU power but user has input a default one. We use it
|
| 134 |
+
user_input_power = self.tracker._force_cpu_power
|
| 135 |
+
logger.debug(f"Using user input TDP: {user_input_power} W")
|
| 136 |
+
self.cpu_tracker = "User Input TDP constant"
|
| 137 |
+
max_power = user_input_power
|
| 138 |
+
logger.info(f"CPU Model on constant consumption mode: {model}")
|
| 139 |
+
self.tracker._conf["cpu_model"] = model
|
| 140 |
+
if tdp:
|
| 141 |
+
if cpu.is_psutil_available():
|
| 142 |
+
logger.warning(
|
| 143 |
+
"No CPU tracking mode found. Falling back on CPU load mode."
|
| 144 |
+
)
|
| 145 |
+
hardware_cpu = CPU.from_utils(
|
| 146 |
+
self.tracker._output_dir,
|
| 147 |
+
MODE_CPU_LOAD,
|
| 148 |
+
model,
|
| 149 |
+
max_power,
|
| 150 |
+
tracking_mode=self.tracker._tracking_mode,
|
| 151 |
+
)
|
| 152 |
+
self.cpu_tracker = MODE_CPU_LOAD
|
| 153 |
+
else:
|
| 154 |
+
logger.warning(
|
| 155 |
+
"No CPU tracking mode found. Falling back on CPU constant mode."
|
| 156 |
+
)
|
| 157 |
+
hardware_cpu = CPU.from_utils(
|
| 158 |
+
self.tracker._output_dir, "constant", model, max_power
|
| 159 |
+
)
|
| 160 |
+
self.cpu_tracker = "global constant"
|
| 161 |
+
self.tracker._hardware.append(hardware_cpu)
|
| 162 |
+
else:
|
| 163 |
+
if cpu.is_psutil_available():
|
| 164 |
+
logger.warning(
|
| 165 |
+
"Failed to match CPU TDP constant. Falling back on CPU load mode."
|
| 166 |
+
)
|
| 167 |
+
hardware_cpu = CPU.from_utils(
|
| 168 |
+
self.tracker._output_dir,
|
| 169 |
+
MODE_CPU_LOAD,
|
| 170 |
+
model,
|
| 171 |
+
max_power,
|
| 172 |
+
tracking_mode=self.tracker._tracking_mode,
|
| 173 |
+
)
|
| 174 |
+
self.cpu_tracker = MODE_CPU_LOAD
|
| 175 |
+
else:
|
| 176 |
+
logger.warning(
|
| 177 |
+
"Failed to match CPU TDP constant. Falling back on a global constant."
|
| 178 |
+
)
|
| 179 |
+
self.cpu_tracker = "global constant"
|
| 180 |
+
hardware_cpu = CPU.from_utils(self.tracker._output_dir, "constant")
|
| 181 |
+
self.tracker._hardware.append(hardware_cpu)
|
| 182 |
+
|
| 183 |
+
def set_GPU_tracking(self):
|
| 184 |
+
logger.info("[setup] GPU Tracking...")
|
| 185 |
+
if self.tracker._gpu_ids:
|
| 186 |
+
# If _gpu_ids is a string or a list of int, parse it to a list of ints
|
| 187 |
+
if isinstance(self.tracker._gpu_ids, str) or (
|
| 188 |
+
isinstance(self.tracker._gpu_ids, list)
|
| 189 |
+
and all(isinstance(gpu_id, int) for gpu_id in self.tracker._gpu_ids)
|
| 190 |
+
):
|
| 191 |
+
self.tracker._gpu_ids: List = parse_gpu_ids(self.tracker._gpu_ids)
|
| 192 |
+
self.tracker._conf["gpu_ids"] = self.tracker._gpu_ids
|
| 193 |
+
self.tracker._conf["gpu_count"] = len(self.tracker._gpu_ids)
|
| 194 |
+
else:
|
| 195 |
+
logger.warning(
|
| 196 |
+
"Invalid gpu_ids format. Expected a string or a list of ints."
|
| 197 |
+
)
|
| 198 |
+
if gpu.is_gpu_details_available():
|
| 199 |
+
logger.info("Tracking Nvidia GPU via pynvml")
|
| 200 |
+
gpu_devices = GPU.from_utils(self.tracker._gpu_ids)
|
| 201 |
+
self.tracker._hardware.append(gpu_devices)
|
| 202 |
+
gpu_names = [n["name"] for n in gpu_devices.devices.get_gpu_static_info()]
|
| 203 |
+
gpu_names_dict = Counter(gpu_names)
|
| 204 |
+
self.tracker._conf["gpu_model"] = "".join(
|
| 205 |
+
[f"{i} x {name}" for name, i in gpu_names_dict.items()]
|
| 206 |
+
)
|
| 207 |
+
if self.tracker._conf.get("gpu_count") is None:
|
| 208 |
+
self.tracker._conf["gpu_count"] = len(
|
| 209 |
+
gpu_devices.devices.get_gpu_static_info()
|
| 210 |
+
)
|
| 211 |
+
self.gpu_tracker = "pynvml"
|
| 212 |
+
else:
|
| 213 |
+
logger.info("No GPU found.")
|
| 214 |
+
|
| 215 |
+
def set_CPU_GPU_ram_tracking(self):
|
| 216 |
+
"""
|
| 217 |
+
Set up CPU, GPU and RAM tracking based on the user's configuration.
|
| 218 |
+
param tracker: BaseEmissionsTracker object
|
| 219 |
+
"""
|
| 220 |
+
self.set_RAM_tracking()
|
| 221 |
+
self.set_CPU_tracking()
|
| 222 |
+
self.set_GPU_tracking()
|
| 223 |
+
|
| 224 |
+
logger.info(
|
| 225 |
+
f"""The below tracking methods have been set up:
|
| 226 |
+
RAM Tracking Method: {self.ram_tracker}
|
| 227 |
+
CPU Tracking Method: {self.cpu_tracker}
|
| 228 |
+
GPU Tracking Method: {self.gpu_tracker}
|
| 229 |
+
"""
|
| 230 |
+
)
|
codecarbon/core/schemas.py
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Here is the schemas used to communicate with the API.
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from dataclasses import dataclass
|
| 6 |
+
from datetime import datetime
|
| 7 |
+
from typing import Optional
|
| 8 |
+
from uuid import UUID
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
@dataclass
|
| 12 |
+
class EmissionBase:
|
| 13 |
+
timestamp: str
|
| 14 |
+
run_id: str
|
| 15 |
+
duration: int
|
| 16 |
+
emissions_sum: float
|
| 17 |
+
emissions_rate: float
|
| 18 |
+
cpu_power: float
|
| 19 |
+
gpu_power: float
|
| 20 |
+
ram_power: float
|
| 21 |
+
cpu_energy: float
|
| 22 |
+
gpu_energy: float
|
| 23 |
+
ram_energy: float
|
| 24 |
+
energy_consumed: float
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
class EmissionCreate(EmissionBase):
|
| 28 |
+
pass
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class Emission(EmissionBase):
|
| 32 |
+
id: str
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
@dataclass
|
| 36 |
+
class RunBase:
|
| 37 |
+
timestamp: str
|
| 38 |
+
experiment_id: str
|
| 39 |
+
os: Optional[str]
|
| 40 |
+
python_version: Optional[str]
|
| 41 |
+
codecarbon_version: Optional[str]
|
| 42 |
+
cpu_count: Optional[int]
|
| 43 |
+
cpu_model: Optional[str]
|
| 44 |
+
gpu_count: Optional[int]
|
| 45 |
+
gpu_model: Optional[str]
|
| 46 |
+
longitude: Optional[float]
|
| 47 |
+
latitude: Optional[float]
|
| 48 |
+
region: Optional[str]
|
| 49 |
+
provider: Optional[str]
|
| 50 |
+
ram_total_size: Optional[float]
|
| 51 |
+
tracking_mode: Optional[str]
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
class RunCreate(RunBase):
|
| 55 |
+
pass
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
class Run(RunBase):
|
| 59 |
+
id: str
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
@dataclass
|
| 63 |
+
class ExperimentBase:
|
| 64 |
+
timestamp: datetime
|
| 65 |
+
name: str
|
| 66 |
+
description: str
|
| 67 |
+
on_cloud: bool
|
| 68 |
+
project_id: UUID
|
| 69 |
+
country_name: Optional[str] = None
|
| 70 |
+
country_iso_code: Optional[str] = None
|
| 71 |
+
region: Optional[str] = None
|
| 72 |
+
cloud_provider: Optional[str] = None
|
| 73 |
+
cloud_region: Optional[str] = None
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
class ExperimentCreate(ExperimentBase):
|
| 77 |
+
pass
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
class Experiment(ExperimentBase):
|
| 81 |
+
id: str
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
@dataclass
|
| 85 |
+
class OrganizationBase:
|
| 86 |
+
name: str
|
| 87 |
+
description: str
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
class OrganizationCreate(OrganizationBase):
|
| 91 |
+
pass
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
class Organization(OrganizationBase):
|
| 95 |
+
id: str
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
@dataclass
|
| 99 |
+
class ProjectBase:
|
| 100 |
+
name: str
|
| 101 |
+
description: str
|
| 102 |
+
organization_id: str
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class ProjectCreate(ProjectBase):
|
| 106 |
+
pass
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
class Project(ProjectBase):
|
| 110 |
+
id: str
|
codecarbon/core/units.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Provides functionality for unit conversions
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
from dataclasses import dataclass, field
|
| 6 |
+
|
| 7 |
+
# from pydantic.dataclasses import dataclass, field
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
@dataclass
|
| 11 |
+
class Time:
|
| 12 |
+
"""
|
| 13 |
+
Measured in seconds
|
| 14 |
+
"""
|
| 15 |
+
|
| 16 |
+
seconds: float
|
| 17 |
+
SECONDS_TO_HOURS = 1 / 3600
|
| 18 |
+
|
| 19 |
+
@property
|
| 20 |
+
def hours(self) -> float:
|
| 21 |
+
return self.seconds * Time.SECONDS_TO_HOURS
|
| 22 |
+
|
| 23 |
+
@classmethod
|
| 24 |
+
def from_seconds(cls, seconds: float) -> "Time":
|
| 25 |
+
return cls(seconds=seconds)
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
@dataclass
|
| 29 |
+
class EmissionsPerKWh:
|
| 30 |
+
"""
|
| 31 |
+
Measured in kg/kWh
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
LBS_MWH_TO_KG_KWH = 0.00045359237
|
| 35 |
+
G_KWH_TO_KG_KWH = 0.001
|
| 36 |
+
|
| 37 |
+
kgs_per_kWh: float
|
| 38 |
+
|
| 39 |
+
@classmethod
|
| 40 |
+
def from_lbs_per_mWh(cls, lbs_per_mWh: float) -> "EmissionsPerKWh":
|
| 41 |
+
return cls(kgs_per_kWh=lbs_per_mWh * EmissionsPerKWh.LBS_MWH_TO_KG_KWH)
|
| 42 |
+
|
| 43 |
+
@classmethod
|
| 44 |
+
def from_g_per_kWh(cls, g_per_kWh: float) -> "EmissionsPerKWh":
|
| 45 |
+
return cls(kgs_per_kWh=g_per_kWh * EmissionsPerKWh.G_KWH_TO_KG_KWH)
|
| 46 |
+
|
| 47 |
+
@classmethod
|
| 48 |
+
def from_kgs_per_kWh(cls, kgs_per_kWh: float) -> "EmissionsPerKWh":
|
| 49 |
+
return cls(kgs_per_kWh=kgs_per_kWh)
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
@dataclass(order=True)
|
| 53 |
+
class Energy:
|
| 54 |
+
"""
|
| 55 |
+
Measured in kWh
|
| 56 |
+
"""
|
| 57 |
+
|
| 58 |
+
UJOULES_TO_JOULES = 10 ** (-6)
|
| 59 |
+
MILLIJOULES_TO_JOULES = 10 ** (-3)
|
| 60 |
+
JOULES_TO_KWH = 2.77778e-7
|
| 61 |
+
|
| 62 |
+
kWh: float = field(compare=True)
|
| 63 |
+
|
| 64 |
+
def __post_init__(self):
|
| 65 |
+
self.kWh = float(self.kWh)
|
| 66 |
+
|
| 67 |
+
@classmethod
|
| 68 |
+
def from_power_and_time(cls, *, power: "Power", time: "Time") -> "Energy":
|
| 69 |
+
assert isinstance(power.kW, float)
|
| 70 |
+
assert isinstance(time.hours, float)
|
| 71 |
+
energy = power.kW * time.hours
|
| 72 |
+
return cls(kWh=energy)
|
| 73 |
+
|
| 74 |
+
@classmethod
|
| 75 |
+
def from_ujoules(cls, energy: float) -> "Energy":
|
| 76 |
+
return cls(kWh=energy * Energy.UJOULES_TO_JOULES * Energy.JOULES_TO_KWH)
|
| 77 |
+
|
| 78 |
+
@classmethod
|
| 79 |
+
def from_millijoules(cls, energy: float) -> "Energy":
|
| 80 |
+
return cls(kWh=energy * Energy.MILLIJOULES_TO_JOULES * Energy.JOULES_TO_KWH)
|
| 81 |
+
|
| 82 |
+
@classmethod
|
| 83 |
+
def from_energy(cls, kWh: float) -> "Energy":
|
| 84 |
+
return cls(kWh=kWh)
|
| 85 |
+
|
| 86 |
+
def __sub__(self, other: "Energy") -> "Energy":
|
| 87 |
+
return Energy(self.kWh - other.kWh)
|
| 88 |
+
|
| 89 |
+
def __add__(self, other: "Energy") -> "Energy":
|
| 90 |
+
return Energy(self.kWh + other.kWh)
|
| 91 |
+
|
| 92 |
+
def __mul__(self, factor: float) -> "Energy":
|
| 93 |
+
assert isinstance(factor, float)
|
| 94 |
+
assert isinstance(self.kWh, float)
|
| 95 |
+
result = Energy(self.kWh * factor)
|
| 96 |
+
return result
|
| 97 |
+
|
| 98 |
+
def __float__(self) -> float:
|
| 99 |
+
return float(self.kWh)
|
| 100 |
+
|
| 101 |
+
def __truediv__(self, divisor: float) -> "Energy":
|
| 102 |
+
return Energy(self.kWh / divisor)
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
@dataclass
|
| 106 |
+
class Power:
|
| 107 |
+
"""
|
| 108 |
+
Measured in kW
|
| 109 |
+
"""
|
| 110 |
+
|
| 111 |
+
MILLI_WATTS_TO_WATTS = 0.001
|
| 112 |
+
WATTS_TO_KILO_WATTS = 0.001
|
| 113 |
+
|
| 114 |
+
kW: float
|
| 115 |
+
|
| 116 |
+
@classmethod
|
| 117 |
+
def from_milli_watts(cls, milli_watts: float) -> "Power":
|
| 118 |
+
return cls(
|
| 119 |
+
kW=milli_watts * Power.MILLI_WATTS_TO_WATTS * Power.WATTS_TO_KILO_WATTS
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
@classmethod
|
| 123 |
+
def from_watts(cls, watts: float) -> "Power":
|
| 124 |
+
return cls(kW=watts * Power.WATTS_TO_KILO_WATTS)
|
| 125 |
+
|
| 126 |
+
@classmethod
|
| 127 |
+
def from_energies_and_delay(cls, e1: "Energy", e2: "Energy", delay: "Time"):
|
| 128 |
+
"""
|
| 129 |
+
P = (E_{t1} - E_{t2}) / delay (=t2-t1)
|
| 130 |
+
kW kWh kWh h
|
| 131 |
+
|
| 132 |
+
Args:
|
| 133 |
+
e1 (Energy): First measurement
|
| 134 |
+
e2 (Energy): Second measurement
|
| 135 |
+
delay (Time): Time between measurements
|
| 136 |
+
|
| 137 |
+
Returns:
|
| 138 |
+
Power: Resulting Power estimation
|
| 139 |
+
"""
|
| 140 |
+
delta_energy = float(abs(e2.kWh - e1.kWh))
|
| 141 |
+
kW = delta_energy / delay.hours if delay.hours != 0.0 else 0.0
|
| 142 |
+
return cls(kW=kW)
|
| 143 |
+
|
| 144 |
+
@classmethod
|
| 145 |
+
def from_energy_delta_and_delay(cls, e: "Energy", delay: "Time"):
|
| 146 |
+
return cls.from_energies_and_delay(e, Energy(0), delay)
|
| 147 |
+
|
| 148 |
+
@property
|
| 149 |
+
def W(self):
|
| 150 |
+
if not isinstance(self.kW, float):
|
| 151 |
+
return self.kW
|
| 152 |
+
return self.kW * 1000
|
| 153 |
+
|
| 154 |
+
def __add__(self, other: "Power") -> "Power":
|
| 155 |
+
return Power(self.kW + other.kW)
|
| 156 |
+
|
| 157 |
+
def __mul__(self, factor: float) -> "Power":
|
| 158 |
+
return Power(self.kW * factor)
|
| 159 |
+
|
| 160 |
+
def __truediv__(self, divisor: float) -> "Power":
|
| 161 |
+
return Power(self.kW / divisor)
|
| 162 |
+
|
| 163 |
+
def __floordiv__(self, divisor: float) -> "Power":
|
| 164 |
+
return Power(self.kW // divisor)
|
codecarbon/core/util.py
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import re
|
| 3 |
+
import subprocess
|
| 4 |
+
import sys
|
| 5 |
+
from contextlib import contextmanager
|
| 6 |
+
from os.path import expandvars
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
from typing import Optional, Union
|
| 9 |
+
|
| 10 |
+
import cpuinfo
|
| 11 |
+
import psutil
|
| 12 |
+
|
| 13 |
+
from codecarbon.external.logger import logger
|
| 14 |
+
|
| 15 |
+
SLURM_JOB_ID = os.environ.get(
|
| 16 |
+
"SLURM_JOB_ID", # default
|
| 17 |
+
os.environ.get("SLURM_JOBID"), # deprecated but may still be used
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
@contextmanager
|
| 22 |
+
def suppress(*exceptions):
|
| 23 |
+
try:
|
| 24 |
+
yield
|
| 25 |
+
except exceptions:
|
| 26 |
+
logger.warning("graceful shutdown. Exceptions:")
|
| 27 |
+
logger.warning(
|
| 28 |
+
exceptions if len(exceptions) != 1 else exceptions[0], exc_info=True
|
| 29 |
+
)
|
| 30 |
+
logger.warning("stopping.")
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
def resolve_path(path: Union[str, Path]) -> Path:
|
| 34 |
+
"""
|
| 35 |
+
Fully resolve a path:
|
| 36 |
+
resolve env vars ($HOME etc.) -> expand user (~) -> make absolute
|
| 37 |
+
|
| 38 |
+
Args:
|
| 39 |
+
path (Union[str, Path]): Path to a file or repository to resolve as
|
| 40 |
+
string or pathlib.Path
|
| 41 |
+
|
| 42 |
+
Returns:
|
| 43 |
+
pathlib.Path: resolved absolute path
|
| 44 |
+
"""
|
| 45 |
+
return Path(expandvars(str(path))).expanduser().resolve()
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def backup(file_path: Union[str, Path], ext: Optional[str] = ".bak") -> None:
|
| 49 |
+
"""
|
| 50 |
+
Resolves the path to a path then backs it up, adding the extension provided.
|
| 51 |
+
Warning : this function will rename the file in place, it's the calling function that will write a new file at the original path.
|
| 52 |
+
This function will not overwrite existing backups but add a number.
|
| 53 |
+
|
| 54 |
+
Args:
|
| 55 |
+
file_path (Union[str, Path]): Path to a file to backup.
|
| 56 |
+
ext (Optional[str], optional): extension to append to the filename when
|
| 57 |
+
backing it up. Defaults to ".bak".
|
| 58 |
+
"""
|
| 59 |
+
file_path = resolve_path(file_path)
|
| 60 |
+
if not file_path.exists():
|
| 61 |
+
return
|
| 62 |
+
assert file_path.is_file()
|
| 63 |
+
idx = 0
|
| 64 |
+
parent = file_path.parent
|
| 65 |
+
file_name = f"{file_path.name}{ext}"
|
| 66 |
+
backup_path = parent / file_name
|
| 67 |
+
|
| 68 |
+
while backup_path.exists():
|
| 69 |
+
file_name = f"{file_path.name}_{idx}{ext}"
|
| 70 |
+
backup_path = parent / file_name
|
| 71 |
+
idx += 1
|
| 72 |
+
|
| 73 |
+
file_path.rename(backup_path)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def detect_cpu_model() -> str:
|
| 77 |
+
cpu_info = cpuinfo.get_cpu_info()
|
| 78 |
+
if cpu_info:
|
| 79 |
+
cpu_model_detected = cpu_info.get("brand_raw", "")
|
| 80 |
+
return cpu_model_detected
|
| 81 |
+
return None
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def is_mac_os() -> str:
|
| 85 |
+
system = sys.platform.lower()
|
| 86 |
+
return system.startswith("dar")
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def is_windows_os() -> str:
|
| 90 |
+
system = sys.platform.lower()
|
| 91 |
+
return system.startswith("win")
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
def is_linux_os() -> str:
|
| 95 |
+
system = sys.platform.lower()
|
| 96 |
+
return system.startswith("lin")
|
| 97 |
+
|
| 98 |
+
|
| 99 |
+
def count_physical_cpus():
|
| 100 |
+
import platform
|
| 101 |
+
import subprocess
|
| 102 |
+
|
| 103 |
+
if platform.system() == "Windows":
|
| 104 |
+
return int(os.environ.get("NUMBER_OF_PROCESSORS", 1))
|
| 105 |
+
else:
|
| 106 |
+
try:
|
| 107 |
+
output = subprocess.check_output(["lscpu"], text=True)
|
| 108 |
+
for line in output.split("\n"):
|
| 109 |
+
if "Socket(s):" in line:
|
| 110 |
+
return int(line.split(":")[1].strip())
|
| 111 |
+
else:
|
| 112 |
+
return 1
|
| 113 |
+
except Exception as e:
|
| 114 |
+
logger.warning(
|
| 115 |
+
f"Error while trying to count physical CPUs: {e}. Defaulting to 1."
|
| 116 |
+
)
|
| 117 |
+
return 1
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
def count_cpus() -> int:
|
| 121 |
+
if SLURM_JOB_ID is None:
|
| 122 |
+
return psutil.cpu_count()
|
| 123 |
+
|
| 124 |
+
try:
|
| 125 |
+
logger.debug(
|
| 126 |
+
"SLURM environment detected for job {SLURM_JOB_ID}, running"
|
| 127 |
+
+ " `scontrol show job $SLURM_JOB_ID` to count SLURM-available cpus."
|
| 128 |
+
)
|
| 129 |
+
scontrol = subprocess.check_output(
|
| 130 |
+
[f"scontrol show job {SLURM_JOB_ID}"], shell=True
|
| 131 |
+
).decode()
|
| 132 |
+
except subprocess.CalledProcessError:
|
| 133 |
+
logger.warning(
|
| 134 |
+
"Error running `scontrol show job $SLURM_JOB_ID` "
|
| 135 |
+
+ "to count SLURM-available cpus. Using the machine's cpu count."
|
| 136 |
+
)
|
| 137 |
+
return psutil.cpu_count(logical=True)
|
| 138 |
+
|
| 139 |
+
num_cpus_matches = re.findall(r"NumCPUs=\d+", scontrol)
|
| 140 |
+
|
| 141 |
+
if len(num_cpus_matches) == 0:
|
| 142 |
+
logger.warning(
|
| 143 |
+
"Could not find NumCPUs= after running `scontrol show job $SLURM_JOB_ID` "
|
| 144 |
+
+ "to count SLURM-available cpus. Using the machine's cpu count."
|
| 145 |
+
)
|
| 146 |
+
return psutil.cpu_count(logical=True)
|
| 147 |
+
|
| 148 |
+
if len(num_cpus_matches) > 1:
|
| 149 |
+
logger.warning(
|
| 150 |
+
"Unexpected output after running `scontrol show job $SLURM_JOB_ID` "
|
| 151 |
+
+ "to count SLURM-available cpus. Using the machine's cpu count."
|
| 152 |
+
)
|
| 153 |
+
return psutil.cpu_count(logical=True)
|
| 154 |
+
|
| 155 |
+
num_cpus = num_cpus_matches[0].replace("NumCPUs=", "")
|
| 156 |
+
logger.debug(f"Detected {num_cpus} cpus available on SLURM.")
|
| 157 |
+
return int(num_cpus)
|
codecarbon/data/canada_provinces.geojson
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
codecarbon/data/cloud/impact.csv
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
provider,providerName,offsetRatio,region,regionName,country_name,countryIsoCode,state,city,impact,source,comment
|
| 2 |
+
gcp,Google Cloud Platform,100,africa-south1,,South Africa,ZAF,,Johannesburg,646,https://cloud.google.com/sustainability/region-carbon#data,
|
| 3 |
+
gcp,Google Cloud Platform,100,asia-east1,,Taiwan,TWN,,Changhua County,451,https://cloud.google.com/sustainability/region-carbon#data,
|
| 4 |
+
gcp,Google Cloud Platform,100,asia-east2,,China,CHN,,Hong Kong,360,https://cloud.google.com/sustainability/region-carbon#data,
|
| 5 |
+
gcp,Google Cloud Platform,100,asia-northeast1,,Japan,JPN,,Tokyo,459,https://cloud.google.com/sustainability/region-carbon#data,
|
| 6 |
+
gcp,Google Cloud Platform,100,asia-northeast2,,Japan,JPN,,Osaka,385,https://cloud.google.com/sustainability/region-carbon#data,
|
| 7 |
+
gcp,Google Cloud Platform,100,asia-northeast3,,Korea,KOR,South Korea,Seoul,378,https://cloud.google.com/sustainability/region-carbon#data,
|
| 8 |
+
gcp,Google Cloud Platform,100,asia-south1,,India,IND,,Mumbai,648,https://cloud.google.com/sustainability/region-carbon#data,
|
| 9 |
+
gcp,Google Cloud Platform,100,asia-south2,,India,IND,,Delhi,529,https://cloud.google.com/sustainability/region-carbon#data,
|
| 10 |
+
gcp,Google Cloud Platform,100,asia-southeast1,,Singapore,SGP,,Jurong West,369,https://cloud.google.com/sustainability/region-carbon#data,
|
| 11 |
+
gcp,Google Cloud Platform,100,asia-southeast2,,Indonesia,IDN,,Jakarta,580,https://cloud.google.com/sustainability/region-carbon#data,
|
| 12 |
+
gcp,Google Cloud Platform,100,australia-southeast1,,Australia,AUS,,Sydney,501,https://cloud.google.com/sustainability/region-carbon#data,
|
| 13 |
+
gcp,Google Cloud Platform,100,australia-southeast2,,Australia,AUS,,Melbourne,456,https://cloud.google.com/sustainability/region-carbon#data,
|
| 14 |
+
gcp,Google Cloud Platform,100,europe-central2,,Poland,POL,,Warsaw,723,https://cloud.google.com/sustainability/region-carbon#data,
|
| 15 |
+
gcp,Google Cloud Platform,100,europe-north1,,Finland,FIN,,Hamina,46,https://cloud.google.com/sustainability/region-carbon#data,
|
| 16 |
+
gcp,Google Cloud Platform,100,europe-southwest1,,Spain,ESP,,Madrid,131,https://cloud.google.com/sustainability/region-carbon#data,
|
| 17 |
+
gcp,Google Cloud Platform,100,europe-west1,,Belgium,BEL,,St. Ghislain,122,https://cloud.google.com/sustainability/region-carbon#data,
|
| 18 |
+
gcp,Google Cloud Platform,100,europe-west2,,United Kingdom,GBR,England,London,136,https://cloud.google.com/sustainability/region-carbon#data,
|
| 19 |
+
gcp,Google Cloud Platform,100,europe-west3,,Germany,DEU,,Frankfurt,345,https://cloud.google.com/sustainability/region-carbon#data,
|
| 20 |
+
gcp,Google Cloud Platform,100,europe-west4,,Netherlands,NLD,,Eemshaven,236,https://cloud.google.com/sustainability/region-carbon#data,
|
| 21 |
+
gcp,Google Cloud Platform,100,europe-west6,,Switzerland,CHE,,Zurich,59,https://cloud.google.com/sustainability/region-carbon#data,
|
| 22 |
+
gcp,Google Cloud Platform,100,europe-west8,,Italy,ITA,,Milan,249,https://cloud.google.com/sustainability/region-carbon#data,
|
| 23 |
+
gcp,Google Cloud Platform,100,europe-west9,,France,FRA,,Paris,34,https://cloud.google.com/sustainability/region-carbon#data,
|
| 24 |
+
gcp,Google Cloud Platform,100,europe-west10,,Germany,DEU,,Berlin,345,https://cloud.google.com/sustainability/region-carbon#data,
|
| 25 |
+
gcp,Google Cloud Platform,100,europe-west12,,Italy,ITA,,Turin,249,https://cloud.google.com/sustainability/region-carbon#data,
|
| 26 |
+
gcp,Google Cloud Platform,100,me-cenrtal1,,Qatar,QAT,,Doha,575,https://cloud.google.com/sustainability/region-carbon#data,
|
| 27 |
+
gcp,Google Cloud Platform,100,me-central2,,Saudi Arabia,SAU,,Dammam,569,https://cloud.google.com/sustainability/region-carbon#data,
|
| 28 |
+
gcp,Google Cloud Platform,100,me-west1,,Israel,ISR,,Tel Aviv,463,https://cloud.google.com/sustainability/region-carbon#data,
|
| 29 |
+
gcp,Google Cloud Platform,100,northamerica-northeast1,,Canada,CAN,Quebec,Montreal,2,https://cloud.google.com/sustainability/region-carbon#data,
|
| 30 |
+
gcp,Google Cloud Platform,100,northamerica-northeast2,,Canada,CAN,,Toronto,47,https://cloud.google.com/sustainability/region-carbon#data,
|
| 31 |
+
gcp,Google Cloud Platform,100,southamerica-east1,,Brazil,BRA,,Sao Paulo,56,https://cloud.google.com/sustainability/region-carbon#data,
|
| 32 |
+
gcp,Google Cloud Platform,100,southamerica-west1,,Chile,CHL,,Santiago,138,https://cloud.google.com/sustainability/region-carbon#data,
|
| 33 |
+
gcp,Google Cloud Platform,100,us-central1,,USA,USA,Iowa,Council Bluffs,430,https://cloud.google.com/sustainability/region-carbon#data,
|
| 34 |
+
gcp,Google Cloud Platform,100,us-east1,,USA,USA,South Carolina,Moncks Corner,560,https://cloud.google.com/sustainability/region-carbon#data,
|
| 35 |
+
gcp,Google Cloud Platform,100,us-east4,,USA,USA,Northern Virginia,Ashburn,322,https://cloud.google.com/sustainability/region-carbon#data,
|
| 36 |
+
gcp,Google Cloud Platform,100,us-east5,,USA,USA,,Columbus,322,https://cloud.google.com/sustainability/region-carbon#data,
|
| 37 |
+
gcp,Google Cloud Platform,100,us-south1,,USA,USA,,Dallas,321,https://cloud.google.com/sustainability/region-carbon#data,
|
| 38 |
+
gcp,Google Cloud Platform,100,us-west1,,USA,USA,Oregon,The Dalles,94,https://cloud.google.com/sustainability/region-carbon#data,
|
| 39 |
+
gcp,Google Cloud Platform,100,us-west2,,USA,USA,California,Los Angeles,198,https://cloud.google.com/sustainability/region-carbon#data,
|
| 40 |
+
gcp,Google Cloud Platform,100,us-west3,,USA,USA,Utah,Salt Lake City,588,https://cloud.google.com/sustainability/region-carbon#data,
|
| 41 |
+
gcp,Google Cloud Platform,100,us-west4,,USA,USA,Nevada,Las Vegas,373,https://cloud.google.com/sustainability/region-carbon#data,
|
codecarbon/data/hardware/cpu_dataset_builder/CPU_Create_Dataset.ipynb
ADDED
|
@@ -0,0 +1,1671 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"We want to build a CPU dataset.\n",
|
| 8 |
+
"There is pointer on https://github.com/felixsteinke/cpu-spec-dataset\n",
|
| 9 |
+
"\n",
|
| 10 |
+
"## AMD Dataset\n",
|
| 11 |
+
"\n",
|
| 12 |
+
"Manually Export Data as CSV/Excel from https://www.amd.com/en/products/specifications/processors\n",
|
| 13 |
+
"Website Screenshot\n",
|
| 14 |
+
"\n",
|
| 15 |
+
"blob:https://www.amd.com/fc70f2d3-27d4-4bf1-a466-9912927167de\n",
|
| 16 |
+
"\n",
|
| 17 |
+
"## Ampere Dataset\n",
|
| 18 |
+
"\n",
|
| 19 |
+
"Extracted from https://amperecomputing.com/briefs/ampere-altra-family-product-brief with the responsible Web Scraper.\n",
|
| 20 |
+
"\n",
|
| 21 |
+
"cd ampere-web-scraper\n",
|
| 22 |
+
"java -jar ./target/exectuable.jar\n",
|
| 23 |
+
"\n",
|
| 24 |
+
"## Intel Dataset\n",
|
| 25 |
+
"\n",
|
| 26 |
+
"Extracted from https://ark.intel.com/content/www/us/en/ark.html with the responsible Web Scraper.\n",
|
| 27 |
+
"\n",
|
| 28 |
+
"cd intel-web-scraper\n",
|
| 29 |
+
"java -jar ./target/exectuable.jar\n",
|
| 30 |
+
"\n",
|
| 31 |
+
"## CPU Benchmark Dataset\n",
|
| 32 |
+
"\n",
|
| 33 |
+
"Extracted from https://www.cpubenchmark.net/cpu_list.php with the responsible Web Scraper.\n",
|
| 34 |
+
"\n",
|
| 35 |
+
"cd benchmark-web-scraper\n",
|
| 36 |
+
"java -jar ./target/exectuable.jar\n",
|
| 37 |
+
"\n",
|
| 38 |
+
"## CPU World Dataset\n",
|
| 39 |
+
"\n",
|
| 40 |
+
"Extracted from https://www.cpu-world.com/CPUs/CPU.html with the responsible Web Scraper.\n",
|
| 41 |
+
"\n",
|
| 42 |
+
"cd cpuworld-web-scraper\n",
|
| 43 |
+
"mvn -jar ./target/exectuable.jar"
|
| 44 |
+
]
|
| 45 |
+
},
|
| 46 |
+
{
|
| 47 |
+
"cell_type": "markdown",
|
| 48 |
+
"metadata": {},
|
| 49 |
+
"source": [
|
| 50 |
+
"test"
|
| 51 |
+
]
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
"cell_type": "markdown",
|
| 55 |
+
"metadata": {},
|
| 56 |
+
"source": [
|
| 57 |
+
"Extraction from https://www.intel.com/content/www/us/en/ark/products/series/236644/5th-gen-intel-xeon-scalable-processors.html\n",
|
| 58 |
+
"```html\n",
|
| 59 |
+
"<table id=\"product-table\" class=\"table table-sorter sorting tablesorter tablesorter-default\">\n",
|
| 60 |
+
" <thead>\n",
|
| 61 |
+
" <tr class=\"tablesorter-headerRow\">\n",
|
| 62 |
+
" <th class=\"product-table-sortable-col product-name-col ark-product-name xlarge-column component header tablesorter-header\" data-component=\"wa_skip_track\" data-component-id=\"1\" data-col=\"productName\" data-sort-field=\"productName\" role=\"columnheader\" aria-sort=\"\" aria-rowindex=\"1\" data-column=\"0\"><div class=\"tablesorter-header-inner\">\n",
|
| 63 |
+
" <div class=\"header-additional-padding\">\n",
|
| 64 |
+
" <div class=\"header-text-space\">\n",
|
| 65 |
+
" Product Name\n",
|
| 66 |
+
" </div>\n",
|
| 67 |
+
" </div>\n",
|
| 68 |
+
" </div></th>\n",
|
| 69 |
+
" \n",
|
| 70 |
+
" \n",
|
| 71 |
+
" \n",
|
| 72 |
+
" <th class=\"product-table-sortable-col component medium-column descending tablesorter-header\" data-component=\"wa_skip_track\" data-component-id=\"1\" data-col=\"BornOnDate\" role=\"columnheader\" aria-sort=\"\" aria-rowindex=\"1\" data-column=\"1\"><div class=\"tablesorter-header-inner\">\n",
|
| 73 |
+
" <div class=\"header-additional-padding\">\n",
|
| 74 |
+
" <div class=\"header-text-space\">\n",
|
| 75 |
+
" Launch Date\n",
|
| 76 |
+
" </div>\n",
|
| 77 |
+
" </div>\n",
|
| 78 |
+
" </div></th>\n",
|
| 79 |
+
" \n",
|
| 80 |
+
" \n",
|
| 81 |
+
" \n",
|
| 82 |
+
" <th class=\"product-table-sortable-col component medium-column tablesorter-header\" data-component=\"wa_skip_track\" data-component-id=\"1\" data-col=\"CoreCount\" role=\"columnheader\" aria-sort=\"\" aria-rowindex=\"1\" data-column=\"2\"><div class=\"tablesorter-header-inner\">\n",
|
| 83 |
+
" <div class=\"header-additional-padding\">\n",
|
| 84 |
+
" <div class=\"header-text-space\">\n",
|
| 85 |
+
" Total Cores\n",
|
| 86 |
+
" </div>\n",
|
| 87 |
+
" </div>\n",
|
| 88 |
+
" </div></th>\n",
|
| 89 |
+
" \n",
|
| 90 |
+
" \n",
|
| 91 |
+
" \n",
|
| 92 |
+
" <th class=\"product-table-sortable-col component medium-column tablesorter-header\" data-component=\"wa_skip_track\" data-component-id=\"1\" data-col=\"ClockSpeedMax\" role=\"columnheader\" aria-sort=\"\" aria-rowindex=\"1\" data-column=\"3\"><div class=\"tablesorter-header-inner\">\n",
|
| 93 |
+
" <div class=\"header-additional-padding\">\n",
|
| 94 |
+
" <div class=\"header-text-space\">\n",
|
| 95 |
+
" Max Turbo Frequency\n",
|
| 96 |
+
" </div>\n",
|
| 97 |
+
" </div>\n",
|
| 98 |
+
" </div></th>\n",
|
| 99 |
+
" \n",
|
| 100 |
+
" \n",
|
| 101 |
+
" \n",
|
| 102 |
+
" <th class=\"product-table-sortable-col component medium-column tablesorter-header\" data-component=\"wa_skip_track\" data-component-id=\"1\" data-col=\"ClockSpeed\" role=\"columnheader\" aria-sort=\"\" aria-rowindex=\"1\" data-column=\"4\"><div class=\"tablesorter-header-inner\">\n",
|
| 103 |
+
" <div class=\"header-additional-padding\">\n",
|
| 104 |
+
" <div class=\"header-text-space\">\n",
|
| 105 |
+
" Processor Base Frequency\n",
|
| 106 |
+
" </div>\n",
|
| 107 |
+
" </div>\n",
|
| 108 |
+
" </div></th>\n",
|
| 109 |
+
" \n",
|
| 110 |
+
" \n",
|
| 111 |
+
" \n",
|
| 112 |
+
" <th class=\"product-table-sortable-col component medium-column tablesorter-header\" data-component=\"wa_skip_track\" data-component-id=\"1\" data-col=\"Cache\" role=\"columnheader\" aria-sort=\"\" aria-rowindex=\"1\" data-column=\"5\"><div class=\"tablesorter-header-inner\">\n",
|
| 113 |
+
" <div class=\"header-additional-padding\">\n",
|
| 114 |
+
" <div class=\"header-text-space\">\n",
|
| 115 |
+
" Cache\n",
|
| 116 |
+
" </div>\n",
|
| 117 |
+
" </div>\n",
|
| 118 |
+
" </div></th>\n",
|
| 119 |
+
" \n",
|
| 120 |
+
" \n",
|
| 121 |
+
" \n",
|
| 122 |
+
" <th class=\"product-table-sortable-col component medium-column tablesorter-header\" data-component=\"wa_skip_track\" data-component-id=\"1\" data-col=\"MaxTDP\" role=\"columnheader\" aria-sort=\"\" aria-rowindex=\"1\" data-column=\"6\"><div class=\"tablesorter-header-inner\">\n",
|
| 123 |
+
" <div class=\"header-additional-padding\">\n",
|
| 124 |
+
" <div class=\"header-text-space\">\n",
|
| 125 |
+
" TDP\n",
|
| 126 |
+
" </div>\n",
|
| 127 |
+
" </div>\n",
|
| 128 |
+
" </div></th>\n",
|
| 129 |
+
" \n",
|
| 130 |
+
" \n",
|
| 131 |
+
" \n",
|
| 132 |
+
" </tr>\n",
|
| 133 |
+
" </thead>\n",
|
| 134 |
+
" <tbody>\n",
|
| 135 |
+
" \n",
|
| 136 |
+
" <tr class=\"blank-table-row seg-server seg-embedded seg-retailsku\" data-codename=\"Sapphire Rapids\" data-filter=\"Server\" data-product-id=\"236639\">\n",
|
| 137 |
+
"\n",
|
| 138 |
+
" \n",
|
| 139 |
+
" \n",
|
| 140 |
+
"\n",
|
| 141 |
+
" <td class=\"ark-product-name ark-accessible-color component\" data-value=\"1\" data-component=\"arkproductlink\" data-component-id=\"1\">\n",
|
| 142 |
+
" <div class=\"add-compare-wrap\">\n",
|
| 143 |
+
" <label class=\"containerCB component\" data-component=\"wa_skip_track\" data-component-id=\"1\">\n",
|
| 144 |
+
" <input class=\"compare-checkbox compare-toggle\" data-component=\"ark-component\" data-product-id=\"236639\" type=\"checkbox\">\n",
|
| 145 |
+
" <span class=\"checkmark\"></span>\n",
|
| 146 |
+
" </label>\n",
|
| 147 |
+
" <a href=\"/content/www/us/en/products/sku/236639/intel-xeon-bronze-3508u-processor-22-5m-cache-2-10-ghz/specifications.html\">Intel® Xeon® Bronze 3508U Processor</a>\n",
|
| 148 |
+
" </div>\n",
|
| 149 |
+
" </td>\n",
|
| 150 |
+
"\n",
|
| 151 |
+
" \n",
|
| 152 |
+
" \n",
|
| 153 |
+
" <td class=\"\" data-value=\"\">\n",
|
| 154 |
+
" \n",
|
| 155 |
+
" \n",
|
| 156 |
+
" \n",
|
| 157 |
+
" \n",
|
| 158 |
+
" \n",
|
| 159 |
+
" Q4'23\n",
|
| 160 |
+
" \n",
|
| 161 |
+
" \n",
|
| 162 |
+
" \n",
|
| 163 |
+
" </td>\n",
|
| 164 |
+
" \n",
|
| 165 |
+
" \n",
|
| 166 |
+
" \n",
|
| 167 |
+
" <td class=\"\" data-value=\"8\">\n",
|
| 168 |
+
" \n",
|
| 169 |
+
" \n",
|
| 170 |
+
" \n",
|
| 171 |
+
" \n",
|
| 172 |
+
" \n",
|
| 173 |
+
" 8\n",
|
| 174 |
+
" \n",
|
| 175 |
+
" \n",
|
| 176 |
+
" \n",
|
| 177 |
+
" </td>\n",
|
| 178 |
+
" \n",
|
| 179 |
+
" \n",
|
| 180 |
+
" \n",
|
| 181 |
+
" <td class=\"\" data-value=\"2200\">\n",
|
| 182 |
+
" \n",
|
| 183 |
+
" \n",
|
| 184 |
+
" \n",
|
| 185 |
+
" \n",
|
| 186 |
+
" \n",
|
| 187 |
+
" 2.2 GHz\n",
|
| 188 |
+
" \n",
|
| 189 |
+
" \n",
|
| 190 |
+
" \n",
|
| 191 |
+
" </td>\n",
|
| 192 |
+
" \n",
|
| 193 |
+
" \n",
|
| 194 |
+
" \n",
|
| 195 |
+
" <td class=\"\" data-value=\"2100\">\n",
|
| 196 |
+
" \n",
|
| 197 |
+
" \n",
|
| 198 |
+
" \n",
|
| 199 |
+
" \n",
|
| 200 |
+
" \n",
|
| 201 |
+
" 2.10 GHz\n",
|
| 202 |
+
" \n",
|
| 203 |
+
" \n",
|
| 204 |
+
" \n",
|
| 205 |
+
" </td>\n",
|
| 206 |
+
" \n",
|
| 207 |
+
" \n",
|
| 208 |
+
" \n",
|
| 209 |
+
" <td class=\"\" data-value=\"23040\">\n",
|
| 210 |
+
" \n",
|
| 211 |
+
" \n",
|
| 212 |
+
" \n",
|
| 213 |
+
" \n",
|
| 214 |
+
" \n",
|
| 215 |
+
" 22.5 MB\n",
|
| 216 |
+
" \n",
|
| 217 |
+
" \n",
|
| 218 |
+
" \n",
|
| 219 |
+
" </td>\n",
|
| 220 |
+
" \n",
|
| 221 |
+
" \n",
|
| 222 |
+
" \n",
|
| 223 |
+
" <td class=\"\" data-value=\"125\">\n",
|
| 224 |
+
" \n",
|
| 225 |
+
" \n",
|
| 226 |
+
" \n",
|
| 227 |
+
" \n",
|
| 228 |
+
" \n",
|
| 229 |
+
" 125 W\n",
|
| 230 |
+
" \n",
|
| 231 |
+
" \n",
|
| 232 |
+
" \n",
|
| 233 |
+
" </td>\n",
|
| 234 |
+
" \n",
|
| 235 |
+
" \n",
|
| 236 |
+
" </tr>\n",
|
| 237 |
+
" \n",
|
| 238 |
+
" ```"
|
| 239 |
+
]
|
| 240 |
+
},
|
| 241 |
+
{
|
| 242 |
+
"cell_type": "markdown",
|
| 243 |
+
"metadata": {},
|
| 244 |
+
"source": [
|
| 245 |
+
"**AI Prompt**\n",
|
| 246 |
+
"\n",
|
| 247 |
+
"How to automate extraction ?"
|
| 248 |
+
]
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"cell_type": "markdown",
|
| 252 |
+
"metadata": {},
|
| 253 |
+
"source": [
|
| 254 |
+
"**AI Response**\n",
|
| 255 |
+
"\n",
|
| 256 |
+
"I see you're looking to extract CPU data from Intel's website. Before diving into the automation, I'd like to understand a few things:\n",
|
| 257 |
+
"\n",
|
| 258 |
+
"1. Are you comfortable with Python programming? \n",
|
| 259 |
+
"2. Have you tried web scraping before?\n",
|
| 260 |
+
"3. Would you prefer using a specific library (like BeautifulSoup, Scrapy, or Selenium)?\n",
|
| 261 |
+
"\n",
|
| 262 |
+
"This looks like a dynamic table with sortable columns, so we'll need to consider the best approach based on your experience level and requirements. Let me know your preferences, and I'll help guide you through the process."
|
| 263 |
+
]
|
| 264 |
+
},
|
| 265 |
+
{
|
| 266 |
+
"cell_type": "markdown",
|
| 267 |
+
"metadata": {},
|
| 268 |
+
"source": [
|
| 269 |
+
"**AI Prompt**\n",
|
| 270 |
+
"\n",
|
| 271 |
+
"BeautifulSoup"
|
| 272 |
+
]
|
| 273 |
+
},
|
| 274 |
+
{
|
| 275 |
+
"cell_type": "markdown",
|
| 276 |
+
"metadata": {},
|
| 277 |
+
"source": [
|
| 278 |
+
"**AI Response**\n",
|
| 279 |
+
"\n",
|
| 280 |
+
"Great choice! BeautifulSoup is perfect for this. Looking at the HTML you shared, we can extract the table data. Would you like me to:\n",
|
| 281 |
+
"\n",
|
| 282 |
+
"1. Help you write the code step by step, or\n",
|
| 283 |
+
"2. Provide a complete solution?\n",
|
| 284 |
+
"\n",
|
| 285 |
+
"Also, do you need to:\n",
|
| 286 |
+
"- Extract just this one page, or\n",
|
| 287 |
+
"- Navigate through multiple pages?\n",
|
| 288 |
+
"\n",
|
| 289 |
+
"Let me know your preference and I'll help accordingly."
|
| 290 |
+
]
|
| 291 |
+
},
|
| 292 |
+
{
|
| 293 |
+
"cell_type": "markdown",
|
| 294 |
+
"metadata": {},
|
| 295 |
+
"source": [
|
| 296 |
+
"**AI Prompt**\n",
|
| 297 |
+
"\n",
|
| 298 |
+
"Extract just this one page"
|
| 299 |
+
]
|
| 300 |
+
},
|
| 301 |
+
{
|
| 302 |
+
"cell_type": "markdown",
|
| 303 |
+
"metadata": {},
|
| 304 |
+
"source": [
|
| 305 |
+
"**AI Response**\n",
|
| 306 |
+
"\n",
|
| 307 |
+
"I'll help you extract data from this page. Let's break it down into steps:\n",
|
| 308 |
+
"\n",
|
| 309 |
+
"1. First, we'll need to set up BeautifulSoup and make the request. Would you like to start by writing the code to import the required libraries and fetch the page?\n",
|
| 310 |
+
"\n",
|
| 311 |
+
"The libraries we'll need are:\n",
|
| 312 |
+
"- `beautifulsoup4`\n",
|
| 313 |
+
"- `requests`\n",
|
| 314 |
+
"\n",
|
| 315 |
+
"Would you like to try writing this first part, or would you like me to show you how?"
|
| 316 |
+
]
|
| 317 |
+
},
|
| 318 |
+
{
|
| 319 |
+
"cell_type": "markdown",
|
| 320 |
+
"metadata": {},
|
| 321 |
+
"source": [
|
| 322 |
+
"**AI Prompt**\n",
|
| 323 |
+
"\n",
|
| 324 |
+
"give me the code"
|
| 325 |
+
]
|
| 326 |
+
},
|
| 327 |
+
{
|
| 328 |
+
"cell_type": "markdown",
|
| 329 |
+
"metadata": {},
|
| 330 |
+
"source": [
|
| 331 |
+
"**AI Response**\n",
|
| 332 |
+
"\n",
|
| 333 |
+
"Here's the code to get started:\n",
|
| 334 |
+
"\n",
|
| 335 |
+
"```python\n",
|
| 336 |
+
"import requests\n",
|
| 337 |
+
"from bs4 import BeautifulSoup\n",
|
| 338 |
+
"\n",
|
| 339 |
+
"url = \"https://www.intel.com/content/www/us/en/ark/products/series/236644/5th-gen-intel-xeon-scalable-processors.html\"\n",
|
| 340 |
+
"response = requests.get(url)\n",
|
| 341 |
+
"soup = BeautifulSoup(response.text, 'html.parser')\n",
|
| 342 |
+
"```\n",
|
| 343 |
+
"\n",
|
| 344 |
+
"Try running this code. Let me know if it works, and then we'll move on to extracting the table data. \n",
|
| 345 |
+
"\n",
|
| 346 |
+
"(Note: If you get any errors about missing libraries, you'll need to install them first using `pip install requests beautifulsoup4`)"
|
| 347 |
+
]
|
| 348 |
+
},
|
| 349 |
+
{
|
| 350 |
+
"cell_type": "code",
|
| 351 |
+
"execution_count": null,
|
| 352 |
+
"metadata": {},
|
| 353 |
+
"outputs": [],
|
| 354 |
+
"source": [
|
| 355 |
+
"import requests\n",
|
| 356 |
+
"from bs4 import BeautifulSoup\n",
|
| 357 |
+
"\n",
|
| 358 |
+
"url = \"https://www.intel.com/content/www/us/en/ark/products/series/236644/5th-gen-intel-xeon-scalable-processors.html\"\n",
|
| 359 |
+
"response = requests.get(url)\n",
|
| 360 |
+
"soup = BeautifulSoup(response.text, \"html.parser\")"
|
| 361 |
+
]
|
| 362 |
+
},
|
| 363 |
+
{
|
| 364 |
+
"cell_type": "markdown",
|
| 365 |
+
"metadata": {},
|
| 366 |
+
"source": [
|
| 367 |
+
"**AI Prompt**\n",
|
| 368 |
+
"\n",
|
| 369 |
+
"fine, give me the code to extract the data ?"
|
| 370 |
+
]
|
| 371 |
+
},
|
| 372 |
+
{
|
| 373 |
+
"cell_type": "markdown",
|
| 374 |
+
"metadata": {},
|
| 375 |
+
"source": [
|
| 376 |
+
"**AI Response**\n",
|
| 377 |
+
"\n",
|
| 378 |
+
"Here's the code to extract the table data:\n",
|
| 379 |
+
"\n",
|
| 380 |
+
"```python\n",
|
| 381 |
+
"# Find the table\n",
|
| 382 |
+
"table = soup.find('table', id='product-table')\n",
|
| 383 |
+
"\n",
|
| 384 |
+
"# Extract headers\n",
|
| 385 |
+
"headers = []\n",
|
| 386 |
+
"for th in table.find_all('th'):\n",
|
| 387 |
+
" header_text = th.find('div', class_='header-text-space').text.strip()\n",
|
| 388 |
+
" headers.append(header_text)\n",
|
| 389 |
+
"\n",
|
| 390 |
+
"# Extract rows\n",
|
| 391 |
+
"data = []\n",
|
| 392 |
+
"for row in table.find('tbody').find_all('tr'):\n",
|
| 393 |
+
" row_data = {}\n",
|
| 394 |
+
" cells = row.find_all('td')\n",
|
| 395 |
+
" for i, cell in enumerate(cells):\n",
|
| 396 |
+
" row_data[headers[i]] = cell.text.strip()\n",
|
| 397 |
+
" data.append(row_data)\n",
|
| 398 |
+
"\n",
|
| 399 |
+
"# Convert to pandas DataFrame for easy viewing/export\n",
|
| 400 |
+
"import pandas as pd\n",
|
| 401 |
+
"df = pd.DataFrame(data)\n",
|
| 402 |
+
"print(df)\n",
|
| 403 |
+
"```\n",
|
| 404 |
+
"\n",
|
| 405 |
+
"Would you like me to explain how this code works, or would you prefer to see how to modify it for specific needs?"
|
| 406 |
+
]
|
| 407 |
+
},
|
| 408 |
+
{
|
| 409 |
+
"cell_type": "code",
|
| 410 |
+
"execution_count": null,
|
| 411 |
+
"metadata": {},
|
| 412 |
+
"outputs": [
|
| 413 |
+
{
|
| 414 |
+
"name": "stdout",
|
| 415 |
+
"output_type": "stream",
|
| 416 |
+
"text": [
|
| 417 |
+
" Product Name Launch Date ... Cache TDP\n",
|
| 418 |
+
"0 Intel® Xeon® Bronze 3508U Processor Q4'23 ... 22.5 MB 125 W\n",
|
| 419 |
+
"1 Intel® Xeon® Gold 5512U Processor Q4'23 ... 52.5 MB 185 W\n",
|
| 420 |
+
"2 Intel® Xeon® Gold 5515+ Processor Q4'23 ... 22.5 MB 165 W\n",
|
| 421 |
+
"3 Intel® Xeon® Gold 5520+ Processor Q4'23 ... 52.5 MB 205 W\n",
|
| 422 |
+
"4 Intel® Xeon® Gold 6526Y Processor Q4'23 ... 37.5 MB 195 W\n",
|
| 423 |
+
"5 Intel® Xeon® Gold 6530 Processor Q4'23 ... 160 MB 270 W\n",
|
| 424 |
+
"6 Intel® Xeon® Gold 6534 Processor Q4'23 ... 22.5 MB 195 W\n",
|
| 425 |
+
"7 Intel® Xeon® Gold 6538N Processor Q4'23 ... 60 MB 205 W\n",
|
| 426 |
+
"8 Intel® Xeon® Gold 6538Y+ Processor Q4'23 ... 60 MB 225 W\n",
|
| 427 |
+
"9 Intel® Xeon® Gold 6542Y Processor Q4'23 ... 60 MB 250 W\n",
|
| 428 |
+
"10 Intel® Xeon® Gold 6544Y Processor Q4'23 ... 45 MB 270 W\n",
|
| 429 |
+
"11 Intel® Xeon® Gold 6548N Processor Q4'23 ... 60 MB 250 W\n",
|
| 430 |
+
"12 Intel® Xeon® Gold 6548Y+ Processor Q4'23 ... 60 MB 250 W\n",
|
| 431 |
+
"13 Intel® Xeon® Gold 6554S Processor Q4'23 ... 180 MB 270 W\n",
|
| 432 |
+
"14 Intel® Xeon® Gold 6558Q Processor Q4'23 ... 60 MB 350 W\n",
|
| 433 |
+
"15 Intel® Xeon® Platinum 8558 Processor Q4'23 ... 260 MB 330 W\n",
|
| 434 |
+
"16 Intel® Xeon® Platinum 8558P Processor Q4'23 ... 260 MB 350 W\n",
|
| 435 |
+
"17 Intel® Xeon® Platinum 8558U Processor Q4'23 ... 260 MB 300 W\n",
|
| 436 |
+
"18 Intel® Xeon® Platinum 8562Y+ Processor Q4'23 ... 60 MB 300 W\n",
|
| 437 |
+
"19 Intel® Xeon® Platinum 8568Y+ Processor Q4'23 ... 300 MB 350 W\n",
|
| 438 |
+
"20 Intel® Xeon® Platinum 8570 Processor Q4'23 ... 300 MB 350 W\n",
|
| 439 |
+
"21 Intel® Xeon® Platinum 8571N Processor Q4'23 ... 300 MB 300 W\n",
|
| 440 |
+
"22 Intel® Xeon® Platinum 8580 Processor Q4'23 ... 300 MB 350 W\n",
|
| 441 |
+
"23 Intel® Xeon® Platinum 8581V Processor Q4'23 ... 300 MB 270 W\n",
|
| 442 |
+
"24 Intel® Xeon® Platinum 8592+ Processor Q4'23 ... 320 MB 350 W\n",
|
| 443 |
+
"25 Intel® Xeon® Platinum 8592V Processor Q4'23 ... 320 MB 330 W\n",
|
| 444 |
+
"26 Intel® Xeon® Platinum 8593Q Processor Q4'23 ... 320 MB 385 W\n",
|
| 445 |
+
"27 Intel® Xeon® Silver 4509Y Processor Q4'23 ... 22.5 MB 125 W\n",
|
| 446 |
+
"28 Intel® Xeon® Silver 4510 Processor Q4'23 ... 30 MB 150 W\n",
|
| 447 |
+
"29 Intel® Xeon® Silver 4510T Processor Q4'23 ... 30 MB 115 W\n",
|
| 448 |
+
"30 Intel® Xeon® Silver 4514Y Processor Q4'23 ... 30 MB 150 W\n",
|
| 449 |
+
"31 Intel® Xeon® Silver 4516Y+ Processor Q4'23 ... 45 MB 185 W\n",
|
| 450 |
+
"\n",
|
| 451 |
+
"[32 rows x 7 columns]\n"
|
| 452 |
+
]
|
| 453 |
+
}
|
| 454 |
+
],
|
| 455 |
+
"source": [
|
| 456 |
+
"# Find the table\n",
|
| 457 |
+
"table = soup.find(\"table\", id=\"product-table\")\n",
|
| 458 |
+
"\n",
|
| 459 |
+
"# Extract headers\n",
|
| 460 |
+
"headers = []\n",
|
| 461 |
+
"for th in table.find_all(\"th\"):\n",
|
| 462 |
+
" header_text = th.find(\"div\", class_=\"header-text-space\").text.strip()\n",
|
| 463 |
+
" headers.append(header_text)\n",
|
| 464 |
+
"\n",
|
| 465 |
+
"# Extract rows\n",
|
| 466 |
+
"data = []\n",
|
| 467 |
+
"for row in table.find(\"tbody\").find_all(\"tr\"):\n",
|
| 468 |
+
" row_data = {}\n",
|
| 469 |
+
" cells = row.find_all(\"td\")\n",
|
| 470 |
+
" for i, cell in enumerate(cells):\n",
|
| 471 |
+
" row_data[headers[i]] = cell.text.strip()\n",
|
| 472 |
+
" data.append(row_data)\n",
|
| 473 |
+
"\n",
|
| 474 |
+
"# Convert to pandas DataFrame for easy viewing/export\n",
|
| 475 |
+
"import pandas as pd\n",
|
| 476 |
+
"\n",
|
| 477 |
+
"df = pd.DataFrame(data)\n",
|
| 478 |
+
"print(df)"
|
| 479 |
+
]
|
| 480 |
+
},
|
| 481 |
+
{
|
| 482 |
+
"cell_type": "code",
|
| 483 |
+
"execution_count": null,
|
| 484 |
+
"metadata": {},
|
| 485 |
+
"outputs": [
|
| 486 |
+
{
|
| 487 |
+
"data": {
|
| 488 |
+
"text/plain": [
|
| 489 |
+
"0 125 W\n",
|
| 490 |
+
"1 185 W\n",
|
| 491 |
+
"2 165 W\n",
|
| 492 |
+
"3 205 W\n",
|
| 493 |
+
"4 195 W\n",
|
| 494 |
+
"5 270 W\n",
|
| 495 |
+
"6 195 W\n",
|
| 496 |
+
"7 205 W\n",
|
| 497 |
+
"8 225 W\n",
|
| 498 |
+
"9 250 W\n",
|
| 499 |
+
"10 270 W\n",
|
| 500 |
+
"11 250 W\n",
|
| 501 |
+
"12 250 W\n",
|
| 502 |
+
"13 270 W\n",
|
| 503 |
+
"14 350 W\n",
|
| 504 |
+
"15 330 W\n",
|
| 505 |
+
"16 350 W\n",
|
| 506 |
+
"17 300 W\n",
|
| 507 |
+
"18 300 W\n",
|
| 508 |
+
"19 350 W\n",
|
| 509 |
+
"20 350 W\n",
|
| 510 |
+
"21 300 W\n",
|
| 511 |
+
"22 350 W\n",
|
| 512 |
+
"23 270 W\n",
|
| 513 |
+
"24 350 W\n",
|
| 514 |
+
"25 330 W\n",
|
| 515 |
+
"26 385 W\n",
|
| 516 |
+
"27 125 W\n",
|
| 517 |
+
"28 150 W\n",
|
| 518 |
+
"29 115 W\n",
|
| 519 |
+
"30 150 W\n",
|
| 520 |
+
"31 185 W\n",
|
| 521 |
+
"Name: TDP, dtype: object"
|
| 522 |
+
]
|
| 523 |
+
},
|
| 524 |
+
"execution_count": null,
|
| 525 |
+
"metadata": {},
|
| 526 |
+
"output_type": "execute_result"
|
| 527 |
+
}
|
| 528 |
+
],
|
| 529 |
+
"source": [
|
| 530 |
+
"df[\"TDP\"].replace(\"W\", \"\")"
|
| 531 |
+
]
|
| 532 |
+
},
|
| 533 |
+
{
|
| 534 |
+
"cell_type": "markdown",
|
| 535 |
+
"metadata": {},
|
| 536 |
+
"source": [
|
| 537 |
+
"## AMD"
|
| 538 |
+
]
|
| 539 |
+
},
|
| 540 |
+
{
|
| 541 |
+
"cell_type": "code",
|
| 542 |
+
"execution_count": 24,
|
| 543 |
+
"metadata": {},
|
| 544 |
+
"outputs": [
|
| 545 |
+
{
|
| 546 |
+
"name": "stdout",
|
| 547 |
+
"output_type": "stream",
|
| 548 |
+
"text": [
|
| 549 |
+
"Average TDP per core from AMD dataset: 4.73 W\n"
|
| 550 |
+
]
|
| 551 |
+
}
|
| 552 |
+
],
|
| 553 |
+
"source": [
|
| 554 |
+
"import pandas as pd\n",
|
| 555 |
+
"\n",
|
| 556 |
+
"# Path to your manually exported AMD CPU dataset.\n",
|
| 557 |
+
"# (Adjust the file path as needed.)\n",
|
| 558 |
+
"amd_csv_path = \"./AMD_CPU_desktop_laptop.csv\"\n",
|
| 559 |
+
"\n",
|
| 560 |
+
"try:\n",
|
| 561 |
+
" amd_df = pd.read_csv(amd_csv_path)\n",
|
| 562 |
+
" amd_df = amd_df[amd_df[\"Launch Date\"].str.contains(\"2024|2025\", na=False)]\n",
|
| 563 |
+
" amd_df = amd_df[amd_df[\"Form Factor\"].str.contains(\"Desktops\", na=False)]\n",
|
| 564 |
+
"\n",
|
| 565 |
+
" # Convert columns to numeric, forcing errors to NaN\n",
|
| 566 |
+
" # amd_df['Default TDP'] = amd_df['Default TDP'].str.replace('W', '').astype(float)\n",
|
| 567 |
+
" amd_df[\"TDP\"] = pd.to_numeric(\n",
|
| 568 |
+
" amd_df[\"Default TDP\"].str.replace(\"W\", \"\"), errors=\"coerce\"\n",
|
| 569 |
+
" )\n",
|
| 570 |
+
" amd_df[\"# of Threads\"] = pd.to_numeric(amd_df[\"# of Threads\"], errors=\"coerce\")\n",
|
| 571 |
+
"\n",
|
| 572 |
+
" # It is assumed the CSV contains columns named 'TDP' (in Watts) and 'Total Cores'\n",
|
| 573 |
+
" # Adjust the column names if they differ.\n",
|
| 574 |
+
" amd_df[\"TDP_per_core\"] = amd_df[\"TDP\"] / amd_df[\"# of Threads\"]\n",
|
| 575 |
+
"\n",
|
| 576 |
+
" average_tdp_per_core = amd_df[\"TDP_per_core\"].mean()\n",
|
| 577 |
+
" print(\n",
|
| 578 |
+
" \"Average TDP per core from AMD dataset: {:.2f} W\".format(average_tdp_per_core)\n",
|
| 579 |
+
" )\n",
|
| 580 |
+
"except Exception as e:\n",
|
| 581 |
+
" print(\"Error loading or processing AMD dataset:\", e)"
|
| 582 |
+
]
|
| 583 |
+
},
|
| 584 |
+
{
|
| 585 |
+
"cell_type": "code",
|
| 586 |
+
"execution_count": 28,
|
| 587 |
+
"metadata": {},
|
| 588 |
+
"outputs": [
|
| 589 |
+
{
|
| 590 |
+
"name": "stdout",
|
| 591 |
+
"output_type": "stream",
|
| 592 |
+
"text": [
|
| 593 |
+
"Average TDP per core from AMD dataset: 3.61 W\n"
|
| 594 |
+
]
|
| 595 |
+
}
|
| 596 |
+
],
|
| 597 |
+
"source": [
|
| 598 |
+
"# https://www.amd.com/en/products/specifications/server-processor.html\n",
|
| 599 |
+
"import pandas as pd\n",
|
| 600 |
+
"\n",
|
| 601 |
+
"# Path to your manually exported AMD CPU dataset.\n",
|
| 602 |
+
"# (Adjust the file path as needed.)\n",
|
| 603 |
+
"amd_csv_path = \"./AMD_Server_Processor_Specifications.csv\"\n",
|
| 604 |
+
"\n",
|
| 605 |
+
"try:\n",
|
| 606 |
+
" amd_df = pd.read_csv(amd_csv_path)\n",
|
| 607 |
+
" amd_df = amd_df[amd_df[\"Launch Date\"].str.contains(\"2024|2025\", na=False)]\n",
|
| 608 |
+
"\n",
|
| 609 |
+
" # Convert columns to numeric, forcing errors to NaN\n",
|
| 610 |
+
" # amd_df['Default TDP'] = amd_df['Default TDP'].str.replace('W', '').astype(float)\n",
|
| 611 |
+
" amd_df[\"TDP\"] = pd.to_numeric(\n",
|
| 612 |
+
" amd_df[\"Default TDP\"].str.replace(\"W\", \"\"), errors=\"coerce\"\n",
|
| 613 |
+
" )\n",
|
| 614 |
+
" amd_df[\"# of Threads\"] = pd.to_numeric(amd_df[\"# of Threads\"], errors=\"coerce\")\n",
|
| 615 |
+
"\n",
|
| 616 |
+
" # It is assumed the CSV contains columns named 'TDP' (in Watts) and 'Total Cores'\n",
|
| 617 |
+
" # Adjust the column names if they differ.\n",
|
| 618 |
+
" amd_df[\"TDP_per_core\"] = amd_df[\"TDP\"] / amd_df[\"# of Threads\"]\n",
|
| 619 |
+
"\n",
|
| 620 |
+
" average_tdp_per_core = amd_df[\"TDP_per_core\"].mean()\n",
|
| 621 |
+
" print(\n",
|
| 622 |
+
" \"Average TDP per core from AMD dataset: {:.2f} W\".format(average_tdp_per_core)\n",
|
| 623 |
+
" )\n",
|
| 624 |
+
"except Exception as e:\n",
|
| 625 |
+
" print(\"Error loading or processing AMD dataset:\", e)"
|
| 626 |
+
]
|
| 627 |
+
},
|
| 628 |
+
{
|
| 629 |
+
"cell_type": "code",
|
| 630 |
+
"execution_count": 11,
|
| 631 |
+
"metadata": {},
|
| 632 |
+
"outputs": [
|
| 633 |
+
{
|
| 634 |
+
"data": {
|
| 635 |
+
"text/plain": [
|
| 636 |
+
"Index(['Name', 'Family', 'Series', 'Form Factor', '# of CPU Cores',\n",
|
| 637 |
+
" '# of Threads', 'Max. Boost Clock', 'Base Clock', 'L2 Cache',\n",
|
| 638 |
+
" 'L3 Cache', 'Default TDP', 'L1 Cache', 'AMD Configurable TDP (cTDP)',\n",
|
| 639 |
+
" 'Processor Technology for CPU Cores', 'Unlocked for Overclocking',\n",
|
| 640 |
+
" 'CPU Socket', 'Thermal Solution (PIB)', 'Recommended Cooler',\n",
|
| 641 |
+
" 'Thermal Solution (MPK)', 'Max. Operating Temperature (Tjmax)',\n",
|
| 642 |
+
" 'Launch Date', '*OS Support', 'PCI Express® Version',\n",
|
| 643 |
+
" 'System Memory Type', 'Memory Channels', 'System Memory Specification',\n",
|
| 644 |
+
" 'Graphics Model', 'Graphics Core Count', 'Graphics Frequency',\n",
|
| 645 |
+
" 'AMD Ryzen™ AI', 'Product ID Boxed', 'Product ID Tray',\n",
|
| 646 |
+
" 'Product ID MPK', 'Supported Technologies', 'TDP_per_core'],\n",
|
| 647 |
+
" dtype='object')"
|
| 648 |
+
]
|
| 649 |
+
},
|
| 650 |
+
"execution_count": 11,
|
| 651 |
+
"metadata": {},
|
| 652 |
+
"output_type": "execute_result"
|
| 653 |
+
}
|
| 654 |
+
],
|
| 655 |
+
"source": [
|
| 656 |
+
"amd_df.columns"
|
| 657 |
+
]
|
| 658 |
+
},
|
| 659 |
+
{
|
| 660 |
+
"cell_type": "code",
|
| 661 |
+
"execution_count": 26,
|
| 662 |
+
"metadata": {},
|
| 663 |
+
"outputs": [
|
| 664 |
+
{
|
| 665 |
+
"data": {
|
| 666 |
+
"text/html": [
|
| 667 |
+
"<div>\n",
|
| 668 |
+
"<style scoped>\n",
|
| 669 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 670 |
+
" vertical-align: middle;\n",
|
| 671 |
+
" }\n",
|
| 672 |
+
"\n",
|
| 673 |
+
" .dataframe tbody tr th {\n",
|
| 674 |
+
" vertical-align: top;\n",
|
| 675 |
+
" }\n",
|
| 676 |
+
"\n",
|
| 677 |
+
" .dataframe thead th {\n",
|
| 678 |
+
" text-align: right;\n",
|
| 679 |
+
" }\n",
|
| 680 |
+
"</style>\n",
|
| 681 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 682 |
+
" <thead>\n",
|
| 683 |
+
" <tr style=\"text-align: right;\">\n",
|
| 684 |
+
" <th></th>\n",
|
| 685 |
+
" <th>Name</th>\n",
|
| 686 |
+
" <th>TDP</th>\n",
|
| 687 |
+
" <th># of Threads</th>\n",
|
| 688 |
+
" <th>TDP_per_core</th>\n",
|
| 689 |
+
" <th>Launch Date</th>\n",
|
| 690 |
+
" </tr>\n",
|
| 691 |
+
" </thead>\n",
|
| 692 |
+
" <tbody>\n",
|
| 693 |
+
" <tr>\n",
|
| 694 |
+
" <th>34</th>\n",
|
| 695 |
+
" <td>AMD Ryzen™ 9 9950X</td>\n",
|
| 696 |
+
" <td>170</td>\n",
|
| 697 |
+
" <td>32.0</td>\n",
|
| 698 |
+
" <td>5.312500</td>\n",
|
| 699 |
+
" <td>08/15/2024</td>\n",
|
| 700 |
+
" </tr>\n",
|
| 701 |
+
" <tr>\n",
|
| 702 |
+
" <th>36</th>\n",
|
| 703 |
+
" <td>AMD Ryzen™ 9 9900X</td>\n",
|
| 704 |
+
" <td>120</td>\n",
|
| 705 |
+
" <td>24.0</td>\n",
|
| 706 |
+
" <td>5.000000</td>\n",
|
| 707 |
+
" <td>08/15/2024</td>\n",
|
| 708 |
+
" </tr>\n",
|
| 709 |
+
" <tr>\n",
|
| 710 |
+
" <th>38</th>\n",
|
| 711 |
+
" <td>AMD Ryzen™ 7 9800X3D</td>\n",
|
| 712 |
+
" <td>120</td>\n",
|
| 713 |
+
" <td>16.0</td>\n",
|
| 714 |
+
" <td>7.500000</td>\n",
|
| 715 |
+
" <td>11/07/2024</td>\n",
|
| 716 |
+
" </tr>\n",
|
| 717 |
+
" <tr>\n",
|
| 718 |
+
" <th>39</th>\n",
|
| 719 |
+
" <td>AMD Ryzen™ 7 9700X</td>\n",
|
| 720 |
+
" <td>65</td>\n",
|
| 721 |
+
" <td>16.0</td>\n",
|
| 722 |
+
" <td>4.062500</td>\n",
|
| 723 |
+
" <td>08/08/2024</td>\n",
|
| 724 |
+
" </tr>\n",
|
| 725 |
+
" <tr>\n",
|
| 726 |
+
" <th>40</th>\n",
|
| 727 |
+
" <td>AMD Ryzen™ 5 9600X</td>\n",
|
| 728 |
+
" <td>65</td>\n",
|
| 729 |
+
" <td>12.0</td>\n",
|
| 730 |
+
" <td>5.416667</td>\n",
|
| 731 |
+
" <td>08/08/2024</td>\n",
|
| 732 |
+
" </tr>\n",
|
| 733 |
+
" <tr>\n",
|
| 734 |
+
" <th>44</th>\n",
|
| 735 |
+
" <td>AMD Ryzen™ 7 PRO 8845HS</td>\n",
|
| 736 |
+
" <td>45</td>\n",
|
| 737 |
+
" <td>16.0</td>\n",
|
| 738 |
+
" <td>2.812500</td>\n",
|
| 739 |
+
" <td>04/16/2024</td>\n",
|
| 740 |
+
" </tr>\n",
|
| 741 |
+
" <tr>\n",
|
| 742 |
+
" <th>46</th>\n",
|
| 743 |
+
" <td>AMD Ryzen™ 7 PRO 8700GE</td>\n",
|
| 744 |
+
" <td>35</td>\n",
|
| 745 |
+
" <td>16.0</td>\n",
|
| 746 |
+
" <td>2.187500</td>\n",
|
| 747 |
+
" <td>4/16/2024</td>\n",
|
| 748 |
+
" </tr>\n",
|
| 749 |
+
" <tr>\n",
|
| 750 |
+
" <th>47</th>\n",
|
| 751 |
+
" <td>AMD Ryzen™ 7 PRO 8700G</td>\n",
|
| 752 |
+
" <td>65</td>\n",
|
| 753 |
+
" <td>16.0</td>\n",
|
| 754 |
+
" <td>4.062500</td>\n",
|
| 755 |
+
" <td>4/16/2024</td>\n",
|
| 756 |
+
" </tr>\n",
|
| 757 |
+
" <tr>\n",
|
| 758 |
+
" <th>51</th>\n",
|
| 759 |
+
" <td>AMD Ryzen™ 5 PRO 8600GE</td>\n",
|
| 760 |
+
" <td>35</td>\n",
|
| 761 |
+
" <td>12.0</td>\n",
|
| 762 |
+
" <td>2.916667</td>\n",
|
| 763 |
+
" <td>4/16/2024</td>\n",
|
| 764 |
+
" </tr>\n",
|
| 765 |
+
" <tr>\n",
|
| 766 |
+
" <th>52</th>\n",
|
| 767 |
+
" <td>AMD Ryzen™ 5 PRO 8600G</td>\n",
|
| 768 |
+
" <td>65</td>\n",
|
| 769 |
+
" <td>12.0</td>\n",
|
| 770 |
+
" <td>5.416667</td>\n",
|
| 771 |
+
" <td>4/16/2024</td>\n",
|
| 772 |
+
" </tr>\n",
|
| 773 |
+
" <tr>\n",
|
| 774 |
+
" <th>54</th>\n",
|
| 775 |
+
" <td>AMD Ryzen™ 5 PRO 8500GE</td>\n",
|
| 776 |
+
" <td>35</td>\n",
|
| 777 |
+
" <td>12.0</td>\n",
|
| 778 |
+
" <td>2.916667</td>\n",
|
| 779 |
+
" <td>4/16/2024</td>\n",
|
| 780 |
+
" </tr>\n",
|
| 781 |
+
" <tr>\n",
|
| 782 |
+
" <th>55</th>\n",
|
| 783 |
+
" <td>AMD Ryzen™ 5 PRO 8500G</td>\n",
|
| 784 |
+
" <td>65</td>\n",
|
| 785 |
+
" <td>12.0</td>\n",
|
| 786 |
+
" <td>5.416667</td>\n",
|
| 787 |
+
" <td>4/16/2024</td>\n",
|
| 788 |
+
" </tr>\n",
|
| 789 |
+
" <tr>\n",
|
| 790 |
+
" <th>57</th>\n",
|
| 791 |
+
" <td>AMD Ryzen™ 3 PRO 8300GE</td>\n",
|
| 792 |
+
" <td>35</td>\n",
|
| 793 |
+
" <td>8.0</td>\n",
|
| 794 |
+
" <td>4.375000</td>\n",
|
| 795 |
+
" <td>4/16/2024</td>\n",
|
| 796 |
+
" </tr>\n",
|
| 797 |
+
" <tr>\n",
|
| 798 |
+
" <th>58</th>\n",
|
| 799 |
+
" <td>AMD Ryzen™ 3 PRO 8300G</td>\n",
|
| 800 |
+
" <td>65</td>\n",
|
| 801 |
+
" <td>8.0</td>\n",
|
| 802 |
+
" <td>8.125000</td>\n",
|
| 803 |
+
" <td>4/16/2024</td>\n",
|
| 804 |
+
" </tr>\n",
|
| 805 |
+
" <tr>\n",
|
| 806 |
+
" <th>62</th>\n",
|
| 807 |
+
" <td>AMD Ryzen™ 7 8700G</td>\n",
|
| 808 |
+
" <td>65</td>\n",
|
| 809 |
+
" <td>16.0</td>\n",
|
| 810 |
+
" <td>4.062500</td>\n",
|
| 811 |
+
" <td>1/31/2024</td>\n",
|
| 812 |
+
" </tr>\n",
|
| 813 |
+
" <tr>\n",
|
| 814 |
+
" <th>63</th>\n",
|
| 815 |
+
" <td>AMD Ryzen™ 7 8700F</td>\n",
|
| 816 |
+
" <td>65</td>\n",
|
| 817 |
+
" <td>16.0</td>\n",
|
| 818 |
+
" <td>4.062500</td>\n",
|
| 819 |
+
" <td>04/01/2024</td>\n",
|
| 820 |
+
" </tr>\n",
|
| 821 |
+
" <tr>\n",
|
| 822 |
+
" <th>67</th>\n",
|
| 823 |
+
" <td>AMD Ryzen™ 5 8600G</td>\n",
|
| 824 |
+
" <td>65</td>\n",
|
| 825 |
+
" <td>12.0</td>\n",
|
| 826 |
+
" <td>5.416667</td>\n",
|
| 827 |
+
" <td>1/31/2024</td>\n",
|
| 828 |
+
" </tr>\n",
|
| 829 |
+
" <tr>\n",
|
| 830 |
+
" <th>69</th>\n",
|
| 831 |
+
" <td>AMD Ryzen™ 5 8500GE</td>\n",
|
| 832 |
+
" <td>35</td>\n",
|
| 833 |
+
" <td>12.0</td>\n",
|
| 834 |
+
" <td>2.916667</td>\n",
|
| 835 |
+
" <td>4/16/2024</td>\n",
|
| 836 |
+
" </tr>\n",
|
| 837 |
+
" <tr>\n",
|
| 838 |
+
" <th>70</th>\n",
|
| 839 |
+
" <td>AMD Ryzen™ 5 8500G</td>\n",
|
| 840 |
+
" <td>65</td>\n",
|
| 841 |
+
" <td>12.0</td>\n",
|
| 842 |
+
" <td>5.416667</td>\n",
|
| 843 |
+
" <td>1/31/2024</td>\n",
|
| 844 |
+
" </tr>\n",
|
| 845 |
+
" <tr>\n",
|
| 846 |
+
" <th>72</th>\n",
|
| 847 |
+
" <td>AMD Ryzen™ 3 8300GE</td>\n",
|
| 848 |
+
" <td>35</td>\n",
|
| 849 |
+
" <td>8.0</td>\n",
|
| 850 |
+
" <td>4.375000</td>\n",
|
| 851 |
+
" <td>4/16/2024</td>\n",
|
| 852 |
+
" </tr>\n",
|
| 853 |
+
" <tr>\n",
|
| 854 |
+
" <th>73</th>\n",
|
| 855 |
+
" <td>AMD Ryzen™ 5 8400F</td>\n",
|
| 856 |
+
" <td>65</td>\n",
|
| 857 |
+
" <td>12.0</td>\n",
|
| 858 |
+
" <td>5.416667</td>\n",
|
| 859 |
+
" <td>04/01/2024</td>\n",
|
| 860 |
+
" </tr>\n",
|
| 861 |
+
" <tr>\n",
|
| 862 |
+
" <th>74</th>\n",
|
| 863 |
+
" <td>AMD Ryzen™ 3 8300G</td>\n",
|
| 864 |
+
" <td>65</td>\n",
|
| 865 |
+
" <td>8.0</td>\n",
|
| 866 |
+
" <td>8.125000</td>\n",
|
| 867 |
+
" <td>1/31/2024</td>\n",
|
| 868 |
+
" </tr>\n",
|
| 869 |
+
" <tr>\n",
|
| 870 |
+
" <th>105</th>\n",
|
| 871 |
+
" <td>AMD Ryzen™ 9 7940HX</td>\n",
|
| 872 |
+
" <td>55</td>\n",
|
| 873 |
+
" <td>32.0</td>\n",
|
| 874 |
+
" <td>1.718750</td>\n",
|
| 875 |
+
" <td>1/17/2024</td>\n",
|
| 876 |
+
" </tr>\n",
|
| 877 |
+
" <tr>\n",
|
| 878 |
+
" <th>111</th>\n",
|
| 879 |
+
" <td>AMD Ryzen™ 7 7840HX</td>\n",
|
| 880 |
+
" <td>55</td>\n",
|
| 881 |
+
" <td>24.0</td>\n",
|
| 882 |
+
" <td>2.291667</td>\n",
|
| 883 |
+
" <td>1/17/2024</td>\n",
|
| 884 |
+
" </tr>\n",
|
| 885 |
+
" <tr>\n",
|
| 886 |
+
" <th>124</th>\n",
|
| 887 |
+
" <td>AMD Ryzen™ 5 7600X3D</td>\n",
|
| 888 |
+
" <td>65</td>\n",
|
| 889 |
+
" <td>12.0</td>\n",
|
| 890 |
+
" <td>5.416667</td>\n",
|
| 891 |
+
" <td>9/5/2024</td>\n",
|
| 892 |
+
" </tr>\n",
|
| 893 |
+
" <tr>\n",
|
| 894 |
+
" <th>138</th>\n",
|
| 895 |
+
" <td>AMD Ryzen™ 5 7400F</td>\n",
|
| 896 |
+
" <td>65</td>\n",
|
| 897 |
+
" <td>12.0</td>\n",
|
| 898 |
+
" <td>5.416667</td>\n",
|
| 899 |
+
" <td>1/9/2025</td>\n",
|
| 900 |
+
" </tr>\n",
|
| 901 |
+
" <tr>\n",
|
| 902 |
+
" <th>178</th>\n",
|
| 903 |
+
" <td>AMD Ryzen™ 7 PRO 5755GE</td>\n",
|
| 904 |
+
" <td>35</td>\n",
|
| 905 |
+
" <td>16.0</td>\n",
|
| 906 |
+
" <td>2.187500</td>\n",
|
| 907 |
+
" <td>9/5/2024</td>\n",
|
| 908 |
+
" </tr>\n",
|
| 909 |
+
" <tr>\n",
|
| 910 |
+
" <th>179</th>\n",
|
| 911 |
+
" <td>AMD Ryzen™ 7 PRO 5755G</td>\n",
|
| 912 |
+
" <td>65</td>\n",
|
| 913 |
+
" <td>16.0</td>\n",
|
| 914 |
+
" <td>4.062500</td>\n",
|
| 915 |
+
" <td>9/5/2024</td>\n",
|
| 916 |
+
" </tr>\n",
|
| 917 |
+
" <tr>\n",
|
| 918 |
+
" <th>183</th>\n",
|
| 919 |
+
" <td>AMD Ryzen™ 5 PRO 5655GE</td>\n",
|
| 920 |
+
" <td>35</td>\n",
|
| 921 |
+
" <td>12.0</td>\n",
|
| 922 |
+
" <td>2.916667</td>\n",
|
| 923 |
+
" <td>5/7/2024</td>\n",
|
| 924 |
+
" </tr>\n",
|
| 925 |
+
" <tr>\n",
|
| 926 |
+
" <th>184</th>\n",
|
| 927 |
+
" <td>AMD Ryzen™ 5 PRO 5655G</td>\n",
|
| 928 |
+
" <td>65</td>\n",
|
| 929 |
+
" <td>12.0</td>\n",
|
| 930 |
+
" <td>5.416667</td>\n",
|
| 931 |
+
" <td>5/7/2024</td>\n",
|
| 932 |
+
" </tr>\n",
|
| 933 |
+
" <tr>\n",
|
| 934 |
+
" <th>191</th>\n",
|
| 935 |
+
" <td>AMD Ryzen™ 3 PRO 5355GE</td>\n",
|
| 936 |
+
" <td>35</td>\n",
|
| 937 |
+
" <td>8.0</td>\n",
|
| 938 |
+
" <td>4.375000</td>\n",
|
| 939 |
+
" <td>9/5/2024</td>\n",
|
| 940 |
+
" </tr>\n",
|
| 941 |
+
" <tr>\n",
|
| 942 |
+
" <th>192</th>\n",
|
| 943 |
+
" <td>AMD Ryzen™ 3 PRO 5355G</td>\n",
|
| 944 |
+
" <td>65</td>\n",
|
| 945 |
+
" <td>8.0</td>\n",
|
| 946 |
+
" <td>8.125000</td>\n",
|
| 947 |
+
" <td>9/5/2024</td>\n",
|
| 948 |
+
" </tr>\n",
|
| 949 |
+
" <tr>\n",
|
| 950 |
+
" <th>198</th>\n",
|
| 951 |
+
" <td>AMD Ryzen™ 9 5900XT</td>\n",
|
| 952 |
+
" <td>105</td>\n",
|
| 953 |
+
" <td>32.0</td>\n",
|
| 954 |
+
" <td>3.281250</td>\n",
|
| 955 |
+
" <td>07/31/2024</td>\n",
|
| 956 |
+
" </tr>\n",
|
| 957 |
+
" <tr>\n",
|
| 958 |
+
" <th>206</th>\n",
|
| 959 |
+
" <td>AMD Ryzen™ 7 5800XT</td>\n",
|
| 960 |
+
" <td>105</td>\n",
|
| 961 |
+
" <td>16.0</td>\n",
|
| 962 |
+
" <td>6.562500</td>\n",
|
| 963 |
+
" <td>07/31/2024</td>\n",
|
| 964 |
+
" </tr>\n",
|
| 965 |
+
" <tr>\n",
|
| 966 |
+
" <th>214</th>\n",
|
| 967 |
+
" <td>AMD Ryzen™ 7 5700X3D</td>\n",
|
| 968 |
+
" <td>105</td>\n",
|
| 969 |
+
" <td>16.0</td>\n",
|
| 970 |
+
" <td>6.562500</td>\n",
|
| 971 |
+
" <td>01/08/2024</td>\n",
|
| 972 |
+
" </tr>\n",
|
| 973 |
+
" <tr>\n",
|
| 974 |
+
" <th>219</th>\n",
|
| 975 |
+
" <td>AMD Ryzen™ 7 5700</td>\n",
|
| 976 |
+
" <td>65</td>\n",
|
| 977 |
+
" <td>16.0</td>\n",
|
| 978 |
+
" <td>4.062500</td>\n",
|
| 979 |
+
" <td>01/31/2024</td>\n",
|
| 980 |
+
" </tr>\n",
|
| 981 |
+
" <tr>\n",
|
| 982 |
+
" <th>229</th>\n",
|
| 983 |
+
" <td>AMD Ryzen™ 5 5600XT</td>\n",
|
| 984 |
+
" <td>65</td>\n",
|
| 985 |
+
" <td>12.0</td>\n",
|
| 986 |
+
" <td>5.416667</td>\n",
|
| 987 |
+
" <td>10/31/2024</td>\n",
|
| 988 |
+
" </tr>\n",
|
| 989 |
+
" <tr>\n",
|
| 990 |
+
" <th>230</th>\n",
|
| 991 |
+
" <td>AMD Ryzen™ 5 5600T</td>\n",
|
| 992 |
+
" <td>65</td>\n",
|
| 993 |
+
" <td>12.0</td>\n",
|
| 994 |
+
" <td>5.416667</td>\n",
|
| 995 |
+
" <td>10/31/2024</td>\n",
|
| 996 |
+
" </tr>\n",
|
| 997 |
+
" <tr>\n",
|
| 998 |
+
" <th>231</th>\n",
|
| 999 |
+
" <td>AMD Ryzen™ 5 5600GT</td>\n",
|
| 1000 |
+
" <td>65</td>\n",
|
| 1001 |
+
" <td>12.0</td>\n",
|
| 1002 |
+
" <td>5.416667</td>\n",
|
| 1003 |
+
" <td>01/08/2024</td>\n",
|
| 1004 |
+
" </tr>\n",
|
| 1005 |
+
" <tr>\n",
|
| 1006 |
+
" <th>238</th>\n",
|
| 1007 |
+
" <td>AMD Ryzen™ 5 5500GT</td>\n",
|
| 1008 |
+
" <td>65</td>\n",
|
| 1009 |
+
" <td>12.0</td>\n",
|
| 1010 |
+
" <td>5.416667</td>\n",
|
| 1011 |
+
" <td>01/08/2024</td>\n",
|
| 1012 |
+
" </tr>\n",
|
| 1013 |
+
" </tbody>\n",
|
| 1014 |
+
"</table>\n",
|
| 1015 |
+
"</div>"
|
| 1016 |
+
],
|
| 1017 |
+
"text/plain": [
|
| 1018 |
+
" Name TDP # of Threads TDP_per_core Launch Date\n",
|
| 1019 |
+
"34 AMD Ryzen™ 9 9950X 170 32.0 5.312500 08/15/2024\n",
|
| 1020 |
+
"36 AMD Ryzen™ 9 9900X 120 24.0 5.000000 08/15/2024\n",
|
| 1021 |
+
"38 AMD Ryzen™ 7 9800X3D 120 16.0 7.500000 11/07/2024\n",
|
| 1022 |
+
"39 AMD Ryzen™ 7 9700X 65 16.0 4.062500 08/08/2024\n",
|
| 1023 |
+
"40 AMD Ryzen™ 5 9600X 65 12.0 5.416667 08/08/2024\n",
|
| 1024 |
+
"44 AMD Ryzen™ 7 PRO 8845HS 45 16.0 2.812500 04/16/2024\n",
|
| 1025 |
+
"46 AMD Ryzen™ 7 PRO 8700GE 35 16.0 2.187500 4/16/2024\n",
|
| 1026 |
+
"47 AMD Ryzen™ 7 PRO 8700G 65 16.0 4.062500 4/16/2024\n",
|
| 1027 |
+
"51 AMD Ryzen™ 5 PRO 8600GE 35 12.0 2.916667 4/16/2024\n",
|
| 1028 |
+
"52 AMD Ryzen™ 5 PRO 8600G 65 12.0 5.416667 4/16/2024\n",
|
| 1029 |
+
"54 AMD Ryzen™ 5 PRO 8500GE 35 12.0 2.916667 4/16/2024\n",
|
| 1030 |
+
"55 AMD Ryzen™ 5 PRO 8500G 65 12.0 5.416667 4/16/2024\n",
|
| 1031 |
+
"57 AMD Ryzen™ 3 PRO 8300GE 35 8.0 4.375000 4/16/2024\n",
|
| 1032 |
+
"58 AMD Ryzen™ 3 PRO 8300G 65 8.0 8.125000 4/16/2024\n",
|
| 1033 |
+
"62 AMD Ryzen™ 7 8700G 65 16.0 4.062500 1/31/2024\n",
|
| 1034 |
+
"63 AMD Ryzen™ 7 8700F 65 16.0 4.062500 04/01/2024\n",
|
| 1035 |
+
"67 AMD Ryzen™ 5 8600G 65 12.0 5.416667 1/31/2024\n",
|
| 1036 |
+
"69 AMD Ryzen™ 5 8500GE 35 12.0 2.916667 4/16/2024\n",
|
| 1037 |
+
"70 AMD Ryzen™ 5 8500G 65 12.0 5.416667 1/31/2024\n",
|
| 1038 |
+
"72 AMD Ryzen™ 3 8300GE 35 8.0 4.375000 4/16/2024\n",
|
| 1039 |
+
"73 AMD Ryzen™ 5 8400F 65 12.0 5.416667 04/01/2024\n",
|
| 1040 |
+
"74 AMD Ryzen™ 3 8300G 65 8.0 8.125000 1/31/2024\n",
|
| 1041 |
+
"105 AMD Ryzen™ 9 7940HX 55 32.0 1.718750 1/17/2024\n",
|
| 1042 |
+
"111 AMD Ryzen™ 7 7840HX 55 24.0 2.291667 1/17/2024\n",
|
| 1043 |
+
"124 AMD Ryzen™ 5 7600X3D 65 12.0 5.416667 9/5/2024\n",
|
| 1044 |
+
"138 AMD Ryzen™ 5 7400F 65 12.0 5.416667 1/9/2025\n",
|
| 1045 |
+
"178 AMD Ryzen™ 7 PRO 5755GE 35 16.0 2.187500 9/5/2024\n",
|
| 1046 |
+
"179 AMD Ryzen™ 7 PRO 5755G 65 16.0 4.062500 9/5/2024\n",
|
| 1047 |
+
"183 AMD Ryzen™ 5 PRO 5655GE 35 12.0 2.916667 5/7/2024\n",
|
| 1048 |
+
"184 AMD Ryzen™ 5 PRO 5655G 65 12.0 5.416667 5/7/2024\n",
|
| 1049 |
+
"191 AMD Ryzen™ 3 PRO 5355GE 35 8.0 4.375000 9/5/2024\n",
|
| 1050 |
+
"192 AMD Ryzen™ 3 PRO 5355G 65 8.0 8.125000 9/5/2024\n",
|
| 1051 |
+
"198 AMD Ryzen™ 9 5900XT 105 32.0 3.281250 07/31/2024\n",
|
| 1052 |
+
"206 AMD Ryzen™ 7 5800XT 105 16.0 6.562500 07/31/2024\n",
|
| 1053 |
+
"214 AMD Ryzen™ 7 5700X3D 105 16.0 6.562500 01/08/2024\n",
|
| 1054 |
+
"219 AMD Ryzen™ 7 5700 65 16.0 4.062500 01/31/2024\n",
|
| 1055 |
+
"229 AMD Ryzen™ 5 5600XT 65 12.0 5.416667 10/31/2024\n",
|
| 1056 |
+
"230 AMD Ryzen™ 5 5600T 65 12.0 5.416667 10/31/2024\n",
|
| 1057 |
+
"231 AMD Ryzen™ 5 5600GT 65 12.0 5.416667 01/08/2024\n",
|
| 1058 |
+
"238 AMD Ryzen™ 5 5500GT 65 12.0 5.416667 01/08/2024"
|
| 1059 |
+
]
|
| 1060 |
+
},
|
| 1061 |
+
"execution_count": 26,
|
| 1062 |
+
"metadata": {},
|
| 1063 |
+
"output_type": "execute_result"
|
| 1064 |
+
}
|
| 1065 |
+
],
|
| 1066 |
+
"source": [
|
| 1067 |
+
"amd_df[[\"Name\", \"TDP\", \"# of Threads\", \"TDP_per_core\", \"Launch Date\"]]"
|
| 1068 |
+
]
|
| 1069 |
+
},
|
| 1070 |
+
{
|
| 1071 |
+
"cell_type": "markdown",
|
| 1072 |
+
"metadata": {},
|
| 1073 |
+
"source": [
|
| 1074 |
+
"# Update the static CodeCarbon database"
|
| 1075 |
+
]
|
| 1076 |
+
},
|
| 1077 |
+
{
|
| 1078 |
+
"cell_type": "code",
|
| 1079 |
+
"execution_count": 64,
|
| 1080 |
+
"metadata": {},
|
| 1081 |
+
"outputs": [
|
| 1082 |
+
{
|
| 1083 |
+
"data": {
|
| 1084 |
+
"text/html": [
|
| 1085 |
+
"<div>\n",
|
| 1086 |
+
"<style scoped>\n",
|
| 1087 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1088 |
+
" vertical-align: middle;\n",
|
| 1089 |
+
" }\n",
|
| 1090 |
+
"\n",
|
| 1091 |
+
" .dataframe tbody tr th {\n",
|
| 1092 |
+
" vertical-align: top;\n",
|
| 1093 |
+
" }\n",
|
| 1094 |
+
"\n",
|
| 1095 |
+
" .dataframe thead th {\n",
|
| 1096 |
+
" text-align: right;\n",
|
| 1097 |
+
" }\n",
|
| 1098 |
+
"</style>\n",
|
| 1099 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1100 |
+
" <thead>\n",
|
| 1101 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1102 |
+
" <th></th>\n",
|
| 1103 |
+
" <th>Name</th>\n",
|
| 1104 |
+
" <th>TDP</th>\n",
|
| 1105 |
+
" </tr>\n",
|
| 1106 |
+
" </thead>\n",
|
| 1107 |
+
" <tbody>\n",
|
| 1108 |
+
" <tr>\n",
|
| 1109 |
+
" <th>0</th>\n",
|
| 1110 |
+
" <td>1075T</td>\n",
|
| 1111 |
+
" <td>95</td>\n",
|
| 1112 |
+
" </tr>\n",
|
| 1113 |
+
" <tr>\n",
|
| 1114 |
+
" <th>1</th>\n",
|
| 1115 |
+
" <td>255e</td>\n",
|
| 1116 |
+
" <td>45</td>\n",
|
| 1117 |
+
" </tr>\n",
|
| 1118 |
+
" <tr>\n",
|
| 1119 |
+
" <th>2</th>\n",
|
| 1120 |
+
" <td>3260 HE</td>\n",
|
| 1121 |
+
" <td>45</td>\n",
|
| 1122 |
+
" </tr>\n",
|
| 1123 |
+
" <tr>\n",
|
| 1124 |
+
" <th>3</th>\n",
|
| 1125 |
+
" <td>3280</td>\n",
|
| 1126 |
+
" <td>65</td>\n",
|
| 1127 |
+
" </tr>\n",
|
| 1128 |
+
" <tr>\n",
|
| 1129 |
+
" <th>4</th>\n",
|
| 1130 |
+
" <td>3320 EE</td>\n",
|
| 1131 |
+
" <td>25</td>\n",
|
| 1132 |
+
" </tr>\n",
|
| 1133 |
+
" <tr>\n",
|
| 1134 |
+
" <th>...</th>\n",
|
| 1135 |
+
" <td>...</td>\n",
|
| 1136 |
+
" <td>...</td>\n",
|
| 1137 |
+
" </tr>\n",
|
| 1138 |
+
" <tr>\n",
|
| 1139 |
+
" <th>3923</th>\n",
|
| 1140 |
+
" <td>TL-52</td>\n",
|
| 1141 |
+
" <td>31</td>\n",
|
| 1142 |
+
" </tr>\n",
|
| 1143 |
+
" <tr>\n",
|
| 1144 |
+
" <th>3924</th>\n",
|
| 1145 |
+
" <td>TL-60</td>\n",
|
| 1146 |
+
" <td>31</td>\n",
|
| 1147 |
+
" </tr>\n",
|
| 1148 |
+
" <tr>\n",
|
| 1149 |
+
" <th>3925</th>\n",
|
| 1150 |
+
" <td>TL-64</td>\n",
|
| 1151 |
+
" <td>35</td>\n",
|
| 1152 |
+
" </tr>\n",
|
| 1153 |
+
" <tr>\n",
|
| 1154 |
+
" <th>3926</th>\n",
|
| 1155 |
+
" <td>X1150</td>\n",
|
| 1156 |
+
" <td>17</td>\n",
|
| 1157 |
+
" </tr>\n",
|
| 1158 |
+
" <tr>\n",
|
| 1159 |
+
" <th>3927</th>\n",
|
| 1160 |
+
" <td>X940</td>\n",
|
| 1161 |
+
" <td>45</td>\n",
|
| 1162 |
+
" </tr>\n",
|
| 1163 |
+
" </tbody>\n",
|
| 1164 |
+
"</table>\n",
|
| 1165 |
+
"<p>3928 rows × 2 columns</p>\n",
|
| 1166 |
+
"</div>"
|
| 1167 |
+
],
|
| 1168 |
+
"text/plain": [
|
| 1169 |
+
" Name TDP\n",
|
| 1170 |
+
"0 1075T 95\n",
|
| 1171 |
+
"1 255e 45\n",
|
| 1172 |
+
"2 3260 HE 45\n",
|
| 1173 |
+
"3 3280 65\n",
|
| 1174 |
+
"4 3320 EE 25\n",
|
| 1175 |
+
"... ... ..\n",
|
| 1176 |
+
"3923 TL-52 31\n",
|
| 1177 |
+
"3924 TL-60 31\n",
|
| 1178 |
+
"3925 TL-64 35\n",
|
| 1179 |
+
"3926 X1150 17\n",
|
| 1180 |
+
"3927 X940 45\n",
|
| 1181 |
+
"\n",
|
| 1182 |
+
"[3928 rows x 2 columns]"
|
| 1183 |
+
]
|
| 1184 |
+
},
|
| 1185 |
+
"execution_count": 64,
|
| 1186 |
+
"metadata": {},
|
| 1187 |
+
"output_type": "execute_result"
|
| 1188 |
+
}
|
| 1189 |
+
],
|
| 1190 |
+
"source": [
|
| 1191 |
+
"df = pd.read_csv(\"cpu_power.csv\")\n",
|
| 1192 |
+
"df"
|
| 1193 |
+
]
|
| 1194 |
+
},
|
| 1195 |
+
{
|
| 1196 |
+
"cell_type": "code",
|
| 1197 |
+
"execution_count": 65,
|
| 1198 |
+
"metadata": {},
|
| 1199 |
+
"outputs": [
|
| 1200 |
+
{
|
| 1201 |
+
"data": {
|
| 1202 |
+
"text/html": [
|
| 1203 |
+
"<div>\n",
|
| 1204 |
+
"<style scoped>\n",
|
| 1205 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1206 |
+
" vertical-align: middle;\n",
|
| 1207 |
+
" }\n",
|
| 1208 |
+
"\n",
|
| 1209 |
+
" .dataframe tbody tr th {\n",
|
| 1210 |
+
" vertical-align: top;\n",
|
| 1211 |
+
" }\n",
|
| 1212 |
+
"\n",
|
| 1213 |
+
" .dataframe thead th {\n",
|
| 1214 |
+
" text-align: right;\n",
|
| 1215 |
+
" }\n",
|
| 1216 |
+
"</style>\n",
|
| 1217 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1218 |
+
" <thead>\n",
|
| 1219 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1220 |
+
" <th></th>\n",
|
| 1221 |
+
" <th>Name</th>\n",
|
| 1222 |
+
" <th>TDP</th>\n",
|
| 1223 |
+
" </tr>\n",
|
| 1224 |
+
" </thead>\n",
|
| 1225 |
+
" <tbody>\n",
|
| 1226 |
+
" <tr>\n",
|
| 1227 |
+
" <th>0</th>\n",
|
| 1228 |
+
" <td>AMD EPYC 9965</td>\n",
|
| 1229 |
+
" <td>500.0</td>\n",
|
| 1230 |
+
" </tr>\n",
|
| 1231 |
+
" <tr>\n",
|
| 1232 |
+
" <th>1</th>\n",
|
| 1233 |
+
" <td>AMD EPYC 9845</td>\n",
|
| 1234 |
+
" <td>390.0</td>\n",
|
| 1235 |
+
" </tr>\n",
|
| 1236 |
+
" <tr>\n",
|
| 1237 |
+
" <th>2</th>\n",
|
| 1238 |
+
" <td>AMD EPYC 9825</td>\n",
|
| 1239 |
+
" <td>390.0</td>\n",
|
| 1240 |
+
" </tr>\n",
|
| 1241 |
+
" </tbody>\n",
|
| 1242 |
+
"</table>\n",
|
| 1243 |
+
"</div>"
|
| 1244 |
+
],
|
| 1245 |
+
"text/plain": [
|
| 1246 |
+
" Name TDP\n",
|
| 1247 |
+
"0 AMD EPYC 9965 500.0\n",
|
| 1248 |
+
"1 AMD EPYC 9845 390.0\n",
|
| 1249 |
+
"2 AMD EPYC 9825 390.0"
|
| 1250 |
+
]
|
| 1251 |
+
},
|
| 1252 |
+
"execution_count": 65,
|
| 1253 |
+
"metadata": {},
|
| 1254 |
+
"output_type": "execute_result"
|
| 1255 |
+
}
|
| 1256 |
+
],
|
| 1257 |
+
"source": [
|
| 1258 |
+
"amd_csv_path = \"./AMD_Server_Processor_Specifications.csv\"\n",
|
| 1259 |
+
"amd_df = pd.read_csv(amd_csv_path)\n",
|
| 1260 |
+
"amd_df[\"TDP\"] = pd.to_numeric(\n",
|
| 1261 |
+
" amd_df[\"Default TDP\"].str.replace(\"W\", \"\"), errors=\"coerce\"\n",
|
| 1262 |
+
")\n",
|
| 1263 |
+
"amd_df[\"Name\"] = amd_df[\"Name\"].str.replace(\"™\", \"\")\n",
|
| 1264 |
+
"amd_server = amd_df[[\"Name\", \"TDP\"]]\n",
|
| 1265 |
+
"amd_server = amd_server.dropna(subset=[\"TDP\"])\n",
|
| 1266 |
+
"amd_server.head(3)"
|
| 1267 |
+
]
|
| 1268 |
+
},
|
| 1269 |
+
{
|
| 1270 |
+
"cell_type": "code",
|
| 1271 |
+
"execution_count": 66,
|
| 1272 |
+
"metadata": {},
|
| 1273 |
+
"outputs": [
|
| 1274 |
+
{
|
| 1275 |
+
"name": "stderr",
|
| 1276 |
+
"output_type": "stream",
|
| 1277 |
+
"text": [
|
| 1278 |
+
"/tmp/ipykernel_52381/4222190993.py:6: SettingWithCopyWarning: \n",
|
| 1279 |
+
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
|
| 1280 |
+
"Try using .loc[row_indexer,col_indexer] = value instead\n",
|
| 1281 |
+
"\n",
|
| 1282 |
+
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
|
| 1283 |
+
" new_cpus['TDP'] = new_cpus['TDP_AMD']\n"
|
| 1284 |
+
]
|
| 1285 |
+
},
|
| 1286 |
+
{
|
| 1287 |
+
"data": {
|
| 1288 |
+
"text/html": [
|
| 1289 |
+
"<div>\n",
|
| 1290 |
+
"<style scoped>\n",
|
| 1291 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1292 |
+
" vertical-align: middle;\n",
|
| 1293 |
+
" }\n",
|
| 1294 |
+
"\n",
|
| 1295 |
+
" .dataframe tbody tr th {\n",
|
| 1296 |
+
" vertical-align: top;\n",
|
| 1297 |
+
" }\n",
|
| 1298 |
+
"\n",
|
| 1299 |
+
" .dataframe thead th {\n",
|
| 1300 |
+
" text-align: right;\n",
|
| 1301 |
+
" }\n",
|
| 1302 |
+
"</style>\n",
|
| 1303 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1304 |
+
" <thead>\n",
|
| 1305 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1306 |
+
" <th></th>\n",
|
| 1307 |
+
" <th>Name</th>\n",
|
| 1308 |
+
" <th>TDP</th>\n",
|
| 1309 |
+
" <th>TDP_AMD</th>\n",
|
| 1310 |
+
" <th>_merge</th>\n",
|
| 1311 |
+
" </tr>\n",
|
| 1312 |
+
" </thead>\n",
|
| 1313 |
+
" <tbody>\n",
|
| 1314 |
+
" <tr>\n",
|
| 1315 |
+
" <th>505</th>\n",
|
| 1316 |
+
" <td>AMD EPYC 4124P</td>\n",
|
| 1317 |
+
" <td>65</td>\n",
|
| 1318 |
+
" <td>65</td>\n",
|
| 1319 |
+
" <td>right_only</td>\n",
|
| 1320 |
+
" </tr>\n",
|
| 1321 |
+
" <tr>\n",
|
| 1322 |
+
" <th>506</th>\n",
|
| 1323 |
+
" <td>AMD EPYC 4244P</td>\n",
|
| 1324 |
+
" <td>65</td>\n",
|
| 1325 |
+
" <td>65</td>\n",
|
| 1326 |
+
" <td>right_only</td>\n",
|
| 1327 |
+
" </tr>\n",
|
| 1328 |
+
" <tr>\n",
|
| 1329 |
+
" <th>507</th>\n",
|
| 1330 |
+
" <td>AMD EPYC 4344P</td>\n",
|
| 1331 |
+
" <td>65</td>\n",
|
| 1332 |
+
" <td>65</td>\n",
|
| 1333 |
+
" <td>right_only</td>\n",
|
| 1334 |
+
" </tr>\n",
|
| 1335 |
+
" <tr>\n",
|
| 1336 |
+
" <th>508</th>\n",
|
| 1337 |
+
" <td>AMD EPYC 4364P</td>\n",
|
| 1338 |
+
" <td>105</td>\n",
|
| 1339 |
+
" <td>105</td>\n",
|
| 1340 |
+
" <td>right_only</td>\n",
|
| 1341 |
+
" </tr>\n",
|
| 1342 |
+
" <tr>\n",
|
| 1343 |
+
" <th>509</th>\n",
|
| 1344 |
+
" <td>AMD EPYC 4464P</td>\n",
|
| 1345 |
+
" <td>65</td>\n",
|
| 1346 |
+
" <td>65</td>\n",
|
| 1347 |
+
" <td>right_only</td>\n",
|
| 1348 |
+
" </tr>\n",
|
| 1349 |
+
" <tr>\n",
|
| 1350 |
+
" <th>...</th>\n",
|
| 1351 |
+
" <td>...</td>\n",
|
| 1352 |
+
" <td>...</td>\n",
|
| 1353 |
+
" <td>...</td>\n",
|
| 1354 |
+
" <td>...</td>\n",
|
| 1355 |
+
" </tr>\n",
|
| 1356 |
+
" <tr>\n",
|
| 1357 |
+
" <th>752</th>\n",
|
| 1358 |
+
" <td>AMD Opteron 6328</td>\n",
|
| 1359 |
+
" <td>115</td>\n",
|
| 1360 |
+
" <td>115</td>\n",
|
| 1361 |
+
" <td>right_only</td>\n",
|
| 1362 |
+
" </tr>\n",
|
| 1363 |
+
" <tr>\n",
|
| 1364 |
+
" <th>753</th>\n",
|
| 1365 |
+
" <td>AMD Opteron 6338P</td>\n",
|
| 1366 |
+
" <td>99</td>\n",
|
| 1367 |
+
" <td>99</td>\n",
|
| 1368 |
+
" <td>right_only</td>\n",
|
| 1369 |
+
" </tr>\n",
|
| 1370 |
+
" <tr>\n",
|
| 1371 |
+
" <th>754</th>\n",
|
| 1372 |
+
" <td>AMD Opteron 6344</td>\n",
|
| 1373 |
+
" <td>115</td>\n",
|
| 1374 |
+
" <td>115</td>\n",
|
| 1375 |
+
" <td>right_only</td>\n",
|
| 1376 |
+
" </tr>\n",
|
| 1377 |
+
" <tr>\n",
|
| 1378 |
+
" <th>757</th>\n",
|
| 1379 |
+
" <td>AMD Opteron 6370P</td>\n",
|
| 1380 |
+
" <td>99</td>\n",
|
| 1381 |
+
" <td>99</td>\n",
|
| 1382 |
+
" <td>right_only</td>\n",
|
| 1383 |
+
" </tr>\n",
|
| 1384 |
+
" <tr>\n",
|
| 1385 |
+
" <th>807</th>\n",
|
| 1386 |
+
" <td>AMD Opteron X2170 APU</td>\n",
|
| 1387 |
+
" <td>25</td>\n",
|
| 1388 |
+
" <td>25</td>\n",
|
| 1389 |
+
" <td>right_only</td>\n",
|
| 1390 |
+
" </tr>\n",
|
| 1391 |
+
" </tbody>\n",
|
| 1392 |
+
"</table>\n",
|
| 1393 |
+
"<p>113 rows × 4 columns</p>\n",
|
| 1394 |
+
"</div>"
|
| 1395 |
+
],
|
| 1396 |
+
"text/plain": [
|
| 1397 |
+
" Name TDP TDP_AMD _merge\n",
|
| 1398 |
+
"505 AMD EPYC 4124P 65 65 right_only\n",
|
| 1399 |
+
"506 AMD EPYC 4244P 65 65 right_only\n",
|
| 1400 |
+
"507 AMD EPYC 4344P 65 65 right_only\n",
|
| 1401 |
+
"508 AMD EPYC 4364P 105 105 right_only\n",
|
| 1402 |
+
"509 AMD EPYC 4464P 65 65 right_only\n",
|
| 1403 |
+
".. ... ... ... ...\n",
|
| 1404 |
+
"752 AMD Opteron 6328 115 115 right_only\n",
|
| 1405 |
+
"753 AMD Opteron 6338P 99 99 right_only\n",
|
| 1406 |
+
"754 AMD Opteron 6344 115 115 right_only\n",
|
| 1407 |
+
"757 AMD Opteron 6370P 99 99 right_only\n",
|
| 1408 |
+
"807 AMD Opteron X2170 APU 25 25 right_only\n",
|
| 1409 |
+
"\n",
|
| 1410 |
+
"[113 rows x 4 columns]"
|
| 1411 |
+
]
|
| 1412 |
+
},
|
| 1413 |
+
"execution_count": 66,
|
| 1414 |
+
"metadata": {},
|
| 1415 |
+
"output_type": "execute_result"
|
| 1416 |
+
}
|
| 1417 |
+
],
|
| 1418 |
+
"source": [
|
| 1419 |
+
"# Merge df with amd_server, avoiding duplicates\n",
|
| 1420 |
+
"amd_server[\"TDP\"] = amd_server[\"TDP\"].astype(int).astype(str)\n",
|
| 1421 |
+
"merged_df = df.merge(\n",
|
| 1422 |
+
" amd_server, on=\"Name\", how=\"outer\", suffixes=(\"\", \"_AMD\"), indicator=True\n",
|
| 1423 |
+
")\n",
|
| 1424 |
+
"# Filter for new entries that are only in amd_server\n",
|
| 1425 |
+
"new_cpus = merged_df[merged_df[\"_merge\"] == \"right_only\"]\n",
|
| 1426 |
+
"new_cpus[\"TDP\"] = new_cpus[\"TDP_AMD\"]\n",
|
| 1427 |
+
"new_cpus"
|
| 1428 |
+
]
|
| 1429 |
+
},
|
| 1430 |
+
{
|
| 1431 |
+
"cell_type": "code",
|
| 1432 |
+
"execution_count": 67,
|
| 1433 |
+
"metadata": {},
|
| 1434 |
+
"outputs": [
|
| 1435 |
+
{
|
| 1436 |
+
"data": {
|
| 1437 |
+
"text/html": [
|
| 1438 |
+
"<div>\n",
|
| 1439 |
+
"<style scoped>\n",
|
| 1440 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1441 |
+
" vertical-align: middle;\n",
|
| 1442 |
+
" }\n",
|
| 1443 |
+
"\n",
|
| 1444 |
+
" .dataframe tbody tr th {\n",
|
| 1445 |
+
" vertical-align: top;\n",
|
| 1446 |
+
" }\n",
|
| 1447 |
+
"\n",
|
| 1448 |
+
" .dataframe thead th {\n",
|
| 1449 |
+
" text-align: right;\n",
|
| 1450 |
+
" }\n",
|
| 1451 |
+
"</style>\n",
|
| 1452 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1453 |
+
" <thead>\n",
|
| 1454 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1455 |
+
" <th></th>\n",
|
| 1456 |
+
" <th>Name</th>\n",
|
| 1457 |
+
" <th>TDP</th>\n",
|
| 1458 |
+
" </tr>\n",
|
| 1459 |
+
" </thead>\n",
|
| 1460 |
+
" <tbody>\n",
|
| 1461 |
+
" <tr>\n",
|
| 1462 |
+
" <th>505</th>\n",
|
| 1463 |
+
" <td>AMD EPYC 4124P</td>\n",
|
| 1464 |
+
" <td>65</td>\n",
|
| 1465 |
+
" </tr>\n",
|
| 1466 |
+
" <tr>\n",
|
| 1467 |
+
" <th>506</th>\n",
|
| 1468 |
+
" <td>AMD EPYC 4244P</td>\n",
|
| 1469 |
+
" <td>65</td>\n",
|
| 1470 |
+
" </tr>\n",
|
| 1471 |
+
" <tr>\n",
|
| 1472 |
+
" <th>507</th>\n",
|
| 1473 |
+
" <td>AMD EPYC 4344P</td>\n",
|
| 1474 |
+
" <td>65</td>\n",
|
| 1475 |
+
" </tr>\n",
|
| 1476 |
+
" <tr>\n",
|
| 1477 |
+
" <th>508</th>\n",
|
| 1478 |
+
" <td>AMD EPYC 4364P</td>\n",
|
| 1479 |
+
" <td>105</td>\n",
|
| 1480 |
+
" </tr>\n",
|
| 1481 |
+
" <tr>\n",
|
| 1482 |
+
" <th>509</th>\n",
|
| 1483 |
+
" <td>AMD EPYC 4464P</td>\n",
|
| 1484 |
+
" <td>65</td>\n",
|
| 1485 |
+
" </tr>\n",
|
| 1486 |
+
" <tr>\n",
|
| 1487 |
+
" <th>...</th>\n",
|
| 1488 |
+
" <td>...</td>\n",
|
| 1489 |
+
" <td>...</td>\n",
|
| 1490 |
+
" </tr>\n",
|
| 1491 |
+
" <tr>\n",
|
| 1492 |
+
" <th>752</th>\n",
|
| 1493 |
+
" <td>AMD Opteron 6328</td>\n",
|
| 1494 |
+
" <td>115</td>\n",
|
| 1495 |
+
" </tr>\n",
|
| 1496 |
+
" <tr>\n",
|
| 1497 |
+
" <th>753</th>\n",
|
| 1498 |
+
" <td>AMD Opteron 6338P</td>\n",
|
| 1499 |
+
" <td>99</td>\n",
|
| 1500 |
+
" </tr>\n",
|
| 1501 |
+
" <tr>\n",
|
| 1502 |
+
" <th>754</th>\n",
|
| 1503 |
+
" <td>AMD Opteron 6344</td>\n",
|
| 1504 |
+
" <td>115</td>\n",
|
| 1505 |
+
" </tr>\n",
|
| 1506 |
+
" <tr>\n",
|
| 1507 |
+
" <th>757</th>\n",
|
| 1508 |
+
" <td>AMD Opteron 6370P</td>\n",
|
| 1509 |
+
" <td>99</td>\n",
|
| 1510 |
+
" </tr>\n",
|
| 1511 |
+
" <tr>\n",
|
| 1512 |
+
" <th>807</th>\n",
|
| 1513 |
+
" <td>AMD Opteron X2170 APU</td>\n",
|
| 1514 |
+
" <td>25</td>\n",
|
| 1515 |
+
" </tr>\n",
|
| 1516 |
+
" </tbody>\n",
|
| 1517 |
+
"</table>\n",
|
| 1518 |
+
"<p>113 rows × 2 columns</p>\n",
|
| 1519 |
+
"</div>"
|
| 1520 |
+
],
|
| 1521 |
+
"text/plain": [
|
| 1522 |
+
" Name TDP\n",
|
| 1523 |
+
"505 AMD EPYC 4124P 65\n",
|
| 1524 |
+
"506 AMD EPYC 4244P 65\n",
|
| 1525 |
+
"507 AMD EPYC 4344P 65\n",
|
| 1526 |
+
"508 AMD EPYC 4364P 105\n",
|
| 1527 |
+
"509 AMD EPYC 4464P 65\n",
|
| 1528 |
+
".. ... ...\n",
|
| 1529 |
+
"752 AMD Opteron 6328 115\n",
|
| 1530 |
+
"753 AMD Opteron 6338P 99\n",
|
| 1531 |
+
"754 AMD Opteron 6344 115\n",
|
| 1532 |
+
"757 AMD Opteron 6370P 99\n",
|
| 1533 |
+
"807 AMD Opteron X2170 APU 25\n",
|
| 1534 |
+
"\n",
|
| 1535 |
+
"[113 rows x 2 columns]"
|
| 1536 |
+
]
|
| 1537 |
+
},
|
| 1538 |
+
"execution_count": 67,
|
| 1539 |
+
"metadata": {},
|
| 1540 |
+
"output_type": "execute_result"
|
| 1541 |
+
}
|
| 1542 |
+
],
|
| 1543 |
+
"source": [
|
| 1544 |
+
"# merged_df.query('Name.str.contains(\"EPYC\")')\n",
|
| 1545 |
+
"new_cpus_to_add = new_cpus.drop(columns=[\"_merge\"]).loc[:, df.columns]\n",
|
| 1546 |
+
"new_cpus_to_add"
|
| 1547 |
+
]
|
| 1548 |
+
},
|
| 1549 |
+
{
|
| 1550 |
+
"cell_type": "code",
|
| 1551 |
+
"execution_count": 68,
|
| 1552 |
+
"metadata": {},
|
| 1553 |
+
"outputs": [
|
| 1554 |
+
{
|
| 1555 |
+
"data": {
|
| 1556 |
+
"text/html": [
|
| 1557 |
+
"<div>\n",
|
| 1558 |
+
"<style scoped>\n",
|
| 1559 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 1560 |
+
" vertical-align: middle;\n",
|
| 1561 |
+
" }\n",
|
| 1562 |
+
"\n",
|
| 1563 |
+
" .dataframe tbody tr th {\n",
|
| 1564 |
+
" vertical-align: top;\n",
|
| 1565 |
+
" }\n",
|
| 1566 |
+
"\n",
|
| 1567 |
+
" .dataframe thead th {\n",
|
| 1568 |
+
" text-align: right;\n",
|
| 1569 |
+
" }\n",
|
| 1570 |
+
"</style>\n",
|
| 1571 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 1572 |
+
" <thead>\n",
|
| 1573 |
+
" <tr style=\"text-align: right;\">\n",
|
| 1574 |
+
" <th></th>\n",
|
| 1575 |
+
" <th>Name</th>\n",
|
| 1576 |
+
" <th>TDP</th>\n",
|
| 1577 |
+
" </tr>\n",
|
| 1578 |
+
" </thead>\n",
|
| 1579 |
+
" <tbody>\n",
|
| 1580 |
+
" <tr>\n",
|
| 1581 |
+
" <th>3928</th>\n",
|
| 1582 |
+
" <td>AMD EPYC 4124P</td>\n",
|
| 1583 |
+
" <td>65</td>\n",
|
| 1584 |
+
" </tr>\n",
|
| 1585 |
+
" </tbody>\n",
|
| 1586 |
+
"</table>\n",
|
| 1587 |
+
"</div>"
|
| 1588 |
+
],
|
| 1589 |
+
"text/plain": [
|
| 1590 |
+
" Name TDP\n",
|
| 1591 |
+
"3928 AMD EPYC 4124P 65"
|
| 1592 |
+
]
|
| 1593 |
+
},
|
| 1594 |
+
"execution_count": 68,
|
| 1595 |
+
"metadata": {},
|
| 1596 |
+
"output_type": "execute_result"
|
| 1597 |
+
}
|
| 1598 |
+
],
|
| 1599 |
+
"source": [
|
| 1600 |
+
"# Option 2: Append the new CPUs to the original df\n",
|
| 1601 |
+
"df = pd.concat([df, new_cpus_to_add], ignore_index=True)\n",
|
| 1602 |
+
"df.sort_values(\"Name\", ascending=True, inplace=True)\n",
|
| 1603 |
+
"df.query('Name.str.contains(\"AMD EPYC 4124P\")')"
|
| 1604 |
+
]
|
| 1605 |
+
},
|
| 1606 |
+
{
|
| 1607 |
+
"cell_type": "code",
|
| 1608 |
+
"execution_count": 69,
|
| 1609 |
+
"metadata": {},
|
| 1610 |
+
"outputs": [],
|
| 1611 |
+
"source": [
|
| 1612 |
+
"df.to_csv(\"cpu_power.csv\", index=False)"
|
| 1613 |
+
]
|
| 1614 |
+
},
|
| 1615 |
+
{
|
| 1616 |
+
"cell_type": "markdown",
|
| 1617 |
+
"metadata": {},
|
| 1618 |
+
"source": [
|
| 1619 |
+
"# Remove with..."
|
| 1620 |
+
]
|
| 1621 |
+
},
|
| 1622 |
+
{
|
| 1623 |
+
"cell_type": "code",
|
| 1624 |
+
"execution_count": 1,
|
| 1625 |
+
"metadata": {},
|
| 1626 |
+
"outputs": [],
|
| 1627 |
+
"source": [
|
| 1628 |
+
"import pandas as pd\n",
|
| 1629 |
+
"# Load the existing dataset\n",
|
| 1630 |
+
"df = pd.read_csv(\"../cpu_power.csv\")\n",
|
| 1631 |
+
"# Replace with re.sub(r\" with.*\", \"\", name)\n",
|
| 1632 |
+
"def clean_cpu_name(name):\n",
|
| 1633 |
+
" import re\n",
|
| 1634 |
+
" # Remove \"with\" and everything after it\n",
|
| 1635 |
+
" name = re.sub(r\" with.*\", \"\", name)\n",
|
| 1636 |
+
" # Remove \"™\" symbol\n",
|
| 1637 |
+
" name = name.replace(\"™\", \"\")\n",
|
| 1638 |
+
" return name.strip()\n",
|
| 1639 |
+
"df[\"Name\"] = df[\"Name\"].apply(clean_cpu_name)\n",
|
| 1640 |
+
"# Save the cleaned dataset\n",
|
| 1641 |
+
"df.to_csv(\"../cpu_power.csv\", index=False)"
|
| 1642 |
+
]
|
| 1643 |
+
},
|
| 1644 |
+
{
|
| 1645 |
+
"cell_type": "markdown",
|
| 1646 |
+
"metadata": {},
|
| 1647 |
+
"source": []
|
| 1648 |
+
}
|
| 1649 |
+
],
|
| 1650 |
+
"metadata": {
|
| 1651 |
+
"kernelspec": {
|
| 1652 |
+
"display_name": "3.10.5",
|
| 1653 |
+
"language": "python",
|
| 1654 |
+
"name": "python3"
|
| 1655 |
+
},
|
| 1656 |
+
"language_info": {
|
| 1657 |
+
"codemirror_mode": {
|
| 1658 |
+
"name": "ipython",
|
| 1659 |
+
"version": 3
|
| 1660 |
+
},
|
| 1661 |
+
"file_extension": ".py",
|
| 1662 |
+
"mimetype": "text/x-python",
|
| 1663 |
+
"name": "python",
|
| 1664 |
+
"nbconvert_exporter": "python",
|
| 1665 |
+
"pygments_lexer": "ipython3",
|
| 1666 |
+
"version": "3.10.5"
|
| 1667 |
+
}
|
| 1668 |
+
},
|
| 1669 |
+
"nbformat": 4,
|
| 1670 |
+
"nbformat_minor": 4
|
| 1671 |
+
}
|
codecarbon/data/hardware/cpu_dataset_builder/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# How to update the CPU database
|
| 2 |
+
|
| 3 |
+
To update the CPU database, you have to run:
|
| 4 |
+
|
| 5 |
+
```bash
|
| 6 |
+
cd codecarbon/data/hardware/cpu_dataset_builder
|
| 7 |
+
hatch run pip install playwright beautifulsoup4
|
| 8 |
+
hatch run python intel_cpu_scrapper.py
|
| 9 |
+
hatch run python amd_cpu_scrapper.py
|
| 10 |
+
hatch run python merge_scrapped_cpu_power.py
|
| 11 |
+
```
|
| 12 |
+
|
| 13 |
+
Then commit the changes to the CSV files.
|
| 14 |
+
|
| 15 |
+
CodeCarbon only use the `cpu_power.csv` file, but we keep the other files for reference and to allow someone else to use them if needed.
|
codecarbon/data/hardware/cpu_dataset_builder/amd_cpu_desktop_dataset.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
codecarbon/data/hardware/cpu_dataset_builder/amd_cpu_scrapper.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This script uses Playwright to scrape AMD CPU data from their website and save it as a CSV file.
|
| 3 |
+
|
| 4 |
+
hatch run pip install playwright
|
| 5 |
+
hatch run python amd_cpu_scrapper.py
|
| 6 |
+
"""
|
| 7 |
+
|
| 8 |
+
import asyncio
|
| 9 |
+
|
| 10 |
+
from playwright.async_api import Page, async_playwright
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
async def handle_cookie_banner(page: Page):
|
| 14 |
+
"""Attempts to find and click a 'Reject All' button for cookie consent."""
|
| 15 |
+
try:
|
| 16 |
+
reject_button_selectors = [
|
| 17 |
+
"button:has-text('Reject All')",
|
| 18 |
+
"button:has-text('Decline All')",
|
| 19 |
+
"button[id*='reject']",
|
| 20 |
+
"button[class*='reject']",
|
| 21 |
+
"//button[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'reject all')]",
|
| 22 |
+
"//button[contains(translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'decline all')]",
|
| 23 |
+
]
|
| 24 |
+
|
| 25 |
+
reject_button = None
|
| 26 |
+
for selector in reject_button_selectors:
|
| 27 |
+
try:
|
| 28 |
+
button = page.locator(selector).first
|
| 29 |
+
if await button.is_visible(
|
| 30 |
+
timeout=2000
|
| 31 |
+
): # Short timeout for visibility check
|
| 32 |
+
reject_button = button
|
| 33 |
+
print(f"Found cookie consent button with selector: {selector}")
|
| 34 |
+
break
|
| 35 |
+
except Exception:
|
| 36 |
+
pass # Selector not found or button not visible, try next
|
| 37 |
+
|
| 38 |
+
if reject_button:
|
| 39 |
+
await reject_button.click()
|
| 40 |
+
print("Clicked 'Reject All' on cookie banner.")
|
| 41 |
+
await page.wait_for_timeout(1000) # Wait a bit for the banner to disappear
|
| 42 |
+
else:
|
| 43 |
+
print(
|
| 44 |
+
"Cookie banner 'Reject All' button not found or not visible after trying common selectors."
|
| 45 |
+
)
|
| 46 |
+
|
| 47 |
+
except Exception as cookie_error:
|
| 48 |
+
print(f"Could not handle cookie banner: {cookie_error}")
|
| 49 |
+
|
| 50 |
+
|
| 51 |
+
async def download_csv_from_url(page: Page, url: str, output_filename: str):
|
| 52 |
+
"""Navigates to a URL, handles cookie banner, and downloads a CSV file."""
|
| 53 |
+
print(f"Attempting to download from: {url}")
|
| 54 |
+
retries = 2
|
| 55 |
+
for attempt in range(retries):
|
| 56 |
+
try:
|
| 57 |
+
await page.goto(url, timeout=30000) # Increased timeout for page load
|
| 58 |
+
await handle_cookie_banner(page)
|
| 59 |
+
break # If goto is successful, break the loop
|
| 60 |
+
except Exception as e:
|
| 61 |
+
print(f"Attempt {attempt + 1} to navigate to {url} failed: {e}")
|
| 62 |
+
if attempt < retries - 1:
|
| 63 |
+
await asyncio.sleep(5) # Wait for 5 seconds before retrying
|
| 64 |
+
else:
|
| 65 |
+
print(f"All retries failed for {url}.")
|
| 66 |
+
return # Exit if all retries fail
|
| 67 |
+
|
| 68 |
+
try:
|
| 69 |
+
# Wait for the download to start after clicking the button
|
| 70 |
+
async with page.expect_download(
|
| 71 |
+
timeout=30000
|
| 72 |
+
) as download_info: # Increased timeout for download
|
| 73 |
+
# Click the button with the class "buttons-csv"
|
| 74 |
+
await page.locator(".buttons-csv").click()
|
| 75 |
+
print(f"Clicked download button for {url}")
|
| 76 |
+
|
| 77 |
+
download = await download_info.value
|
| 78 |
+
|
| 79 |
+
# Save the downloaded file
|
| 80 |
+
file_path = f"{output_filename}"
|
| 81 |
+
await download.save_as(file_path)
|
| 82 |
+
print(f"File downloaded from {url} and saved as {file_path}")
|
| 83 |
+
|
| 84 |
+
except Exception as e:
|
| 85 |
+
print(f"An error occurred while downloading from {url}: {e}")
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
async def main():
|
| 89 |
+
async with async_playwright() as p:
|
| 90 |
+
browser = await p.chromium.launch(
|
| 91 |
+
headless=False, # Set to True for production
|
| 92 |
+
args=[
|
| 93 |
+
"--no-sandbox",
|
| 94 |
+
"--disable-setuid-sandbox",
|
| 95 |
+
"--disable-dev-shm-usage",
|
| 96 |
+
"--disable-gpu",
|
| 97 |
+
],
|
| 98 |
+
)
|
| 99 |
+
page = await browser.new_page()
|
| 100 |
+
|
| 101 |
+
urls_to_download = [
|
| 102 |
+
{
|
| 103 |
+
"url": "https://www.amd.com/en/products/specifications/server-processor.html",
|
| 104 |
+
"filename": "amd_cpu_server_dataset.csv",
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
"url": "https://www.amd.com/en/products/specifications/processors.html",
|
| 108 |
+
"filename": "amd_cpu_desktop_dataset.csv",
|
| 109 |
+
},
|
| 110 |
+
]
|
| 111 |
+
|
| 112 |
+
for item in urls_to_download:
|
| 113 |
+
await download_csv_from_url(page, item["url"], item["filename"])
|
| 114 |
+
await asyncio.sleep(2) # Small delay between downloads
|
| 115 |
+
|
| 116 |
+
await browser.close()
|
| 117 |
+
|
| 118 |
+
|
| 119 |
+
if __name__ == "__main__":
|
| 120 |
+
asyncio.run(main())
|
codecarbon/data/hardware/cpu_dataset_builder/amd_cpu_server_dataset.csv
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"Name","Series","# of CPU Cores","# of Threads","Max. Boost Clock","All Core Boost Speed","Base Clock","L3 Cache","1kU Pricing","Default TDP","AMD Configurable TDP (cTDP)","CPU Socket","Socket Count","Launch Date","PCI Express® Version","System Memory Type","Memory Channels","System Memory Specification","Per Socket Mem BW","Product ID Boxed","Product ID Tray","AMD Infinity Guard","Supported Technologies","Workload Affinity"
|
| 2 |
+
"AMD EPYC™ 9965","EPYC 9005 Series","192","384","Up to 3.7 GHz","3.35 GHz","2.25 GHz","384 MB","14813 USD","500W","450-500W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000000976","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , Content mgmt , HPC , Media streaming , Networking|NFV , Security , VDI , VM Density , Web Serving , CDC"
|
| 3 |
+
"AMD EPYC™ 9845","EPYC 9005 Series","160","320","Up to 3.7 GHz","3.25 GHz","2.1 GHz","320 MB","13564 USD","390W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001458","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CDC , Content mgmt , HPC , Media streaming , Networking|NFV , Security , VDI , VM Density , Web Serving"
|
| 4 |
+
"AMD EPYC™ 9825","EPYC 9005 Series","144","288","Up to 3.7 GHz","3.3 GHz","2.2 GHz","384 MB","13006 USD","390W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000000837","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CDC , Content mgmt , HPC , Media streaming , Networking|NFV , Security , VDI , VM Density , Web Serving"
|
| 5 |
+
"AMD EPYC™ 9755","EPYC 9005 Series","128","256","Up to 4.1 GHz","4.1 GHz","2.7 GHz","512 MB","12984 USD","500W","450-500W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001443","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , Content mgmt , HPC , Media streaming , Networking|NFV , Security , VDI , VM Density , Web Serving , CDC"
|
| 6 |
+
"AMD EPYC™ 9745","EPYC 9005 Series","128","256","Up to 3.7 GHz","3.45 GHz","2.4 GHz","256 MB","12141 USD","400W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001460","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , Content mgmt , HPC , Media streaming , Networking|NFV , Security , VDI , VM Density , Web Serving , CDC"
|
| 7 |
+
"AMD EPYC™ 9655P","EPYC 9005 Series","96","192","Up to 4.5 GHz","4.1 GHz","2.6 GHz","384 MB","10811 USD","400W","320-400W","SP5","1P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001522","","AMD Infinity Guard , AMD Infinity Architecture","CAE|CFD|FEA , High capacity data mgmt (NR|RDBMS) , HPC"
|
| 8 |
+
"AMD EPYC™ 9655","EPYC 9005 Series","96","192","Up to 4.5 GHz","4.1 GHz","2.6 GHz","384 MB","11852 USD","400W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000000674","","AMD Infinity Guard , AMD Infinity Architecture","CAE|CFD|FEA , High capacity data mgmt (NR|RDBMS) , HPC"
|
| 9 |
+
"AMD EPYC™ 9645","EPYC 9005 Series","96","192","Up to 3.7 GHz","3.3 GHz","2.3 GHz","256 MB","11048 USD","320W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001461","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , Consumer-Oriented Digital Services , Content mgmt , ERM|SCM|CRM apps"
|
| 10 |
+
"AMD EPYC™ 9575F","EPYC 9005 Series","64","128","Up to 5 GHz","4.5 GHz","3.3 GHz","256 MB","11791 USD","400W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001554","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 11 |
+
"AMD EPYC™ 9565","EPYC 9005 Series","72","144","Up to 4.3 GHz","4.2 GHz","3.15 GHz","384 MB","10486 USD","400W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001447","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , HPC , VM Density"
|
| 12 |
+
"AMD EPYC™ 9555P","EPYC 9005 Series","64","128","Up to 4.4 GHz","4.2 GHz","3.2 GHz","256 MB","7983 USD","360W","320-400W","SP5","1P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001523","","AMD Infinity Guard , 4th Gen AMD Infinity Architecture","App dev|test , ERM|SCM|CRM apps , Value data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 13 |
+
"AMD EPYC™ 9555","EPYC 9005 Series","64","128","Up to 4.4 GHz","4.2 GHz","3.2 GHz","256 MB","9826 USD","360W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001142","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , HPC , VM Density"
|
| 14 |
+
"AMD EPYC™ 9535","EPYC 9005 Series","64","128","Up to 4.3 GHz","3.5 GHz","2.4 GHz","256 MB","8992 USD","300W","240-300W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001147","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 15 |
+
"AMD EPYC™ 9475F","EPYC 9005 Series","48","96","Up to 4.8 GHz","4.4 GHz","3.65 GHz","256 MB","7592 USD","400W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001143","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 16 |
+
"AMD EPYC™ 9455P","EPYC 9005 Series","48","96","Up to 4.4 GHz","4.1 GHz","3.15 GHz","256 MB","4819 USD","300W","240-300W","SP5","1P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001563","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 17 |
+
"AMD EPYC™ 9455","EPYC 9005 Series","48","96","Up to 4.4 GHz","4.1 GHz","3.15 GHz","256 MB","5412 USD","300W","240-300W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001542","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 18 |
+
"AMD EPYC™ 9375F","EPYC 9005 Series","32","64","Up to 4.8 GHz","4.4 GHz","3.8 GHz","256 MB","5306 USD","320W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001197","","AMD Infinity Guard , AMD Infinity Architecture","EDA , HCI , High performance VM Density , Per core CAE|CFD|FEA , VDI"
|
| 19 |
+
"AMD EPYC™ 9365","EPYC 9005 Series","36","72","Up to 4.3 GHz","4.15 GHz","3.4 GHz","192 MB","4341 USD","300W","240-300W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001448","","AMD Infinity Guard , AMD Infinity Architecture","Content mgmt , ERM|SCM|CRM apps , General Purpose , CDN"
|
| 20 |
+
"AMD EPYC™ 9355P","EPYC 9005 Series","32","64","Up to 4.4 GHz","4.2 GHz","3.55 GHz","256 MB","2998 USD","280W","240-300W","SP5","1P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001521","","AMD Infinity Guard , AMD Infinity Architecture","ERM|SCM|CRM apps , Value data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 21 |
+
"AMD EPYC™ 9355","EPYC 9005 Series","32","64","Up to 4.4 GHz","4.2 GHz","3.55 GHz","256 MB","3694 USD","280W","240-300W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001148","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , Media streaming , Medium capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 22 |
+
"AMD EPYC™ 9335","EPYC 9005 Series","32","64","Up to 4.4 GHz","4 GHz","3 GHz","128 MB","3178 USD","210W","200-240W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001149","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , Media streaming , Medium capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 23 |
+
"AMD EPYC™ 9275F","EPYC 9005 Series","24","48","Up to 4.8 GHz","4.5 GHz","4.1 GHz","256 MB","3439 USD","320W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001144","","AMD Infinity Architecture , AMD Infinity Guard","General Purpose , GPU|FPGA Accelerated , Per core CAE|CFD|FEA , SW-defined storage"
|
| 24 |
+
"AMD EPYC™ 9255","EPYC 9005 Series","24","48","Up to 4.3 GHz","4 GHz","3.2 GHz","128 MB","2495 USD","200W","200-240W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000000694","","AMD Infinity Architecture , AMD Infinity Guard","ERM|SCM|CRM apps , General Purpose , Networking|NFV , Web Serving"
|
| 25 |
+
"AMD EPYC™ 9175F","EPYC 9005 Series","16","32","Up to 5 GHz","4.55 GHz","4.2 GHz","512 MB","4256 USD","320W","320-400W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001145","","AMD Infinity Architecture , AMD Infinity Guard","CAE|CFD|FEA , EDA , HPC"
|
| 26 |
+
"AMD EPYC™ 9135","EPYC 9005 Series","16","32","Up to 4.3 GHz","4.25 GHz","3.65 GHz","64 MB","1214 USD","200W","200-240W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001150","","AMD Infinity Architecture , AMD Infinity Guard","EDA , High-speed data mgmt (NR|RDBMS) , Per core CAE|CFD|FEA"
|
| 27 |
+
"AMD EPYC™ 9115","EPYC 9005 Series","16","32","Up to 4.1 GHz","3.3 GHz","2.6 GHz","64 MB","726 USD","125W","120-155W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001552","","AMD Infinity Architecture , AMD Infinity Guard","Media streaming , Per core CAE|CFD|FEA , Value"
|
| 28 |
+
"AMD EPYC™ 9015","EPYC 9005 Series","8","16","Up to 4.1 GHz","3.95 GHz","3.6 GHz","64 MB","527 USD","125W","120-155W","SP5","1P / 2P","10/10/2024","PCIe® 5.0 x128","DDR5","12","Up to 6400 MT/s","614 GB/s","","100-000001553","","AMD Infinity Architecture , AMD Infinity Guard","Collaborative , ERM|SCM|CRM apps , General Purpose"
|
| 29 |
+
"AMD EPYC™ 9754S","EPYC 9004 Series","128","128","Up to 3.1 GHz","3.1 GHz","2.25 GHz","256 MB","10200 USD","360W","320-400W","SP5","1P / 2P","06/13/2023","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000001371","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , Collaborative , Consumer-Oriented Digital Services , Content mgmt , General Purpose , HPC , Media streaming , VDI , VM Density , Web Serving"
|
| 30 |
+
"AMD EPYC™ 9754","EPYC 9004 Series","128","256","Up to 3.1 GHz","3.1 GHz","2.25 GHz","256 MB","11900 USD","360W","320-400W","SP5","1P / 2P","06/13/2023","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000001234","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , Collaborative , Consumer-Oriented Digital Services , Content mgmt , General Purpose , HPC , Media streaming , VDI , VM Density , Web Serving"
|
| 31 |
+
"AMD EPYC™ 9734","EPYC 9004 Series","112","224","Up to 3 GHz","3 GHz","2.2 GHz","256 MB","9600 USD","340W","320-400W","SP5","1P / 2P","06/13/2023","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000001235","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , Collaborative , Consumer-Oriented Digital Services , Content mgmt , General Purpose , HPC , Media streaming , VDI , VM Density , Web Serving"
|
| 32 |
+
"AMD EPYC™ 9684X","EPYC 9004 Series","96","192","Up to 3.7 GHz","3.42 GHz","2.55 GHz","1152 MB","14756 USD","400W","320-400W","SP5","1P / 2P","06/13/2023","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000001254","","AMD 3D V-Cache™ Technology , AMD Infinity Guard , AMD Infinity Architecture","CAE|CFD|FEA , High capacity data mgmt (NR|RDBMS) , HPC"
|
| 33 |
+
"AMD EPYC™ 9654P","EPYC 9004 Series","96","192","Up to 3.7 GHz","3.55 GHz","2.4 GHz","384 MB","10625 USD","360W","320-400W","SP5","1P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000803","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , Consumer-Oriented Digital Services , Content mgmt , ERM|SCM|CRM apps"
|
| 34 |
+
"AMD EPYC™ 9654","EPYC 9004 Series","96","192","Up to 3.7 GHz","3.55 GHz","2.4 GHz","384 MB","11805 USD","360W","320-400W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000789","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , Consumer-Oriented Digital Services , Content mgmt , ERM|SCM|CRM apps"
|
| 35 |
+
"AMD EPYC™ 9634","EPYC 9004 Series","84","168","Up to 3.7 GHz","3.1 GHz","2.25 GHz","384 MB","10304 USD","290W","240-300W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000797","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , Consumer-Oriented Digital Services , Content mgmt , ERM|SCM|CRM apps"
|
| 36 |
+
"AMD EPYC™ 9554P","EPYC 9004 Series","64","128","Up to 3.75 GHz","3.75 GHz","3.1 GHz","256 MB","7104 USD","360W","320-400W","SP5","1P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000804","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , ERM|SCM|CRM apps , Value data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 37 |
+
"AMD EPYC™ 9554","EPYC 9004 Series","64","128","Up to 3.75 GHz","3.75 GHz","3.1 GHz","256 MB","9087 USD","360W","320-400W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000790","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , HPC , VM Density"
|
| 38 |
+
"AMD EPYC™ 9534","EPYC 9004 Series","64","128","Up to 3.7 GHz","3.55 GHz","2.45 GHz","256 MB","8803 USD","280W","240-300W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000799","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 39 |
+
"AMD EPYC™ 9474F","EPYC 9004 Series","48","96","Up to 4.1 GHz","3.95 GHz","3.6 GHz","256 MB","6780 USD","360W","320-400W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000788","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 40 |
+
"AMD EPYC™ 9454P","EPYC 9004 Series","48","96","Up to 3.8 GHz","3.65 GHz","2.75 GHz","256 MB","4598 USD","290W","240-300W","SP5","1P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000873","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 41 |
+
"AMD EPYC™ 9454","EPYC 9004 Series","48","96","Up to 3.8 GHz","3.65 GHz","2.75 GHz","256 MB","5225 USD","290W","240-300W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000478","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 42 |
+
"AMD EPYC™ 9384X","EPYC 9004 Series","32","64","Up to 3.9 GHz","3.5 GHz","3.1 GHz","768 MB","5529 USD","320W","320-400W","SP5","1P / 2P","06/13/2023","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000001256","","AMD 3D V-Cache™ Technology , AMD Infinity Guard , AMD Infinity Architecture","CAE|CFD|FEA , EDA , HPC"
|
| 43 |
+
"AMD EPYC™ 9374F","EPYC 9004 Series","32","64","Up to 4.3 GHz","4.1 GHz","3.85 GHz","256 MB","4850 USD","320W","320-400W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000792","","AMD Infinity Guard , AMD Infinity Architecture","EDA , HCI , High performance VM Density , Per core CAE|CFD|FEA , VDI"
|
| 44 |
+
"AMD EPYC™ 9354P","EPYC 9004 Series","32","64","Up to 3.8 GHz","3.75 GHz","3.25 GHz","256 MB","2730 USD","280W","240-300W","SP5","1P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000805","","AMD Infinity Guard , AMD Infinity Architecture","ERM|SCM|CRM apps , Value data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 45 |
+
"AMD EPYC™ 9354","EPYC 9004 Series","32","64","Up to 3.8 GHz","3.75 GHz","3.25 GHz","256 MB","3420 USD","280W","240-300W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000798","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , Media streaming , Medium capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 46 |
+
"AMD EPYC™ 9334","EPYC 9004 Series","32","64","Up to 3.9 GHz","3.85 GHz","2.7 GHz","128 MB","2990 USD","210W","200-240W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000800","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , Media streaming , Medium capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 47 |
+
"AMD EPYC™ 9274F","EPYC 9004 Series","24","48","Up to 4.3 GHz","4.1 GHz","4.05 GHz","256 MB","3060 USD","320W","320-400W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000794","","AMD Infinity Guard , AMD Infinity Architecture","EDA , HCI , High performance VM Density , Per core CAE|CFD|FEA , VDI"
|
| 48 |
+
"AMD EPYC™ 9254","EPYC 9004 Series","24","48","Up to 4.15 GHz","3.9 GHz","2.9 GHz","128 MB","2299 USD","200W","200-240W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000480","","AMD Infinity Guard , AMD Infinity Architecture","General Purpose , GPU|FPGA Accelerated , Per core CAE|CFD|FEA , SW-defined storage"
|
| 49 |
+
"AMD EPYC™ 9224","EPYC 9004 Series","24","48","Up to 3.7 GHz","3.65 GHz","2.5 GHz","64 MB","1825 USD","200W","200-240W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000939","","AMD Infinity Guard , AMD Infinity Architecture","ERM|SCM|CRM apps , General Purpose , Networking|NFV , Web Serving"
|
| 50 |
+
"AMD EPYC™ 9184X","EPYC 9004 Series","16","32","Up to 4.2 GHz","3.85 GHz","3.55 GHz","768 MB","4928 USD","320W","320-400W","SP5","1P / 2P","06/13/2023","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000001255","","AMD 3D V-Cache™ Technology , AMD Infinity Guard , AMD Infinity Architecture","CAE|CFD|FEA , EDA , HPC"
|
| 51 |
+
"AMD EPYC™ 9174F","EPYC 9004 Series","16","32","Up to 4.4 GHz","4.15 GHz","4.1 GHz","256 MB","3850 USD","320W","320-400W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000796","","AMD Infinity Guard , AMD Infinity Architecture","EDA , High-speed data mgmt (NR|RDBMS) , Per core CAE|CFD|FEA"
|
| 52 |
+
"AMD EPYC™ 9124","EPYC 9004 Series","16","32","Up to 3.7 GHz","3.6 GHz","3 GHz","64 MB","1083 USD","200W","200-240W","SP5","1P / 2P","11/10/2022","PCIe® 5.0 x128","DDR5","12","Up to 4800 MT/s","460.8 GB/s","","100-000000802","","AMD Infinity Guard , AMD Infinity Architecture","Media streaming , Per core CAE|CFD|FEA , Value"
|
| 53 |
+
"AMD EPYC™ 8534PN","EPYC 8004 Series","64","128","Up to 3.1 GHz","3.05 GHz","2 GHz","128 MB","5450 USD","175W","","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000001172","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage , Telco"
|
| 54 |
+
"AMD EPYC™ 8534P","EPYC 8004 Series","64","128","Up to 3.1 GHz","3.1 GHz","2.3 GHz","128 MB","4950 USD","200W","155-225W","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000000875","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage"
|
| 55 |
+
"AMD EPYC™ 8434PN","EPYC 8004 Series","48","96","Up to 3 GHz","3 GHz","2 GHz","128 MB","3150 USD","155W","","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000001174","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage , Telco"
|
| 56 |
+
"AMD EPYC™ 8434P","EPYC 8004 Series","48","96","Up to 3.1 GHz","3.1 GHz","2.5 GHz","128 MB","2700 USD","200W","155-225W","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000000877","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage"
|
| 57 |
+
"AMD EPYC™ 8324PN","EPYC 8004 Series","32","64","Up to 3 GHz","3 GHz","2.05 GHz","128 MB","2125 USD","130W","","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000001162","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , SW-defined storage , Telco"
|
| 58 |
+
"AMD EPYC™ 8324P","EPYC 8004 Series","32","64","Up to 3 GHz","3 GHz","2.65 GHz","128 MB","1895 USD","180W","155-225W","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000001133","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage"
|
| 59 |
+
"AMD EPYC™ 8224PN","EPYC 8004 Series","24","48","Up to 3 GHz","2.9 GHz","2 GHz","64 MB","1015 USD","120W","","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000001164","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage , Telco"
|
| 60 |
+
"AMD EPYC™ 8224P","EPYC 8004 Series","24","48","Up to 3 GHz","3 GHz","2.55 GHz","64 MB","855 USD","160W","155-225W","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000001134","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage"
|
| 61 |
+
"AMD EPYC™ 8124PN","EPYC 8004 Series","16","32","Up to 3 GHz","2.9 GHz","2 GHz","64 MB","790 USD","100W","","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000001166","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage , Telco"
|
| 62 |
+
"AMD EPYC™ 8124P","EPYC 8004 Series","16","32","Up to 3 GHz","2.95 GHz","2.45 GHz","64 MB","639 USD","125W","120-150W","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000001135","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage"
|
| 63 |
+
"AMD EPYC™ 8024PN","EPYC 8004 Series","8","16","Up to 3 GHz","2.95 GHz","2.05 GHz","32 MB","525 USD","80W","","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000001170","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage , Telco"
|
| 64 |
+
"AMD EPYC™ 8024P","EPYC 8004 Series","8","16","Up to 3 GHz","2.95 GHz","2.4 GHz","32 MB","409 USD","90W","70-100W","SP6","1P","09/18/2023","PCIe® 5.0 x96","DDR5","6","Up to 4800 MT/s","230.4 GB/s","","100-000001136","","AMD Infinity Guard , AMD Infinity Architecture","Client-Middleware Computing , HCI , Media streaming , Networking|NFV , SW-defined storage"
|
| 65 |
+
"AMD EPYC™ 7203P","EPYC 7003 Series","8","16","Up to 3.4 GHz","","2.8 GHz","64 MB","338 USD","120W","120-150W","SP3","1P","09/05/2023","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-000001287WOF","100-000001287","","AMD Infinity Guard , AMD Infinity Architecture","General Purpose"
|
| 66 |
+
"AMD EPYC™ 7203","EPYC 7003 Series","8","16","Up to 3.4 GHz","","2.8 GHz","64 MB","348 USD","120W","120-150W","SP3","1P / 2P","09/05/2023","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-000001286WOF","100-000001286","","AMD Infinity Guard , AMD Infinity Architecture","General Purpose"
|
| 67 |
+
"AMD EPYC™ 7303P","EPYC 7003 Series","16","32","Up to 3.4 GHz","","2.4 GHz","64 MB","594 USD","130W","120-150W","SP3","1P","09/05/2023","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-000001289WOF","100-000001289","","AMD Infinity Guard , AMD Infinity Architecture","Cost-optimized , General Purpose"
|
| 68 |
+
"AMD EPYC™ 7303","EPYC 7003 Series","16","32","Up to 3.4 GHz","","2.4 GHz","64 MB","604 USD","130W","120-150W","SP3","1P / 2P","09/05/2023","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-000001288WOF","100-000001288","","AMD Infinity Guard , AMD Infinity Architecture","Cost-optimized , General Purpose"
|
| 69 |
+
"AMD EPYC™ 7643P","EPYC 7003 Series","48","96","Up to 3.6 GHz","","2.3 GHz","256 MB","2722 USD","225W","225-240W","SP3","1P","09/05/2023","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000001285","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 70 |
+
"AMD EPYC™ 7773X","EPYC 7003 Series","64","128","Up to 3.5 GHz","","2.2 GHz","768 MB","8800 USD","280W","225-280W","SP3","1P / 2P","03/22/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000504","","AMD 3D V-Cache™ Technology , AMD Infinity Guard , AMD Infinity Architecture","Cache-sensitive scale-up|out , CFD , FEA Solvers"
|
| 71 |
+
"AMD EPYC™ 7763","EPYC 7003 Series","64","128","Up to 3.5 GHz","","2.45 GHz","256 MB","7890 USD","280W","225-280W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000312WOF","100-000000312","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , Cache-sensitive scale-up|out , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VM Density"
|
| 72 |
+
"AMD EPYC™ 7713P","EPYC 7003 Series","64","128","Up to 3.67 GHz","","2 GHz","256 MB","5010 USD","225W","225-240W","SP3","1P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000337","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , ERM|SCM|CRM apps , Value data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 73 |
+
"AMD EPYC™ 7713","EPYC 7003 Series","64","128","Up to 3.67 GHz","","2 GHz","256 MB","7060 USD","225W","225-240W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000344WOF","100-000000344","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 74 |
+
"AMD EPYC™ 7663","EPYC 7003 Series","56","112","Up to 3.5 GHz","","2 GHz","256 MB","6366 USD","240W","225-240W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000318","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 75 |
+
"AMD EPYC™ 7643","EPYC 7003 Series","48","96","Up to 3.6 GHz","","2.3 GHz","256 MB","4995 USD","225W","225-240W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000326","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 76 |
+
"AMD EPYC™ 7663P","EPYC 7003 Series","56","112","Up to 3.5 GHz","","2 GHz","256 MB","3139 USD","240W","225-280W","SP3","1P","09/05/2023","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000001284","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 77 |
+
"AMD EPYC™ 75F3","EPYC 7003 Series","32","64","Up to 4 GHz","","2.95 GHz","256 MB","4860 USD","280W","225-280W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000313","","AMD Infinity Guard , AMD Infinity Architecture","EDA , HCI , High performance VM Density , Per core CAE|CFD|FEA , VDI"
|
| 78 |
+
"AMD EPYC™ 7573X","EPYC 7003 Series","32","64","Up to 3.6 GHz","","2.8 GHz","768 MB","5590 USD","280W","225-280W","SP3","1P / 2P","03/22/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000506","","AMD 3D V-Cache™ Technology , AMD Infinity Guard , AMD Infinity Architecture","CFD , FEA Solvers"
|
| 79 |
+
"AMD EPYC™ 7543P","EPYC 7003 Series","32","64","Up to 3.7 GHz","","2.8 GHz","256 MB","2730 USD","225W","225-240W","SP3","1P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000341WOF","100-000000341","","AMD Infinity Guard , AMD Infinity Architecture","ERM|SCM|CRM apps , Value data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 80 |
+
"AMD EPYC™ 7543","EPYC 7003 Series","32","64","Up to 3.7 GHz","","2.8 GHz","256 MB","3761 USD","225W","225-240W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000345WOF","100-000000345","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , Media streaming , Medium capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 81 |
+
"AMD EPYC™ 7513","EPYC 7003 Series","32","64","Up to 3.65 GHz","","2.6 GHz","128 MB","2840 USD","200W","165-200W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000334WOF","100-000000334","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , Content mgmt , General Purpose"
|
| 82 |
+
"AMD EPYC™ 74F3","EPYC 7003 Series","24","48","Up to 4 GHz","","3.2 GHz","256 MB","2900 USD","240W","225-240W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000317","","AMD Infinity Guard , AMD Infinity Architecture","EDA , HCI , High performance VM Density , Per core CAE|CFD|FEA , VDI"
|
| 83 |
+
"AMD EPYC™ 7473X","EPYC 7003 Series","24","48","Up to 3.7 GHz","","2.8 GHz","768 MB","3900 USD","240W","225-280W","SP3","1P / 2P","03/22/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000507","","AMD 3D V-Cache™ Technology , AMD Infinity Guard , AMD Infinity Architecture","CFD , EDA , FEA Solvers"
|
| 84 |
+
"AMD EPYC™ 7453","EPYC 7003 Series","28","56","Up to 3.45 GHz","","2.75 GHz","64 MB","1570 USD","225W","225-240W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000319","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , Content mgmt , General Purpose , Value , Value data mgmt (NR|RDBMS)"
|
| 85 |
+
"AMD EPYC™ 7443P","EPYC 7003 Series","24","48","Up to 4 GHz","","2.85 GHz","128 MB","1337 USD","200W","165-200W","SP3","1P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000342WOF","100-000000342","","AMD Infinity Guard , AMD Infinity Architecture","General Purpose , SW-defined storage , Value"
|
| 86 |
+
"AMD EPYC™ 7443","EPYC 7003 Series","24","48","Up to 4 GHz","","2.85 GHz","128 MB","2010 USD","200W","165-200W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000340","","AMD Infinity Guard , AMD Infinity Architecture","General Purpose , GPU|FPGA Accelerated , Per core CAE|CFD|FEA , SW-defined storage"
|
| 87 |
+
"AMD EPYC™ 7413","EPYC 7003 Series","24","48","Up to 3.6 GHz","","2.65 GHz","128 MB","1825 USD","180W","165-200W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000323WOF","100-000000323","","AMD Infinity Guard , AMD Infinity Architecture","ERM|SCM|CRM apps , General Purpose , Networking|NFV , Web Serving"
|
| 88 |
+
"AMD EPYC™ 73F3","EPYC 7003 Series","16","32","Up to 4 GHz","","3.5 GHz","256 MB","3521 USD","240W","225-240W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000321","","AMD Infinity Guard , AMD Infinity Architecture","EDA , High-speed data mgmt (NR|RDBMS) , Per core CAE|CFD|FEA"
|
| 89 |
+
"AMD EPYC™ 7373X","EPYC 7003 Series","16","32","Up to 3.8 GHz","","3.05 GHz","768 MB","4185 USD","240W","225-280W","SP3","1P / 2P","03/22/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000508","","AMD 3D V-Cache™ Technology , AMD Infinity Guard , AMD Infinity Architecture","CFD , EDA , FEA Solvers"
|
| 90 |
+
"AMD EPYC™ 7343","EPYC 7003 Series","16","32","Up to 3.9 GHz","","3.2 GHz","128 MB","1565 USD","190W","165-200W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000338","","AMD Infinity Guard , AMD Infinity Architecture","EDA , General Purpose , Media streaming , Per core CAE|CFD|FEA , Value"
|
| 91 |
+
"AMD EPYC™ 7313P","EPYC 7003 Series","16","32","Up to 3.7 GHz","","3 GHz","128 MB","913 USD","155W","155-180W","SP3","1P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000339WOF","100-000000339","","AMD Infinity Guard , AMD Infinity Architecture","EDA , Media streaming , Value per core CAE|CFD|FEA"
|
| 92 |
+
"AMD EPYC™ 7313","EPYC 7003 Series","16","32","Up to 3.7 GHz","","3 GHz","128 MB","1083 USD","155W","155-180W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000329WOF","100-000000329","","AMD Infinity Guard , AMD Infinity Architecture","EDA , Media streaming , Per core CAE|CFD|FEA"
|
| 93 |
+
"AMD EPYC™ 72F3","EPYC 7003 Series","8","16","Up to 4.1 GHz","","3.7 GHz","256 MB","2468 USD","180W","165-200W","SP3","1P / 2P","03/15/2021","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","","100-000000327","","AMD Infinity Guard , AMD Infinity Architecture","Departmental CAE|CFD|FEA , EDA , FSI risk analysis , Licensed per core data mgmt (RDBMS)"
|
| 94 |
+
"AMD EPYC™ 7H12","EPYC 7002 Series","64","128","Up to 3.3 GHz","","2.6 GHz","256 MB","7250 USD","280W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000055WOF","100-000000055","","AMD Infinity Guard , AMD Infinity Architecture","Specialized CAE|CFD|FEA"
|
| 95 |
+
"AMD EPYC™ 7F72","EPYC 7002 Series","24","48","Up to 3.7 GHz","","3.2 GHz","192 MB","2450 USD","240W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-000000141WOF","100-000000141","","AMD Infinity Guard , AMD Infinity Architecture","EDA , HCI , High performance VM Density , Per core CAE|CFD|FEA , VDI"
|
| 96 |
+
"AMD EPYC™ 7F52","EPYC 7002 Series","16","32","Up to 3.9 GHz","","3.5 GHz","256 MB","3100 USD","240W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-000000140WOF","100-000000140","","AMD Infinity Guard , AMD Infinity Architecture","EDA , High-speed data mgmt (NR|RDBMS) , Per core CAE|CFD|FEA"
|
| 97 |
+
"AMD EPYC™ 7F32","EPYC 7002 Series","8","16","Up to 3.9 GHz","","3.7 GHz","128 MB","2100 USD","180W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-000000139WOF","100-000000139","","AMD Infinity Guard , AMD Infinity Architecture","Departmental CAE|CFD|FEA , EDA , FSI risk analysis , Licensed per core data mgmt (RDBMS)"
|
| 98 |
+
"AMD EPYC™ 4585PX","EPYC 4005 Series","16","32","Up to 5.7 GHz","","4.3 GHz","128 MB","699 USD","170W","","AM5","1P","5/13/2025","PCIe® 5.0 x28","DDR5","2","Up to 5600 MT/s","89.6 GB/s","100-100001561WOF","100-000001561","","AMD Infinity Guard , AMD Infinity Architecture",""
|
| 99 |
+
"AMD EPYC™ 7742","EPYC 7002 Series","64","128","Up to 3.4 GHz","","2.25 GHz","256 MB","6950 USD","225W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000053WOF","100-000000053","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , Cache-sensitive scale-up|out , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VM Density"
|
| 100 |
+
"AMD EPYC™ 4565P","EPYC 4005 Series","16","32","Up to 5.7 GHz","","4.3 GHz","64 MB","589 USD","170W","","AM5","1P","5/13/2025","PCIe® 5.0 x28","DDR5","2","Up to 5600 MT/s","89.6 GB/s","100-100001559WOF","100-000001559","","AMD Infinity Architecture , AMD Infinity Guard",""
|
| 101 |
+
"AMD EPYC™ 4545P","EPYC 4005 Series","16","32","Up to 5.4 GHz","","3 GHz","64 MB","549 USD","65W","","AM5","1P","5/13/2025","PCIe® 5.0 x28","DDR5","2","Up to 5600 MT/s","89.6 GB/s","100-100001764WOF","100-000001764","","AMD Infinity Guard , AMD Infinity Architecture",""
|
| 102 |
+
"AMD EPYC™ 7702P","EPYC 7002 Series","64","128","Up to 3.35 GHz","","2 GHz","256 MB","4425 USD","200W","","SP3","1P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000047WOF","100-000000047","","AMD Infinity Guard , AMD Infinity Architecture","ERM|SCM|CRM apps , Security , Value data mgmt (NR|RDBMS) , VM Density"
|
| 103 |
+
"AMD EPYC™ 4465P","EPYC 4005 Series","12","24","Up to 5.4 GHz","","3.4 GHz","64 MB","399 USD","65W","","AM5","1P","5/13/2025","PCIe® 5.0 x28","DDR5","2","Up to 5600 MT/s","89.6 GB/s","100-100001558WOF","100-000001558","","AMD Infinity Guard , AMD Infinity Architecture",""
|
| 104 |
+
"AMD EPYC™ 4345P","EPYC 4005 Series","8","16","Up to 5.5 GHz","","3.8 GHz","32 MB","329 USD","65W","","AM5","1P","5/13/2025","PCIe® 5.0 x28","DDR5","2","Up to 5600 MT/s","89.6 GB/s","100-100001556WOF","100-000001556","","AMD Infinity Guard , AMD Infinity Architecture",""
|
| 105 |
+
"AMD EPYC™ 7702","EPYC 7002 Series","64","128","Up to 3.35 GHz","","2 GHz","256 MB","6450 USD","200W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000038WOF","100-000000038","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , Cache-sensitive scale-up|out , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VM Density"
|
| 106 |
+
"AMD EPYC™ 4245P","EPYC 4005 Series","6","12","Up to 5.4 GHz","","3.9 GHz","32 MB","239 USD","65W","","AM5","1P","5/13/2025","PCIe® 5.0 x28","DDR5","2","Up to 5600 MT/s","89.6 GB/s","100-100001555WOF","100-000001555","","AMD Infinity Guard , AMD Infinity Architecture",""
|
| 107 |
+
"AMD EPYC™ 7662","EPYC 7002 Series","64","128","Up to 3.3 GHz","","2 GHz","256 MB","6150 USD","225W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-000000137WOF","100-000000137","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 108 |
+
"AMD EPYC™ 7642","EPYC 7002 Series","48","96","Up to 3.3 GHz","","2.3 GHz","256 MB","4775 USD","225W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000074WOF","100-000000074","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 109 |
+
"AMD EPYC™ 7552","EPYC 7002 Series","48","96","Up to 3.3 GHz","","2.2 GHz","192 MB","4025 USD","200W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000076WOF","100-000000076","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 110 |
+
"AMD EPYC™ 7542","EPYC 7002 Series","32","64","Up to 3.4 GHz","","2.9 GHz","128 MB","3400 USD","225W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000075WOF","100-000000075","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , Media streaming , Medium capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 111 |
+
"AMD EPYC™ 7532","EPYC 7002 Series","32","64","Up to 3.3 GHz","","2.4 GHz","256 MB","2380 USD","200W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-000000136WOF","100-000000136","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , Media streaming , Medium capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 112 |
+
"AMD EPYC™ 7502P","EPYC 7002 Series","32","64","Up to 3.35 GHz","","2.5 GHz","128 MB","2300 USD","180W","","SP3","1P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000045WOF","100-000000045","","AMD Infinity Guard , AMD Infinity Architecture","ERM|SCM|CRM apps , Value data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 113 |
+
"AMD EPYC™ 7502","EPYC 7002 Series","32","64","Up to 3.35 GHz","","2.5 GHz","128 MB","2600 USD","180W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000054WOF","100-000000054","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , Media streaming , Medium capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 114 |
+
"AMD EPYC™ 7452","EPYC 7002 Series","32","64","Up to 3.35 GHz","","2.35 GHz","128 MB","2025 USD","155W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000057WOF","100-000000057","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , Content mgmt , General Purpose"
|
| 115 |
+
"AMD EPYC™ 7402P","EPYC 7002 Series","24","48","Up to 3.35 GHz","","2.8 GHz","128 MB","1250 USD","180W","","SP3","1P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000048WOF","100-000000048","","AMD Infinity Guard , AMD Infinity Architecture","General Purpose , SW-defined storage , Value"
|
| 116 |
+
"AMD EPYC™ 7402","EPYC 7002 Series","24","48","Up to 3.35 GHz","","2.8 GHz","128 MB","1783 USD","180W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000046WOF","100-000000046","","AMD Infinity Guard , AMD Infinity Architecture","General Purpose , GPU|FPGA Accelerated , Per core CAE|CFD|FEA , SW-defined storage"
|
| 117 |
+
"AMD EPYC™ 7352","EPYC 7002 Series","24","48","Up to 3.2 GHz","","2.3 GHz","128 MB","1080 USD","155W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000077WOF","100-000000077","","AMD Infinity Guard , AMD Infinity Architecture","ERM|SCM|CRM apps , Networking|NFV , Web Serving"
|
| 118 |
+
"AMD EPYC™ 7302P","EPYC 7002 Series","16","32","Up to 3.3 GHz","","3 GHz","128 MB","825 USD","155W","","SP3","1P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000049WOF","100-000000049","","AMD Infinity Guard , AMD Infinity Architecture","EDA , Media streaming , Value per core CAE|CFD|FEA"
|
| 119 |
+
"AMD EPYC™ 7302","EPYC 7002 Series","16","32","Up to 3.3 GHz","","3 GHz","128 MB","978 USD","155W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000043WOF","100-000000043","","AMD Infinity Guard , AMD Infinity Architecture","EDA , Media streaming , Per core CAE|CFD|FEA"
|
| 120 |
+
"AMD EPYC™ 7282","EPYC 7002 Series","16","32","Up to 3.2 GHz","","2.8 GHz","64 MB","604 USD","120W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","85.3 GB/s","100-100000078WOF","100-000000078","","AMD Infinity Guard , AMD Infinity Architecture","Cost-optimized , General Purpose , SW-defined storage"
|
| 121 |
+
"AMD EPYC™ 7272","EPYC 7002 Series","12","24","Up to 3.2 GHz","","2.9 GHz","64 MB","549 USD","120W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","85.3 GB/s","100-100000079WOF","100-000000079","","AMD Infinity Guard , AMD Infinity Architecture","Content mgmt , Cost-optimized , General Purpose"
|
| 122 |
+
"AMD EPYC™ 7262","EPYC 7002 Series","8","16","Up to 3.4 GHz","","3.2 GHz","128 MB","505 USD","155W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","204.8 GB/s","100-100000041WOF","100-000000041","","AMD Infinity Guard , AMD Infinity Architecture","Collaborative , Cost-optimized , Departmental CAE|CFD|FEA , EDA , Licensed per core data mgmt (RDBMS)"
|
| 123 |
+
"AMD EPYC™ 7252","EPYC 7002 Series","8","16","Up to 3.2 GHz","","3.1 GHz","64 MB","348 USD","120W","","SP3","1P / 2P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","85.3 GB/s","100-100000080WOF","100-000000080","","AMD Infinity Guard , AMD Infinity Architecture","Collaborative , Cost-optimized , Departmental CAE|CFD|FEA , EDA , Licensed per core data mgmt (RDBMS)"
|
| 124 |
+
"AMD EPYC™ 7232P","EPYC 7002 Series","8","16","Up to 3.2 GHz","","3.1 GHz","32 MB","338 USD","120W","","SP3","1P","","PCIe® 4.0 x128","DDR4","8","Up to 3200 MT/s","85.3 GB/s","100-100000081WOF","100-000000081","","AMD Infinity Guard , AMD Infinity Architecture","Cost-optimized , Per core license , Value"
|
| 125 |
+
"AMD EPYC™ 7601","EPYC 7001 Series","32","64","Up to 3.2 GHz","","2.2 GHz","64 MB","3270 USD","180W","","SP3","1P / 2P","","PCIe® 3.0 x128","DDR4","8","Up to 2666 MT/s","170.6 GB/s","PS7601BDAFWOF","PS7601BDVIHAF","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , Cache-sensitive scale-up|out , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS)"
|
| 126 |
+
"AMD EPYC™ 7551P","EPYC 7001 Series","32","64","Up to 3 GHz","","2 GHz","64 MB","1830 USD","180W","","SP3","1P","","PCIe® 3.0 x128","DDR4","8","Up to 2666 MT/s","170.6 GB/s","PS755PBDAFWOF","PS755PBDVIHAF","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , Cache-sensitive scale-up|out , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 127 |
+
"AMD EPYC™ 7551","EPYC 7001 Series","32","64","Up to 3 GHz","","2 GHz","64 MB","2660 USD","180W","","SP3","1P / 2P","","PCIe® 3.0 x128","DDR4","8","Up to 2666 MT/s","170.6 GB/s","PS7551BDAFWOF","PS7551BDVIHAF","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , App dev|test , Cache-sensitive scale-up|out , CAE|CFD|FEA , ERM|SCM|CRM apps , High capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 128 |
+
"AMD EPYC™ 7501","EPYC 7001 Series","32","64","Up to 3 GHz","","2 GHz","64 MB","2870 USD","155W / 170W","","SP3","1P / 2P","","PCIe® 3.0 x128","DDR4","8","2400 MT/s / 2666 MT/s","153.6 GB/s / 170.6 GB/s","PS7501BEAFWOF","PS7501BEVIHAF","","AMD Infinity Guard , AMD Infinity Architecture","Analytics , CAE|CFD|FEA , ERM|SCM|CRM apps , Media streaming , Medium capacity data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 129 |
+
"AMD EPYC™ 7451","EPYC 7001 Series","24","48","Up to 3.2 GHz","","2.3 GHz","64 MB","1880 USD","180W","","SP3","1P / 2P","","PCIe® 3.0 x128","DDR4","8","Up to 2666 MT/s","170.6 GB/s","PS7451BDAFWOF","PS7451BDVHCAF","","AMD Infinity Guard , AMD Infinity Architecture","App dev|test , Content mgmt , General Purpose"
|
| 130 |
+
"AMD EPYC™ 7401P","EPYC 7001 Series","24","48","Up to 3 GHz","","2 GHz","64 MB","920 USD","155W / 170W","","SP3","1P","","PCIe® 3.0 x128","DDR4","8","2400 MT/s / 2666 MT/s","153.6 GB/s / 170.6 GB/s","PS740PBEAFWOF","PS740PBEVHCAF","","AMD Infinity Guard , AMD Infinity Architecture","ERM|SCM|CRM apps , Value data mgmt (NR|RDBMS) , VDI , VM Density"
|
| 131 |
+
"AMD EPYC™ 7401","EPYC 7001 Series","24","48","Up to 3 GHz","","2 GHz","64 MB","1620 USD","155W / 170W","","SP3","1P / 2P","","PCIe® 3.0 x128","DDR4","8","2400 MT/s / 2666 MT/s","153.6 GB/s / 170.6 GB/s","PS7401BEAFWOF","PS7401BEVHCAF","","AMD Infinity Guard , AMD Infinity Architecture","General Purpose , GPU|FPGA Accelerated , SW-defined storage"
|
| 132 |
+
"AMD EPYC™ 7371","EPYC 7001 Series","16","32","Up to 3.8 GHz","","3.1 GHz","64 MB","1550 USD","200W","","SP3","1P / 2P","","PCIe® 3.0 x128","DDR4","8","Up to 2666 MT/s","170.6 GB/s","","","","AMD Infinity Guard , AMD Infinity Architecture","EDA , ERM|SCM|CRM apps , Media streaming , Networking|NFV , Per core CAE|CFD|FEA , Web Serving"
|
| 133 |
+
"AMD EPYC™ 7351P","EPYC 7001 Series","16","32","Up to 2.9 GHz","","2.4 GHz","64 MB","660 USD","155W / 170W","","SP3","1P","","PCIe® 3.0 x128","DDR4","8","2400 MT/s / 2666 MT/s","153.6 GB/s / 170.6 GB/s","PS735PBEAFWOF","PS735PBEVGPAF","","AMD Infinity Guard , AMD Infinity Architecture","Cost-optimized , EDA , General Purpose , Media streaming , Value per core CAE|CFD|FEA"
|
| 134 |
+
"AMD EPYC™ 7351","EPYC 7001 Series","16","32","Up to 2.9 GHz","","2.4 GHz","64 MB","890 USD","155W / 170W","","SP3","1P / 2P","","PCIe® 3.0 x128","DDR4","8","2400 MT/s / 2666 MT/s","153.6 GB/s / 170.6 GB/s","PS7351BEAFWOF","PS7351BEVGPAF","","AMD Infinity Guard , AMD Infinity Architecture","General Purpose , Media streaming , Per core CAE|CFD|FEA , Web Serving"
|
| 135 |
+
"AMD EPYC™ 7301","EPYC 7001 Series","16","32","Up to 2.7 GHz","","2.2 GHz","64 MB","740 USD","155W / 170W","","SP3","1P / 2P","","PCIe® 3.0 x128","DDR4","8","2400 MT/s / 2666 MT/s","153.6 GB/s / 170.6 GB/s","PS7301BEAFWOF","PS7301BEVGPAF","","AMD Infinity Guard , AMD Infinity Architecture","EDA , General Purpose , Media streaming , Per core CAE|CFD|FEA"
|
| 136 |
+
"AMD EPYC™ 7281","EPYC 7001 Series","16","32","Up to 2.7 GHz","","2.1 GHz","32 MB","580 USD","155W / 170W","","SP3","1P / 2P","","PCIe® 3.0 x128","DDR4","8","2400 MT/s / 2666 MT/s","153.6 GB/s / 170.6 GB/s","PS7281BEAFWOF","PS7281BEVGAAF","","AMD Infinity Guard , AMD Infinity Architecture","Cost-optimized , General Purpose , SW-defined storage"
|
| 137 |
+
"AMD EPYC™ 7261","EPYC 7001 Series","8","16","Up to 2.9 GHz","","2.5 GHz","64 MB","570 USD","155W / 170W","","SP3","1P / 2P","","","DDR4","8","2400 MT/s / 2666 MT/s","153.6 GB/s / 170.6 GB/s","","PS7261BEV8RAF","","AMD Infinity Guard , AMD Infinity Architecture","Collaborative , Cost-optimized , Departmental CAE|CFD|FEA , EDA , Per core license , Value data mgmt (NR|RDBMS)"
|
| 138 |
+
"AMD EPYC™ 7251","EPYC 7001 Series","8","16","Up to 2.9 GHz","","2.1 GHz","32 MB","400 USD","120W","","SP3","1P / 2P","","PCIe® 3.0 x128","DDR4","8","Up to 2400 MT/s","153.6 GB/s","PS7251BFAFWOF","PS7251BFV8SAF","","AMD Infinity Guard , AMD Infinity Architecture","Collaborative , Cost-optimized , Per core license , Value data mgmt (NR|RDBMS)"
|
| 139 |
+
"AMD EPYC™ 4584PX","EPYC 4004 Series","16","32","Up to 5.7 GHz","5.7 GHz","4.2 GHz","128 MB","699 USD","120W","","AM5","1P","","PCIe® 5.0 x28","DDR5","2","Up to 5200 MT/s","","100-100001481WOF","100-000001481","Yes","AMD Infinity Architecture",""
|
| 140 |
+
"AMD EPYC™ 4564P","EPYC 4004 Series","16","32","Up to 5.7 GHz","","4.5 GHz","64 MB","699 USD","170W","","AM5","1P","","PCIe® 5.0 x28","DDR5","2","Up to 5200 MT/s","","100-100001476WOF","100-000001476","Yes","AMD Infinity Architecture",""
|
| 141 |
+
"AMD EPYC™ 4484PX","EPYC 4004 Series","12","24","Up to 5.6 GHz","","4.4 GHz","128 MB","599 USD","120W","","AM5","1P","","PCIe® 5.0 x28","DDR5","2","Up to 5200 MT/s","","100-100001482WOF","100-000001482","Yes","AMD Infinity Architecture",""
|
| 142 |
+
"AMD EPYC™ 4464P","EPYC 4004 Series","12","24","Up to 5.4 GHz","","3.7 GHz","64 MB","429 USD","65W","","AM5","1P","","PCIe® 5.0 x28","DDR5","2","Up to 5200 MT/s","","100-100001478WOF","100-000001478","Yes","AMD Infinity Architecture",""
|
| 143 |
+
"AMD EPYC™ 4364P","EPYC 4004 Series","8","16","Up to 5.4 GHz","","4.5 GHz","32 MB","399 USD","105W","","AM5","1P","","PCIe® 5.0 x28","DDR5","2","Up to 5200 MT/s","","100-100001477WOF","100-000001477","Yes","AMD Infinity Architecture",""
|
| 144 |
+
"AMD EPYC™ 4344P","EPYC 4004 Series","8","16","Up to 5.3 GHz","","3.8 GHz","32 MB","329 USD","65W","","AM5","1P","","PCIe® 5.0 x28","DDR5","2","Up to 5200 MT/s","","100-100001479WOF","100-000001479","Yes","AMD Infinity Architecture",""
|
| 145 |
+
"AMD EPYC™ 4244P","EPYC 4004 Series","6","12","Up to 5.1 GHz","","3.8 GHz","32 MB","229 USD","65W","","AM5","1P","","PCIe® 5.0 x28","DDR5","2","Up to 5200 MT/s","","100-100001480WOF","100-000001480","Yes","AMD Infinity Architecture",""
|
| 146 |
+
"AMD EPYC™ 4124P","EPYC 4004 Series","4","8","Up to 5.1 GHz","","3.8 GHz","16 MB","149 USD","65W","","AM5","1P","","PCIe® 5.0 x28","DDR5","2","Up to 5200 MT/s","","100-100001570WOF","100-000001570","Yes","AMD Infinity Architecture",""
|
| 147 |
+
"AMD Opteron™ X2170 APU","Opteron X2100 Series APU","4","4","","","2.4 GHz","","","25W","","FT3","","","","DDR3","","Up to 1866 MT/s","","","","","Graphics Core Next Architecture , AMD X86 SoC Technology",""
|
| 148 |
+
"AMD Opteron™ X2150 APU","Opteron X2100 Series APU","4","4","","","1.9 GHz","","","22W","","FT3","","","","DDR3","","","","n/a","OX2150IAJ44HM","","Catalyst Software , AMD HD3D Technology",""
|
| 149 |
+
"AMD Opteron™ X1150","Opteron X1100 Series","4","4","","","2 GHz","","","17W","","FT3","","","","DDR3","","Up to 800 MT/s","","n/a","OX1150IPJ44HM","","",""
|
| 150 |
+
"AMD Opteron™ 6386 SE","Opteron 6300 Series","16","16","Up to 3.5 GHz","","2.8 GHz","16 MB","","140W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6386YETGGHK","","",""
|
| 151 |
+
"AMD Opteron™ 6370P","Opteron 6300 Series","16","16","Up to 2.5 GHz","","2 GHz","16 MB","","99W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6370WQTGGHK","","",""
|
| 152 |
+
"AMD Opteron™ 6366 HE","Opteron 6300 Series","16","16","Up to 3.1 GHz","","1.8 GHz","16 MB","","85W","","G34","","","","DDR3","","Up to 1800 MT/s","","n/a","OS6366VATGGHK","","",""
|
| 153 |
+
"AMD Opteron™ 6338P","Opteron 6300 Series","12","12","Up to 2.8 GHz","","2.3 GHz","16 MB","","99W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6338WQTCGHK","","",""
|
| 154 |
+
"AMD Opteron™ 6380","Opteron 6300 Series","16","16","Up to 3.4 GHz","","2.5 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6380WKTGGHK","","",""
|
| 155 |
+
"AMD Opteron™ 6378","Opteron 6300 Series","16","16","Up to 3.3 GHz","","2.4 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6378WKTGGHK","","",""
|
| 156 |
+
"AMD Opteron™ 6376","Opteron 6300 Series","16","16","Up to 2 GHz","","2.3 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6376WKTGGHK","","",""
|
| 157 |
+
"AMD Opteron™ 6348","Opteron 6300 Series","12","12","Up to 3.4 GHz","","2.8 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6348WKTCGHK","","",""
|
| 158 |
+
"AMD Opteron™ 6344","Opteron 6300 Series","12","12","Up to 2 GHz","","2.6 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6344WKTCGHK","","",""
|
| 159 |
+
"AMD Opteron™ 6328","Opteron 6300 Series","8","8","Up to 3.8 GHz","","3.2 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6328WKT8GHK","","",""
|
| 160 |
+
"AMD Opteron™ 6320","Opteron 6300 Series","8","8","Up to 3.3 GHz","","2.8 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6320WKT8GHK","","",""
|
| 161 |
+
"AMD Opteron™ 6308","Opteron 6300 Series","4","4","","","3.5 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6308WKT4GHK","","",""
|
| 162 |
+
"AMD Opteron™ 4376 HE","Opteron 4300 Series","8","8","Up to 3.6 GHz","","2.6 GHz","8 MB","","65W","","C32","","","","DDR3","","Up to 2000 MT/s","","n/a","OS4376OFU8KHK","","",""
|
| 163 |
+
"AMD Opteron™ 4332 HE","Opteron 4300 Series","6","6","Up to 3.7 GHz","","3 GHz","8 MB","","65W","","C32","","","","DDR3","","Up to 2000 MT/s","","n/a","OS4332OFU6KHK","","",""
|
| 164 |
+
"AMD Opteron™ 4310 EE","Opteron 4300 Series","6","6","Up to 3 GHz","","2.2 GHz","8 MB","","35W","","C32","","","","DDR3","","Up to 1600 MT/s","","n/a","OS4310HPU4KHK","","",""
|
| 165 |
+
"AMD Opteron™ 4386","Opteron 4300 Series","8","8","Up to 3.8 GHz","","3.1 GHz","8 MB","","95W","","C32","","","","DDR3","","Up to 2200 MT/s","","n/a","OS4386WLU8KHK","","",""
|
| 166 |
+
"AMD Opteron™ 4365","Opteron 4300 Series","8","8","Up to 2.8 GHz","","2 GHz","8 MB","","40W","","C32","","","","DDR3","","Up to 1600 MT/s","","n/a","n/a","","",""
|
| 167 |
+
"AMD Opteron™ 4340","Opteron 4300 Series","6","6","Up to 3.8 GHz","","3.5 GHz","8 MB","","95W","","C32","","","","DDR3","","Up to 2200 MT/s","","n/a","OS4340WLU6KHK","","",""
|
| 168 |
+
"AMD Opteron™ 4334","Opteron 4300 Series","6","6","Up to 3.5 GHz","","3.1 GHz","8 MB","","95W","","C32","","","","DDR3","","Up to 2000 MT/s","","n/a","OS4334WLU6KHK","","",""
|
| 169 |
+
"AMD Opteron™ 3350 HE","Opteron 3300 Series","4","4","Up to 3.8 GHz","","2.8 GHz","8 MB","","45W","","AM3+","","","","DDR3","","Up to 2000 MT/s","","n/a","OS3350HOW4KHK","","",""
|
| 170 |
+
"AMD Opteron™ 3320 EE","Opteron 3300 Series","4","4","Up to 2.5 GHz","","1.9 GHz","8 MB","","25W","","AM3+","","","","DDR3","","Up to 1400 MT/s","","n/a","OS3320SJW4KHK","","",""
|
| 171 |
+
"AMD Opteron™ 3380","Opteron 3300 Series","8","8","Up to 3.6 GHz","","2.6 GHz","8 MB","","65W","","AM3+","","","","DDR3","","Up to 2000 MT/s","","n/a","OS3380OLW8KHK","","",""
|
| 172 |
+
"AMD Opteron™ 3365","Opteron 3300 Series","8","8","Up to 3.3 GHz","","2.3 GHz","8 MB","","65W","","AM3+","","","","DDR3","","Up to 2000 MT/s","","n/a","OS3365OLW8KHK","","",""
|
| 173 |
+
"AMD Opteron™ 6284 SE","Opteron 6200 Series","16","16","Up to 3.4 GHz","","2.7 GHz","16 MB","","140W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6284YETGGGU","","",""
|
| 174 |
+
"AMD Opteron™ 6282 SE","Opteron 6200 Series","16","16","Up to 3.3 GHz","","2.6 GHz","16 MB","","140W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6282YETGGGU","","",""
|
| 175 |
+
"AMD Opteron™ 6262 HE","Opteron 6200 Series","16","16","Up to 2.9 GHz","","1.6 GHz","16 MB","","85W","","G34","","","","DDR3","","Up to 1800 MT/s","","n/a","OS6262VATGGGU","","",""
|
| 176 |
+
"AMD Opteron™ 6278","Opteron 6200 Series","16","16","Up to 3.3 GHz","","2.4 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6278WKTGGGU","","",""
|
| 177 |
+
"AMD Opteron™ 6276","Opteron 6200 Series","16","16","Up to 3.2 GHz","","2.3 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6276WKTGGGU","","",""
|
| 178 |
+
"AMD Opteron™ 6274","Opteron 6200 Series","16","16","Up to 3.1 GHz","","2.2 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6274WKTGGGU","","",""
|
| 179 |
+
"AMD Opteron™ 6272","Opteron 6200 Series","16","16","Up to 3 GHz","","2.1 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6272WKTGGGU","","",""
|
| 180 |
+
"AMD Opteron™ 6238","Opteron 6200 Series","12","12","Up to 3.2 GHz","","2.6 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6238WKTCGGU","","",""
|
| 181 |
+
"AMD Opteron™ 6234","Opteron 6200 Series","12","12","Up to 3 GHz","","2.4 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6234WKTCGGU","","",""
|
| 182 |
+
"AMD Opteron™ 6220","Opteron 6200 Series","8","8","Up to 3.6 GHz","","3 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6220WKT8GGU","","",""
|
| 183 |
+
"AMD Opteron™ 6212","Opteron 6200 Series","8","8","Up to 3.2 GHz","","2.6 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6212WKT8GGU","","",""
|
| 184 |
+
"AMD Opteron™ 6204","Opteron 6200 Series","4","4","","","3.3 GHz","16 MB","","115W","","G34","","","","DDR3","","Up to 2000 MT/s","","n/a","OS6204WKT4GGU","","",""
|
| 185 |
+
"AMD Opteron™ 4276 HE","Opteron 4200 Series","8","8","Up to 3.6 GHz","","2.6 GHz","8 MB","","65W","","C32","","","","DDR3","","Up to 2000 MT/s","","n/a","OS4276OFU8KGU","","",""
|
| 186 |
+
"AMD Opteron™ 4274 HE","Opteron 4200 Series","8","8","Up to 3.5 GHz","","2.5 GHz","8 MB","","65W","","C32","","","","DDR3","","Up to 2000 MT/s","","n/a","OS4274OFU8KGU","","",""
|
| 187 |
+
"AMD Opteron™ 4256 EE","Opteron 4200 Series","8","8","Up to 2.8 GHz","","1.6 GHz","8 MB","","35W","","C32","","","","DDR3","","Up to 1600 MT/s","","n/a","OS4256HJU8KGU","","",""
|
| 188 |
+
"AMD Opteron™ 4230 HE","Opteron 4200 Series","6","6","Up to 3.7 GHz","","2.9 GHz","8 MB","","65W","","C32","","","","DDR3","","Up to 2000 MT/s","","n/a","OS4230OFU6KGU","","",""
|
| 189 |
+
"AMD Opteron™ 4228 HE","Opteron 4200 Series","6","6","Up to 3.6 GHz","","2.8 GHz","8 MB","","65W","","C32","","","","DDR3","","Up to 2000 MT/s","","n/a","OS4228OFU6KGU","","",""
|
| 190 |
+
"AMD Opteron™ 4284","Opteron 4200 Series","8","8","Up to 3.7 GHz","","3 GHz","8 MB","","95W","","C32","","","","DDR3","","Up to 2200 MT/s","","n/a","OS4284WLU8KGU","","",""
|
| 191 |
+
"AMD Opteron™ 4280","Opteron 4200 Series","8","8","Up to 2.2 GHz","","2.8 GHz","8 MB","","95W","","C32","","","","DDR3","","Up to 2200 MT/s","","n/a","OS4280WLU8KGU","","",""
|
| 192 |
+
"AMD Opteron™ 4240","Opteron 4200 Series","6","6","Up to 3.8 GHz","","3.4 GHz","8 MB","","95W","","C32","","","","DDR3","","","","n/a","OS4240WLU6KGU","","",""
|
| 193 |
+
"AMD Opteron™ 4238","Opteron 4200 Series","6","6","Up to 3.7 GHz","","3.3 GHz","8 MB","","95W","","C32","","","","DDR3","","Up to 2200 MT/s","","n/a","OS4238WLU6KGU","","",""
|
| 194 |
+
"AMD Opteron™ 4234","Opteron 4200 Series","6","6","Up to 3.5 GHz","","3.1 GHz","8 MB","","95W","","C32","","","","DDR3","","Up to 2200 MT/s","","n/a","OS4234WLU6KGU","","",""
|
| 195 |
+
"AMD Opteron™ 4226","Opteron 4200 Series","6","6","Up to 3.1 GHz","","2.7 GHz","8 MB","","95W","","C32","","","","DDR3","","Up to 2000 MT/s","","n/a","OS4226WLU6KGU","","",""
|
| 196 |
+
"AMD Opteron™ 3260 HE","Opteron 3200 Series","4","4","Up to 3.7 GHz","","2.7 GHz","4 MB","","45W","","AM3+","","","","DDR3","","Up to 2000 MT/s","","OS3260HOW4MGUBOX","OS3260HOW4MGU","","",""
|
| 197 |
+
"AMD Opteron™ 3250 HE","Opteron 3200 Series","","","Up to 3.5 GHz","","2.5 GHz","4 MB","","45W","","AM3+","","","","DDR3","","Up to 2000 MT/s","","OS3250HOW4MGUBOX","OS3250HOW4MGU","","",""
|
| 198 |
+
"AMD Opteron™ 3280","Opteron 3200 Series","8","8","Up to 3.4 GHz","","2.4 GHz","8 MB","","65W","","AM3+","","","","DDR3","","Up to 2000 MT/s","","OS3280OLW8KGUBOX","OS3280OLW8KGU","","",""
|
| 199 |
+
"AMD Opteron™ 6180 SE","Opteron 6100 Series","12","12","","","2.5 GHz","12 MB","","140W","","G34","","","","DDR3","","Up to 1800 MT/s","","n/a","OS6180YETCEGO","","",""
|
| 200 |
+
"AMD Opteron™ 6166 HE","Opteron 6100 Series","12","12","","","1.8 GHz","12 MB","","85W","","G34","","","","DDR3","","Up to 1800 MT/s","","n/a","OS6166VATCEGO","","",""
|
| 201 |
+
"AMD Opteron™ 6132 HE","Opteron 6100 Series","8","8","","","2.2 GHz","12 MB","","85W","","G34","","","","DDR3","","Up to 1800 MT/s","","n/a","OS6132VAT8EGO","","",""
|
| 202 |
+
"AMD Opteron™ 6176","Opteron 6100 Series","12","12","","","2.3 GHz","12 MB","","115W","","G34","","","","DDR3","","Up to 1800 MT/s","","OS6176WKTCEGOWOF","OS6176WKTCEGO","","",""
|
| 203 |
+
"AMD Opteron™ 6140","Opteron 6100 Series","8","8","","","2.6 GHz","12 MB","","115W","","G34","","","","DDR3","","Up to 1800 MT/s","","OS6140WKT8EGOWOF","OS6140WKT8EGO","","",""
|
codecarbon/data/hardware/cpu_dataset_builder/intel_cpu_ark_dataset.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
codecarbon/data/hardware/cpu_dataset_builder/intel_cpu_scrapper.py
ADDED
|
@@ -0,0 +1,284 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Intel CPU Scraper
|
| 4 |
+
|
| 5 |
+
This script uses requests and BeautifulSoup to scrape CPU names and their associated TDP values
|
| 6 |
+
from the Intel ARK website using the advanced filter search URL.
|
| 7 |
+
|
| 8 |
+
hatch run pip install beautifulsoup4
|
| 9 |
+
hatch run python intel_cpu_scrapper.py
|
| 10 |
+
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
import csv
|
| 14 |
+
import os
|
| 15 |
+
import re
|
| 16 |
+
import time
|
| 17 |
+
|
| 18 |
+
import requests
|
| 19 |
+
from bs4 import BeautifulSoup
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
class IntelCpuScraper:
|
| 23 |
+
"""Scraper for Intel CPU data from ARK website."""
|
| 24 |
+
|
| 25 |
+
def __init__(self):
|
| 26 |
+
"""Initialize the scraper."""
|
| 27 |
+
self.base_url = "https://www.intel.com/libs/apps/intel/support/ark/advancedFilterSearch?productType=873&3_MaxTDP-Min=0.03&3_MaxTDP-Max=500&forwardPath=/content/www/us/en/ark/featurefilter.html&pageNo={page_num}&sort=&sortType="
|
| 28 |
+
self.results = []
|
| 29 |
+
self.headers = {
|
| 30 |
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
def fetch_page(self, page_num):
|
| 34 |
+
"""Fetch a single page of results."""
|
| 35 |
+
url = self.base_url.format(page_num=page_num)
|
| 36 |
+
print(f"Fetching URL: {url}")
|
| 37 |
+
try:
|
| 38 |
+
response = requests.get(url, headers=self.headers, timeout=30)
|
| 39 |
+
response.raise_for_status() # Raise an exception for bad status codes
|
| 40 |
+
return response.text
|
| 41 |
+
except requests.exceptions.RequestException as e:
|
| 42 |
+
print(f"Error fetching page {page_num}: {e}")
|
| 43 |
+
return None
|
| 44 |
+
|
| 45 |
+
def parse_html(self, html_content):
|
| 46 |
+
"""Parse HTML content to extract CPU data."""
|
| 47 |
+
soup = BeautifulSoup(html_content, "html.parser")
|
| 48 |
+
# Prioritize rows with 'data-product-id' as they are likely the CPU entries
|
| 49 |
+
rows = soup.find_all("tr", {"data-product-id": True})
|
| 50 |
+
|
| 51 |
+
if not rows:
|
| 52 |
+
no_results_message = soup.find("div", class_="no-results-message")
|
| 53 |
+
if (
|
| 54 |
+
no_results_message
|
| 55 |
+
and "no results found" in no_results_message.text.lower()
|
| 56 |
+
):
|
| 57 |
+
print("No results found on this page (no-results-message).")
|
| 58 |
+
return []
|
| 59 |
+
if "No products matching your selection were found" in html_content:
|
| 60 |
+
print("No results found on this page (No products matching text).")
|
| 61 |
+
return []
|
| 62 |
+
print("No CPU data rows with 'data-product-id' found on the page.")
|
| 63 |
+
return None # Indicate an issue or unexpected structure if no specific "no results" message
|
| 64 |
+
|
| 65 |
+
page_results = []
|
| 66 |
+
for row in rows:
|
| 67 |
+
try:
|
| 68 |
+
# Get all direct child <td> elements of the row
|
| 69 |
+
tds = row.find_all("td", recursive=False)
|
| 70 |
+
|
| 71 |
+
# Expected columns: Name, Launch, Cores, Max Turbo, Base Freq, Cache, TDP
|
| 72 |
+
if len(tds) < 7:
|
| 73 |
+
# print(f"Skipping row, expected at least 7 columns, got {len(tds)}.")
|
| 74 |
+
continue
|
| 75 |
+
|
| 76 |
+
# 1. Product Name
|
| 77 |
+
cpu_name_tag = tds[0].find("a")
|
| 78 |
+
if not cpu_name_tag:
|
| 79 |
+
# print("Skipping row: CPU name tag not found in first cell.")
|
| 80 |
+
continue
|
| 81 |
+
cpu_name = cpu_name_tag.text.strip()
|
| 82 |
+
|
| 83 |
+
# Helper to get text from a td cell
|
| 84 |
+
def get_cell_text(cell_index, tds):
|
| 85 |
+
if cell_index < len(tds) and tds[cell_index]:
|
| 86 |
+
return tds[cell_index].text.strip()
|
| 87 |
+
return ""
|
| 88 |
+
|
| 89 |
+
# 2. Launch Date (e.g., "Q2'25")
|
| 90 |
+
launch_date = get_cell_text(1, tds)
|
| 91 |
+
|
| 92 |
+
# 3. Total Cores (e.g., "40")
|
| 93 |
+
total_cores = get_cell_text(2, tds)
|
| 94 |
+
|
| 95 |
+
# 4. Max Turbo Frequency (e.g., "3.5 GHz")
|
| 96 |
+
max_turbo_frequency = get_cell_text(3, tds)
|
| 97 |
+
|
| 98 |
+
# 5. Processor Base Frequency (e.g., "2.5 GHz")
|
| 99 |
+
processor_base_frequency = get_cell_text(4, tds)
|
| 100 |
+
|
| 101 |
+
# 6. Cache (e.g., "160 MB")
|
| 102 |
+
cache = get_cell_text(5, tds)
|
| 103 |
+
|
| 104 |
+
# 7. TDP (e.g., "235 W")
|
| 105 |
+
tdp_text_content = get_cell_text(6, tds)
|
| 106 |
+
tdp_data_value = (
|
| 107 |
+
tds[6].get("data-value") if len(tds) > 6 and tds[6] else None
|
| 108 |
+
)
|
| 109 |
+
|
| 110 |
+
tdp_numeric = None
|
| 111 |
+
if tdp_data_value and tdp_data_value.replace(".", "", 1).isdigit():
|
| 112 |
+
tdp_numeric = float(tdp_data_value)
|
| 113 |
+
elif "W" in tdp_text_content:
|
| 114 |
+
tdp_match = re.search(r"([\\d.]+)\\s*W", tdp_text_content)
|
| 115 |
+
if tdp_match:
|
| 116 |
+
tdp_numeric = float(tdp_match.group(1))
|
| 117 |
+
|
| 118 |
+
if not cpu_name: # Basic validation
|
| 119 |
+
# print("Skipping row: CPU name is empty.")
|
| 120 |
+
continue
|
| 121 |
+
|
| 122 |
+
result_item = {
|
| 123 |
+
"cpu_name": cpu_name,
|
| 124 |
+
"launch_date": launch_date,
|
| 125 |
+
"total_cores": total_cores,
|
| 126 |
+
"max_turbo_frequency": max_turbo_frequency,
|
| 127 |
+
"processor_base_frequency": processor_base_frequency,
|
| 128 |
+
"cache": cache,
|
| 129 |
+
"tdp": (
|
| 130 |
+
tdp_numeric if tdp_numeric is not None else ""
|
| 131 |
+
), # Store numeric TDP in Watts
|
| 132 |
+
}
|
| 133 |
+
page_results.append(result_item)
|
| 134 |
+
# print(f"Processed: {cpu_name}, TDP: {tdp_numeric if tdp_numeric is not None else 'N/A'}")
|
| 135 |
+
|
| 136 |
+
except Exception as e:
|
| 137 |
+
print(f"Error parsing a row: {e}")
|
| 138 |
+
# print(f"Problematic row HTML snippet: {str(row)[:500]}")
|
| 139 |
+
return page_results
|
| 140 |
+
|
| 141 |
+
def scrape_all_cpus(self):
|
| 142 |
+
"""Scrape all CPU data by iterating through pages."""
|
| 143 |
+
page_num = 1
|
| 144 |
+
consecutive_empty_pages = 0 # To detect end of results
|
| 145 |
+
max_consecutive_empty = (
|
| 146 |
+
2 # Stop after 2 consecutive pages with no new valid entries
|
| 147 |
+
)
|
| 148 |
+
|
| 149 |
+
while True:
|
| 150 |
+
print(f"Processing page {page_num}...")
|
| 151 |
+
html_content = self.fetch_page(page_num)
|
| 152 |
+
|
| 153 |
+
if html_content is None:
|
| 154 |
+
print(f"Failed to fetch page {page_num} after retries. Stopping.")
|
| 155 |
+
break
|
| 156 |
+
|
| 157 |
+
page_results = self.parse_html(html_content)
|
| 158 |
+
|
| 159 |
+
if page_results is None: # Indicates an unexpected page structure or error
|
| 160 |
+
print(
|
| 161 |
+
f"Could not parse data from page {page_num} or unexpected structure. Stopping."
|
| 162 |
+
)
|
| 163 |
+
break
|
| 164 |
+
|
| 165 |
+
if not page_results:
|
| 166 |
+
consecutive_empty_pages += 1
|
| 167 |
+
print(
|
| 168 |
+
f"No results extracted from page {page_num}. Consecutive empty pages: {consecutive_empty_pages}"
|
| 169 |
+
)
|
| 170 |
+
if consecutive_empty_pages >= max_consecutive_empty:
|
| 171 |
+
print("Reached max consecutive empty pages. Assuming end of data.")
|
| 172 |
+
break
|
| 173 |
+
else:
|
| 174 |
+
consecutive_empty_pages = 0 # Reset counter if we found data
|
| 175 |
+
new_cpus_found_on_page = 0
|
| 176 |
+
for res in page_results:
|
| 177 |
+
if (
|
| 178 |
+
res not in self.results
|
| 179 |
+
): # Avoid duplicates if any page re-processing happens
|
| 180 |
+
self.results.append(res)
|
| 181 |
+
new_cpus_found_on_page += 1
|
| 182 |
+
print(
|
| 183 |
+
f"Added {new_cpus_found_on_page} new CPUs from page {page_num}. Total CPUs: {len(self.results)}"
|
| 184 |
+
)
|
| 185 |
+
if new_cpus_found_on_page == 0 and len(page_results) > 0:
|
| 186 |
+
# This means all CPUs on this page were duplicates, could be an issue or end of new data
|
| 187 |
+
print(
|
| 188 |
+
f"All {len(page_results)} CPUs on page {page_num} are duplicates. Considering this as end of new data."
|
| 189 |
+
)
|
| 190 |
+
break
|
| 191 |
+
|
| 192 |
+
page_num += 1
|
| 193 |
+
time.sleep(1) # Be respectful to the server
|
| 194 |
+
|
| 195 |
+
print(f"Scraping complete. Found {len(self.results)} CPUs.")
|
| 196 |
+
|
| 197 |
+
def save_to_csv(self, filename="intel_cpu_ark_dataset.csv"):
|
| 198 |
+
"""Save the scraped data to a CSV file."""
|
| 199 |
+
filepath = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename)
|
| 200 |
+
if not self.results:
|
| 201 |
+
print("No data to save to CSV.")
|
| 202 |
+
return
|
| 203 |
+
|
| 204 |
+
keys = self.results[0].keys()
|
| 205 |
+
with open(filepath, "w", newline="", encoding="utf-8") as f:
|
| 206 |
+
writer = csv.DictWriter(f, fieldnames=keys)
|
| 207 |
+
writer.writeheader()
|
| 208 |
+
writer.writerows(self.results)
|
| 209 |
+
print(f"Data saved to {filepath}")
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
def main():
|
| 213 |
+
"""Main function to run the scraper."""
|
| 214 |
+
scraper = IntelCpuScraper()
|
| 215 |
+
scraper.scrape_all_cpus()
|
| 216 |
+
|
| 217 |
+
if scraper.results:
|
| 218 |
+
scraper.save_to_csv()
|
| 219 |
+
else:
|
| 220 |
+
print("No data was scraped.")
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
if __name__ == "__main__":
|
| 224 |
+
main()
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
"""
|
| 228 |
+
|
| 229 |
+
Sample content from the Intel ARK page:
|
| 230 |
+
|
| 231 |
+
Product Name
|
| 232 |
+
Launch Date
|
| 233 |
+
Total Cores
|
| 234 |
+
Max Turbo Frequency
|
| 235 |
+
Processor Base Frequency
|
| 236 |
+
Cache
|
| 237 |
+
TDP
|
| 238 |
+
|
| 239 |
+
<tr class="blank-table-row seg-server seg-embedded "
|
| 240 |
+
data-codename="Granite Rapids-D"
|
| 241 |
+
data-filter="Server"
|
| 242 |
+
data-product-id="242908">
|
| 243 |
+
<td class="ark-product-name ark-accessible-color component"
|
| 244 |
+
data-value="4" data-component="arkproductlink"
|
| 245 |
+
data-component-id="1">
|
| 246 |
+
<div class="add-compare-wrap">
|
| 247 |
+
<label class="containerCB component" data-component="wa_skip_track"
|
| 248 |
+
data-component-id="1">
|
| 249 |
+
<input class="compare-checkbox compare-toggle"
|
| 250 |
+
data-component="ark-component"
|
| 251 |
+
data-product-id="242908" type="checkbox">
|
| 252 |
+
<span class="checkmark"></span>
|
| 253 |
+
</label>
|
| 254 |
+
<a href="/content/www/us/en/products/sku/242908/intel-xeon-6716pb-processor-160m-cache-2-50-ghz/specifications.html">Intel® Xeon® 6716P-B Processor</a>
|
| 255 |
+
</div>
|
| 256 |
+
</td>
|
| 257 |
+
|
| 258 |
+
<td class=""
|
| 259 |
+
data-value="">
|
| 260 |
+
Q2'25
|
| 261 |
+
</td>
|
| 262 |
+
<td class=""
|
| 263 |
+
data-value="40">
|
| 264 |
+
|
| 265 |
+
40
|
| 266 |
+
</td>
|
| 267 |
+
<td class=""
|
| 268 |
+
data-value="3500">
|
| 269 |
+
3.5 GHz
|
| 270 |
+
</td>
|
| 271 |
+
<td class=""
|
| 272 |
+
data-value="2500">
|
| 273 |
+
2.5 GHz
|
| 274 |
+
</td>
|
| 275 |
+
<td class=""
|
| 276 |
+
data-value="163840">
|
| 277 |
+
160 MB
|
| 278 |
+
</td>
|
| 279 |
+
<td class=""
|
| 280 |
+
data-value="235">
|
| 281 |
+
235 W
|
| 282 |
+
</td>
|
| 283 |
+
</tr>
|
| 284 |
+
"""
|
codecarbon/data/hardware/cpu_dataset_builder/merge_scrapped_cpu_power.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This script updates the CPU power data by reading from Intel and AMD CPU data file,
|
| 3 |
+
cleaning the CPU names, and merging the data into an existing CPU power CSV file.
|
| 4 |
+
It ensures that the TDP values are numeric and updates existing entries or adds new ones.
|
| 5 |
+
|
| 6 |
+
cd codecarbon/data/hardware/cpu_dataset_builder
|
| 7 |
+
hatch run python merge_scrapped_cpu_power.py
|
| 8 |
+
|
| 9 |
+
"""
|
| 10 |
+
|
| 11 |
+
import re
|
| 12 |
+
|
| 13 |
+
import pandas as pd
|
| 14 |
+
|
| 15 |
+
# Define file paths
|
| 16 |
+
intel_cpu_file = "intel_cpu_ark_dataset.csv"
|
| 17 |
+
amd_desktop_cpu_file = "amd_cpu_desktop_dataset.csv"
|
| 18 |
+
amd_server_cpu_file = "amd_cpu_server_dataset.csv"
|
| 19 |
+
cpu_power_file = "../cpu_power.csv"
|
| 20 |
+
|
| 21 |
+
# Read Intel CPU data
|
| 22 |
+
try:
|
| 23 |
+
intel_df = pd.read_csv(intel_cpu_file)
|
| 24 |
+
amd_desktop_df = pd.read_csv(amd_desktop_cpu_file)
|
| 25 |
+
amd_server_df = pd.read_csv(amd_server_cpu_file)
|
| 26 |
+
except FileNotFoundError as e:
|
| 27 |
+
print(f"FATAL Error: Data file not found {e}")
|
| 28 |
+
exit(1)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
# Clean Intel CPU names and select relevant columns
|
| 32 |
+
def clean_intel_cpu_name(name):
|
| 33 |
+
if pd.isna(name):
|
| 34 |
+
return None
|
| 35 |
+
name = re.sub(r"®", "", name)
|
| 36 |
+
name = name.replace(r"(R)", "")
|
| 37 |
+
name = name.replace(r"(TM)", "")
|
| 38 |
+
name = re.sub(r" Processor", "", name)
|
| 39 |
+
name = re.sub(r" Coprocessor", "", name)
|
| 40 |
+
name = re.sub(r"™", "", name)
|
| 41 |
+
name = re.sub(r" with.*", "", name)
|
| 42 |
+
name = name.strip()
|
| 43 |
+
if not name.startswith("Intel "):
|
| 44 |
+
name = "Intel " + name
|
| 45 |
+
return name
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
if not intel_df.empty:
|
| 49 |
+
intel_df["Name"] = intel_df["cpu_name"].apply(clean_intel_cpu_name)
|
| 50 |
+
intel_df = intel_df[["Name", "tdp"]].copy()
|
| 51 |
+
intel_df.rename(columns={"tdp": "TDP"}, inplace=True)
|
| 52 |
+
else:
|
| 53 |
+
intel_df = pd.DataFrame(columns=["Name", "TDP"])
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
# Clean AMD CPU names
|
| 57 |
+
def clean_amd_cpu_name(name):
|
| 58 |
+
if pd.isna(name):
|
| 59 |
+
return None
|
| 60 |
+
name = str(name) # Ensure name is a string
|
| 61 |
+
name = re.sub(r"®", "", name)
|
| 62 |
+
name = name.replace(r"(R)", "")
|
| 63 |
+
name = name.replace(r"(TM)", "")
|
| 64 |
+
name = re.sub(r" Processor", "", name)
|
| 65 |
+
name = re.sub(r"™", "", name)
|
| 66 |
+
name = re.sub(r" with.*", "", name)
|
| 67 |
+
name = name.strip()
|
| 68 |
+
if not name.startswith("AMD "):
|
| 69 |
+
name = "AMD " + name
|
| 70 |
+
return name
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def extract_tdp_value(tdp_str):
|
| 74 |
+
if pd.isna(tdp_str):
|
| 75 |
+
return None
|
| 76 |
+
tdp_str = str(tdp_str).replace("W", "").strip()
|
| 77 |
+
# If it's a range like "15-54", take the upper value
|
| 78 |
+
if "-" in tdp_str:
|
| 79 |
+
try:
|
| 80 |
+
return float(tdp_str.split("-")[-1])
|
| 81 |
+
except ValueError:
|
| 82 |
+
return None
|
| 83 |
+
try:
|
| 84 |
+
return float(tdp_str)
|
| 85 |
+
except ValueError:
|
| 86 |
+
return None
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
amd_desktop_df["Name"] = amd_desktop_df["Name"].apply(clean_amd_cpu_name)
|
| 90 |
+
amd_desktop_df.rename(columns={"Default TDP": "TDP"}, inplace=True)
|
| 91 |
+
amd_desktop_df = amd_desktop_df[["Name", "TDP"]].copy()
|
| 92 |
+
amd_desktop_df["TDP"] = amd_desktop_df["TDP"].apply(extract_tdp_value)
|
| 93 |
+
|
| 94 |
+
amd_server_df["Name"] = amd_server_df["Name"].apply(clean_amd_cpu_name)
|
| 95 |
+
amd_server_df = amd_server_df[["Name", "Default TDP"]].copy()
|
| 96 |
+
amd_server_df.rename(columns={"Default TDP": "TDP"}, inplace=True)
|
| 97 |
+
amd_server_df["TDP"] = amd_server_df["TDP"].apply(extract_tdp_value)
|
| 98 |
+
|
| 99 |
+
# Concatenate all CPU data
|
| 100 |
+
all_cpus_df = pd.concat([intel_df, amd_desktop_df, amd_server_df], ignore_index=True)
|
| 101 |
+
|
| 102 |
+
print(
|
| 103 |
+
f"Total CPUs found: {len(all_cpus_df)} using Intel {len(intel_df)}, AMD Desktop {len(amd_desktop_df)}, and AMD Server {len(amd_server_df)} datasets."
|
| 104 |
+
)
|
| 105 |
+
|
| 106 |
+
# Ensure TDP is numeric, coercing errors to NaN (which will be dropped)
|
| 107 |
+
all_cpus_df["TDP"] = pd.to_numeric(all_cpus_df["TDP"], errors="coerce")
|
| 108 |
+
all_cpus_df.dropna(subset=["Name", "TDP"], inplace=True)
|
| 109 |
+
all_cpus_df["TDP"] = all_cpus_df["TDP"].astype(int)
|
| 110 |
+
|
| 111 |
+
|
| 112 |
+
# Read existing CPU power data
|
| 113 |
+
try:
|
| 114 |
+
cpu_power_df = pd.read_csv(cpu_power_file)
|
| 115 |
+
except FileNotFoundError:
|
| 116 |
+
print(f"FATAL ERROR: cpu_power.csv not found at {cpu_power_file}. Exiting.")
|
| 117 |
+
exit(1)
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
# Ensure 'Name' column is string type for merging
|
| 121 |
+
cpu_power_df["Name"] = cpu_power_df["Name"].astype(str)
|
| 122 |
+
all_cpus_df["Name"] = all_cpus_df["Name"].astype(str)
|
| 123 |
+
|
| 124 |
+
# Remove duplicates from cpu_power_df before setting index
|
| 125 |
+
cpu_power_df.drop_duplicates(subset=["Name"], keep="first", inplace=True)
|
| 126 |
+
# Remove duplicates from all_cpus_df before setting index to avoid issues if source data also has dupes
|
| 127 |
+
all_cpus_df.drop_duplicates(subset=["Name"], keep="first", inplace=True)
|
| 128 |
+
|
| 129 |
+
# Set 'Name' as index for easier update/merge
|
| 130 |
+
cpu_power_df.set_index("Name", inplace=True)
|
| 131 |
+
all_cpus_df.set_index("Name", inplace=True)
|
| 132 |
+
|
| 133 |
+
# Update existing entries and add new ones
|
| 134 |
+
# For CPUs in all_cpus_df, their TDP will overwrite existing TDP in cpu_power_df
|
| 135 |
+
# New CPUs from all_cpus_df will be added
|
| 136 |
+
cpu_power_df.update(all_cpus_df)
|
| 137 |
+
# Add CPUs from all_cpus_df that were not in cpu_power_df
|
| 138 |
+
new_cpus = all_cpus_df[~all_cpus_df.index.isin(cpu_power_df.index)]
|
| 139 |
+
combined_df = pd.concat([cpu_power_df, new_cpus])
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
# Reset index and sort
|
| 143 |
+
combined_df.reset_index(inplace=True)
|
| 144 |
+
combined_df.sort_values(by="Name", inplace=True, kind="mergesort")
|
| 145 |
+
|
| 146 |
+
# Drop duplicates, keeping the first occurrence (which would be the updated/new one if there were any issues)
|
| 147 |
+
combined_df.drop_duplicates(subset=["Name"], keep="first", inplace=True)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
# Save the updated dataframe
|
| 151 |
+
try:
|
| 152 |
+
combined_df.to_csv(cpu_power_file, index=False)
|
| 153 |
+
print(
|
| 154 |
+
f"Successfully updated {cpu_power_file} with data from Intel and AMD CPU datasets."
|
| 155 |
+
)
|
| 156 |
+
except Exception as e:
|
| 157 |
+
print(f"Error writing to {cpu_power_file}: {e}")
|
| 158 |
+
|
| 159 |
+
print(f"Script finished. {cpu_power_file} has been updated.")
|
codecarbon/data/hardware/cpu_load_profiling/AMD_EPYC_8024P_8C/compare_cpu_load_and_RAPL-all_cores-AMD_EPYC_8024P_8-Core_Processor-2025-01-14-tasks.csv
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
codecarbon/data/hardware/cpu_load_profiling/AMD_EPYC_8024P_8C/compare_cpu_load_and_RAPL-all_cores-AMD_EPYC_8024P_8-Core_Processor-2025-01-14.csv
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
task_name,load_type,cpu_name,timestamp,cores_used,cpu_load,temperature,cpu_freq,rapl_power,rapl_energy,estimated_power,estimated_energy,tapo_power,tapo_energy,tapo_time_delta,duration
|
| 2 |
+
Load for 0 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870539.3604305,16,0.6,0,1588.8038125,0.5890910446092622,0.0001549484709031223,0.5283870967741936,4.483109622193541e-06,0,0,0,30.545820467999988
|
| 3 |
+
Load for 10 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870570.4132967,16,10.0,0,1499.2493125,18.614618427174943,0.0002482180077409144,9.351290322580647,7.94934203722469e-05,0,0,0,30.604371506000007
|
| 4 |
+
Load for 20 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870601.5247905,16,20.0,0,1710.87575,29.50062862301284,0.0003278735881319947,18.08709677419355,0.00015376875545155633,0,0,0,30.60747165600003
|
| 5 |
+
Load for 30 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870632.6398633,16,30.0,0,2275.4458125,38.665937352398046,0.00035451283138781577,26.628387096774198,0.000226326359785935,0,0,0,30.59898082199993
|
| 6 |
+
Load for 40 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870663.7467482,16,40.3,0,2005.7899375,41.7532422053059,0.000365986424177794,35.12903225806452,0.0002984793734458876,0,0,0,30.587945687
|
| 7 |
+
Load for 50 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870694.8418806,16,50.0,0,2995.3906875,43.218847417139216,0.0004040316335028266,43.96064516129032,0.00037339789414168585,0,0,0,30.579274994000002
|
| 8 |
+
Load for 60 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870725.9287038,16,64.6,0,2995.0565625,47.60235461601638,0.0004135376972187821,52.64709677419356,0.0004470785513329841,0,0,0,30.572279641000023
|
| 9 |
+
Load for 70 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870757.008383,16,70.2,0,2995.4159375,48.71374809013383,0.00041818504176998825,61.33064516129033,0.0005208395157953634,0,0,0,30.573280777000036
|
| 10 |
+
Load for 80 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870788.0900218,16,80.0,0,2995.0515,49.29431270782221,0.00043202708951028436,69.78193548387098,0.0005926033291364812,0,0,0,30.572722531999943
|
| 11 |
+
Load for 90 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870819.169809,16,89.4,0,2995.3314375,50.71795701044753,0.00039116028792797984,78.46548387096773,0.0006661357492079613,0,0,0,30.563372235000088
|
| 12 |
+
Load for 100 threads or % load on all_cores,all_cores,AMD EPYC 8024P 8-Core Processor,1736870850.241218,16,100.0,0,2960.06425,46.07999203334885,0.0003927146597270323,86.62645161290322,0.0007355714738463658,0,0,0,30.57010326000011
|
codecarbon/data/hardware/cpu_load_profiling/AMD_EPYC_8024P_8C/compare_cpu_load_and_RAPL-some_cores-AMD_EPYC_8024P_8-Core_Processor-2025-01-14-tasks.csv
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
codecarbon/data/hardware/cpu_load_profiling/AMD_EPYC_8024P_8C/compare_cpu_load_and_RAPL-some_cores-AMD_EPYC_8024P_8-Core_Processor-2025-01-14.csv
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
task_name,load_type,cpu_name,timestamp,cores_used,cpu_load,temperature,cpu_freq,rapl_power,rapl_energy,estimated_power,estimated_energy,tapo_power,tapo_energy,tapo_time_delta,duration
|
| 2 |
+
Load for 0 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736870885.4314823,0,0.0,0,1573.6895625,0.570341609175781,0.0001498387148708754,0.4006451612903227,3.3952651785241804e-06,0,0,0,30.509340853999902
|
| 3 |
+
Load for 1 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736870916.4484718,1,6.8,0,1674.0149375,18.32137992981586,0.0003186004209912441,6.143225806451613,5.213020505654175e-05,0,0,0,30.548963089000154
|
| 4 |
+
Load for 3 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736870947.5048661,3,18.6,0,1875.329125,37.67548313872943,0.00035289236703589175,16.79806451612903,0.00014253898582775382,0,0,0,30.54814376499985
|
| 5 |
+
Load for 4 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736870978.5606444,4,24.8,0,1917.428375,41.64788408234253,0.0003687826669703416,22.357741935483872,0.00018972382129295778,0,0,0,30.549244971999997
|
| 6 |
+
Load for 6 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736871009.6169264,6,37.3,0,2390.904875,43.577488003823284,0.00040014462511544363,33.12870967741936,0.0002811189356871732,0,0,0,30.54906796199998
|
| 7 |
+
Load for 8 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736871040.6735368,8,50.3,0,2577.975125,47.22484688134498,0.0004186007634914522,43.899677419354845,0.00037251962926638875,0,0,0,30.54776646800019
|
| 8 |
+
Load for 9 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736871071.7283158,9,56.2,0,2552.9630625,49.348595570337984,0.00042330994975879783,49.53193548387097,0.00042031326421113654,0,0,0,30.549575562999962
|
| 9 |
+
Load for 11 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736871102.7853847,11,71.6,0,2786.4235,49.929496571226025,0.0004353003696289052,60.29419354838709,0.0005116486368893932,0,0,0,30.549821148999854
|
| 10 |
+
Load for 12 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736871133.8423305,12,78.1,0,2864.8995625,51.11155331744621,0.0003866883171281862,65.8741935483871,0.0005590049861902901,0,0,0,30.550244901000042
|
| 11 |
+
Load for 14 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736871164.901577,14,87.5,0,2994.7883125,45.597339246911396,0.00039462264042008227,76.74677419354839,0.0006513229867146689,0,0,0,30.552348375000065
|
| 12 |
+
Load for 16 threads or % load on some_cores,some_cores,AMD EPYC 8024P 8-Core Processor,1736871195.9626908,16,100.0,0,2953.2051875,46.50666589353752,0.00039668247206794613,87.01548387096774,0.0007384650344527547,0,0,0,30.552532602999918
|
codecarbon/data/hardware/cpu_load_profiling/AMD_Threadripper/compare_cpu_load_and_RAPL-all_cores-AMD_Ryzen_Threadripper_1950X_16-Core_Processor-2025-01-14.csv
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
task_name,load_type,cpu_name,timestamp,cores_used,cpu_load,temperature,cpu_freq,rapl_power,rapl_energy,estimated_power,estimated_energy,tapo_power,tapo_energy,tapo_time_delta,duration
|
| 2 |
+
Load for 0 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861292.1865184,32,2.8,34.0,2332.872375,1.376693725703893,0.00036348698592824497,2.685483870967742,2.287107937566501e-05,115,0,25.784160137176514,30.67482220400052
|
| 3 |
+
Load for 10 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861323.3733351,32,13.9,39.0,2398.1069375,43.30157205175239,0.0005287301286782094,18.41632258064516,0.00015699294566882027,147,2,31.239955186843872,30.690144125997904
|
| 4 |
+
Load for 20 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861354.606225,32,23.2,49.0,2525.59284375,62.548275592287716,0.000667400991698144,51.95264516129033,0.0004430374025184006,198,1,31.248691082000732,30.67295572799776
|
| 5 |
+
Load for 30 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861385.796707,32,36.4,46.0,2797.5584375,79.17104774627222,0.0009009795239774861,82.75797881016943,0.0007061364594770959,226,2,31.160773754119873,30.710970439999073
|
| 6 |
+
Load for 40 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861417.028149,32,44.8,51.0,2821.1256562500002,106.32788732711822,0.0010895405520484095,121.69003144108179,0.001039181644778305,257,2,31.274537086486816,30.744163438001124
|
| 7 |
+
Load for 50 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861448.2934384,32,53.1,52.0,2987.12765625,128.12680031791092,0.0012224324344729436,150.75142340191675,0.0012868445490575916,219,2,31.180025577545166,30.71990360300333
|
| 8 |
+
Load for 60 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861479.5261245,32,66.0,56.0,3690.57340625,144.1489018144105,0.0014702612339858234,160.82284379438934,0.0013702119021750114,285,2,31.250231504440308,30.68199840700254
|
| 9 |
+
Load for 70 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861510.718988,32,72.1,57.0,3576.53553125,172.4348439188416,0.0014511648695420768,166.20343002665635,0.001415799954084005,278,3,31.177345514297485,30.66615740099951
|
| 10 |
+
Load for 80 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861541.892845,32,83.1,56.0,3418.62696875,170.32448690508448,0.0014419653435713518,169.0462755144238,0.001440005981082607,279,2,31.25270128250122,30.67268269300257
|
| 11 |
+
Load for 90 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861573.0767784,32,91.7,56.0,3357.159875,169.17512402821018,0.001424203854084394,170.99110652598637,0.0014592032859312692,277,2,31.135616064071655,30.722248964000755
|
| 12 |
+
Load for 100 threads or % load on all_cores,all_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861604.3297272,32,99.7,56.0,3323.42371875,166.8914474009169,0.0014241745394776087,172.01108915577154,0.0014670329755684629,278,3,31.260193586349487,30.684765958001663
|
codecarbon/data/hardware/cpu_load_profiling/AMD_Threadripper/compare_cpu_load_and_RAPL-some_cores-AMD_Ryzen_Threadripper_1950X_16-Core_Processor-2025-01-14.csv
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
task_name,load_type,cpu_name,timestamp,cores_used,cpu_load,temperature,cpu_freq,rapl_power,rapl_energy,estimated_power,estimated_energy,tapo_power,tapo_energy,tapo_time_delta,duration
|
| 2 |
+
Load for 0 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861645.8957796,0,5.0,44.0,2404.504125,1.4314313929445108,0.00037612030867378377,2.5403225806451615,2.1533075069456695e-05,161,2,41.54746890068054,30.50736453400168
|
| 3 |
+
Load for 3 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861676.92222,3,12.2,53.0,2470.4883125,45.38482572705677,0.000643388347349155,15.636774193548389,0.00013281317053516283,159,1,31.027068614959717,30.60917342099856
|
| 4 |
+
Load for 6 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861708.0628958,6,22.9,57.0,2782.765875,76.2361648967495,0.0007852407877754612,45.20264516129032,0.00038409021052205965,178,2,31.136895179748535,30.582065591002902
|
| 5 |
+
Load for 9 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861739.1693892,9,32.2,53.0,2985.71678125,93.3325909425021,0.0010383771248677017,79.43787901061218,0.0006748331769033504,266,2,31.1038601398468,30.566226797000127
|
| 6 |
+
Load for 12 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861770.2447922,12,41.4,56.0,3206.83459375,123.02110940943629,0.0012440137061823899,106.22233175845183,0.000901886908494226,278,2,31.06801199913025,30.572869749998063
|
| 7 |
+
Load for 16 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861801.3405495,16,52.0,59.0,3497.22140625,147.40291619865533,0.0014847857724110004,151.95548639522778,0.0012909726593646263,278,2,31.09264326095581,30.595551153000997
|
| 8 |
+
Load for 19 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861832.4449117,19,64.0,61.0,3411.51403125,174.78376979270854,0.001472625799905254,161.29498553839264,0.0013694488571545866,279,3,31.248048543930054,30.567659471998923
|
| 9 |
+
Load for 22 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861863.553106,22,73.1,60.0,3552.37396875,173.30973054466918,0.0014398759664831836,165.96767419530283,0.0014106243805873664,324,2,31.02893352508545,30.57063357000152
|
| 10 |
+
Load for 25 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861894.641952,25,80.1,60.0,3314.47165625,169.42739506124113,0.0014223668401147846,169.16041577918944,0.0014371547304600357,326,3,31.0912823677063,30.577015545000904
|
| 11 |
+
Load for 28 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861925.7400923,28,92.5,59.0,3611.6851875,167.4199618733835,0.0014106022938975976,170.8023391866958,0.0014508931444192387,280,3,31.036678552627563,30.5716582189998
|
| 12 |
+
Load for 32 threads or % load on some_cores,some_cores,AMD Ryzen Threadripper 1950X 16-Core Processor,1736861956.8230855,32,100.0,58.0,3399.25659375,166.03346252141944,0.0014042897956531592,172.11738734560865,0.0014619673561903947,290,2,31.138123273849487,30.579071764001128
|
codecarbon/data/hardware/cpu_load_profiling/E3-1240/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14-tasks.csv
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
codecarbon/data/hardware/cpu_load_profiling/E3-1240/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14.csv
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
task_name,load_type,cpu_name,timestamp,cores_used,cpu_load,temperature,cpu_freq,rapl_power,rapl_energy,estimated_power,estimated_energy,tapo_power,tapo_energy,tapo_time_delta,duration
|
| 2 |
+
Load for 0 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866099.9980605,8,2.5,49.0,1599.327875,0.1762793799621185,4.6355697362304715e-05,0.9059032258064517,7.684335073074023e-06,0,0,0,30.538775300999987
|
| 3 |
+
Load for 10 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866131.0446987,8,12.5,49.8,1599.292875,5.5088107550388195,5.799798473168395e-05,7.701290322580645,6.536165501667947e-05,0,0,0,30.556003262000104
|
| 4 |
+
Load for 20 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866162.1088045,8,21.8,49.8,1615.887,6.874427700098117,6.887324732077552e-05,14.45883870967742,0.00012281514661734017,0,0,0,30.5808577480002
|
| 5 |
+
Load for 30 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866193.198372,8,32.5,51.2,1608.707625,8.150962966608036,8.008787768136114e-05,21.122903225806454,0.00017917736530554418,0,0,0,30.538505429999987
|
| 6 |
+
Load for 40 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866224.2449238,8,41.2,52.6,1774.674,9.590357335248587,0.00011939784885153792,27.519870967741934,0.00023356720765311314,0,0,0,30.55596754599992
|
| 7 |
+
Load for 50 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866255.3088953,8,51.3,67.0,3691.3945,14.386126401140913,0.0002032038075629114,34.119387096774204,0.0002894370308469203,0,0,0,30.540959523999845
|
| 8 |
+
Load for 60 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866286.357926,8,60.8,67.8,3203.470375,24.131781439057242,0.0002502017190501027,40.80125806451613,0.00034607542561449563,0,0,0,30.536806867999985
|
| 9 |
+
Load for 70 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866317.402762,8,71.3,82.6,3592.053,29.980918434149974,0.0003775369217515201,47.27390322580646,0.0004010445097183033,0,0,0,30.541943295000237
|
| 10 |
+
Load for 80 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866348.452758,8,80.2,86.0,3594.7035,44.58692502781162,0.0004000440664238894,53.58183870967742,0.00045449143269400997,0,0,0,30.537735556999905
|
| 11 |
+
Load for 90 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866379.4978347,8,88.9,84.6,3591.723,47.199718258502074,0.0004102256151246736,60.172451612903224,0.0005103165358412896,0,0,0,30.533969553000134
|
| 12 |
+
Load for 100 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866410.5401917,8,100.0,85.2,3591.759875,48.40222176814008,0.00041915237032163,66.44032258064517,0.0005636082589397366,0,0,0,30.540446279000207
|
codecarbon/data/hardware/cpu_load_profiling/E3-1240/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14-tasks.csv
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
codecarbon/data/hardware/cpu_load_profiling/E3-1240/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14.csv
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
task_name,load_type,cpu_name,timestamp,cores_used,cpu_load,temperature,cpu_freq,rapl_power,rapl_energy,estimated_power,estimated_energy,tapo_power,tapo_energy,tapo_time_delta,duration
|
| 2 |
+
Load for 0 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866451.8262937,0,2.5,59.4,1622.370375,0.1829557095380892,4.8066226786283583e-05,1.175225806451613,9.959652394347182e-06,0,0,0,30.510028410999894
|
| 3 |
+
Load for 1 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866482.8443036,1,13.7,66.8,2909.180125,6.1681087430444785,0.00017863574624181477,8.820870967741937,7.480994601777782e-05,0,0,0,30.532809745000122
|
| 4 |
+
Load for 2 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866513.885087,2,25.3,74.4,3154.836875,21.330531392160513,0.0002490961023322788,17.167645161290324,0.00014560237809553166,0,0,0,30.533378567
|
| 5 |
+
Load for 3 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866544.926259,3,38.8,82.4,3379.551,29.60393014529158,0.000310693952443852,25.54335483870968,0.00021663643725879813,0,0,0,30.533274188000178
|
| 6 |
+
Load for 4 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866575.9672496,4,50.0,90.6,3093.732375,36.830415975414766,0.000362681275978122,33.9123870967742,0.00028761470732627394,0,0,0,30.533258208000007
|
| 7 |
+
Load for 5 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866607.008547,5,60.8,93.8,3591.593,42.818970213978986,0.00037760179374785995,41.602548387096775,0.0003528519844455608,0,0,0,30.534384863000014
|
| 8 |
+
Load for 6 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866638.0509386,6,76.2,90.0,3342.7835,44.592887191004166,0.0003967921685445921,50.56587096774194,0.00042885450421531923,0,0,0,30.533063157000015
|
| 9 |
+
Load for 7 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866669.0927322,7,88.7,83.0,3591.758125,46.8127764264249,0.0004043059895556436,59.023935483870964,0.0005006315188387323,0,0,0,30.53561314799981
|
| 10 |
+
Load for 8 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736866700.138663,8,100.0,84.2,3591.768875,47.73004219703574,0.0004210827754770616,66.56941935483871,0.0005645897030578939,0,0,0,30.5334539090004
|
codecarbon/data/hardware/cpu_load_profiling/E5-1240/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14-tasks.csv
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
codecarbon/data/hardware/cpu_load_profiling/E5-1240/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14.csv
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
task_name,load_type,cpu_name,timestamp,cores_used,cpu_load,temperature,cpu_freq,rapl_power,rapl_energy,estimated_power,estimated_energy,tapo_power,tapo_energy,tapo_time_delta,duration
|
| 2 |
+
Load for 0 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864264.566133,8,2.5,55.4,1597.2875,0.24045452886021762,6.321467779392322e-05,0.9437419354838712,8.00299163331743e-06,0,0,0,30.530655949999982
|
| 3 |
+
Load for 10 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864295.6047955,8,10.3,56.0,1608.7538749999999,7.538504597340449,8.54672550404164e-05,7.728000000000001,6.558665694214691e-05,0,0,0,30.552170786000033
|
| 4 |
+
Load for 20 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864326.6656816,8,21.3,56.6,1596.3545,10.155731937011202,0.00010787949074796827,14.314161290322582,0.00012158928507307066,0,0,0,30.58094489799987
|
| 5 |
+
Load for 30 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864357.7544494,8,31.6,57.4,1597.23125,12.777656622991184,0.00012821319923714356,21.04277419354839,0.0001784956265845537,0,0,0,30.539114385999937
|
| 6 |
+
Load for 40 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864388.8024442,8,41.3,58.6,2180.2647500000003,15.395214417842357,0.0002021824959125328,27.571064516129034,0.00023397646594410047,0,0,0,30.551980603000175
|
| 7 |
+
Load for 50 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864419.8624222,8,51.9,61.8,1793.815125,24.21258198840792,0.0003044742055236128,34.221774193548384,0.00029040600192907343,0,0,0,30.55149350800002
|
| 8 |
+
Load for 60 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864450.9216642,8,62.0,78.2,3588.65625,36.60190500045977,0.0004947912699993662,40.71445161290323,0.00034540601126875473,0,0,0,30.542951248999998
|
| 9 |
+
Load for 70 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864481.9730074,8,70.0,87.6,3591.77275,59.21681786864419,0.0007304884855014321,47.18487096774194,0.0004002782981833257,0,0,0,30.540747797999984
|
| 10 |
+
Load for 80 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864513.0216124,8,80.0,92.4,3591.752625,86.28703440247716,0.0007775349425830115,53.49503225806452,0.00045366902355707455,0,0,0,30.532312602000047
|
| 11 |
+
Load for 90 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864544.062235,8,89.6,93.8,3591.755875,91.60016243312562,0.0007568507235356488,58.56987096774195,0.0004968053414603382,0,0,0,30.538087567000048
|
| 12 |
+
Load for 100 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864575.1117647,8,84.6,93.4,3591.759375,89.35810683301246,0.0007923197952442191,63.940741935483864,0.0005423658388764648,0,0,0,30.537738765000086
|
codecarbon/data/hardware/cpu_load_profiling/E5-1240/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14-tasks.csv
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
codecarbon/data/hardware/cpu_load_profiling/E5-1240/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E3-1240_V2_@_3.40GHz-2025-01-14.csv
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
task_name,load_type,cpu_name,timestamp,cores_used,cpu_load,temperature,cpu_freq,rapl_power,rapl_energy,estimated_power,estimated_energy,tapo_power,tapo_energy,tapo_time_delta,duration
|
| 2 |
+
Load for 0 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864616.3802829,0,1.3,64.4,1722.9547499999999,0.24348604948238767,6.396986895363006e-05,0.9637741935483872,8.167858581407357e-06,0,0,0,30.510393207000106
|
| 3 |
+
Load for 1 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864647.3992167,1,13.8,71.8,2908.105125,8.546889319740076,0.00032664317798099946,8.972225806451613,7.609811727004668e-05,0,0,0,30.53422949700007
|
| 4 |
+
Load for 2 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864678.4420338,2,25.0,77.6,2677.836875,39.05248608945464,0.00046885920175372686,17.312322580645162,0.00014683093029187213,0,0,0,30.53335141499997
|
| 5 |
+
Load for 3 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864709.4832304,3,38.8,82.0,3093.805875,55.74034273843472,0.00058967813118657,25.610129032258065,0.0002172003980805138,0,0,0,30.53297458499992
|
| 6 |
+
Load for 4 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864740.5242574,4,51.3,89.4,3592.125625,69.91521339597362,0.000691733977831184,34.019225806451615,0.0002885280151346684,0,0,0,30.534353922000037
|
| 7 |
+
Load for 5 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864771.5664937,5,60.0,94.6,3591.77,81.68108269518869,0.0007244284862089941,41.13290322580646,0.0003488550486577481,0,0,0,30.533480329999975
|
| 8 |
+
Load for 6 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864802.6076632,6,70.9,92.6,3591.811375,85.51117470400919,0.0007499405605075199,49.79129032258064,0.0004222963451957981,0,0,0,30.534298728000067
|
| 9 |
+
Load for 7 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864833.6504998,7,88.9,90.6,3591.7715,88.5859467712891,0.000793641966024175,59.197548387096774,0.0005020658069015539,0,0,0,30.533413398999983
|
| 10 |
+
Load for 8 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E3-1240 V2 @ 3.40GHz,1736864864.6926847,8,100.0,90.6,3591.7475,93.67184784435268,0.0008193529074262459,66.63396774193548,0.000565153702695967,0,0,0,30.53452582199975
|
codecarbon/data/hardware/cpu_load_profiling/E5-2620/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E5-2620_v3_@_2.40GHz-2025-01-14-tasks.csv
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
codecarbon/data/hardware/cpu_load_profiling/E5-2620/compare_cpu_load_and_RAPL-all_cores-Intel(R)_Xeon(R)_CPU_E5-2620_v3_@_2.40GHz-2025-01-14.csv
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
task_name,load_type,cpu_name,timestamp,cores_used,cpu_load,temperature,cpu_freq,rapl_power,rapl_energy,estimated_power,estimated_energy,tapo_power,tapo_energy,tapo_time_delta,duration
|
| 2 |
+
Load for 0 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736851743.3478487,24,0.0,32.92857142857143,1666.6777916666667,0.5133866472185064,0.00013516682896670684,0.13709677419354838,1.1643220985035955e-06,0,0,0,30.57596656700025
|
| 3 |
+
Load for 10 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736851774.4329672,24,10.0,34.0,1395.8670833333333,16.393231698147034,0.0002615093458739823,16.70387096774194,0.00014209152257347633,0,0,0,30.625665163999656
|
| 4 |
+
Load for 20 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736851805.5679224,24,20.0,35.214285714285715,1200.067875,30.981249858901204,0.00032480096234055456,33.150000000000006,0.00028184237688695906,0,0,0,30.609375409999302
|
| 5 |
+
Load for 30 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736851836.6865406,24,30.0,36.42857142857143,1200.0924166666666,38.4109895669274,0.0003803408392724292,49.54677419354839,0.00042138001590360423,0,0,0,30.619102634000228
|
| 6 |
+
Load for 40 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736851867.8147955,24,40.5,39.0,1359.3699583333334,45.28221173134997,0.0005286525493105876,65.92709677419354,0.000560481283428218,0,0,0,30.607923018999827
|
| 7 |
+
Load for 50 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736851898.9319813,24,50.2,40.07142857142857,1675.1815833333333,62.15733970891361,0.0005226188955947848,82.30741935483871,0.0006995284841773753,0,0,0,30.598696191000272
|
| 8 |
+
Load for 60 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736851930.0399046,24,60.0,42.42857142857143,2081.6238333333336,61.94885605758223,0.0006439153740207745,98.64935483870968,0.0008383901874825152,0,0,0,30.59755781199965
|
| 9 |
+
Load for 70 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736851961.1466608,24,69.9,47.42857142857143,2600.2822499999997,76.92334580239137,0.0009501084453639348,114.92,0.0009769654159054015,0,0,0,30.606379566000214
|
| 10 |
+
Load for 80 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736851992.2622006,24,80.8,49.714285714285715,2606.1148333333335,111.88460818853675,0.0009838415673504054,131.25645161290325,0.0011155469922320095,0,0,0,30.59841364100066
|
| 11 |
+
Load for 90 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852023.370749,24,89.7,51.642857142857146,2566.944875,115.80752337627442,0.0009980875206916026,147.63129032258067,0.0012548379009832316,0,0,0,30.60126471300009
|
| 12 |
+
Load for 100 threads or % load on all_cores,all_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852054.4802783,24,99.6,51.214285714285715,2400.266,117.01747308959027,0.0008921996457035876,163.77032258064517,0.001391876641844674,0,0,0,30.598267295999904
|
codecarbon/data/hardware/cpu_load_profiling/E5-2620/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E5-2620_v3_@_2.40GHz-2025-01-14-tasks.csv
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
|
codecarbon/data/hardware/cpu_load_profiling/E5-2620/compare_cpu_load_and_RAPL-some_cores-Intel(R)_Xeon(R)_CPU_E5-2620_v3_@_2.40GHz-2025-01-14.csv
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
task_name,load_type,cpu_name,timestamp,cores_used,cpu_load,temperature,cpu_freq,rapl_power,rapl_energy,estimated_power,estimated_energy,tapo_power,tapo_energy,tapo_time_delta,duration
|
| 2 |
+
Load for 0 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852095.9750729,0,0.0,42.142857142857146,1479.1971666666668,0.5065285278727721,0.00013308117646485332,0.10419354838709678,8.830525274655887e-07,0,0,0,30.511303407000014
|
| 3 |
+
Load for 2 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852126.9954355,2,8.7,41.0,1316.7375833333333,16.312251102677653,0.00029392221235980537,13.852258064516132,0.00011764077408649119,0,0,0,30.57471732799968
|
| 4 |
+
Load for 4 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852158.079285,4,17.0,40.142857142857146,1212.5389583333333,34.76638021452525,0.00033555079427375484,27.671612903225803,0.00023500116479415815,0,0,0,30.57451805099936
|
| 5 |
+
Load for 7 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852189.1629093,7,29.0,41.214285714285715,1361.3113333333333,39.833438799011766,0.0004206977390579236,48.15387096774193,0.00040898022458755426,0,0,0,30.57759773700036
|
| 6 |
+
Load for 9 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852220.2496197,9,37.9,41.0,1200.0558333333333,49.54412283036035,0.00042417380406099825,61.92387096774194,0.0005259465888520012,0,0,0,30.577943293000317
|
| 7 |
+
Load for 12 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852251.3367052,12,50.0,42.214285714285715,1254.2069583333334,50.48931782182756,0.0005688961442832166,82.45548387096774,0.0007003238567262363,0,0,0,30.577464056999816
|
| 8 |
+
Load for 14 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852282.4232924,14,58.7,43.642857142857146,1400.1012083333335,67.12624394179127,0.0006075904494053028,96.15419354838708,0.0008166565664626951,0,0,0,30.5767449519999
|
| 9 |
+
Load for 16 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852313.508811,16,66.7,44.642857142857146,1458.4309166666665,71.54867753236186,0.0006107800055680582,109.87483870967742,0.0009332072212445437,0,0,0,30.57744154000011
|
| 10 |
+
Load for 19 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852344.5952287,19,79.2,45.92857142857143,1721.068375,72.0308325399428,0.0006425051590037145,130.43387096774194,0.0011079623452897123,0,0,0,30.58129966099932
|
| 11 |
+
Load for 21 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852375.6856108,21,87.5,46.214285714285715,1712.7019166666666,75.74636452660306,0.0006716593131603499,144.1051612903226,0.001224281732537364,0,0,0,30.589186831000006
|
| 12 |
+
Load for 24 threads or % load on some_cores,some_cores,Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz,1736852406.785565,24,100.0,48.07142857142857,2250.244458333333,79.60567601760141,0.0008177076741656131,164.37354838709678,0.0013961793068869984,0,0,0,30.57898776299953
|
codecarbon/data/hardware/cpu_power.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
codecarbon/data/private_infra/2016/canada_energy_mix.json
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"british columbia": {
|
| 3 |
+
"naturalGas": 1.1,
|
| 4 |
+
"nuclear": 0.0,
|
| 5 |
+
"petroleum": 0.7,
|
| 6 |
+
"biomass": 6.4,
|
| 7 |
+
"coal": 0.0,
|
| 8 |
+
"other": 0.0,
|
| 9 |
+
"solar": 0.0,
|
| 10 |
+
"tidal": 0.0,
|
| 11 |
+
"total": 100,
|
| 12 |
+
"wind": 1.3,
|
| 13 |
+
"hydro": 90.5
|
| 14 |
+
},
|
| 15 |
+
"newfoundland and labrador": {
|
| 16 |
+
"naturalGas": 0.7,
|
| 17 |
+
"nuclear": 0.0,
|
| 18 |
+
"petroleum": 4.8,
|
| 19 |
+
"biomass": 0.3,
|
| 20 |
+
"coal": 0.0,
|
| 21 |
+
"other": 0.0,
|
| 22 |
+
"solar": 0.0,
|
| 23 |
+
"tidal": 0.0,
|
| 24 |
+
"total": 100,
|
| 25 |
+
"wind": 0.5,
|
| 26 |
+
"hydro": 93.7
|
| 27 |
+
},
|
| 28 |
+
"saskatchewan": {
|
| 29 |
+
"naturalGas": 35.7,
|
| 30 |
+
"nuclear": 0.0,
|
| 31 |
+
"petroleum": 0.0,
|
| 32 |
+
"biomass": 0.0,
|
| 33 |
+
"coal": 46.6,
|
| 34 |
+
"other": 0.0,
|
| 35 |
+
"solar": 0.1,
|
| 36 |
+
"tidal": 0.0,
|
| 37 |
+
"total": 99.9,
|
| 38 |
+
"wind": 3.8,
|
| 39 |
+
"hydro": 13.7
|
| 40 |
+
},
|
| 41 |
+
"prince edward island": {
|
| 42 |
+
"naturalGas": 0.0,
|
| 43 |
+
"nuclear": 0.0,
|
| 44 |
+
"petroleum": 1.1,
|
| 45 |
+
"biomass": 0.7,
|
| 46 |
+
"coal": 0.0,
|
| 47 |
+
"other": 0.0,
|
| 48 |
+
"solar": 0.3,
|
| 49 |
+
"tidal": 0.0,
|
| 50 |
+
"total": 100,
|
| 51 |
+
"wind": 97.9,
|
| 52 |
+
"hydro": 0.0
|
| 53 |
+
},
|
| 54 |
+
"ontario": {
|
| 55 |
+
"naturalGas": 5.2,
|
| 56 |
+
"nuclear": 58.6,
|
| 57 |
+
"petroleum": 0.1,
|
| 58 |
+
"biomass": 1.3,
|
| 59 |
+
"coal": 0.0,
|
| 60 |
+
"other": 0.0,
|
| 61 |
+
"solar": 2.2,
|
| 62 |
+
"tidal": 0.0,
|
| 63 |
+
"total": 100,
|
| 64 |
+
"wind": 6.7,
|
| 65 |
+
"hydro": 25.9
|
| 66 |
+
},
|
| 67 |
+
"nova scotia": {
|
| 68 |
+
"naturalGas": 14.3,
|
| 69 |
+
"nuclear": 0.0,
|
| 70 |
+
"petroleum": 12.2,
|
| 71 |
+
"biomass": 4.9,
|
| 72 |
+
"coal": 47.9,
|
| 73 |
+
"other": 0.0,
|
| 74 |
+
"solar": 0.03,
|
| 75 |
+
"tidal": 0.2,
|
| 76 |
+
"total": 100.13,
|
| 77 |
+
"wind": 11.8,
|
| 78 |
+
"hydro": 8.8
|
| 79 |
+
},
|
| 80 |
+
"quebec": {
|
| 81 |
+
"naturalGas": 0.1,
|
| 82 |
+
"nuclear": 0.0,
|
| 83 |
+
"petroleum": 0.2,
|
| 84 |
+
"biomass": 0.8,
|
| 85 |
+
"coal": 0.0,
|
| 86 |
+
"other": 0.0,
|
| 87 |
+
"solar": 0.0,
|
| 88 |
+
"tidal": 0.0,
|
| 89 |
+
"total": 100,
|
| 90 |
+
"wind": 3.9,
|
| 91 |
+
"hydro": 95.0
|
| 92 |
+
},
|
| 93 |
+
"alberta": {
|
| 94 |
+
"naturalGas": 42.2,
|
| 95 |
+
"nuclear": 0.0,
|
| 96 |
+
"petroleum": 2.6,
|
| 97 |
+
"biomass": 2.2,
|
| 98 |
+
"coal": 44.9,
|
| 99 |
+
"other": 0.2,
|
| 100 |
+
"solar": 0.1,
|
| 101 |
+
"tidal": 0.0,
|
| 102 |
+
"total": 100.1,
|
| 103 |
+
"wind": 5.4,
|
| 104 |
+
"hydro": 2.5
|
| 105 |
+
},
|
| 106 |
+
"manitoba": {
|
| 107 |
+
"naturalGas": 0.0,
|
| 108 |
+
"nuclear": 0.0,
|
| 109 |
+
"petroleum": 0.2,
|
| 110 |
+
"biomass": 0.1,
|
| 111 |
+
"coal": 0.1,
|
| 112 |
+
"other": 0.0,
|
| 113 |
+
"solar": 0.0,
|
| 114 |
+
"tidal": 0.0,
|
| 115 |
+
"total": 99.9,
|
| 116 |
+
"wind": 2.7,
|
| 117 |
+
"hydro": 96.8
|
| 118 |
+
},
|
| 119 |
+
"northwest territories": {
|
| 120 |
+
"naturalGas": 4.0,
|
| 121 |
+
"nuclear": 0.0,
|
| 122 |
+
"petroleum": 55.3,
|
| 123 |
+
"biomass": 0.0,
|
| 124 |
+
"coal": 0.0,
|
| 125 |
+
"other": 0.0,
|
| 126 |
+
"solar": 0.2,
|
| 127 |
+
"tidal": 0.0,
|
| 128 |
+
"total": 100,
|
| 129 |
+
"wind": 2.0,
|
| 130 |
+
"hydro": 38.5
|
| 131 |
+
},
|
| 132 |
+
"new brunswick": {
|
| 133 |
+
"naturalGas": 9.9,
|
| 134 |
+
"nuclear": 36.1,
|
| 135 |
+
"petroleum": 7.6,
|
| 136 |
+
"biomass": 4.2,
|
| 137 |
+
"coal": 15.8,
|
| 138 |
+
"other": 0.0,
|
| 139 |
+
"solar": 0.0,
|
| 140 |
+
"tidal": 0.0,
|
| 141 |
+
"total": 99.8,
|
| 142 |
+
"wind": 6.6,
|
| 143 |
+
"hydro": 19.6
|
| 144 |
+
},
|
| 145 |
+
"nunavut": {
|
| 146 |
+
"naturalGas": 0.0,
|
| 147 |
+
"nuclear": 0.0,
|
| 148 |
+
"petroleum": 100.0,
|
| 149 |
+
"biomass": 0.0,
|
| 150 |
+
"coal": 0.0,
|
| 151 |
+
"other": 0.0,
|
| 152 |
+
"solar": 0.0,
|
| 153 |
+
"tidal": 0.0,
|
| 154 |
+
"total": 100,
|
| 155 |
+
"wind": 0.0,
|
| 156 |
+
"hydro": 0.0
|
| 157 |
+
},
|
| 158 |
+
"yukon": {
|
| 159 |
+
"naturalGas": 2.0,
|
| 160 |
+
"nuclear": 0.0,
|
| 161 |
+
"petroleum": 5.5,
|
| 162 |
+
"biomass": 0.0,
|
| 163 |
+
"coal": 0.0,
|
| 164 |
+
"other": 0.0,
|
| 165 |
+
"solar": 0.3,
|
| 166 |
+
"tidal": 0.0,
|
| 167 |
+
"total": 100,
|
| 168 |
+
"wind": 0.0,
|
| 169 |
+
"hydro": 92.2
|
| 170 |
+
}
|
| 171 |
+
}
|