Reputation: 201
I am trying to track the memory usage and cpu time of a subroutine in a Fortran 90 program. To track the track the cpu time, I use the following:
call cpu_time(tic)
call subroutine(args)
call cpu_time(toc)
time = toc-tic
Is there a way to do something similar to record memory usage? What is the best way to do this? Thanks in advance for the help.
Upvotes: 10
Views: 9226
Reputation: 1807
I know this is already answered, but I just wanted to add some here. First of all the most votes answer is right but it can be shorten more by just checking the /proc/self/status
file instead of checking for the process id and then checking that file implicitly. But this will only work if the Fortran code itself is reading the file instead of calling through a shell command. Here is the code:
function systMemUsage() result(valueRSS)
character(len=80) :: line
integer :: ios, fu, valueRSS
valueRSS = -1
open(newunit=fu, file='/proc/self/status', action='read')
do
read(fu, '(a)',iostat=ios ) line
if(ios /=0) exit
if(line(1:6) == 'VmRSS:') then
read(line(7:), *) valueRSS
exit
endif
enddo
close(fu)
end
Another way for unix like system is to call the getrusage
. This can be used for several other measurements too (check https://man7.org/linux/man-pages/man2/getrusage.2.html). Heres the code:
#include <sys/time.h>
#include <sys/resource.h>
#include <stdio.h>
void getSize(long int *val) {
struct rusage usage;
getrusage(RUSAGE_SELF, &usage);
*val = usage.ru_maxrss;
}
function systMemUsageC() result(valueRSS)
use iso_c_binding
interface
subroutine getSize(val) bind(c, name='getSize')
import :: c_long
integer(kind=c_long) :: val
end
end interface
integer(kind=8) :: valueRSS
call getSize(valueRSS)
end
Upvotes: 1
Reputation: 251
liskawc has a very nice solution and I've been looking for something like this for a while.
He asked for feedback, and there were a couple of areas that could be improved.
I've modified his original program to overcome these issues:
subroutine system_mem_usage(valueRSS)
implicit none
use ifport !if on intel compiler
integer, intent(out) :: valueRSS
character(len=200):: filename=' '
character(len=80) :: line
character(len=8) :: pid_char=' '
integer :: pid
logical :: ifxst
valueRSS=-1 ! return negative number if not found
!--- get process ID
pid=getpid()
write(pid_char,'(I8)') pid
filename='/proc/'//trim(adjustl(pid_char))//'/status'
!--- read system file
inquire (file=filename,exist=ifxst)
if (.not.ifxst) then
write (*,*) 'system file does not exist'
return
endif
open(unit=100, file=filename, action='read')
do
read (100,'(a)',end=120) line
if (line(1:6).eq.'VmRSS:') then
read (line(7:),*) valueRSS
exit
endif
enddo
120 continue
close(100)
return
end subroutine system_mem_usage
Please feel free to update if you can improve this program any further!
Upvotes: 13
Reputation: 379
You can use valgrind with the massif http://valgrind.org/docs/manual/ms-manual.html . This would dump a very detailed output file. Then you can dynamically visualize it using gprof2dot tool http://code.google.com/p/jrfonseca/wiki/Gprof2Dot which gives you a perfectly intuitive flowchart of your code including call-graph and memory usage per subroutine inline in the call-graph. If you want to go fancier then you might make this process automated for example you can script your doxygen such that it updates this stuff in your code documentation whenever you commit a change. I hope this helps.
Upvotes: 4
Reputation: 85
By memory usage i will assume you want RSS at a given moment in your program on a linux machine. If you dont want to use a profiler, then this routine might help a bit:
I use this routine (which actually quite ugly to be honest) but worked so far. Brief description of subroutine:
when you call the subroutine it issues a series of system calls, that search within the /proc/ filesystem information about your program. whatever is in there you can get, if you modify this sub, i use this one specifically to get RSS value for example. The routine returns valueRSS as a character, which you can then write to a specific file if you wish to have a profile of how ram usage is within your program. You could also convert the string to a number, but i leave that to you if you need it.
subroutine system_mem_usage(valueRSS)
use ifport !if on intel compiler
character(len=30) :: count_char,pid_char, dummy
character(len=200) :: filename
character(len=200) :: command
integer :: count,pid,res
character(len=50), intent(out) :: valueRSS
call system_clock(count)
pid=getpid()
write(count_char,'(I10)') count
write(pid_char,'(I10)') pid
filename='~/tmp/mem_use.'//trim(count_char)
command='cat /proc/'//trim(adjustl(pid_char))//'/status >'//trim(adjustl(filename))
res=system(command)
command='cat '//trim(adjustl(filename))//' | grep RSS > ~/tmp/rss_use.'//trim(count_char)
res=system(command)
open(unit=100, file='~/tmp/rss_use.'//trim(count_char))
read(100,*) dummy, valueRSS
close(100)
return
end subroutine
if you are interested in some other value than RSS, then just edit the part at "grep RSS". This subroutine also assumes you have a tmp directory within your home.
Oh yea, feel free to modify the script as you wish and if anyone has any ideas on how to do this more elegantly i would much appreciate it.
Upvotes: 4