Initial commit
This commit is contained in:
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Python-generated files
|
||||||
|
__pycache__/
|
||||||
|
*.py[oc]
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
wheels/
|
||||||
|
*.egg-info
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.14
|
||||||
85
main.py
Normal file
85
main.py
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
from dataclasses import dataclass
|
||||||
|
import dataclasses
|
||||||
|
from decimal import Decimal
|
||||||
|
from functools import reduce
|
||||||
|
from typing import NamedTuple, Optional
|
||||||
|
from line_profiler import profile
|
||||||
|
import psutil
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ProcessSwapInfo:
|
||||||
|
pid: int
|
||||||
|
name: str
|
||||||
|
swap: int
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ProcessSwapGroup:
|
||||||
|
name: str
|
||||||
|
processes: list[ProcessSwapInfo] = dataclasses.field(default_factory=list)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def total_swap(self) -> int:
|
||||||
|
return sum(map(lambda x: x.swap, self.processes))
|
||||||
|
|
||||||
|
type ProcessName = str
|
||||||
|
|
||||||
|
def convert_bytes_to_mb(value: int) -> Decimal:
|
||||||
|
return Decimal(value) / (1024 * 1024)
|
||||||
|
|
||||||
|
@profile
|
||||||
|
def get_process_swap_usage() -> None:
|
||||||
|
print(f"{'PID':>6} {'Name':<25} {'Swap (MB)':>10}")
|
||||||
|
print("-" * 45)
|
||||||
|
|
||||||
|
total_swap_used = 0
|
||||||
|
|
||||||
|
swap_used: list[ProcessSwapInfo] = []
|
||||||
|
|
||||||
|
for proc in psutil.process_iter(['pid', 'name', 'memory_full_info']):
|
||||||
|
try:
|
||||||
|
with proc.oneshot():
|
||||||
|
memory_info: Optional[NamedTuple] = proc.info['memory_full_info']
|
||||||
|
swap: int = getattr(memory_info, "swap", 0)
|
||||||
|
if swap > 0:
|
||||||
|
swap_used.append(ProcessSwapInfo(proc.pid, proc.name(), swap))
|
||||||
|
total_swap_used += swap
|
||||||
|
except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||||
|
continue
|
||||||
|
|
||||||
|
swap_used.sort(key=lambda x: x.swap)
|
||||||
|
|
||||||
|
def _add_to_group(groups: dict[ProcessName, ProcessSwapGroup], process: ProcessSwapInfo) -> dict[ProcessName, ProcessSwapGroup]:
|
||||||
|
if process.name not in groups:
|
||||||
|
groups[process.name] = ProcessSwapGroup(process.name)
|
||||||
|
groups[process.name].processes.append(process)
|
||||||
|
return groups
|
||||||
|
|
||||||
|
swap_used_groups: list[ProcessSwapGroup] = sorted(
|
||||||
|
(item for item in reduce(_add_to_group, swap_used, dict()).values()),
|
||||||
|
key=lambda x: x.total_swap
|
||||||
|
)
|
||||||
|
|
||||||
|
for group in swap_used_groups:
|
||||||
|
print(f"{group.name:<32} {convert_bytes_to_mb(group.total_swap):10.2f}")
|
||||||
|
for item in group.processes:
|
||||||
|
print(f"{item.pid:>32} {convert_bytes_to_mb(item.swap):10.2f}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
print("-" * 45)
|
||||||
|
print(f"{'Total swap used by processes:':<32} {convert_bytes_to_mb(total_swap_used):10.2f} MB")
|
||||||
|
|
||||||
|
def show_swap_summary() -> None:
|
||||||
|
swap = psutil.swap_memory()
|
||||||
|
print("\n=== Swap Summary ===")
|
||||||
|
print(f"Total: {convert_bytes_to_mb(swap.total):.2f} MB")
|
||||||
|
print(f"Used: {convert_bytes_to_mb(swap.used):.2f} MB")
|
||||||
|
print(f"Free: {convert_bytes_to_mb(swap.free):.2f} MB")
|
||||||
|
print(f"Percent Used: {swap.percent:.1f}%")
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
print("=== Process Swap Usage ===")
|
||||||
|
get_process_swap_usage()
|
||||||
|
show_swap_summary()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
51
profile.txt
Normal file
51
profile.txt
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
Wrote profile results to 'main.py.lprof'
|
||||||
|
Timer unit: 1e-06 s
|
||||||
|
|
||||||
|
Total time: 0.465667 s
|
||||||
|
File: main.py
|
||||||
|
Function: get_process_swap_usage at line 29
|
||||||
|
|
||||||
|
Line # Hits Time Per Hit % Time Line Contents
|
||||||
|
==============================================================
|
||||||
|
29 @profile
|
||||||
|
30 def get_process_swap_usage() -> None:
|
||||||
|
31 1 4.7 4.7 0.0 print(f"{'PID':>6} {'Name':<25} {'Swap (MB)':>10}")
|
||||||
|
32 1 1.9 1.9 0.0 print("-" * 45)
|
||||||
|
33
|
||||||
|
34 1 1.5 1.5 0.0 total_swap_used = 0
|
||||||
|
35
|
||||||
|
36 1 1.5 1.5 0.0 swap_used: list[ProcessSwapInfo] = []
|
||||||
|
37
|
||||||
|
38 476 428514.1 900.2 92.0 for proc in psutil.process_iter(['pid', 'name', 'memory_full_info']):
|
||||||
|
39 475 894.0 1.9 0.2 try:
|
||||||
|
40 950 19757.6 20.8 4.2 with proc.oneshot():
|
||||||
|
41 475 878.1 1.8 0.2 mem_info = proc.info['memory_full_info']
|
||||||
|
42 475 942.4 2.0 0.2 s: int = getattr(mem_info, "swap", 0)
|
||||||
|
43 475 880.2 1.9 0.2 if s > 0:
|
||||||
|
44 167 10376.3 62.1 2.2 swap_used.append(ProcessSwapInfo(proc.pid, proc.name(), s))
|
||||||
|
45 167 320.2 1.9 0.1 total_swap_used += s
|
||||||
|
46 except (psutil.NoSuchProcess, psutil.AccessDenied):
|
||||||
|
47 continue
|
||||||
|
48
|
||||||
|
49 1 97.1 97.1 0.0 swap_used.sort(key=lambda x: x.swap)
|
||||||
|
50
|
||||||
|
51 1 2.4 2.4 0.0 def add_to_group(groups: dict[ProcessName, ProcessSwapGroup], process: ProcessSwapInfo) -> dict[ProcessName, ProcessSwapGroup]:
|
||||||
|
52 if process.name not in groups:
|
||||||
|
53 groups[process.name] = ProcessSwapGroup(process.name)
|
||||||
|
54 groups[process.name].processes.append(process)
|
||||||
|
55 return groups
|
||||||
|
56
|
||||||
|
57 2 247.9 124.0 0.1 swap_used_groups: list[ProcessSwapGroup] = sorted(
|
||||||
|
58 1 548.6 548.6 0.1 (item for item in reduce(add_to_group, swap_used, dict()).values()),
|
||||||
|
59 1 2.4 2.4 0.0 key=lambda x: x.total_swap
|
||||||
|
60 )
|
||||||
|
61
|
||||||
|
62 103 191.7 1.9 0.0 for group in swap_used_groups:
|
||||||
|
63 102 617.0 6.0 0.1 print(f"{group.name:<32} {bytes_to_mb(group.total_swap):10.2f}")
|
||||||
|
64 269 489.7 1.8 0.1 for item in group.processes:
|
||||||
|
65 167 679.6 4.1 0.1 print(f"{item.pid:>32} {bytes_to_mb(item.swap):10.2f}")
|
||||||
|
66 102 210.4 2.1 0.0 print()
|
||||||
|
67
|
||||||
|
68 1 2.4 2.4 0.0 print("-" * 45)
|
||||||
|
69 1 5.2 5.2 0.0 print(f"{'Total swap used by processes:':<32} {bytes_to_mb(total_swap_used):10.2f} MB")
|
||||||
|
|
||||||
14
pyproject.toml
Normal file
14
pyproject.toml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[project]
|
||||||
|
name = "swap"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.14"
|
||||||
|
dependencies = [
|
||||||
|
"psutil>=7.1.3",
|
||||||
|
]
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = [
|
||||||
|
"line-profiler>=5.0.0",
|
||||||
|
]
|
||||||
48
uv.lock
generated
Normal file
48
uv.lock
generated
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.14"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "line-profiler"
|
||||||
|
version = "5.0.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ea/5c/bbe9042ef5cf4c6cad4bf4d6f7975193430eba9191b7278ea114a3993fbb/line_profiler-5.0.0.tar.gz", hash = "sha256:a80f0afb05ba0d275d9dddc5ff97eab637471167ff3e66dcc7d135755059398c", size = 376919, upload-time = "2025-07-23T20:15:41.819Z" }
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "psutil"
|
||||||
|
version = "7.1.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/e1/88/bdd0a41e5857d5d703287598cbf08dad90aed56774ea52ae071bae9071b6/psutil-7.1.3.tar.gz", hash = "sha256:6c86281738d77335af7aec228328e944b30930899ea760ecf33a4dba66be5e74", size = 489059, upload-time = "2025-11-02T12:25:54.619Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2e/bb/6670bded3e3236eb4287c7bcdc167e9fae6e1e9286e437f7111caed2f909/psutil-7.1.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b403da1df4d6d43973dc004d19cee3b848e998ae3154cc8097d139b77156c353", size = 239843, upload-time = "2025-11-02T12:26:11.968Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b8/66/853d50e75a38c9a7370ddbeefabdd3d3116b9c31ef94dc92c6729bc36bec/psutil-7.1.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ad81425efc5e75da3f39b3e636293360ad8d0b49bed7df824c79764fb4ba9b8b", size = 240369, upload-time = "2025-11-02T12:26:14.358Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/41/bd/313aba97cb5bfb26916dc29cf0646cbe4dd6a89ca69e8c6edce654876d39/psutil-7.1.3-cp314-cp314t-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8f33a3702e167783a9213db10ad29650ebf383946e91bc77f28a5eb083496bc9", size = 288210, upload-time = "2025-11-02T12:26:16.699Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c2/fa/76e3c06e760927a0cfb5705eb38164254de34e9bd86db656d4dbaa228b04/psutil-7.1.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fac9cd332c67f4422504297889da5ab7e05fd11e3c4392140f7370f4208ded1f", size = 291182, upload-time = "2025-11-02T12:26:18.848Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/1d/5774a91607035ee5078b8fd747686ebec28a962f178712de100d00b78a32/psutil-7.1.3-cp314-cp314t-win_amd64.whl", hash = "sha256:3792983e23b69843aea49c8f5b8f115572c5ab64c153bada5270086a2123c7e7", size = 250466, upload-time = "2025-11-02T12:26:21.183Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/00/ca/e426584bacb43a5cb1ac91fae1937f478cd8fbe5e4ff96574e698a2c77cd/psutil-7.1.3-cp314-cp314t-win_arm64.whl", hash = "sha256:31d77fcedb7529f27bb3a0472bea9334349f9a04160e8e6e5020f22c59893264", size = 245756, upload-time = "2025-11-02T12:26:23.148Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ef/94/46b9154a800253e7ecff5aaacdf8ebf43db99de4a2dfa18575b02548654e/psutil-7.1.3-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:2bdbcd0e58ca14996a42adf3621a6244f1bb2e2e528886959c72cf1e326677ab", size = 238359, upload-time = "2025-11-02T12:26:25.284Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/68/3a/9f93cff5c025029a36d9a92fef47220ab4692ee7f2be0fba9f92813d0cb8/psutil-7.1.3-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc31fa00f1fbc3c3802141eede66f3a2d51d89716a194bf2cd6fc68310a19880", size = 239171, upload-time = "2025-11-02T12:26:27.23Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/b1/5f49af514f76431ba4eea935b8ad3725cdeb397e9245ab919dbc1d1dc20f/psutil-7.1.3-cp36-abi3-manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3bb428f9f05c1225a558f53e30ccbad9930b11c3fc206836242de1091d3e7dd3", size = 263261, upload-time = "2025-11-02T12:26:29.48Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/95/992c8816a74016eb095e73585d747e0a8ea21a061ed3689474fabb29a395/psutil-7.1.3-cp36-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:56d974e02ca2c8eb4812c3f76c30e28836fffc311d55d979f1465c1feeb2b68b", size = 264635, upload-time = "2025-11-02T12:26:31.74Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/55/4c/c3ed1a622b6ae2fd3c945a366e64eb35247a31e4db16cf5095e269e8eb3c/psutil-7.1.3-cp37-abi3-win_amd64.whl", hash = "sha256:f39c2c19fe824b47484b96f9692932248a54c43799a84282cfe58d05a6449efd", size = 247633, upload-time = "2025-11-02T12:26:33.887Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/ad/33b2ccec09bf96c2b2ef3f9a6f66baac8253d7565d8839e024a6b905d45d/psutil-7.1.3-cp37-abi3-win_arm64.whl", hash = "sha256:bd0d69cee829226a761e92f28140bec9a5ee9d5b4fb4b0cc589068dbfff559b1", size = 244608, upload-time = "2025-11-02T12:26:36.136Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "swap"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { virtual = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "psutil" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.dev-dependencies]
|
||||||
|
dev = [
|
||||||
|
{ name = "line-profiler" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [{ name = "psutil", specifier = ">=7.1.3" }]
|
||||||
|
|
||||||
|
[package.metadata.requires-dev]
|
||||||
|
dev = [{ name = "line-profiler", specifier = ">=5.0.0" }]
|
||||||
Reference in New Issue
Block a user