ms-components 0.5.0__tar.gz → 0.5.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ms_components-0.5.0 → ms_components-0.5.2}/PKG-INFO +1 -1
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_executors.py +4 -2
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/detail.py +19 -1
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/models.py +1 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/polling.py +1 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/resources.py +12 -3
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components.egg-info/PKG-INFO +1 -1
- ms_components-0.5.2/src/ms_components.egg-info/scm_version.json +8 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_molsuite_monitor_widgets.py +26 -0
- ms_components-0.5.0/src/ms_components.egg-info/scm_version.json +0 -8
- {ms_components-0.5.0 → ms_components-0.5.2}/.github/workflows/docs.yml +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/.github/workflows/publish.yml +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/.gitignore +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/LICENSE +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/MANIFEST.in +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/README.md +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/examples/tutorial_demo.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/examples/tutorial_demo.toml +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/licenses/qt-themes-LICENSE.txt +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/pyproject.toml +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/setup.cfg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/__init__.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/backdrop.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/base.qss +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/chips.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ketcher.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/listview.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_dockwidget/__init__.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_dockwidget/resources/__init__.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_dockwidget/resources/icons/__init__.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_dockwidget/resources/icons/folder.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_dockwidget/widget.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/__init__.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/bridge.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/config.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/formatting.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/jobs.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/palette.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_monitor/widget.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_projects/__init__.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_projects/app.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_projects/backend.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_projects/browser.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_projects/scratch.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_projects/widget.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/__init__.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/command_line.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/actions.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/box.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/center.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/display.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/hide.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/hydrogens-polar.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/hydrogens.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/menu.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/orient.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/presets.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/rock.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/selection.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/settings.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/style.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/zoom.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/plugins.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/scene.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/widget.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_settings/__init__.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_settings/panel.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_stepper.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/__init__.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/action_header.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/cell_delegate.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/column_panel.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/example_usage.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/filter_panel.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/icons/columns.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/icons/export.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/icons/filter.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/icons/menu.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/icons/reload.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/icons/search.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/icons/settings.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/icons/sort-asc.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/icons/sort-desc.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/icons/sort.svg +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/metric_filter_bar.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/pagination_control.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/query_builder.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/session_provider.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/smart_table_view.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/sort_panel.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/table_config.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/table_interaction.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/table_model.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/test_external_filters.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/test_toolbar.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_tutorial/__init__.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_tutorial/bindings.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_tutorial/controller.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_tutorial/models.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_tutorial/overlay.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/opengl.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/pagination.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/palettes.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/step_dialog.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/theme.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/tool_panel.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/wheel.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components.egg-info/SOURCES.txt +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components.egg-info/dependency_links.txt +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components.egg-info/requires.txt +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components.egg-info/scm_file_list.json +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components.egg-info/top_level.txt +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/conftest.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_app_settings.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_chips.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_dock_window.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_executors_ui.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_ketcher.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_molsuite_monitor_bridge.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_monitor_config.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_ms_projects_widget.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_opengl.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_optional_integrations.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_progress_column.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_project_browser.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_pymol_command_line.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_pymol_grid.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_pymol_scene.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_pymol_toolbar.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_query_builder_keyset.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_shift_hscroll.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_split_button_style.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_step_dialog.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_table_interaction.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_table_toolbar.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_table_view_state.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_theme_contrast.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_tool_panel.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/tests/test_tutorial.py +0 -0
- {ms_components-0.5.0 → ms_components-0.5.2}/zensical.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ms_components
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: PySide6 UI components for MolSuite: smart table, project browser, job monitor, PyMOL dock, steppers.
|
|
5
5
|
Author: Mario S. Valdés-Tresanco, Mario E. Valdés-Tresanco
|
|
6
6
|
License-Expression: MIT
|
|
@@ -165,9 +165,11 @@ def describe_host(address: str, env: str = "", packages=(), tools=None) -> str:
|
|
|
165
165
|
tools = tools or {}
|
|
166
166
|
python = f"{env.rstrip('/')}/bin/python" if env else ("" if address else sys.executable)
|
|
167
167
|
script = "; ".join([
|
|
168
|
-
"export LC_ALL=C", "uname -srm",
|
|
168
|
+
"export LC_ALL=C", "uname -srm",
|
|
169
|
+
'(. /etc/os-release 2>/dev/null && echo "$PRETTY_NAME") || (v=$(sw_vers -productVersion 2>/dev/null) && echo "macOS $v")',
|
|
169
170
|
'echo "CPUs: $(nproc 2>/dev/null || sysctl -n hw.ncpu)"',
|
|
170
|
-
"awk '/MemTotal/ {printf \"Memory: %.1f GB\\n\", $2/1048576}' /proc/meminfo 2>/dev/null"
|
|
171
|
+
"awk '/MemTotal/ {printf \"Memory: %.1f GB\\n\", $2/1048576}' /proc/meminfo 2>/dev/null"
|
|
172
|
+
" || sysctl -n hw.memsize | awk '{printf \"Memory: %.1f GB\\n\", $1/1073741824}'", # macOS: no /proc
|
|
171
173
|
"(nvidia-smi -L 2>/dev/null || echo 'GPUs: none seen by nvidia-smi')",
|
|
172
174
|
"echo",
|
|
173
175
|
*([f"if [ -x {shlex.quote(python)} ]; then {shlex.quote(python)} -c {shlex.quote(_VERSIONS)} "
|
|
@@ -628,7 +628,7 @@ class JobDetail(QWidget):
|
|
|
628
628
|
self._traceback.setPlainText("" if item is None else str(item.data(Qt.UserRole) or ""))
|
|
629
629
|
|
|
630
630
|
_FACTS = ("key", "status", "executor", "started", "finished", "elapsed", "chunks", "retried", "throughput",
|
|
631
|
-
"peak memory", "in flight", "errors")
|
|
631
|
+
"peak memory", "CPU", "GPU", "in flight", "errors")
|
|
632
632
|
|
|
633
633
|
def _build_summary(self) -> None:
|
|
634
634
|
self._fact: dict[str, QLabel] = {}
|
|
@@ -661,6 +661,7 @@ class JobDetail(QWidget):
|
|
|
661
661
|
f"{job.chunks_retried:,}",
|
|
662
662
|
format_speed(job.throughput_eps) + ("" if job.is_terminal else " · last 5 min"),
|
|
663
663
|
f"{job.peak_mem_mb:,} MB" if job.peak_mem_mb else "—",
|
|
664
|
+
*_used(job, (end - job.started_at).total_seconds() if job.started_at else 0.0),
|
|
664
665
|
f"{job.tasks_running:,} tasks · {job.cpu_used:,} CPUs" if not job.is_terminal else "—",
|
|
665
666
|
f"{self._error_types:,} types" if self._error_types else "none",
|
|
666
667
|
)
|
|
@@ -668,4 +669,21 @@ class JobDetail(QWidget):
|
|
|
668
669
|
self._fact[key].setText(value)
|
|
669
670
|
|
|
670
671
|
|
|
672
|
+
def _used(job: JobMonitorState, seconds: float) -> tuple[str, str]:
|
|
673
|
+
"""The CPU and GPU lines of a job's summary: what it kept busy, of what it held."""
|
|
674
|
+
usage = job.usage
|
|
675
|
+
if not usage or seconds <= 0:
|
|
676
|
+
return "—", "—"
|
|
677
|
+
cpu = gpu = "—"
|
|
678
|
+
if usage.get("peak_cpu"):
|
|
679
|
+
held = f"{usage['cpu_s'] / seconds:,.1f} held on average · {usage['peak_cpu']:g} at most"
|
|
680
|
+
busy = usage.get("busy_s") # on this machine only: what it read while the job ran
|
|
681
|
+
cpu = held if busy is None else f"{busy / 3600:,.2f} CPU·h · {busy / seconds:,.1f} busy of " + held
|
|
682
|
+
if usage.get("peak_gpu"):
|
|
683
|
+
gpu = f"{usage['gpu_s'] / 3600:,.2f} GPU·h · {usage['peak_gpu']:g} at most"
|
|
684
|
+
if usage.get("vram_mb") is not None:
|
|
685
|
+
gpu += f" · {usage['vram_mb']:,} MB VRAM at most · {usage['gpu_util']:.0f} % busy on average"
|
|
686
|
+
return cpu, gpu
|
|
687
|
+
|
|
688
|
+
|
|
671
689
|
__all__ = ["ChunkGrid", "GRID_MAX", "GRID_STEP", "JobDetail", "counts", "grid_window", "layout_cells", "reason"]
|
|
@@ -50,6 +50,7 @@ class JobMonitorState:
|
|
|
50
50
|
cpu_used: int = 0 # the CPU tokens those tasks hold
|
|
51
51
|
chunks_retried: int = 0
|
|
52
52
|
peak_mem_mb: int = 0
|
|
53
|
+
usage: dict = field(default_factory=dict) # what it used, kept once it ended: see ms_flow's JobSnapshot.usage
|
|
53
54
|
throughput_eps: float = 0.0 # chunks settled per second over the last minutes; since it began once it ended
|
|
54
55
|
throughput_history: list[float] = field(default_factory=list) # the same, one value per few seconds
|
|
55
56
|
started_at: datetime | None = None
|
|
@@ -33,6 +33,7 @@ def job_state(job, now: float) -> JobMonitorState:
|
|
|
33
33
|
cpu_used=getattr(job, "cpu_used", 0),
|
|
34
34
|
chunks_retried=job.chunks_retried,
|
|
35
35
|
peak_mem_mb=job.peak_mem_mb,
|
|
36
|
+
usage=getattr(job, "usage", None) or {}, # ms_flow < 0.8 does not keep it
|
|
36
37
|
throughput_eps=settled / elapsed if elapsed > 0 else 0.0, # the mean; `_Speeds` gives the recent one
|
|
37
38
|
started_at=datetime.fromtimestamp(job.started_at),
|
|
38
39
|
finished_at=datetime.fromtimestamp(job.finished_at) if job.finished_at else None,
|
|
@@ -4,7 +4,7 @@ A host is read where it is: this machine with `psutil` (or `/proc`); a node of a
|
|
|
4
4
|
from the metrics Ray's agent exports there (`Workspace.node_metrics`), so with no ssh; another one
|
|
5
5
|
through `ms_env.Host` (the system's `ssh`), with one command that prints `/proc/stat`,
|
|
6
6
|
`/proc/meminfo` and `nvidia-smi`. The CPU in use is the change of `/proc/stat` between two reads, so the first
|
|
7
|
-
read of a host shows none
|
|
7
|
+
read of a host shows none; a Mac, with no `/proc`, says it from `ps`, `sysctl` and `vm_stat`. Each host is read in its own thread, only while the strip is shown,
|
|
8
8
|
every `interval` seconds: a few for this machine, more for one over the network. The login node
|
|
9
9
|
of a queue is not read: what it uses says nothing of the nodes its jobs got.
|
|
10
10
|
"""
|
|
@@ -30,7 +30,14 @@ INTERVALS = {"local": 5, "ray": 15}
|
|
|
30
30
|
_HISTORY = 120 # reads kept per host: 10 min of this machine, 30 of one over the network
|
|
31
31
|
|
|
32
32
|
_GPU_QUERY = "nvidia-smi --query-gpu=utilization.gpu,memory.used,memory.total --format=csv,noheader,nounits"
|
|
33
|
-
|
|
33
|
+
# macOS has no /proc: the CPU its processes use now (`ps`, 100 = one core), and memory from
|
|
34
|
+
# `sysctl` and `vm_stat` (free + inactive + speculative pages), said the way Linux says it.
|
|
35
|
+
_MAC = ("n=$(sysctl -n hw.ncpu); ps -A -o %cpu= | awk -v n=$n '{s += $1} END {printf \"cpunow %.1f\\n\", s / n}'; "
|
|
36
|
+
"echo \"MemTotal: $(($(sysctl -n hw.memsize) / 1024)) kB\"; "
|
|
37
|
+
"vm_stat | awk '/page size of/ {p = $8} /^Pages (free|inactive|speculative):/ {a += $NF} "
|
|
38
|
+
"END {printf \"MemAvailable: %d kB\\n\", a * p / 1024}'")
|
|
39
|
+
_SCRIPT = (f"if [ -r /proc/stat ]; then head -1 /proc/stat; grep -E '^(MemTotal|MemAvailable):' /proc/meminfo; "
|
|
40
|
+
f"else {_MAC}; fi; {_GPU_QUERY} 2>/dev/null || true")
|
|
34
41
|
|
|
35
42
|
|
|
36
43
|
@dataclass(slots=True)
|
|
@@ -72,7 +79,9 @@ def parse(text: str, previous: tuple[int, int] | None) -> tuple[Sample, tuple[in
|
|
|
72
79
|
"""What `_SCRIPT` printed, and the CPU counters it read (busy, total) for the next read."""
|
|
73
80
|
sample, ticks, mem = Sample(), None, {}
|
|
74
81
|
for line in text.splitlines():
|
|
75
|
-
if line.startswith("
|
|
82
|
+
if line.startswith("cpunow "): # a Mac says its share now, no counters
|
|
83
|
+
sample.cpu = min(100.0, float(line.split()[1]))
|
|
84
|
+
elif line.startswith("cpu "):
|
|
76
85
|
values = [int(v) for v in line.split()[1:]]
|
|
77
86
|
idle = values[3] + (values[4] if len(values) > 4 else 0) # idle + iowait
|
|
78
87
|
ticks = (sum(values) - idle, sum(values))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ms_components
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.2
|
|
4
4
|
Summary: PySide6 UI components for MolSuite: smart table, project browser, job monitor, PyMOL dock, steppers.
|
|
5
5
|
Author: Mario S. Valdés-Tresanco, Mario E. Valdés-Tresanco
|
|
6
6
|
License-Expression: MIT
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import subprocess
|
|
3
4
|
from datetime import datetime
|
|
4
5
|
from types import SimpleNamespace
|
|
5
6
|
|
|
@@ -75,6 +76,14 @@ def test_the_detail_shows_the_numbers_the_tasks_and_the_failures_grouped():
|
|
|
75
76
|
detail.set_job(_job(status="completed", engine_id=None)) # of another session: no grid, a note
|
|
76
77
|
assert not detail._grid.isVisibleTo(detail) and "not run by this session" in detail._meta.text()
|
|
77
78
|
assert detail._fact["status"].text() == "completed"
|
|
79
|
+
assert detail._fact["CPU"].text() == detail._fact["GPU"].text() == "—" # recorded without its usage
|
|
80
|
+
|
|
81
|
+
used = {"cpu_s": 7200.0, "peak_cpu": 4, "busy_s": 5400.0, "gpu_s": 1800.0, "peak_gpu": 1, "vram_mb": 1200,
|
|
82
|
+
"gpu_util": 61.4}
|
|
83
|
+
detail.set_job(_job(status="completed", engine_id=None, started_at=datetime(2026, 1, 1, 10),
|
|
84
|
+
finished_at=datetime(2026, 1, 1, 11), usage=used))
|
|
85
|
+
assert detail._fact["CPU"].text() == "1.50 CPU·h · 1.5 busy of 2.0 held on average · 4 at most"
|
|
86
|
+
assert detail._fact["GPU"].text() == "0.50 GPU·h · 1 at most · 1,200 MB VRAM at most · 61 % busy on average"
|
|
78
87
|
|
|
79
88
|
|
|
80
89
|
def test_monitor_widget_lists_filters_and_selects_the_jobs_and_empties_without_a_project():
|
|
@@ -110,6 +119,23 @@ def test_monitor_widget_lists_filters_and_selects_the_jobs_and_empties_without_a
|
|
|
110
119
|
assert widget._detail._name.text() == "Select a job"
|
|
111
120
|
|
|
112
121
|
|
|
122
|
+
def test_a_mac_is_read_without_proc(tmp_path):
|
|
123
|
+
"""Run the Mac half of the script with stand-ins for its `sysctl`, `ps` and `vm_stat`."""
|
|
124
|
+
from ms_components.ms_monitor.resources import _MAC, parse
|
|
125
|
+
|
|
126
|
+
fakes = {
|
|
127
|
+
"sysctl": 'case "$2" in hw.ncpu) echo 8 ;; hw.memsize) echo 17179869184 ;; esac',
|
|
128
|
+
"ps": "printf ' 100.0\\n 50.0\\n 10.0\\n'", # 160 % of one core = 20 % of eight
|
|
129
|
+
"vm_stat": "printf 'Mach Virtual Memory Statistics: (page size of 16384 bytes)\\nPages free: 65536.\\n"
|
|
130
|
+
"Pages active: 9999.\\nPages inactive: 131072.\\nPages speculative: 65536.\\n'", # 4 GB free
|
|
131
|
+
}
|
|
132
|
+
for name, body in fakes.items():
|
|
133
|
+
(tmp_path / name).write_text(f"#!/bin/sh\n{body}\n")
|
|
134
|
+
(tmp_path / name).chmod(0o755)
|
|
135
|
+
text = subprocess.check_output(["sh", "-c", _MAC], text=True, env={"PATH": f"{tmp_path}:/usr/bin:/bin"})
|
|
136
|
+
sample, _ = parse(text, None)
|
|
137
|
+
assert (sample.cpu, round(sample.mem), round(sample.mem_total_gb)) == (20.0, 75, 16), text
|
|
138
|
+
|
|
113
139
|
def test_the_hosts_are_listed_once_with_their_executors_and_a_queue_is_not_read():
|
|
114
140
|
from ms_components.ms_monitor.resources import parse, workspace_hosts
|
|
115
141
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_dockwidget/resources/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_pymol/icons/hydrogens-polar.svg
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/pagination_control.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ms_components-0.5.0 → ms_components-0.5.2}/src/ms_components/ms_table/test_external_filters.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|