~javiljoen/monitor

Remove references to GitHub from README & setup.py
Fix quoting for bumpversion
ad52b0fa — Jack Viljoen 6 years ago
cleanup
605e2dec — Jack Viljoen 6 years ago
Bump version: 0.4.0 → 1.0.0
ff5f871a — Jack Viljoen 6 years ago
upate (& simplify) for latest psutil

closes #3
617d0ca7 — Jack Viljoen 6 years ago
update example output in readme to exclude i/o
f06cdc93 — Jack Viljoen 6 years ago
fix command in readme
f06cda12 — Jack Viljoen 6 years ago
Bump version: 0.3.0 → 0.4.0
cc075cd3 — Jack Viljoen 6 years ago
make i/o measurements optional

also catch errors when recording i/o
80ae8abb — Jack Viljoen 6 years ago
Bump version: 0.2.0 → 0.3.0
3e2804ca — Jack Viljoen 6 years ago
replace docopt with click as CLI lib
07cc3e00 — Jack Viljoen 6 years ago
clean up script & make pip-installable

diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644
index 0000000..5878d4a --- /dev/null +++ b/.bumpversion.cfg @@ -0,0
+1,13 @@ +[bumpversion] +current_version = 0.2.0 +commit = True +tag =
True + +[bumpversion:file:setup.py] +search =
version="{current_version}" +replace = version="{new_version}" +
+[bumpversion:file:monitor/__init__.py] +search = __version__ =
'{current_version}' +replace = __version__ = '{new_version}' + diff
--git a/README.rst b/README.rst index 985842c..372e5de 100644 ---
a/README.rst +++ b/README.rst @@ -58,16 +58,19 @@ subprocess.
Installation ------------

-``monitor.py`` is a simple, self-contained Python script, so just
-download it from GitHub, ``chmod +x`` it, and run it.
-
-The simplest way to get the whole source folder is:: +Download the
source from GitHub::

    git clone [--depth=1] https://github.com/javiljoen/monitor.git

 where the ``depth`` parameter will get you the latest version only
 instead of the whole commit history.

+Then install the package into a virtual environment, e.g.:: + +   conda
create -n monitor python=3 psutil=1 docopt +   source activate monitor +
pip install monitor +

 Requirements ^^^^^^^^^^^^ @@ -84,7 +87,7 @@ Testing

 ::

-   monitor/monitor.py tests/testscript.sh +   monitor
    monitor/tests/testscript.sh

 ------------------------------------------------------------------------
 diff --git a/monitor/monitor.py b/monitor/monitor.py index
 9cf1273..ea9ecd5 100755 --- a/monitor/monitor.py +++
 b/monitor/monitor.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3
 -'''Per-process resource monitor +"""Per-process resource monitor

 Usage:
-    monitor.py [-i INTERVAL] [-s SEP] [-p PROCTYPE] [-o OUTPUT] CMD
-    monitor.py -h +    monitor [-i INTERVAL] [-s SEP] [-p PROCTYPE] [-o
     OUTPUT] CMD +    monitor -h

 Options: -h --help    this message @@ -19,120 +19,88 @@ with single
 quotes. (If not escaped, it may be unclear whether the options apply to
 the monitoring or the monitored process.)

 e.g.
-    monitor.py 'sleep 2' +    monitor 'sleep 2'

 Warning: Likely to fail on short-running commands (like `du -s .`)!

-This script is inspired by: +""" +from time import sleep

-    * https://github.com/jeetsukumaran/Syrupy
-    * https://github.com/Dieterbe/profile-process +import psutil +from
     docopt import docopt

-It differs from Syrupy in also accounting for child processes, while
-being much less sophisticated in all other regards. It also requires
-the `psutil` module to be installed to provide the `.get_children()`
-method.

-The `psutil` loop is a reimplementation of the one in `profile-process`
-that does not send the data straight to matplotlib for plotting, and
-breaks it up into usage stats per subprocess.  +def monitor(command,
interval=1.0, sep='\t', proctype='pname'): +    """Record resource usage
of `command` every `interval` seconds.

-Dependencies:
-    * Python 3
-    * psutil 1.2 (syntax changes in v. 2)
-    * docopt +    Returns the resource usage of `command` and each
     subprocess it +    spawned as a list of `sep`-separated strings: +
     one for each process at each sampling point in time.

-Tested with Python 3.3.4 and psutil 1.2.1.  +    `proctype` must be
either 'pname' or 'cmdline'.  +    """

-''' +    def measure_resources(process): +        if
process.is_running(): +            cpu_percent =
process.get_cpu_percent(interval=0) +            n_threads =
process.get_num_threads() +            mem_info =
process.get_memory_info() +            io_counters =
process.get_io_counters() +            return cpu_percent, n_threads,
mem_info, io_counters

-from time import sleep -import psutil +    def format_resources(t, pid,
pname, res=None, sep='\t'): +        """Convert bytes to MB and return
fields as a `sep`-separated string.

-def monitor(command, interval, sep, proctype):
-    '''(str, float, str) -> list(str)
-
-    Record resource usage of `command` every `interval` seconds,
-    do some formatting and return the resource usage of `command` and
-    each subprocess it spawned as a list of `sep`-separated strings:
-    one line for each process at each sampling point in time.
-    `proctype` is either 'pname' or 'cmdline'.
-
-    '''
-    def measure_resources(p):
-        '''Process -> (int, int, [int, int], [int, int, int, int])'''
-        if p.is_running():
-            CPU = p.get_cpu_percent(interval=0)
-            THD = p.get_num_threads()
-            MEM = p.get_memory_info()
-            IO  = p.get_io_counters()
-            return (CPU, THD, MEM, IO)
-
-    def format_resources(t, pid, pname, res, sep):
-        '''(float, int, str, (result of measure_resources()), str) ->
         str
-
-        Convert bytes to MB and return fields as a `sep`-separated
         string.  If measure_resources() returned None, return the
         string with empty fields where appropriate.
-
-        ''' +        """ if res is not None:
-            CPU, THD, MEM, IO = res
-            RSS = MEM[0] // 1048576 # convert to MB
-            VMS = MEM[1] // 1048576 # convert to MB
-            IOr, IOw, IOrb, IOwb = IO
-            IOrb = IOrb // 1048576 # convert to MB
-            IOwb = IOwb // 1048576 # convert to MB
-            data = (t, CPU, THD, RSS, VMS, IOr, IOw, IOrb, IOwb, pid,
             pname) +            cpu_percent, n_threads, mem_info,
             io_counters = res +            bytes_per_mb = 2 ** 20 +
             mem_rss = mem_info[0] // bytes_per_mb +            mem_vms
             = mem_info[1] // bytes_per_mb +            reads, writes,
             read_bytes, written_bytes = io_counters +
             read_mb = read_bytes // bytes_per_mb +
             written_mb = written_bytes // bytes_per_mb +
             data = (t, +                    cpu_percent, n_threads,
             mem_rss, mem_vms, +                    reads, writes,
             read_mb, written_mb, +                    pid, pname) else:
             data = (t, '' * 8, pid, pname)

         return sep.join((str(n) for n in data))

-    ## initialize
     # res_use = []
     t = 0

-    ## start the command running
-    proc = psutil.Popen(command, shell=False)
-
-    ## in each sampling interval:
-    ## * check that the main process has not yet terminated
-    ## * get a list of its child processes
-    ## * then for each one, measure resource usage
-    while proc.poll() is None:
-        procs = [proc] + proc.get_children(recursive=True)
-
-        # for p in procs:
-            # resource_use = measure_resources(p)
-            # output_str = format_resources(t, p.pid, p.name,
             resource_use, sep)
-            # res_use.append(output_str)
-
-        ## do all measurements first.
-        ## if using a `for` loop with formatting and IO (as above),
-        ## the next process might end before it is measured
-        resource_use = [measure_resources(p) for p in procs]
-        # output_str = [format_resources(t, procs[i].pid,
         procs[i].name, resource_use[i], sep)
-        #               for i in range(len(procs))]
-        # res_use += output_str
-        for i in range(len(procs)): +    process =
         psutil.Popen(command, shell=False) + +    # In each sampling
         interval: +    # * check that the main process has not yet
         terminated +    # * get a list of its child processes +    # *
         then for each one, measure resource usage +    while
         process.poll() is None: +        processes = [process] +
         process.get_children(recursive=True) + +        # Do all
         measurements first: +        # If doing formatting inside this
         `for` loop, the next process +        # might have ended before
         it is measured.  +        resource_use = [measure_resources(p)
         for p in processes] + +        for proc, res in zip(processes,
         resource_use): if proctype == 'cmdline':
-                cmdline = ' '.join(procs[i].cmdline)
-                yield format_resources(t, procs[i].pid, cmdline,
                 resource_use[i], sep) +                pname = '
                 '.join(proc.cmdline) else:
-                yield format_resources(t, procs[i].pid, procs[i].name,
                 resource_use[i], sep) +                pname =
                 proc.name + +            yield format_resources(t,
                 proc.pid, pname, res, sep)

         sleep(interval) t += interval

-    # return res_use
-
-
-if __name__ == '__main__':
-    from docopt import docopt
-    import sys

-    ## parse user settings +def main(): args = docopt(__doc__) interval
     = float(args['-i']) sep = args['-s'] @@ -145,21 +113,21 @@ if
     __name__ == '__main__': 'IO reads', 'IO writes', 'IO read MB', 'IO
     written MB', 'PID', 'Process')

+    resource_usage = monitor(child_args, interval, sep, proctype) + if
outfile != '-': with open(outfile, 'w') as out:
-            # ## run the command and record resource usage
-            # resource_use = monitor(child_args, interval, sep)
-
-            ## write out results out.write(sep.join(data_heads) + '\n')

-            # for l in resource_use:
-            for i, l in enumerate(monitor(child_args, interval, sep,
             proctype)):
-                out.write(l + '\n') +            for i, line in
                 enumerate(resource_usage): +
                 out.write(line + '\n') if i % 100 == 0: out.flush()
                 else:
-        sys.stdout.write(sep.join(data_heads) + '\n')
-        for l in monitor(child_args, interval, sep, proctype):
-            sys.stdout.write(l + '\n') +
             print(sep.join(data_heads)) +        for line in
             resource_usage: +            print(line)

+ +if __name__ == '__main__': +    main() diff --git a/requirements.txt
b/requirements.txt new file mode 100644 index 0000000..af7189a ---
/dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +docopt==0.6.2
+psutil==1.2.1 diff --git a/setup.py b/setup.py new file mode 100644
index 0000000..2492f46 --- /dev/null +++ b/setup.py @@ -0,0 +1,31 @@
+import setuptools + +setuptools.setup( +    name='monitor', +
version='0.2.0', +    url='https://github.com/javiljoen/monitor', + +
author='Jack Viljoen', +
author_email='javiljoen@users.noreply.github.com', +
+    description='Resource monitor for profiling processes and their subprocesses',
+    long_description=open('README.rst').read(),
+
+    packages=['monitor'],
+
+    install_requires=[
+        'docopt',
+        'psutil>=1,<2',
+    ],
+
+    classifiers=[
+        'Development Status :: 2 - Pre-Alpha',
+        'Programming Language :: Python',
+        'Programming Language :: Python :: 3',
+    ],
+    entry_points={
+        'console_scripts': [
+            'monitor = monitor.monitor:main',
+        ],
+    },
+)
c25681d8 — Jack Viljoen 6 years ago
improve package structure
b041f0af — Jack Viljoen 6 years ago
remove R package & scripts
49d04d12 — Jack Viljoen 6 years ago
Create LICENSE
acc3de0e — Jack Viljoen 8 years ago
add devtools setup script
863eb518 — Jack Viljoen 8 years ago v.0.2
update readme with R package commands
dbb854c5 — Jack Viljoen 8 years ago
add R package files
8c239778 — Jack Viljoen 8 years ago
add plotting function & CLI script
f0b386a6 — Jack Viljoen 8 years ago
cleanup
Next