saggio 1.4.2__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.
- saggio/__init__.py +198 -0
- saggio/__main__.py +32 -0
- saggio/analyze/__init__.py +125 -0
- saggio/analyze/apple.py +542 -0
- saggio/analyze/capability.py +469 -0
- saggio/analyze/cpu.py +389 -0
- saggio/analyze/llm.py +396 -0
- saggio/analyze/power/__init__.py +133 -0
- saggio/analyze/power/accelerator.py +223 -0
- saggio/analyze/power/graphics.py +185 -0
- saggio/analyze/power/meter.py +391 -0
- saggio/analyze/power/rapl.py +156 -0
- saggio/analyze/power/reading.py +97 -0
- saggio/analyze/power/soc.py +72 -0
- saggio/analyze/power/sysfs.py +66 -0
- saggio/analyze/power/tables.py +196 -0
- saggio/analyze/run.py +1117 -0
- saggio/analyze/static/__init__.py +123 -0
- saggio/analyze/static/archetype.py +197 -0
- saggio/analyze/static/calls.py +223 -0
- saggio/analyze/static/findings.py +312 -0
- saggio/analyze/static/languages.py +44 -0
- saggio/analyze/static/read.py +83 -0
- saggio/analyze/static/running.py +267 -0
- saggio/analyze/static/tables.py +358 -0
- saggio/analyze/static/walking.py +238 -0
- saggio/analyze/static/worksize.py +213 -0
- saggio/auditor/__init__.py +74 -0
- saggio/auditor/assumptions.py +230 -0
- saggio/auditor/blocks.py +169 -0
- saggio/auditor/build.py +331 -0
- saggio/auditor/measuring.py +172 -0
- saggio/auditor/naming.py +134 -0
- saggio/auditor/options.py +144 -0
- saggio/auditor/paths.py +56 -0
- saggio/auditor/projections.py +287 -0
- saggio/catalog/__init__.py +71 -0
- saggio/catalog/pricing.py +410 -0
- saggio/catalog/refresh/__init__.py +132 -0
- saggio/catalog/refresh/carbon.py +408 -0
- saggio/catalog/refresh/embodied.py +296 -0
- saggio/catalog/refresh/tariffs.py +350 -0
- saggio/catalog/refresh/timezones.py +233 -0
- saggio/catalog/registry.py +804 -0
- saggio/cli/__init__.py +38 -0
- saggio/cli/app.py +726 -0
- saggio/cli/commands.py +1151 -0
- saggio/cli/exit_codes.py +52 -0
- saggio/data/__init__.py +27 -0
- saggio/data/grid.yaml +553 -0
- saggio/data/hardware.yaml +334 -0
- saggio/data/instances.yaml +119 -0
- saggio/data/providers.yaml +74 -0
- saggio/data/report/i18n.yaml +120 -0
- saggio/data/report/logo.png +0 -0
- saggio/data/report/report.css +245 -0
- saggio/data/report/report.html +38 -0
- saggio/data/report/report.js +168 -0
- saggio/data/services.yaml +111 -0
- saggio/data/templates/annotated.yaml +183 -0
- saggio/data/templates/minimal.yaml +85 -0
- saggio/diff.py +529 -0
- saggio/estimate/__init__.py +124 -0
- saggio/estimate/context.py +618 -0
- saggio/estimate/embodied.py +329 -0
- saggio/estimate/energy.py +580 -0
- saggio/estimate/equivalences.py +263 -0
- saggio/estimate/extrapolate.py +939 -0
- saggio/estimate/machine.py +359 -0
- saggio/estimate/scaling.py +527 -0
- saggio/fold.py +453 -0
- saggio/model/__init__.py +135 -0
- saggio/model/cost_model.py +614 -0
- saggio/model/derivation.py +487 -0
- saggio/model/dimensions.py +371 -0
- saggio/model/quantity.py +482 -0
- saggio/model/results.py +279 -0
- saggio/model/schema.py +170 -0
- saggio/model/taxonomy.py +186 -0
- saggio/model/validate.py +1001 -0
- saggio/report/__init__.py +60 -0
- saggio/report/dashboard.py +273 -0
- saggio/report/figures.py +835 -0
- saggio/report/html.py +1168 -0
- saggio/report/markdown.py +1001 -0
- saggio/report/office.py +146 -0
- saggio/templates.py +112 -0
- saggio-1.4.2.dist-info/METADATA +411 -0
- saggio-1.4.2.dist-info/RECORD +93 -0
- saggio-1.4.2.dist-info/WHEEL +5 -0
- saggio-1.4.2.dist-info/entry_points.txt +2 -0
- saggio-1.4.2.dist-info/licenses/LICENSE +29 -0
- saggio-1.4.2.dist-info/top_level.txt +1 -0
saggio/__init__.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""
|
|
2
|
+
saggio: what it costs to run your code, and how much to trust it.
|
|
3
|
+
|
|
4
|
+
Module summary
|
|
5
|
+
--------------
|
|
6
|
+
This package answers one question about a piece of software, per unit of work:
|
|
7
|
+
what does running it cost? Money, time, energy, carbon, water, and whatever else
|
|
8
|
+
your team decides to watch. The answer is a YAML file you commit next to the code,
|
|
9
|
+
and reports rendered from it.
|
|
10
|
+
|
|
11
|
+
What makes the answer worth having is the second half of every number: its
|
|
12
|
+
*status*. ``measured`` means a counter said so. ``estimated`` means a sourced
|
|
13
|
+
formula said so. ``placeholder`` means the field is being held open. ``TODO`` means
|
|
14
|
+
a human has to supply it. A derived value names the numbers it came from and may
|
|
15
|
+
never claim to be better founded than the weakest of them, and the validator
|
|
16
|
+
enforces that by walking the file rather than by trusting it.
|
|
17
|
+
|
|
18
|
+
The package is organised in four layers with a strict direction of dependency.
|
|
19
|
+
:mod:`~saggio.model` is the pure vocabulary and the rules.
|
|
20
|
+
:mod:`~saggio.catalog` holds sourced facts about the world.
|
|
21
|
+
:mod:`~saggio.estimate` and
|
|
22
|
+
:mod:`~saggio.analyze` turn facts and measurements into numbers.
|
|
23
|
+
:mod:`~saggio.report` and
|
|
24
|
+
:mod:`~saggio.cli` are ways of reaching all of it. Nothing lower
|
|
25
|
+
imports anything higher, so the command line can do nothing a library caller
|
|
26
|
+
cannot.
|
|
27
|
+
|
|
28
|
+
Usage example
|
|
29
|
+
-------------
|
|
30
|
+
>>> import saggio
|
|
31
|
+
>>> result = saggio.audit(".", options=saggio.AuditOptions(run=False, use_llm=False))
|
|
32
|
+
>>> result.report.ok
|
|
33
|
+
True
|
|
34
|
+
>>> saggio.render_markdown(result.model).startswith("# Cost of running")
|
|
35
|
+
True
|
|
36
|
+
|
|
37
|
+
Author
|
|
38
|
+
------
|
|
39
|
+
Warith Harchaoui, Ph.D. — https://linkedin.com/in/warith-harchaoui/
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
from __future__ import annotations
|
|
43
|
+
|
|
44
|
+
import sys
|
|
45
|
+
from typing import Final
|
|
46
|
+
|
|
47
|
+
#: The platforms this package supports, stated before anything else is imported
|
|
48
|
+
#: so that an unsupported one is told why rather than meeting a missing stdlib
|
|
49
|
+
#: module three imports deeper. Repeated from
|
|
50
|
+
#: :mod:`saggio.analyze.capability`, which cannot be imported this early without
|
|
51
|
+
#: a cycle, and pinned to it by a test.
|
|
52
|
+
SUPPORTED_PLATFORMS: Final[tuple[str, ...]] = ("linux", "darwin")
|
|
53
|
+
|
|
54
|
+
if not any(sys.platform.startswith(name) for name in SUPPORTED_PLATFORMS):
|
|
55
|
+
raise ImportError(
|
|
56
|
+
f"saggio does not support {sys.platform}. It supports Linux and macOS, and "
|
|
57
|
+
"Windows is out of scope deliberately: it publishes no vendor-neutral "
|
|
58
|
+
"processor energy counter to an unprivileged process, no machine-wide "
|
|
59
|
+
"processor-time total this package can read, and no POSIX resource "
|
|
60
|
+
"accounting for a child process. A tool whose whole proposition is that a "
|
|
61
|
+
"number says how far it can be trusted should not pretend to support a "
|
|
62
|
+
"platform where it could only ever estimate."
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
#: The installed version, kept in step with pyproject.toml at release.
|
|
66
|
+
__version__: Final[str] = "1.4.2"
|
|
67
|
+
|
|
68
|
+
__author__: Final[str] = "Warith Harchaoui, Ph.D."
|
|
69
|
+
__email__: Final[str] = "warith.harchaoui@sev7n.io"
|
|
70
|
+
|
|
71
|
+
from .analyze import (
|
|
72
|
+
RepositoryReading,
|
|
73
|
+
SliceResult,
|
|
74
|
+
read_repository,
|
|
75
|
+
run_slice,
|
|
76
|
+
)
|
|
77
|
+
from .auditor import AuditOptions, AuditResult, audit, audit_git_url, repository_name
|
|
78
|
+
from .catalog import Catalog, add_row, stale_report
|
|
79
|
+
from .diff import Change, Comparison, compare
|
|
80
|
+
from .estimate import (
|
|
81
|
+
DeploymentContext,
|
|
82
|
+
MachineProfile,
|
|
83
|
+
Observation,
|
|
84
|
+
Projection,
|
|
85
|
+
ScalingFit,
|
|
86
|
+
car_km,
|
|
87
|
+
carbon_from_energy,
|
|
88
|
+
detect_machine,
|
|
89
|
+
embodied_carbon,
|
|
90
|
+
energy_from_runtime,
|
|
91
|
+
equivalences,
|
|
92
|
+
fit_power_law,
|
|
93
|
+
flight_fraction,
|
|
94
|
+
it_energy_from_runtime,
|
|
95
|
+
money_from_energy,
|
|
96
|
+
node_power,
|
|
97
|
+
project_to_completion,
|
|
98
|
+
project_to_machine,
|
|
99
|
+
project_to_processor,
|
|
100
|
+
software_carbon_intensity,
|
|
101
|
+
tree_months,
|
|
102
|
+
water_from_energy,
|
|
103
|
+
)
|
|
104
|
+
from .fold import Fold, fold_measurement
|
|
105
|
+
from .model import (
|
|
106
|
+
CANONICAL_DIMENSIONS,
|
|
107
|
+
ESTIMATED,
|
|
108
|
+
MEASURED,
|
|
109
|
+
PLACEHOLDER,
|
|
110
|
+
SCHEMA_VERSION,
|
|
111
|
+
TODO,
|
|
112
|
+
CostModel,
|
|
113
|
+
Dimension,
|
|
114
|
+
DimensionRegistry,
|
|
115
|
+
Issue,
|
|
116
|
+
Quantity,
|
|
117
|
+
Report,
|
|
118
|
+
overall_status,
|
|
119
|
+
validate,
|
|
120
|
+
weakest,
|
|
121
|
+
)
|
|
122
|
+
from .report import render_dashboard, render_html, render_markdown, render_office
|
|
123
|
+
from .templates import DEFAULT_TEMPLATE, TEMPLATES, template_mapping, template_names, template_text
|
|
124
|
+
|
|
125
|
+
__all__ = [
|
|
126
|
+
"__version__",
|
|
127
|
+
"__author__",
|
|
128
|
+
"__email__",
|
|
129
|
+
# The model and its rules.
|
|
130
|
+
"CostModel",
|
|
131
|
+
"Quantity",
|
|
132
|
+
"Dimension",
|
|
133
|
+
"DimensionRegistry",
|
|
134
|
+
"CANONICAL_DIMENSIONS",
|
|
135
|
+
"SCHEMA_VERSION",
|
|
136
|
+
"MEASURED",
|
|
137
|
+
"ESTIMATED",
|
|
138
|
+
"PLACEHOLDER",
|
|
139
|
+
"TODO",
|
|
140
|
+
"weakest",
|
|
141
|
+
"validate",
|
|
142
|
+
"overall_status",
|
|
143
|
+
"Report",
|
|
144
|
+
"Issue",
|
|
145
|
+
# Facts about the world.
|
|
146
|
+
"Catalog",
|
|
147
|
+
"add_row",
|
|
148
|
+
"stale_report",
|
|
149
|
+
# Estimation.
|
|
150
|
+
"DeploymentContext",
|
|
151
|
+
"MachineProfile",
|
|
152
|
+
"detect_machine",
|
|
153
|
+
"node_power",
|
|
154
|
+
"it_energy_from_runtime",
|
|
155
|
+
"energy_from_runtime",
|
|
156
|
+
"carbon_from_energy",
|
|
157
|
+
"water_from_energy",
|
|
158
|
+
"money_from_energy",
|
|
159
|
+
"tree_months",
|
|
160
|
+
"car_km",
|
|
161
|
+
"flight_fraction",
|
|
162
|
+
"equivalences",
|
|
163
|
+
"Observation",
|
|
164
|
+
"Projection",
|
|
165
|
+
"ScalingFit",
|
|
166
|
+
"embodied_carbon",
|
|
167
|
+
"fit_power_law",
|
|
168
|
+
"project_to_completion",
|
|
169
|
+
"software_carbon_intensity",
|
|
170
|
+
"project_to_machine",
|
|
171
|
+
"project_to_processor",
|
|
172
|
+
# Reading and running a repository.
|
|
173
|
+
"RepositoryReading",
|
|
174
|
+
"read_repository",
|
|
175
|
+
"SliceResult",
|
|
176
|
+
"run_slice",
|
|
177
|
+
# The whole job.
|
|
178
|
+
"AuditOptions",
|
|
179
|
+
"AuditResult",
|
|
180
|
+
"audit",
|
|
181
|
+
"audit_git_url",
|
|
182
|
+
"repository_name",
|
|
183
|
+
"Fold",
|
|
184
|
+
"compare",
|
|
185
|
+
"fold_measurement",
|
|
186
|
+
"Comparison",
|
|
187
|
+
"Change",
|
|
188
|
+
# Reports.
|
|
189
|
+
"render_markdown",
|
|
190
|
+
"render_html",
|
|
191
|
+
"render_office",
|
|
192
|
+
"render_dashboard",
|
|
193
|
+
"template_text",
|
|
194
|
+
"template_mapping",
|
|
195
|
+
"template_names",
|
|
196
|
+
"TEMPLATES",
|
|
197
|
+
"DEFAULT_TEMPLATE",
|
|
198
|
+
]
|
saggio/__main__.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Running the package with ``python -m saggio``.
|
|
2
|
+
|
|
3
|
+
Module summary
|
|
4
|
+
--------------
|
|
5
|
+
The console script installed as ``saggio`` is the ordinary way in. This is the
|
|
6
|
+
other one, and it matters more than it looks: ``python -m saggio`` runs the
|
|
7
|
+
command line out of *this* interpreter's environment, whatever is on the PATH.
|
|
8
|
+
That is what somebody reaches for when two versions are installed, what a test
|
|
9
|
+
suite needs to exercise the working tree rather than whatever was installed
|
|
10
|
+
last, and what works in a container where no scripts directory is on the PATH.
|
|
11
|
+
|
|
12
|
+
Without it the package answers ``'saggio' is a package and cannot be directly
|
|
13
|
+
executed``, which reads as though the tool is broken rather than as though one
|
|
14
|
+
file is missing.
|
|
15
|
+
|
|
16
|
+
Usage example
|
|
17
|
+
-------------
|
|
18
|
+
.. code-block:: console
|
|
19
|
+
|
|
20
|
+
$ python -m saggio --version
|
|
21
|
+
saggio 1.4.2
|
|
22
|
+
|
|
23
|
+
Author
|
|
24
|
+
------
|
|
25
|
+
Warith Harchaoui
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
from .cli.app import run
|
|
31
|
+
|
|
32
|
+
run()
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Finding out what a repository is and what it costs to run.
|
|
3
|
+
|
|
4
|
+
Module summary
|
|
5
|
+
--------------
|
|
6
|
+
Three ways of knowing, in descending order of trust, and each one labelled so the
|
|
7
|
+
difference survives into the report. :mod:`static` reads the code and owns every
|
|
8
|
+
number that comes from reading. :mod:`run` and :mod:`power` execute a bounded
|
|
9
|
+
slice, with the user's explicit consent, and own every number that comes from
|
|
10
|
+
measurement. :mod:`llm` asks a local model what shape the work is, and owns no
|
|
11
|
+
number at all.
|
|
12
|
+
|
|
13
|
+
Usage example
|
|
14
|
+
-------------
|
|
15
|
+
>>> from saggio.analyze import read_repository
|
|
16
|
+
>>> read_repository(".").archetype is not None
|
|
17
|
+
True
|
|
18
|
+
|
|
19
|
+
Author
|
|
20
|
+
------
|
|
21
|
+
Warith Harchaoui
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from .apple import SocEnergy, SocMeter
|
|
27
|
+
from .capability import Interface, measurable, paths_read, probe, summary
|
|
28
|
+
from .llm import (
|
|
29
|
+
WORKLOAD_KINDS,
|
|
30
|
+
Classification,
|
|
31
|
+
classify,
|
|
32
|
+
installed_models,
|
|
33
|
+
is_available,
|
|
34
|
+
pick_model,
|
|
35
|
+
)
|
|
36
|
+
from .power import (
|
|
37
|
+
RAPL_SCOPE_NOTE,
|
|
38
|
+
GraphicsSampler,
|
|
39
|
+
PowerMeter,
|
|
40
|
+
PowerReading,
|
|
41
|
+
read_graphics_energy_microjoules,
|
|
42
|
+
read_graphics_watts,
|
|
43
|
+
read_memory_energy_microjoules,
|
|
44
|
+
read_package_energy_microjoules,
|
|
45
|
+
unavailable_reason,
|
|
46
|
+
)
|
|
47
|
+
from .run import (
|
|
48
|
+
CONSENT_PROMPT,
|
|
49
|
+
DEFAULT_TIMEOUT_SECONDS,
|
|
50
|
+
ProfileEntry,
|
|
51
|
+
SliceResult,
|
|
52
|
+
consent_path,
|
|
53
|
+
has_consent,
|
|
54
|
+
record_consent,
|
|
55
|
+
require_consent,
|
|
56
|
+
run_slice,
|
|
57
|
+
)
|
|
58
|
+
from .static import (
|
|
59
|
+
DEFAULT_CAP_FRACTION,
|
|
60
|
+
RepositoryReading,
|
|
61
|
+
ServiceHit,
|
|
62
|
+
WorkSizeCandidate,
|
|
63
|
+
capped_entrypoint_command,
|
|
64
|
+
detect_archetype,
|
|
65
|
+
detect_frameworks,
|
|
66
|
+
detect_languages,
|
|
67
|
+
detect_services,
|
|
68
|
+
detect_tests,
|
|
69
|
+
find_entrypoint,
|
|
70
|
+
find_work_size,
|
|
71
|
+
read_repository,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
__all__ = [
|
|
75
|
+
# Static reading.
|
|
76
|
+
"RepositoryReading",
|
|
77
|
+
"ServiceHit",
|
|
78
|
+
"WorkSizeCandidate",
|
|
79
|
+
"read_repository",
|
|
80
|
+
"detect_languages",
|
|
81
|
+
"detect_archetype",
|
|
82
|
+
"detect_frameworks",
|
|
83
|
+
"detect_services",
|
|
84
|
+
"detect_tests",
|
|
85
|
+
"find_entrypoint",
|
|
86
|
+
"find_work_size",
|
|
87
|
+
"capped_entrypoint_command",
|
|
88
|
+
"DEFAULT_CAP_FRACTION",
|
|
89
|
+
# Power.
|
|
90
|
+
"PowerMeter",
|
|
91
|
+
"PowerReading",
|
|
92
|
+
"GraphicsSampler",
|
|
93
|
+
"RAPL_SCOPE_NOTE",
|
|
94
|
+
"read_package_energy_microjoules",
|
|
95
|
+
"read_memory_energy_microjoules",
|
|
96
|
+
"read_graphics_energy_microjoules",
|
|
97
|
+
"read_graphics_watts",
|
|
98
|
+
"unavailable_reason",
|
|
99
|
+
# Apple Silicon, read without privileges.
|
|
100
|
+
"SocMeter",
|
|
101
|
+
"SocEnergy",
|
|
102
|
+
# What this machine will let you read, and what it would take.
|
|
103
|
+
"Interface",
|
|
104
|
+
"probe",
|
|
105
|
+
"measurable",
|
|
106
|
+
"summary",
|
|
107
|
+
"paths_read",
|
|
108
|
+
# Running.
|
|
109
|
+
"SliceResult",
|
|
110
|
+
"ProfileEntry",
|
|
111
|
+
"run_slice",
|
|
112
|
+
"has_consent",
|
|
113
|
+
"record_consent",
|
|
114
|
+
"require_consent",
|
|
115
|
+
"consent_path",
|
|
116
|
+
"CONSENT_PROMPT",
|
|
117
|
+
"DEFAULT_TIMEOUT_SECONDS",
|
|
118
|
+
# Local model.
|
|
119
|
+
"Classification",
|
|
120
|
+
"WORKLOAD_KINDS",
|
|
121
|
+
"classify",
|
|
122
|
+
"is_available",
|
|
123
|
+
"installed_models",
|
|
124
|
+
"pick_model",
|
|
125
|
+
]
|