Eleutharios
Eleutharios

Reputation: 201

Track memory usage in Fortran 90

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

Answers (4)

Eular
Eular

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

NuclearFission
NuclearFission

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.

  • there are several system calls that can be eliminated by just reading the system file directly from your Fortran program
  • the solution depends on a temporary file in the users directory
  • my fortran compiler didn't like opening a file starting with the tilde

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

argasm
argasm

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

liskawc
liskawc

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

Related Questions