process Examples

pymemtrace.process is a very lightweight way of logging the total memory usage at regular time intervals. It creates a monitoring thread that writes process information as JSON to your log output.

Monitoring Your Python Process

Here is an example of including pymemtrace.process in your Python code:

import logging
import random
import sys
import time

from pymemtrace import process

logger = logging.getLogger(__file__)

def main() -> int:
    logging.basicConfig(
        level=logging.INFO,
        format=(
            '%(asctime)s - %(filename)s#%(lineno)d - %(process)5d
            ' - (%(threadName)-10s) - %(levelname)-8s - %(message)s'
            ),
    )
    logger.info('Demonstration of logging a process')
    # Log process data to the log file every 0.5 seconds.
    with process.log_process(interval=0.5, log_level=logger.getEffectiveLevel()):
        for i in range(8):
            size = random.randint(128, 128 + 256) * 1024 ** 2
            # Add a message to report in the next process write.
            process.add_message_to_queue(f'String of {size:,d} bytes')
            s = ' ' * size
            time.sleep(0.75 + random.random())
            del s
            time.sleep(0.25 + random.random() / 2)
    return 0

if __name__ == '__main__':
    sys.exit(main())

The output will be something like:

$ python pymemtrace/examples/ex_process.py
2020-11-16 10:36:38,886 - ex_process.py#19 - 14052 - (MainThread) - INFO     - Demonstration of logging a process
2020-11-16 10:36:38,887 - process.py#289 - 14052 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON-START {"timestamp": "2020-11-16 10:36:38.887407", "memory_info": {"rss": 11403264, "vms": 4376133632, "pfaults": 3417, "pageins": 0}, "cpu_times": {"user": 0.07780156, "system": 0.01763538, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 0.09744381904602051, "pid": 14052}
2020-11-16 10:36:39,392 - process.py#293 - 14052 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON {"timestamp": "2020-11-16 10:36:39.392076", "memory_info": {"rss": 209616896, "vms": 4574580736, "pfaults": 51809, "pageins": 0}, "cpu_times": {"user": 0.123138272, "system": 0.080602592, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 0.6022598743438721, "pid": 14052, "label": "String of 198,180,864 bytes"}
2020-11-16 10:36:39,892 - process.py#289 - 14052 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON {"timestamp": "2020-11-16 10:36:39.892747", "memory_info": {"rss": 209620992, "vms": 4574580736, "pfaults": 51810, "pageins": 0}, "cpu_times": {"user": 0.123503456, "system": 0.080648712, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 1.1028308868408203, "pid": 14052}
2020-11-16 10:36:40,397 - process.py#289 - 14052 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON {"timestamp": "2020-11-16 10:36:40.397231", "memory_info": {"rss": 11440128, "vms": 4376395776, "pfaults": 51811, "pageins": 0}, "cpu_times": {"user": 0.123984048, "system": 0.10224284, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 1.6074140071868896, "pid": 14052}
2020-11-16 10:36:40,901 - process.py#293 - 14052 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON {"timestamp": "2020-11-16 10:36:40.901329", "memory_info": {"rss": 320774144, "vms": 4685729792, "pfaults": 127332, "pageins": 0}, "cpu_times": {"user": 0.194056, "system": 0.191915568, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 2.1114120483398438, "pid": 14052, "label": "String of 309,329,920 bytes"}
...

Note the additions of "label": "String of 198,180,864 bytes" in two places.

JSON Data

The JSON data embedded in the log file line is typically:

{
    "cpu_times": {
        "children_system": 0.0,
        "children_user": 0.0,
        "system": 3.594337536,
        "user": 7.388873216
    },
    "elapsed_time": 68.32946181297302,
    "label": "String of 238.000 MB",
    "memory_info": {
        "pageins": 573,
        "pfaults": 518963,
        "rss": 41639936,
        "vms": 35048869888
    },
    "pid": 89781,
    "timestamp": "2026-03-23 11:49:18.406656"
}

Log Level and Frequency

The line:

with process.log_process(interval=0.5, log_level=logger.getEffectiveLevel()):
    # As before.

Instructs pymemtrace.process to report every 0.5 seconds to the current log at the current log level. You can specify an actual log level so:

with process.log_process(interval=0.5, logging.INFO):
    # As before.

And that will suppress any pymemtrace.process output if you have the logging level set at, in this example, INFO.

Using process as a Decorator

Sometimes it is useful to (temporarily) monitor a particular function for debugging purposes. pymemtrace.process provides a decorator pymemtrace.process.log_process_dec() for this purpose. Here is an example, first the imports and preamble:

import logging
import random
import sys
import time

from pymemtrace import process

logger = logging.getLogger(__file__)

Here is a function that just creates a list of large, randomly sized strings. It is decorated with pymemtrace.process.log_process_dec() to report to the log every 0.5 seconds:

@process.log_process_dec(interval=0.5, log_level=logger.getEffectiveLevel())
def example_process_decorator_basic():
    # create_list_of_strings...
    l = []
    for i in range(4):
        l.append(' ' * random.randint(20 * 1024 ** 2, 50 * 1024 ** 2))
        time.sleep(0.5)
    while len(l):
        l.pop()
        time.sleep(0.5)

Adding a main() calling function:

def main() -> int:
    logging.basicConfig(
        level=logging.INFO,
        format=(
            '%(asctime)s - %(filename)s#%(lineno)d - %(process)5d
            ' - (%(threadName)-10s) - %(levelname)-8s - %(message)s'
        ),
        stream=sys.stdout,
    )
    logger.info('Demonstration of logging a process')
    example_process_decorator_basic()
    return 0


if __name__ == '__main__':
    sys.exit(main())

Running this gives this, for example:

$ python3.13 pymemtrace/examples/ex_process_decorator.py
2026-03-21 12:39:35,034 - ex_process_decorator.py#37 - 82965 - (MainThread) - INFO     - Demonstration of logging a process
2026-03-21 12:39:35,035 - process.py#288 - 82965 - (ProcMon   ) - WARNING  - ProcessLoggingThread-JSON-START {"timestamp": "2026-03-21 12:39:35.035089", "memory_info": {"rss": 22712320, "vms": 34986401792, "pfaults": 6566, "pageins": 146}, "cpu_times": {"user": 1.062269568, "system": 1.0507504, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 2.547363042831421, "pid": 82965}
2026-03-21 12:39:35,536 - process.py#288 - 82965 - (ProcMon   ) - WARNING  - ProcessLoggingThread-JSON {"timestamp": "2026-03-21 12:39:35.535948", "memory_info": {"rss": 46358528, "vms": 35010007040, "pfaults": 12339, "pageins": 154}, "cpu_times": {"user": 1.087670144, "system": 1.05609504, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 3.048292875289917, "pid": 82965}
2026-03-21 12:39:36,038 - process.py#288 - 82965 - (ProcMon   ) - WARNING  - ProcessLoggingThread-JSON {"timestamp": "2026-03-21 12:39:36.037811", "memory_info": {"rss": 86491136, "vms": 35050139648, "pfaults": 22137, "pageins": 154}, "cpu_times": {"user": 1.134148608, "system": 1.069060928, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 3.5501270294189453, "pid": 82965}
2026-03-21 12:39:36,543 - process.py#288 - 82965 - (ProcMon   ) - WARNING  - ProcessLoggingThread-JSON {"timestamp": "2026-03-21 12:39:36.543283", "memory_info": {"rss": 126611456, "vms": 35090259968, "pfaults": 31933, "pageins": 154}, "cpu_times": {"user": 1.18200256, "system": 1.081039616, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 4.0557920932769775, "pid": 82965}
2026-03-21 12:39:37,048 - process.py#288 - 82965 - (ProcMon   ) - WARNING  - ProcessLoggingThread-JSON {"timestamp": "2026-03-21 12:39:37.047784", "memory_info": {"rss": 160964608, "vms": 35124613120, "pfaults": 40320, "pageins": 154}, "cpu_times": {"user": 1.225273984, "system": 1.091218048, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 4.5602850914001465, "pid": 82965}
2026-03-21 12:39:37,549 - process.py#288 - 82965 - (ProcMon   ) - WARNING  - ProcessLoggingThread-JSON {"timestamp": "2026-03-21 12:39:37.548690", "memory_info": {"rss": 160964608, "vms": 35124613120, "pfaults": 40320, "pageins": 154}, "cpu_times": {"user": 1.230032896, "system": 1.095199872, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 5.061201095581055, "pid": 82965}
2026-03-21 12:39:38,052 - process.py#288 - 82965 - (ProcMon   ) - WARNING  - ProcessLoggingThread-JSON {"timestamp": "2026-03-21 12:39:38.052779", "memory_info": {"rss": 160968704, "vms": 35124613120, "pfaults": 40321, "pageins": 154}, "cpu_times": {"user": 1.234988032, "system": 1.099866752, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 5.565093040466309, "pid": 82965}
2026-03-21 12:39:38,557 - process.py#288 - 82965 - (ProcMon   ) - WARNING  - ProcessLoggingThread-JSON {"timestamp": "2026-03-21 12:39:38.557330", "memory_info": {"rss": 160968704, "vms": 35124613120, "pfaults": 40322, "pageins": 154}, "cpu_times": {"user": 1.241057152, "system": 1.104048384, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 6.069844007492065, "pid": 82965}
2026-03-21 12:39:39,062 - process.py#288 - 82965 - (ProcMon   ) - WARNING  - ProcessLoggingThread-JSON {"timestamp": "2026-03-21 12:39:39.061620", "memory_info": {"rss": 160968704, "vms": 35124613120, "pfaults": 40322, "pageins": 154}, "cpu_times": {"user": 1.245515776, "system": 1.10786624, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 6.574124813079834, "pid": 82965}
2026-03-21 12:39:39,286 - process.py#288 - 82965 - (MainThread) - WARNING  - ProcessLoggingThread-JSON-STOP {"timestamp": "2026-03-21 12:39:39.286393", "memory_info": {"rss": 160972800, "vms": 35124613120, "pfaults": 40323, "pageins": 154}, "cpu_times": {"user": 1.246212992, "system": 1.10794368, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 6.798800945281982, "pid": 82965}

Process finished with exit code 0

Thst is a lot to swallow so see Summarising the Log File below which simplifies the output to the essential details.

See pymemtrace/examples/ex_process_decorator.py for this example.

Monitoring Another Process

pymemtrace.process can monitor any another process from the command line by giving it the PID:

$ python pymemtrace/process.py -p 71519
2020-11-10 20:46:41,687 - process.py#354 - 71869 - (MainThread) - INFO     - Demonstration of logging a process
Monitoring 71519
2020-11-10 20:46:41,689 - process.py#289 - 71869 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON-START {"timestamp": "2020-11-10 20:46:41.688480", "memory_info": {"rss": 12906496, "vms": 4359774208, "pfaults": 3310, "pageins": 960}, "cpu_times": {"user": 0.248923952, "system": 0.078601624, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 1396.3783469200134, "pid": 71519}
2020-11-10 20:46:42,693 - process.py#289 - 71869 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON {"timestamp": "2020-11-10 20:46:42.693520", "memory_info": {"rss": 12906496, "vms": 4359774208, "pfaults": 3310, "pageins": 960}, "cpu_times": {"user": 0.248923952, "system": 0.078601624, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 1397.3834369182587, "pid": 71519}
2020-11-10 20:46:43,697 - process.py#289 - 71869 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON {"timestamp": "2020-11-10 20:46:43.697247", "memory_info": {"rss": 12906496, "vms": 4359774208, "pfaults": 3310, "pageins": 960}, "cpu_times": {"user": 0.248923952, "system": 0.078601624, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 1398.3871541023254, "pid": 71519}
2020-11-10 20:46:44,701 - process.py#289 - 71869 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON {"timestamp": "2020-11-10 20:46:44.701290", "memory_info": {"rss": 12906496, "vms": 4359774208, "pfaults": 3310, "pageins": 960}, "cpu_times": {"user": 0.248923952, "system": 0.078601624, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 1399.391231060028, "pid": 71519}
2020-11-10 20:46:45,705 - process.py#289 - 71869 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON {"timestamp": "2020-11-10 20:46:45.705679", "memory_info": {"rss": 12906496, "vms": 4359774208, "pfaults": 3310, "pageins": 960}, "cpu_times": {"user": 0.248923952, "system": 0.078601624, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 1400.3956229686737, "pid": 71519}
2020-11-10 20:46:46,708 - process.py#289 - 71869 - (ProcMon   ) - INFO     - ProcessLoggingThread-JSON {"timestamp": "2020-11-10 20:46:46.708657", "memory_info": {"rss": 12906496, "vms": 4359774208, "pfaults": 3310, "pageins": 960}, "cpu_times": {"user": 0.248923952, "system": 0.078601624, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 1401.398586988449, "pid": 71519}
^CKeyboardInterrupt!
2020-11-10 20:46:47,626 - process.py#289 - 71869 - (MainThread) - INFO     - ProcessLoggingThread-JSON-STOP {"timestamp": "2020-11-10 20:46:47.626020", "memory_info": {"rss": 12906496, "vms": 4359774208, "pfaults": 3310, "pageins": 960}, "cpu_times": {"user": 0.248923952, "system": 0.078601624, "children_user": 0.0, "children_system": 0.0}, "elapsed_time": 1402.3160009384155, "pid": 71519}
Bye, bye!

Summarising the Log File

pymemtrace.process can read a captured log file and summarise it.

Taking the decorator example above we can pipe the log to a file:

$ python pymemtrace/examples/ex_process_decorator.py > tmp/ex_process_decorator.py.txt

Then we can analyse the saved log file:

$ python pymemtrace/process.py tmp/ex_process_decorator.py.txt
-------------------------------- PID: 83606 -------------------------------
#t(s)                 RSS PageFaults/s         User    Mean_CPU%    Inst_CPU% Timestamp                     PID Label
0.4              18477056      12104.2          0.2        38.1%        38.1% 2026-03-21T13:07:51.567924  83606 #
0.9              51056640      15748.4          0.2        22.0%         8.8% 2026-03-21T13:07:52.071953  83606 #
1.4              85819392      16833.1          0.3        18.5%        12.2% 2026-03-21T13:07:52.576988  83606 #
1.9             125403136      19279.2          0.3        16.2%         9.5% 2026-03-21T13:07:53.078218  83606 #
2.4             159227904      16374.3          0.4        14.7%         9.2% 2026-03-21T13:07:53.582512  83606 #
2.9             159227904          0.0          0.4        12.3%         0.9% 2026-03-21T13:07:54.086849  83606 #
3.4             159227904          0.0          0.4        11.0%         3.4% 2026-03-21T13:07:54.590127  83606 #
3.9             159227904          0.0          0.4         9.7%         0.5% 2026-03-21T13:07:55.091277  83606 #
4.4             159227904          0.0          0.4         8.7%         1.0% 2026-03-21T13:07:55.596389  83606 #
4.7             159227904          0.0          0.4         8.2%         0.3% 2026-03-21T13:07:55.884672  83606 #
----------------------------- PID: 83606 DONE -----------------------------
Bye, bye!

Using gnuplot on the Log File

pymemtrace.process can extract memory data from the log file and write the necessary files for plotting with gnuplot (which must be installed).

For example run a process and save the log output:

$ mkdir tmp
$ python pymemtrace/examples/ex_process.py > tmp/process.log 2>&1

Now run pymemtrace.process with that log file and an output location:

$ mkdir tmp/gnuplot
$ python pymemtrace/process.py tmp/process.log tmp/gnuplot/
2020-11-16 10:39:55,884 - gnuplot.py#114 - 14141 - (MainThread) - INFO     - gnuplot stdout: None
2020-11-16 10:39:55,887 - gnuplot.py#67 - 14141 - (MainThread) - INFO     - Writing gnuplot data "process.log_14129" in path tmp/gnuplot/
2020-11-16 10:39:55,924 - gnuplot.py#85 - 14141 - (MainThread) - INFO     - gnuplot stdout: None
Bye, bye!

In the destination will be the gnuplot data:

$ ll tmp/gnuplot/
total 160
-rw-r--r--  1 user  staff   4829 16 Nov 10:39 process.log_14129.dat
-rw-r--r--  1 user  staff   2766 16 Nov 10:39 process.log_14129.plt
-rw-r--r--  1 user  staff  32943 16 Nov 10:39 process.log_14129.png
-rw-r--r--  1 user  staff  32100 16 Nov 10:39 test.png

The file process.log_14129.png will look like this. The memory, page faults and CPU usage and the plot is annotated with the lables made by the line process.add_message_to_queue(f'String of {size:,d} bytes') in the script above:

Example of process.py