Skip to content

Commit e2eabc5

Browse files
authored
Merge pull request #3808 from bdbaddog/remove_pywin32_for_memory_usage
Remove using pywin32 to retrieve peak memory usage for --debug=memory
2 parents 29145ce + 0378c0f commit e2eabc5

File tree

3 files changed

+109
-13
lines changed

3 files changed

+109
-13
lines changed

CHANGES.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER
1717
From William Deegan:
1818
- Fix yacc tool, not respecting YACC set at time of tool initialization.
1919
- Refactor SCons.Tool to move all common shared and loadable module linking logic to SCons.Tool.linkCommon
20+
- Remove using pywin32 to retrieve peak memory usage on Win32 for `--debug=memory`
2021

2122
From Michał Górny:
2223
- Fix dvipdf test failure due to passing incorrect flag to dvipdf.

SCons/Debug.py

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ def dumpLoggedInstances(classes, file=sys.stdout):
9090
file.write(' %20s : %s\n' % (key, value))
9191

9292

93-
9493
if sys.platform[:5] == "linux":
9594
# Linux doesn't actually support memory usage stats from getrusage().
9695
def memory():
@@ -102,28 +101,23 @@ def memory():
102101
#TODO really get memory stats for OS X
103102
def memory():
104103
return 0
104+
elif sys.platform == 'win32':
105+
from SCons.compat.win32 import get_peak_memory_usage
106+
memory = get_peak_memory_usage
105107
else:
106108
try:
107109
import resource
108110
except ImportError:
109-
try:
110-
import win32process
111-
import win32api
112-
except ImportError:
113-
def memory():
114-
return 0
115-
else:
116-
def memory():
117-
process_handle = win32api.GetCurrentProcess()
118-
memory_info = win32process.GetProcessMemoryInfo( process_handle )
119-
return memory_info['PeakWorkingSetSize']
111+
def memory():
112+
return 0
120113
else:
121114
def memory():
122115
res = resource.getrusage(resource.RUSAGE_SELF)
123116
return res[4]
124117

125-
# returns caller's stack
118+
126119
def caller_stack():
120+
"""return caller's stack"""
127121
import traceback
128122
tb = traceback.extract_stack()
129123
# strip itself and the caller from the output

SCons/compat/win32.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# MIT License
2+
#
3+
# Copyright The SCons Foundation
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining
6+
# a copy of this software and associated documentation files (the
7+
# "Software"), to deal in the Software without restriction, including
8+
# without limitation the rights to use, copy, modify, merge, publish,
9+
# distribute, sublicense, and/or sell copies of the Software, and to
10+
# permit persons to whom the Software is furnished to do so, subject to
11+
# the following conditions:
12+
#
13+
# The above copyright notice and this permission notice shall be included
14+
# in all copies or substantial portions of the Software.
15+
#
16+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17+
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23+
"""Logic to replicate parts of pywin32 SCons uses."""
24+
25+
__all__ = ['get_current_process', 'get_memory_info', 'get_memory_usage', 'get_peak_memory_usage']
26+
27+
import ctypes
28+
from ctypes import wintypes
29+
30+
#
31+
# From Activestate Recipe
32+
# https://code.activestate.com/recipes/578513-get-memory-usage-of-windows-processes-using-getpro/
33+
# MIT licensed
34+
#
35+
GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess
36+
GetCurrentProcess.argtypes = []
37+
GetCurrentProcess.restype = wintypes.HANDLE
38+
39+
SIZE_T = ctypes.c_size_t
40+
41+
42+
class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
43+
_fields_ = [
44+
('cb', wintypes.DWORD),
45+
('PageFaultCount', wintypes.DWORD),
46+
('PeakWorkingSetSize', SIZE_T),
47+
('WorkingSetSize', SIZE_T),
48+
('QuotaPeakPagedPoolUsage', SIZE_T),
49+
('QuotaPagedPoolUsage', SIZE_T),
50+
('QuotaPeakNonPagedPoolUsage', SIZE_T),
51+
('QuotaNonPagedPoolUsage', SIZE_T),
52+
('PagefileUsage', SIZE_T),
53+
('PeakPagefileUsage', SIZE_T),
54+
('PrivateUsage', SIZE_T),
55+
]
56+
57+
58+
GetProcessMemoryInfo = ctypes.windll.psapi.GetProcessMemoryInfo
59+
GetProcessMemoryInfo.argtypes = [
60+
wintypes.HANDLE,
61+
ctypes.POINTER(PROCESS_MEMORY_COUNTERS_EX),
62+
wintypes.DWORD,
63+
]
64+
GetProcessMemoryInfo.restype = wintypes.BOOL
65+
66+
67+
def get_current_process():
68+
"""Return handle to current process."""
69+
return GetCurrentProcess()
70+
71+
72+
def get_memory_info(process=None):
73+
"""Return Win32 process memory counters structure as a dict."""
74+
if process is None:
75+
process = get_current_process()
76+
counters = PROCESS_MEMORY_COUNTERS_EX()
77+
ret = GetProcessMemoryInfo(process, ctypes.byref(counters),
78+
ctypes.sizeof(counters))
79+
if not ret:
80+
raise ctypes.WinError()
81+
info = dict((name, getattr(counters, name))
82+
for name, _ in counters._fields_)
83+
return info
84+
85+
86+
def get_memory_usage(process=None):
87+
"""Return this process's memory usage in bytes."""
88+
info = get_memory_info(process=process)
89+
return info['PrivateUsage']
90+
91+
92+
def get_peak_memory_usage(process=None):
93+
"""Return this process's memory usage in bytes."""
94+
info = get_memory_info(process=process)
95+
return info['PeakWorkingSetSize']
96+
97+
98+
if __name__ == '__main__':
99+
import pprint
100+
101+
pprint.pprint(get_memory_info())

0 commit comments

Comments
 (0)