1 """!This module allows querying resource usage and limits, as well as
2 setting resource limits. It is a wrapper around the Python resource
5 Setting resource limits:
7 use logging, produtil.rusage
8 logger=logging.logger("rusage")
9 produtil.rusage.setrlimit(logger,data=1e9,nofile=500,aspace=2e9,stack=5e8)
12 Printing resource limits to a logger:
14 use logging, produtil.rusage
15 logger=logging.logger("rusage")
16 u.produtil.rusage.getrlimit(logger) # writes the limits to the logger
17 # Limits are also in the returned object "u"
22 import resource, logging, StringIO, time
25 # Maps the name used in this module for each resource class to the
26 # name used by the Python resource module
27 rtypemap=dict(core=resource.RLIMIT_CORE,
28 cpu=resource.RLIMIT_CPU,
29 fsize=resource.RLIMIT_FSIZE,
30 data=resource.RLIMIT_DATA,
31 stack=resource.RLIMIT_STACK,
32 rss=resource.RLIMIT_RSS,
33 nproc=resource.RLIMIT_NPROC,
34 nofile=resource.RLIMIT_NOFILE,
35 #ofile=resource.RLIMIT_OFILE,
36 memlock=resource.RLIMIT_MEMLOCK,
37 #vmem=resource.RLIMIT_VMEM,
38 aspace=resource.RLIMIT_AS)
39 """Maps the name used
in this module
for each resource
class, to the
40 name used by the Python resource module.
"""
43 # Maps the name used in this module for each resource class, to a
44 # short human-readable string explaining the resource's meaning.
45 rnamemap=dict(core='core file size',
47 fsize='max. file size',
48 data='max. heap size',
49 stack='max. stack size',
50 rss='max. resident set size',
51 nproc='max. processes',
52 nofile='max. open files',
53 #ofile='max. open files (BSD)',
54 memlock='max. locked memory',
55 #vmem='max. virtual memory',
56 aspace='max. address space')
57 """Maps the name used
in this module
for each resource
class, to a
58 short human-readable string explaining the resource
's meaning."""
60 def setrlimit(logger=None, ignore=False, hard=False, **kwargs):
61 """!Sets resource limits.
63 @param ignore If ignore=True, ignores any errors from
64 getrlimit or setrlimit.
65 @param hard If hard=True, attempts to set hard
66 limits, which generally requires administrator privileges.
67 @param logger The logger argument sets the logger (default:
68 produtil.setrlimit logging domain).
69 @param kwargs The kwargs should be a list of resource limits.
70 Accepted resource limits:
71 * core = core file size (RLIMIT_CORE)
72 * cpu = max. cpu usage (RLIMIT_CPU)
73 * fsize = max. file size (RLIMIT_FSIZE)
74 * data = max. heap size (RLIMIT_DATA)
75 * stack = max. stack size (RLIMIT_STACK)
76 * rss = max. resident set size (RLIMIT_RSS)
77 * nproc = max. processes (RLIMIT_NPROC)
78 * nofile = max. open files (RLIMIT_NOFILE or RLIMIT_OFILE)
79 * memlock= max locked memory (RLIMIT_MEMLOCK)
80 * aspace = max. address space (RLIMIT_AS)
81 See "man setrlimit" for details."""
82 if logger
is None: logger=logging.getLogger(
'produtil.setrlimit')
83 for k,v
in kwargs.iteritems():
85 (softL,hardL)=resource.getrlimit(rtypemap[k])
89 if logger
is not None:
90 logger.info(
'Requesting %s (%s) soft=%s hard=%s'
91 %(k,rnamemap[k],softL,hardL))
92 resource.setrlimit(rtypemap[k],(softL,hardL))
93 except (resource.error,EnvironmentError,ValueError,TypeError,KeyError)
as e:
94 if logger
is not None:
95 logger.warning(
"%s: cannot set limit: %s"%(k,str(e)),exc_info=
True)
99 """!Gets the resource limits set on this process:
100 core, cpu, fsize, data, stack, rss, nproc, nofile, memlock, aspace
101 Each is set to a tuple containing the soft and hard limit."""
103 """!RLimit constructor
104 @param logger a logging.Logger for log messages."""
106 logger=logging.getLogger(
'produtil.getrlimit')
107 for (name,limit)
in rtypemap.iteritems():
109 r=resource.getrlimit(limit)
111 logger.warning(
'%s: cannot get limit: '
112 'getrlimit returned None.'%(name,))
113 self.__dict__[
'_limits_'+name]=r
114 except (resource.error,ValueError)
as e:
115 logger.warning(
'%s: cannot get limit: %s'%(name,str(e)),
118 """!Creates a multi-line string representation of the resource
120 out=StringIO.StringIO()
121 for k,v
in self.__dict__.iteritems():
123 if k[0:8]==
'_limits_':
125 if(soft<0): soft=hard
127 out.write(
'%7s - %25s = (unlimited)\n'%(kk,rnamemap[kk]))
129 out.write(
'%7s - %25s = %g\n'%(kk,rnamemap[kk],soft))
130 return out.getvalue()
133 """!Gets the current resource limits. If logger is not None,
134 sends the limits to the logger at level INFO.
135 @returns a RLimit object with resource information"""
136 rlimit=
RLimit(logger=logger)
137 if logger
is not None:
138 for line
in str(rlimit).splitlines():
144 rusage_keys=(
'ru_utime',
'ru_stime',
'ru_maxrss',
'ru_ixrss',
'ru_idrss',
145 'ru_isrss',
'ru_minflt',
'ru_majflt',
'ru_nswap',
'ru_inblock',
146 'ru_oublock',
'ru_msgsnd',
'ru_msgrcv',
'ru_nsignals',
147 'ru_nvcsw',
'ru_nivcsw')
148 """Tuple containing all rusage keys."""
152 rusage_meanings=dict(ru_utime=
'time in user mode',
153 ru_stime=
'time in system mode',
154 ru_maxrss=
'maximum resident set size',
155 ru_ixrss=
'shared memory size',
156 ru_idrss=
'unshared memory size',
157 ru_isrss=
'unshared stack size',
158 ru_minflt=
'page faults not requiring I/O',
159 ru_majflt=
'page faults requiring I/O',
160 ru_nswap=
'number of swap outs',
161 ru_inblock=
'block input operations',
162 ru_oublock=
'block output operations',
163 ru_msgsnd=
'messages sent',
164 ru_msgrcv=
'messages received',
165 ru_nsignals=
'signals received',
166 ru_nvcsw=
'voluntary context switches',
167 ru_nivcsw=
'involuntary context switches')
168 """A mapping from rusage key to a human-readable explanation of the
172 """!Raised when caller makes an RUsage, and tries to generate its
173 report, before calling its __enter__ or __exit__ routines."""
175 class RUsage(object):
176 """!Contains resource usage (rusage) information that can be used
177 with a Python "with" construct to collect the resources utilized
178 by a block of code, or group of subprocesses executing during that
183 with produtil.rusage.RUsage(logger=logging.getLogger("usage")):
185 ... stop doing things ...
188 Just after the "with" block exits, the resource usage is printed
189 to the given logger. The information can be retained for
192 u=produtil.rusage.RUsage(logger=logging.getLogger("usage"))
195 ... stop doing things ...
196 # u.rusage_before is a dict of resource usage before the block
197 # u.time_before contains the time before the block
198 # u.rusage_after contains the resource usage at the end of the block
199 # u.time_after contains the time after the block
202 Note that the logger is optional: without it, nothing is logged."""
203 def __init__(self,who=resource.RUSAGE_CHILDREN,logger=None):
204 """!Creates an RUsage object for input to a "with" statement.
206 @param who Pass who=resource.RUSAGE_SELF to get usage on this
207 process or rusage.RUSAGE_CHILDREN (the default) to get
208 resource usage on child processes.
209 @param logger a logging.Logger for log messages"""
235 """!The "who" parameter to the constructor, which selects
236 whether the usage measured should be of the child processes
237 (RUSAGE_CHILDREN) or this process (RUSAGE_SELF) . See
238 __init__ for details."""
242 """!System page size in bytes from resource.getpagesize().
243 This is needed to interpret return values."""
246 """!Gets the resource usage and time at the top of the "with"
247 block. This function is called automatically by the Python
248 interpreter at the beginning of a "with" block."""
252 """!Gets the resource usage and time at the end of a "with"
253 block. This is called automatically by Python at the end of a
255 @param type,value,tb exception information"""
258 if self.
logger is not None:
259 for line
in self.
report().splitlines():
260 self.logger.info(line)
262 """!Generates a string report of the resource usage utilized.
263 Accessible via str(self)."""
265 s=StringIO.StringIO()
268 if a
is None or b
is None:
269 raise RUsageNotRun(
"You cannot generate an RUsage report until you run RUsage.")
271 for k
in rusage_keys:
272 if hasattr(a,k)
and hasattr(b,k):
273 s.write(
'%11s - %29s = %g\n'%(k,rusage_meanings[k],
274 getattr(a,k)-getattr(b,k)))
275 s.write(
'%11s - %29s = %g\n'%(
'ru_walltime',
'wallclock time',dt))
279 """!Generates a string report of the resource usage utilized."""
281 return '(uninitialized RUsage report)'
289 """A synonym for RUsage"""
Raised when caller makes an RUsage, and tries to generate its report, before calling its enter or exi...
def __enter__(self)
Gets the resource usage and time at the top of the "with" block.
def getrlimit
Gets the current resource limits.
def __init__
Creates an RUsage object for input to a "with" statement.
def pagesize(self)
System page size in bytes from resource.getpagesize().
logger
The logging.Logger for log messages.
def __str__(self)
Generates a string report of the resource usage utilized.
def __init__
RLimit constructor.
def __str__(self)
Creates a multi-line string representation of the resource limits.
def __exit__(self, type, value, tb)
Gets the resource usage and time at the end of a "with" block.
def report(self)
Generates a string report of the resource usage utilized.
def who(self)
The "who" parameter to the constructor, which selects whether the usage measured should be of the chi...
time_before
The current time before usage monitoring began.
rusage_before
Resource usage before monitoring began.
Gets the resource limits set on this process: core, cpu, fsize, data, stack, rss, nproc...
def setrlimit(logger=None, ignore=False, hard=False, kwargs)
Sets resource limits.
time_after
The current time after monitoring ended.
rusage_after
The resource usage after monitoring ended.