pmemstat 3.0.3__tar.gz → 3.0.4__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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.1
2
2
  Name: pmemstat
3
- Version: 3.0.3
3
+ Version: 3.0.4
4
4
  Summary: Report Proportional Memory on Linux
5
5
  Keywords: proportional memory,RAM,htop,top,monitor
6
6
  Author-email: Joe Defen <joedef@duck.com>
@@ -9,9 +9,8 @@ Description-Content-Type: text/markdown
9
9
  Classifier: Programming Language :: Python :: 3
10
10
  Classifier: License :: OSI Approved :: MIT License
11
11
  Classifier: Operating System :: POSIX :: Linux
12
- License-File: LICENSE.txt
13
12
  Requires-Dist: psutil > 5.9
14
- Requires-Dist: console-window >= 1.0.0
13
+ Requires-Dist: console-window >= 1.0.5
15
14
  Project-URL: Bug Tracker, https://github.com/joedefen/pmemstat/issues
16
15
  Project-URL: Homepage, https://github.com/joedefen/pmemstat
17
16
 
@@ -94,6 +94,92 @@ def human(number):
94
94
  return f'{number:.1f}{suffix}'
95
95
  return '' # impossible, but make pylint happy
96
96
 
97
+ ####################################################################################
98
+ # PORTABLE FUNCTION - Copy-pasted from zram-advisor
99
+ # When updating: copy entire function from zram_advisor/main.py (lines 86-166)
100
+ ####################################################################################
101
+ def compute_zram_effective(meminfo_total, meminfo_used, meminfo_available,
102
+ zram_orig_data_size, zram_mem_used_total,
103
+ zram_disksize, zram_mem_limit=0, limit_pct=80):
104
+ """
105
+ Compute effective memory values accounting for zRAM compression.
106
+
107
+ This is a PORTABLE function that can be copy-pasted between projects.
108
+ NO class dependencies - all inputs passed as parameters.
109
+
110
+ Args:
111
+ meminfo_total: Total physical RAM in bytes
112
+ meminfo_used: Currently used RAM in bytes
113
+ meminfo_available: Available RAM in bytes
114
+ zram_orig_data_size: Uncompressed data size stored in zRAM (bytes)
115
+ zram_mem_used_total: Physical RAM consumed by zRAM including overhead (bytes)
116
+ zram_disksize: Max uncompressed data zRAM will accept (bytes)
117
+ zram_mem_limit: Max RAM zRAM can use (0=unlimited) (bytes)
118
+ limit_pct: Arbitrary limit on % of RAM zRAM should use (default 80%)
119
+
120
+ Returns:
121
+ SimpleNamespace with:
122
+ - e_used: Effective memory used (uncompressed equivalent)
123
+ - e_avail: Effective memory available
124
+ - e_max_used: Maximum effective memory at full zRAM capacity
125
+ - ratio_current: Current effective compression ratio
126
+ - ratio_projected: Projected ratio accounting for degradation
127
+ - projection_confidence: 'low', 'medium', or 'high'
128
+ - usage_fraction: Fraction of disksize currently used
129
+ """
130
+ # Calculate effective used memory (what it would be if uncompressed)
131
+ e_used = meminfo_used - zram_mem_used_total + zram_orig_data_size
132
+
133
+ # Determine compression ratio
134
+ ratio = None
135
+ if e_used <= meminfo_used: # zRAM not helping yet
136
+ e_used = meminfo_used
137
+ ratio = 2.75 # Conservative guess for projection when no data yet
138
+
139
+ if ratio is None: # Calculate actual ratio
140
+ ratio = zram_orig_data_size / zram_mem_used_total if zram_mem_used_total > 0 else 2.75
141
+
142
+ # Apply memory limit if configured
143
+ if zram_mem_limit > 0:
144
+ stats_limit_pct = (zram_mem_limit / meminfo_total) * 100
145
+ limit_pct = min(100.0, limit_pct, stats_limit_pct)
146
+
147
+ # Calculate usage fraction and apply degradation
148
+ usage_fraction = zram_orig_data_size / zram_disksize if zram_disksize > 0 else 0
149
+
150
+ # Degradation logic based on current usage
151
+ if usage_fraction < 0.10:
152
+ degradation_factor = 0.75 # Aggressive: little real data
153
+ confidence = "low"
154
+ elif usage_fraction < 0.50:
155
+ degradation_factor = 0.85 # Moderate: some real data
156
+ confidence = "medium"
157
+ else:
158
+ degradation_factor = 0.95 # Conservative: lots of real data
159
+ confidence = "high"
160
+
161
+ projected_ratio = ratio * degradation_factor
162
+
163
+ # Project maximum effective memory when zRAM fills to limit
164
+ e_max_used = projected_ratio * meminfo_total * limit_pct / 100
165
+ # Cap by disksize limit
166
+ e_max_used = min(e_max_used, zram_disksize)
167
+ # Add uncompressed memory not in zRAM
168
+ e_max_used += meminfo_total - e_max_used / projected_ratio
169
+
170
+ # Calculate effective available
171
+ e_avail = e_max_used - e_used
172
+
173
+ return SimpleNamespace(
174
+ e_used=e_used,
175
+ e_avail=e_avail,
176
+ e_max_used=e_max_used,
177
+ ratio_current=ratio,
178
+ ratio_projected=projected_ratio,
179
+ projection_confidence=confidence,
180
+ usage_fraction=usage_fraction
181
+ )
182
+
97
183
  ####################################################################################
98
184
  ###### ZramProjector class
99
185
  ####################################################################################
@@ -156,7 +242,7 @@ class ZramProjector:
156
242
  return infos
157
243
 
158
244
  def compute_effective(self, meminfoKB):
159
- """ Compute the effective values """
245
+ """ Compute the effective values - now uses portable function """
160
246
  def seed(meminfoKB):
161
247
  nonlocal self
162
248
  meminfo = self.meminfo = SimpleNamespace()
@@ -175,6 +261,8 @@ class ZramProjector:
175
261
  devs = self._get_zram_stats()
176
262
  if not devs:
177
263
  return
264
+
265
+ # Aggregate stats from all zRAM devices
178
266
  stats = None
179
267
  for stat in devs.values():
180
268
  # NOTE: generalization for more than one weak unless all
@@ -187,29 +275,25 @@ class ZramProjector:
187
275
  stats = SimpleNamespace(**stats)
188
276
  self.meminfo.MemZram = stats.mem_used_total
189
277
 
190
- e_used = meminfo.MemUsed - stats.mem_used_total + stats.orig_data_size
191
- ratio, self.ratio = None, 0.0
192
- if e_used <= self.e_used: # zram hurts. assume not enuf data to project
193
- e_used = self.e_used
194
- self.ratio = ratio = 3.5 # wild guess for projection
195
- # if self.DB: dump_effective(ns, '(unchg)')
196
- # return ns
197
- self.e_used = e_used
198
- limit_pct = self.limit_pct
199
- if stats.mem_limit > 0:
200
- stats_limit_pct = (stats.limit / meminfo.MemTotal)*100
201
- limit_pct = min(1.0, limit_pct, stats_limit_pct)
202
- # projected amount of orig used memory that fits in limit
203
- if ratio is None: # hopefully about 4 ;-)
204
- self.ratio = ratio = stats.orig_data_size / stats.mem_used_total
205
- e_max_used = ratio * meminfo.MemTotal * limit_pct/100
206
- # now limit by disksize
207
- e_max_used = min(e_max_used, stats.disksize)
208
- # now add uncompressed memory
209
- e_max_used += meminfo.MemTotal - e_max_used/ratio
210
- self.e_max_used = e_max_used
211
- # self.e_max_used = max(e_max_total, e_max_used)
212
- self.e_avail = e_max_used - e_used
278
+ # Call the portable computation function
279
+ result = compute_zram_effective(
280
+ meminfo_total=meminfo.MemTotal,
281
+ meminfo_used=meminfo.MemUsed,
282
+ meminfo_available=meminfo.MemAvailable,
283
+ zram_orig_data_size=stats.orig_data_size,
284
+ zram_mem_used_total=stats.mem_used_total,
285
+ zram_disksize=stats.disksize,
286
+ zram_mem_limit=stats.mem_limit,
287
+ limit_pct=self.limit_pct
288
+ )
289
+
290
+ # Update instance variables from result
291
+ self.e_used = result.e_used
292
+ self.e_avail = result.e_avail
293
+ self.e_max_used = result.e_max_used
294
+ self.ratio = result.ratio_current
295
+ self.ratio_projected = result.ratio_projected
296
+ self.projection_confidence = result.projection_confidence
213
297
 
214
298
 
215
299
  ####################################################################################
@@ -1314,7 +1398,12 @@ def rerun_module_as_root(module_name):
1314
1398
  """ rerun using the module name """
1315
1399
  if os.geteuid() != 0: # Re-run the script with sudo
1316
1400
  os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
1317
- vp = ['sudo', sys.executable, '-m', module_name] + sys.argv[1:]
1401
+ # Preserve PYTHONPATH to allow sudo to find user-installed packages
1402
+ pythonpath = os.pathsep.join(sys.path)
1403
+ env_vars = os.environ.copy()
1404
+ env_vars['PYTHONPATH'] = pythonpath
1405
+ # Use env to pass PYTHONPATH through sudo
1406
+ vp = ['sudo', 'env', f'PYTHONPATH={pythonpath}', sys.executable, '-m', module_name] + sys.argv[1:]
1318
1407
  os.execvp('sudo', vp)
1319
1408
 
1320
1409
  def main():
@@ -4,7 +4,7 @@ build-backend = "flit_core.buildapi"
4
4
 
5
5
  [project]
6
6
  name = "pmemstat"
7
- version = "3.0.3"
7
+ version = "3.0.4"
8
8
  description = "Report Proportional Memory on Linux"
9
9
  authors = [
10
10
  {name = "Joe Defen", email = "joedef@duck.com"},
@@ -20,7 +20,7 @@ classifiers = [
20
20
  ]
21
21
  dependencies = [
22
22
  'psutil > 5.9',
23
- 'console-window >= 1.0.0',
23
+ 'console-window >= 1.0.5',
24
24
  ]
25
25
 
26
26
  [project.urls]
pmemstat-3.0.4/runner ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env python3
2
+ # runner.py
3
+ # Located in the top-level <svr pmemstat> directory
4
+
5
+ import os
6
+ import sys
7
+
8
+ # Add the project directory to PYTHONPATH for editable install support
9
+ project_dir = os.path.dirname(os.path.abspath(__file__))
10
+ if project_dir not in sys.path:
11
+ sys.path.insert(0, project_dir)
12
+
13
+ # Import and run the main module directly
14
+ if __name__ == '__main__':
15
+ sys.argv[0] = 'pmemstat'
16
+ from pmemstat import main
17
+ main.run()
pmemstat-3.0.3/run.sh DELETED
@@ -1,9 +0,0 @@
1
- #!/bin/bash
2
-
3
- SRC="$(dirname "$0")/src"
4
-
5
- set -x
6
- ##### choose one:
7
-
8
- PYTHONPATH="$SRC" python3 -m pmemstat.main "$@"
9
- # PYTHONPATH="$SRC" python3 src/pmemstat/main.py "$@"
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