481

Is there a tool that will run a command-line and report the peak RAM usage total?

I'm imagining something analogous to /usr/bin/time

Christian Hudon
  • 1,881
  • 1
  • 21
  • 42
jes5199
  • 18,324
  • 12
  • 36
  • 40

20 Answers20

523

[Edit: Works on Ubuntu 14.04: /usr/bin/time -v command Make sure to use the full path.]

Looks like /usr/bin/time does give you that info, if you pass -v (this is on Ubuntu 8.10). See, e.g., Maximum resident set size below:

$ /usr/bin/time -v ls /
....
        Command being timed: "ls /"
        User time (seconds): 0.00
        System time (seconds): 0.01
        Percent of CPU this job got: 250%
        Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
        Average shared text size (kbytes): 0
        Average unshared data size (kbytes): 0
        Average stack size (kbytes): 0
        Average total size (kbytes): 0
        Maximum resident set size (kbytes): 0
        Average resident set size (kbytes): 0
        Major (requiring I/O) page faults: 0
        Minor (reclaiming a frame) page faults: 315
        Voluntary context switches: 2
        Involuntary context switches: 0
        Swaps: 0
        File system inputs: 0
        File system outputs: 0
        Socket messages sent: 0
        Socket messages received: 0
        Signals delivered: 0
        Page size (bytes): 4096
        Exit status: 0
Michael Cole
  • 15,473
  • 7
  • 79
  • 96
Jacob Gabrielson
  • 34,800
  • 15
  • 46
  • 64
  • 4
    Probably it always returns 0 because ls isn't doing much. Try a more CPU intensive command. – Jon 'links in bio' Ericson Apr 21 '09 at 21:09
  • me too :( at least on the stack size, which I find strange, as I ran a recursive call for stack-overflow.. – Liran Orevi Apr 21 '09 at 21:34
  • 21
    From the man page: Most information shown by time is derived from the wait3(2) system call. The numbers are only as good as those returned by wait3(2). On systems that do not have a wait3(2) call that returns status information, the times(2) system call is used instead. However, it provides much less information than wait3(2), so on those systems time reports the majority of the resources as zero. – lothar May 06 '09 at 00:27
  • 92
    "bash: -v: command not found" means bash intercepts time to use it's own. `/bin/time -v` solves it. – gcb Nov 22 '10 at 23:12
  • 2
    On a different distribution (CentOS 5.6, a RHEL derivative), the Maximum RSS item is always non-zero and seems reasonable (i.e. bigger for bigger tasks). – Blaisorblade Sep 19 '11 at 11:18
  • 3
    It would be worth it to do a quick check to be sure the output makes sense. Gnu time has a bug where it will report 4x the actual memory usage: http://stackoverflow.com/questions/10035232/maximum-resident-set-size-does-not-make-sense – Ian Jul 17 '12 at 15:20
  • 1
    @Robert: `-l` gives you info on OS resources used, this includes amount of memory shared between processes. It tells nothing about memory consumed by process. – skalee Jan 21 '13 at 04:51
  • Is anyone successful with `time -v` on OS X? – skalee Jan 21 '13 at 04:55
  • 32
    @skalee Try `time -l` on MacOS, gives similar output. – Volker Stolz Feb 09 '13 at 16:41
  • 3
    /usr/bin/time (aka GNU time) 1.7 has a bug and does NOT report accurate peak memory usage info: http://stackoverflow.com/a/10132854/62694 – clint Feb 24 '14 at 15:36
  • You need the `time` RPM on to get /usr/bin/time on Redhat-based linuxes. – KingPong Mar 23 '14 at 18:54
  • 1
    `time` 1.7-24 on Ubuntu from Feb 23 '15 incorporates a fix to the memory reporting. – jnas Mar 02 '15 at 08:56
  • 4
    This method is not accurate. I'm getting different results every time I run a completely deterministic program on Linux 3.19. The "maximum resident set size" field is clearly affected by other things running on the system. – Vladimir Panteleev May 02 '15 at 13:27
  • The memory size bug fix is in Fedora time package from version 1.7-39. To check your version: `rpm -q time`. [Source](http://koji.fedoraproject.org/koji/buildinfo?buildID=567457); search for #702826 in the page. – unagi Mar 02 '16 at 01:38
  • `$(which time) -v ls /` – milahu Jul 04 '22 at 05:45
  • You might get the shell. If so, use `\time` instead. – Benjamin Atkin Aug 11 '23 at 01:25
98

(This is an already answered, old question.. but just for the record :)

I was inspired by Yang's script, and came up with this small tool, named memusg. I simply increased the sampling rate to 0.1 to handle much short living processes. Instead of monitoring a single process, I made it measure rss sum of the process group. (Yeah, I write lots of separate programs that work together) It currently works on Mac OS X and Linux. The usage had to be similar to that of time:

memusg ls -alR / >/dev/null

It only shows the peak for the moment, but I'm interested in slight extensions for recording other (rough) statistics.

It's good to have such simple tool for just taking a look before we start any serious profiling.

netj
  • 111
  • 4
  • 4
  • 1
    all that still uses PS and are only good to determine observed top memory. not real top memory. you can always miss something between one interval and another. – gcb Nov 22 '10 at 23:10
  • 7
    What are the units for the output of the memusg script? Bytes? Kilobytes? – Daniel Standage Sep 22 '11 at 20:33
  • 2
    @DanielStandage: probably in Kilobytes. It simply watches the values shown by `ps -o rss=` where rss is _the real memory (resident set) size of the process (in 1024 byte units)_ from my BSD man page. – netj Sep 30 '11 at 00:32
  • 3
    @gcb So what, that's what you get when you're measuring samples. – Volker Stolz Jan 31 '13 at 12:26
  • @ShiDoiSi something that the kernel triggers every time it change the memory allocation. i think this is what `time -v` uses. but i'm not 100% sure. it's like in programming when you use a while(){ check(); wait();} if something happens during wait(), too bad, you lost it. the other way is to attach events and then you get a message everytime something happens, that way you don't lose any information. – gcb Feb 05 '13 at 04:57
  • 2
    The link to memusg given in the answer seems to be broken. Anyway, /usr/bin/time does this very well. – Tom Cornebize Aug 06 '15 at 07:54
  • ⁺¹ for possibility to easily change memory from RSS to e.g. VSZ, or anything else. – Hi-Angel Aug 15 '16 at 11:43
  • 1
    The accepted answer should be the second one, this one work but is obsolete IMHO. – Florian Mar 14 '17 at 09:43
78

Valgrind one-liner:

valgrind --tool=massif --pages-as-heap=yes --massif-out-file=massif.out ./test.sh; grep mem_heap_B massif.out | sed -e 's/mem_heap_B=\(.*\)/\1/' | sort -g | tail -n 1

Note use of --pages-as-heap to measure all memory in a process. More info here: http://valgrind.org/docs/manual/ms-manual.html

This will slow down your command significantly.

Denis Nikolaenko
  • 250
  • 2
  • 13
jbeard4
  • 12,664
  • 4
  • 57
  • 67
  • 1
    Handy script, but I need sort -g on my Slackware system (I presume you are looking for the highest value). – Nick Coleman Aug 02 '12 at 13:28
  • 1
    I'm missing `--pages-as-heap` option in valgrind-3.5.0 on a centos 5.5 distribution. Also `--trace-children` might be useful option to valgrind. I'm not sure what it does, but I guess it traces child processes also. – NickSoft Jan 04 '13 at 17:29
  • 3
    +1 for `valgrind --massif`. You can also use the `ms_print` tool that comes with it for handy output (including ascii charts of usage over time) – Eli Bendersky Jan 08 '13 at 18:24
  • 9
    Massif has a much higher overhead than `time` though, taking at least 10 times more time on a command like `ls`. – Timothy Gu May 24 '15 at 01:25
  • 12
    It is way too massive indeed. This answer should mention the slow down. The command I want to measure normally takes 35 seconds to complete. I have ran this valgrind command to measure it more than half an hour ago, and it still has not completed… – unagi Mar 02 '16 at 01:49
  • A simple sleep took more than 100MB! – ABCD Jul 12 '19 at 06:05
  • Hi @jbeard4, my program is staticly linked and seem that massif is not useful here. Is there any workarounds? – calvin Dec 08 '20 at 09:24
76

On Linux:

Use /usr/bin/time -v <program> <args> and look for "Maximum resident set size".

(Not to be confused with the Bash time built-in command! So use the full path, /usr/bin/time)

For example:

> /usr/bin/time -v ./myapp
        User time (seconds): 0.00
        . . .
        Maximum resident set size (kbytes): 2792
        . . .

On BSD, MacOS:

Use /usr/bin/time -l <program> <args>, looking for "maximum resident set size":

>/usr/bin/time -l ./myapp
        0.01 real         0.00 user         0.00 sys
      1440  maximum resident set size
      . . .
rustyx
  • 80,671
  • 25
  • 200
  • 267
67

Here's a one-liner that doesn't require any external scripts or utilities and doesn't require you to start the process via another program like Valgrind or time, so you can use it for any process that's already running:

grep ^VmPeak /proc/$PID/status

(replace $PID with the PID of the process you're interested in)

Massimo
  • 3,171
  • 3
  • 28
  • 41
erobertc
  • 644
  • 1
  • 9
  • 20
  • 18
    What if I don't know PID? For example in case when the program runs a small amount of time (<1s) – diralik Feb 23 '19 at 22:38
  • 14
    "VmHWM: Peak resident set size" might be more usable to measure RAM usage (instead of VmPeak that includes a lot of other things too). – jfs Feb 26 '19 at 06:29
  • 3
    @jfs it really depends what you want to find out. IIRC VmPeak is the maximum total memory usage including virtual memory, while VmHWM is the peak RAM usage. So if you want to know the total amount of memory your program has asked for, use VmPeak; if you want to know how much of your actual RAM it has ever used at a given time, use VmHWM. – erobertc Feb 26 '19 at 18:53
  • 1
    @diralik if you are checking a program written by yourself, you can embed a line of code to look into "/proc/self/status" file. – Fileland Mar 19 '20 at 06:00
  • 1
    If your OS is running 64 bit OS, `VmPeak` shouldn't matter much at all. It's the `VmHWM` that causes system to run out of memory. Running out of virtual memory on 64 bit OS before running out of actual RAM is unheard of. – Mikko Rantalainen Sep 04 '21 at 15:07
  • Thanks a lot! Helped me a lot. grepping `/proc/` and `VmHWM` was exactly what I needed. – Bouncner Mar 02 '22 at 09:21
  • I've created a script that copies /proc//status to a temporary file for later inspection: https://raw.githubusercontent.com/SimonLammer/dotfiles/master/data/scripts/status.sh (Can't post this as a proper answer since the question has been closed.) @diralik it works for processees that live longer than ~50ms. – GitProphet Apr 06 '23 at 08:53
41

Perhaps (gnu) time(1) already does what you want. For instance:

$ /usr/bin/time -f "%P %M" command
43% 821248

But other profiling tools may give more accurate results depending on what you are looking for.

dlamblin
  • 43,965
  • 20
  • 101
  • 140
Jon 'links in bio' Ericson
  • 20,880
  • 12
  • 98
  • 148
  • 1
    I seem to always get zeros with this, even for large commands – jes5199 Apr 21 '09 at 21:26
  • I get variable results, like 400% 0, and 0% 0 on the same program.. maybe is should be run for larger periods of time to be exact? – Liran Orevi Apr 21 '09 at 21:54
  • I don't know what to suggest. The code above is exactly what I got running a latex command that happened to be in history. As I say, more accurate results can be obtained with other tools. – Jon 'links in bio' Ericson Apr 21 '09 at 22:16
  • 2
    That works on at least CentOS (and thus, I bet, also RHEL) systems. %P gives unrelated statistics (%CPU) which depends on the scheduler and is thus quite variable. – Blaisorblade Sep 19 '11 at 11:25
  • strangely for me, the "time" command had to be run using the exact path, like in the example, otherwise it would not recognize the "-f" option. – Deleteman Mar 22 '15 at 22:31
  • 2
    @Deleteman: `time` is a built in command when using `csh`. If you use the exact path, it will allow you to run the external command. As far as I know, only the GNU version supports the format option. – Jon 'links in bio' Ericson Mar 23 '15 at 01:10
22

On MacOS Sierra use:

/usr/bin/time -l commandToMeasure

You can use grep to take what you want maybe.

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 6
    This! I've literally spent an hour trying to get Instruments.app and dtrace to give me a memory profile with system integrity turned on (can't turn it off), while all I needed was just this simple command. A small note, you can use `command time -l` instead of `/usr/bin/time -l` which will cause your shell to actually call a binary called `time` instead of the builtin function. (Yes, `command` is not a placeholder, `command time` is different than just `time`.) – Jakub Arnold Jul 26 '18 at 18:29
19

/usr/bin/time maybe does what you want, actually. Something like.

 /usr/bin/time --format='(%Xtext+%Ddata %Mmax)'

See time(1) for details...

simon
  • 7,044
  • 2
  • 28
  • 30
17
time -f '%M' <run_program>
Jason
  • 1,974
  • 24
  • 19
  • 1
    The output is in kilobytes (kibibytes probably?). Note that in bash, you need to specify the full path, e.g. `/usr/bin/time`, in order not to use the builtin `time` keyword which does not support `-f`. – pcworld Jul 23 '20 at 14:31
16

If the process runs for at least a couple seconds, then you can use the following bash script, which will run the given command line then print to stderr the peak RSS (substitute for rss any other attribute you're interested in). It's somewhat lightweight, and it works for me with the ps included in Ubuntu 9.04 (which I can't say for time).

#!/usr/bin/env bash
"$@" & # Run the given command line in the background.
pid=$! peak=0
while true; do
  sleep 1
  sample="$(ps -o rss= $pid 2> /dev/null)" || break
  let peak='sample > peak ? sample : peak'
done
echo "Peak: $peak" 1>&2
Yang
  • 16,037
  • 15
  • 100
  • 142
  • 2
    The major drawback of this method is that if the process allocates much memory for a short period (e.g. near the end), this may not be detected. Reducing the sleep time may help a bit. – vinc17 Dec 13 '16 at 12:23
  • The only way to monitor peak memory usage is to check /proc//status and line VmWHM (water high mark, meaning the peak resident memory usage) if you need to monitor only one process. If you need to monitor total RAM used by a group of processes, you have to use memory cgroup and read status that way. Note that if your system doesn't support `cgroupv2` only `root` can create memory cgroups. Any sampling/polling based hack will miss peaks. – Mikko Rantalainen Sep 04 '21 at 15:10
12

Because /usr/bin/time is not present in many modern distributions (Bash built-in time instead), you can use Busybox time implementation with -v argument:

busybox time -v uname -r

It's output is similar to GNU time output. Busybox is pre-installed in most Linux distros (Debian, Ubuntu, etc.). If you using Arch Linux, you can install it with:

sudo pacman -S busybox
9

Well, if you really want to show the memory peak and some more in-depth statistics i recommend using a profiler such as valgrind. A nice valgrind front-end is alleyoop.

alexn
  • 57,867
  • 14
  • 111
  • 145
5

You can use a tool like Valgrind to do this.

Dana the Sane
  • 14,762
  • 8
  • 58
  • 80
5

Here is (based on the other answers) a very simple script that watches an already running process. You just run it with the pid of the process you want to watch as the argument:

#!/usr/bin/env bash

pid=$1

while ps $pid >/dev/null
do
    ps -o vsz= ${pid}
    sleep 1
done | sort -n | tail -n1

Example usage:

max_mem_usage.sh 23423
static_rtti
  • 53,760
  • 47
  • 136
  • 192
2

Heaptrack is KDE tool that has a GUI and text interface. I find it more suitable than valgrind to understand the memory usage of a process because it provides more details and flamegraphs. It's also faster because it does less checking that valgrind. And it gives you the peak memory usage.

Anyway, tracking rss and vss is misleading because pages could be shared, that's why that memusg. What you should really do is track the sum of Pss in /proc/[pid]/smaps or use pmap. GNOME system-monitor used to do so but it was too expensive.

Benoît
  • 3,355
  • 2
  • 29
  • 34
1

Re-inventing the wheel, with hand made bash script. Quick and clean.

My use case: I wanted to monitor a linux machine which has less RAM and wanted to take a snapshot of per container usage when it runs under heavy usage.

#!/usr/bin/env bash

threshold=$1

echo "$(date '+%Y-%m-%d %H:%M:%S'): Running free memory monitor with threshold $threshold%.."

while(true)
    freePercent=`free -m | grep Mem: | awk '{print ($7/$2)*100}'`    
  do

  if (( $(awk 'BEGIN {print ("'$freePercent'" < "'$threshold'")}') ))
  then
       echo "$(date '+%Y-%m-%d %H:%M:%S'): Free memory $freePercent% is less than $threshold%"
       free -m
       docker stats --no-stream
       sleep 60  
       echo ""  
  else
       echo "$(date '+%Y-%m-%d %H:%M:%S'): Sufficient free memory available: $freePercent%"
  fi
  sleep 30

done

Sample output:

2017-10-12 13:29:33: Running free memory monitor with threshold 30%..

2017-10-12 13:29:33: Sufficient free memory available: 69.4567%

2017-10-12 13:30:03: Sufficient free memory available: 69.4567%

2017-10-12 16:47:02: Free memory 18.9387% is less than 30%

your custom command output

Sankarganesh Eswaran
  • 10,076
  • 3
  • 23
  • 24
1

On macOS, you can use DTrace instead. The "Instruments" app is a nice GUI for that, it comes with XCode afaik.

Michael Böckling
  • 7,341
  • 6
  • 55
  • 76
1

Use Massif: http://valgrind.org/docs/manual/ms-manual.html

Hans W
  • 3,851
  • 1
  • 22
  • 21
-1

'htop' is best command for see which process is using how much RAM.....

for more detail http://manpages.ubuntu.com/manpages/precise/man1/htop.1.html

Sanket
  • 59
  • 5
  • 3
    htop does not list the PEAK usage. Only the CURRENT usage. (Unless you know something I don't. As I've looked yesterday in htop for this exact scenario.) – Katastic Voyage Aug 06 '17 at 08:56
-4

Please be sure to answer the question. Provide details and share your research!

Sorry, I am first time here and can only ask questions…

Used suggested:

valgrind --tool=massif --pages-as-heap=yes --massif-out-file=massif.out ./test.sh; grep mem_heap_B massif.out | sed -e 's/mem_heap_B=\(.*\)/\1/' | sort -g | tail -n 1

then:

grep mem_heap_B massif.out
...
mem_heap_B=1150976
mem_heap_B=1150976
...

this is very different from what top command shows at similar moment:

14673 gu27mox   20   0 3280404 468380  19176 R 100.0  2.9   6:08.84 pwanew_3pic_com

what are measured units from Valgrind??

The /usr/bin/time -v ./test.sh never answered — you must directly feed executable to /usr/bin/time like:

/usr/bin/time -v  pwanew_3pic_compass_2008florian3_dfunc.static  card_0.100-0.141_31212_resubmit1.dat_1.140_1.180   1.140 1.180 31212


    Command being timed: "pwanew_3pic_compass_2008florian3_dfunc.static card_0.100-0.141_31212_resubmit1.dat_1.140_1.180 1.140 1.180 31212"

    User time (seconds): 1468.44
    System time (seconds): 7.37
    Percent of CPU this job got: 99%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 24:37.14
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 574844
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 74
    Minor (reclaiming a frame) page faults: 468880
    Voluntary context switches: 1190
    Involuntary context switches: 20534
    Swaps: 0
    File system inputs: 81128
    File system outputs: 1264
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0
Alexey Vazhnov
  • 1,291
  • 17
  • 20