greenmining 1.0.5__py3-none-any.whl → 1.0.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,9 +13,9 @@ from .base import EnergyMeter, EnergyMetrics, EnergyBackend
13
13
 
14
14
  class RAPLEnergyMeter(EnergyMeter):
15
15
  # Energy measurement using Intel RAPL on Linux.
16
-
16
+
17
17
  RAPL_PATH = Path("/sys/class/powercap/intel-rapl")
18
-
18
+
19
19
  def __init__(self):
20
20
  # Initialize RAPL energy meter.
21
21
  super().__init__(EnergyBackend.RAPL)
@@ -24,12 +24,12 @@ class RAPLEnergyMeter(EnergyMeter):
24
24
  self._start_time: Optional[float] = None
25
25
  self._power_samples: List[float] = []
26
26
  self._discover_domains()
27
-
27
+
28
28
  def _discover_domains(self) -> None:
29
29
  # Discover available RAPL domains.
30
30
  if not self.RAPL_PATH.exists():
31
31
  return
32
-
32
+
33
33
  # Find all RAPL domains (intel-rapl:0, intel-rapl:0:0, etc.)
34
34
  for domain_path in self.RAPL_PATH.glob("intel-rapl:*"):
35
35
  if (domain_path / "energy_uj").exists():
@@ -39,9 +39,9 @@ class RAPLEnergyMeter(EnergyMeter):
39
39
  domain_name = name_file.read_text().strip()
40
40
  else:
41
41
  domain_name = domain_path.name
42
-
42
+
43
43
  self._domains[domain_name] = domain_path / "energy_uj"
44
-
44
+
45
45
  # Check for sub-domains (core, uncore, dram, etc.)
46
46
  for subdomain_path in domain_path.glob("intel-rapl:*:*"):
47
47
  if (subdomain_path / "energy_uj").exists():
@@ -50,24 +50,24 @@ class RAPLEnergyMeter(EnergyMeter):
50
50
  subdomain_name = name_file.read_text().strip()
51
51
  else:
52
52
  subdomain_name = subdomain_path.name
53
-
53
+
54
54
  self._domains[subdomain_name] = subdomain_path / "energy_uj"
55
-
55
+
56
56
  def _read_energy(self, path: Path) -> int:
57
57
  # Read energy value in microjoules from a RAPL file.
58
58
  try:
59
59
  return int(path.read_text().strip())
60
60
  except (PermissionError, FileNotFoundError, ValueError):
61
61
  return 0
62
-
62
+
63
63
  def is_available(self) -> bool:
64
64
  # Check if RAPL is available on this system.
65
65
  if not self.RAPL_PATH.exists():
66
66
  return False
67
-
67
+
68
68
  if not self._domains:
69
69
  return False
70
-
70
+
71
71
  # Try to read at least one domain
72
72
  for path in self._domains.values():
73
73
  try:
@@ -75,68 +75,62 @@ class RAPLEnergyMeter(EnergyMeter):
75
75
  return True
76
76
  except Exception:
77
77
  continue
78
-
78
+
79
79
  return False
80
-
80
+
81
81
  def start(self) -> None:
82
82
  # Start energy measurement.
83
83
  if self._is_measuring:
84
84
  raise RuntimeError("Already measuring energy")
85
-
85
+
86
86
  self._is_measuring = True
87
87
  self._start_time = time.time()
88
88
  self._power_samples = []
89
-
89
+
90
90
  # Read starting energy values for all domains
91
- self._start_energy = {
92
- name: self._read_energy(path)
93
- for name, path in self._domains.items()
94
- }
95
-
91
+ self._start_energy = {name: self._read_energy(path) for name, path in self._domains.items()}
92
+
96
93
  def stop(self) -> EnergyMetrics:
97
94
  # Stop energy measurement and return results.
98
95
  if not self._is_measuring:
99
96
  raise RuntimeError("Not currently measuring energy")
100
-
97
+
101
98
  end_time = time.time()
102
99
  self._is_measuring = False
103
-
100
+
104
101
  # Read ending energy values
105
- end_energy = {
106
- name: self._read_energy(path)
107
- for name, path in self._domains.items()
108
- }
109
-
102
+ end_energy = {name: self._read_energy(path) for name, path in self._domains.items()}
103
+
110
104
  # Calculate energy consumption per domain (in joules)
111
105
  duration = end_time - self._start_time
112
-
106
+
113
107
  # Handle counter wrap-around (RAPL counters are typically 32-bit)
114
108
  MAX_ENERGY_UJ = 2**32
115
-
109
+
116
110
  domain_energy = {}
117
111
  for name in self._domains:
118
112
  start = self._start_energy.get(name, 0)
119
113
  end = end_energy.get(name, 0)
120
-
114
+
121
115
  if end >= start:
122
116
  delta_uj = end - start
123
117
  else:
124
118
  # Counter wrapped around
125
119
  delta_uj = (MAX_ENERGY_UJ - start) + end
126
-
120
+
127
121
  domain_energy[name] = delta_uj / 1_000_000 # Convert to joules
128
-
122
+
129
123
  # Aggregate metrics
130
124
  total_joules = sum(domain_energy.values())
131
-
125
+
132
126
  # Extract component-specific energy
133
127
  cpu_energy = domain_energy.get("core", 0) or domain_energy.get("package-0", total_joules)
134
128
  dram_energy = domain_energy.get("dram", 0)
135
129
  gpu_energy = domain_energy.get("uncore", None) # Integrated GPU
136
-
130
+
137
131
  # Calculate power
138
132
  watts_avg = total_joules / duration if duration > 0 else 0
139
-
133
+
140
134
  return EnergyMetrics(
141
135
  joules=total_joules,
142
136
  watts_avg=watts_avg,
@@ -151,7 +145,7 @@ class RAPLEnergyMeter(EnergyMeter):
151
145
  start_time=datetime.fromtimestamp(self._start_time),
152
146
  end_time=datetime.fromtimestamp(end_time),
153
147
  )
154
-
148
+
155
149
  def get_available_domains(self) -> List[str]:
156
150
  # Get list of available RAPL domains.
157
151
  return list(self._domains.keys())
@@ -3,15 +3,25 @@
3
3
  from .commit_extractor import CommitExtractor
4
4
  from .data_aggregator import DataAggregator
5
5
  from .data_analyzer import DataAnalyzer
6
- from .github_fetcher import GitHubFetcher
7
- from .local_repo_analyzer import LocalRepoAnalyzer
6
+ from .github_graphql_fetcher import GitHubGraphQLFetcher
7
+ from .local_repo_analyzer import (
8
+ LocalRepoAnalyzer,
9
+ CommitAnalysis,
10
+ RepositoryAnalysis,
11
+ MethodMetrics,
12
+ SourceCodeChange,
13
+ )
8
14
  from .reports import ReportGenerator
9
15
 
10
16
  __all__ = [
11
- "GitHubFetcher",
17
+ "GitHubGraphQLFetcher",
12
18
  "CommitExtractor",
13
19
  "DataAnalyzer",
14
20
  "DataAggregator",
15
21
  "ReportGenerator",
16
22
  "LocalRepoAnalyzer",
23
+ "CommitAnalysis",
24
+ "RepositoryAnalysis",
25
+ "MethodMetrics",
26
+ "SourceCodeChange",
17
27
  ]
@@ -41,7 +41,9 @@ class CommitExtractor:
41
41
  self.github = Github(github_token) if github_token else None
42
42
  self.timeout = timeout
43
43
 
44
- def extract_from_repositories(self, repositories: list[dict[str, Any] | Repository]) -> list[dict[str, Any]]:
44
+ def extract_from_repositories(
45
+ self, repositories: list[dict[str, Any] | Repository]
46
+ ) -> list[dict[str, Any]]:
45
47
  # Extract commits from list of repositories.
46
48
  all_commits = []
47
49
  failed_repos = []
@@ -74,15 +76,17 @@ class CommitExtractor:
74
76
  pbar.update(1)
75
77
  except TimeoutError:
76
78
  signal.alarm(0) # Cancel alarm
77
- repo_name = repo.full_name if isinstance(repo, Repository) else repo["full_name"]
78
- colored_print(
79
- f"\nTimeout processing {repo_name} (>{self.timeout}s)", "yellow"
79
+ repo_name = (
80
+ repo.full_name if isinstance(repo, Repository) else repo["full_name"]
80
81
  )
82
+ colored_print(f"\nTimeout processing {repo_name} (>{self.timeout}s)", "yellow")
81
83
  failed_repos.append(repo_name)
82
84
  pbar.update(1)
83
85
  except Exception as e:
84
86
  signal.alarm(0) # Cancel alarm
85
- repo_name = repo.full_name if isinstance(repo, Repository) else repo["full_name"]
87
+ repo_name = (
88
+ repo.full_name if isinstance(repo, Repository) else repo["full_name"]
89
+ )
86
90
  colored_print(f"\nError processing {repo_name}: {e}", "yellow")
87
91
  failed_repos.append(repo_name)
88
92
  pbar.update(1)