LCOV - code coverage report
Current view: top level - shared/common/src/32_util - m_pstat.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 79.2 % 72 57
Test Date: 2026-11-08 00:10:28 Functions: 71.4 % 7 5
Branches: 64.0 % 50 32

             Branch data     Line data    Source code
       1                 :             : !!****m* ABINIT/m_pstat
       2                 :             : !! NAME
       3                 :             : !! m_pstat
       4                 :             : !!
       5                 :             : !! FUNCTION
       6                 :             : !! Interface to the /proc/{pid}/status file available on Linux.
       7                 :             : !!
       8                 :             : !! COPYRIGHT
       9                 :             : !!  Copyright (C) 2017-2026 ABINIT group (MG)
      10                 :             : !!  This file is distributed under the terms of the
      11                 :             : !!  GNU General Public License, see ~abinit/COPYING
      12                 :             : !!  or http://www.gnu.org/copyleft/gpl.txt .
      13                 :             : !!
      14                 :             : !! SOURCE
      15                 :             : 
      16                 :             : #if defined HAVE_CONFIG_H
      17                 :             : #include "config.h"
      18                 :             : #endif
      19                 :             : 
      20                 :             : #include "abi_common.h"
      21                 :             : 
      22                 :             : module m_pstat
      23                 :             : 
      24                 :             :  use, intrinsic :: iso_c_binding
      25                 :             :  use defs_basis
      26                 :             :  use m_xmpi
      27                 :             :  use m_abicore
      28                 :             :  use m_errors
      29                 :             :  use m_yaml
      30                 :             : 
      31                 :             :  use m_fstrings, only : find_and_select, basename
      32                 :             :  use m_clib,     only : clib_getpid
      33                 :             : 
      34                 :             :  implicit none
      35                 :             : 
      36                 :             :  private
      37                 :             : !!***
      38                 :             : 
      39                 :             : !----------------------------------------------------------------------
      40                 :             : 
      41                 :             : !!****t* m_pstat/pstat_t
      42                 :             : !! NAME
      43                 :             : !! pstat_t
      44                 :             : !!
      45                 :             : !! FUNCTION
      46                 :             : !! This object stores the most important quantites reported in the /proc/{pid}/status file
      47                 :             : !! in particular the virtual memory VmRSS. See https://docs.kernel.org/filesystems/proc.html
      48                 :             : !!
      49                 :             : !! NB: This file is only available on Linux hence one should always check the value of pstat%ok
      50                 :             : !! before using quantities such as vmrss_mb.
      51                 :             : !!
      52                 :             : !! SOURCE
      53                 :             : 
      54                 :             :  type, private :: pstat_t
      55                 :             : 
      56                 :             :   logical :: ok = .False.
      57                 :             :   ! False if stat file is not available
      58                 :             : 
      59                 :             :   integer :: pid = -1
      60                 :             :   ! Process identifier.
      61                 :             : 
      62                 :             :   integer :: threads = -1
      63                 :             :   ! number of threads.
      64                 :             : 
      65                 :             :   integer :: fdsize = -1
      66                 :             :    ! Number of file descriptor slots currently allocated.
      67                 :             : 
      68                 :             :   real(dp) :: vmrss_mb = -one
      69                 :             :   ! Actual physical RAM used. It contains the three following parts (VmRSS = RssAnon + RssFile + RssShmem)
      70                 :             : 
      71                 :             :   real(dp) :: vmpeak_mb = -one
      72                 :             :   ! Peak virtual memory size
      73                 :             : 
      74                 :             :   real(dp) :: vmstk_mb = -one
      75                 :             :   ! Size of stack segments
      76                 :             : 
      77                 :             :   character(len=fnlen) :: filepath = ""
      78                 :             :   ! Path of status file
      79                 :             : 
      80                 :             :   character(len=500) :: iomsg = ""
      81                 :             :   ! Error message returned when parsing filepath
      82                 :             : 
      83                 :             :  contains
      84                 :             :    procedure :: from_pid => pstat_from_pid     ! Init object from process identifier (main entry point).
      85                 :             :    procedure :: from_file => pstat_from_file   ! Init object from file (useful for debugging).
      86                 :             :    procedure :: print => pstat_print           ! Print object.
      87                 :             :    procedure :: min_mem_mb_per_proc => pstat_min_mem_mb_per_proc
      88                 :             :  end type pstat_t
      89                 :             : !!***
      90                 :             : 
      91                 :             :  type(pstat_t),save,public :: pstat_proc
      92                 :             : 
      93                 :             : !----------------------------------------------------------------------
      94                 :             : 
      95                 :             : contains
      96                 :             : !!***
      97                 :             : 
      98                 :             : !!****f* m_pstat/pstat_from_pid
      99                 :             : !! NAME
     100                 :             : !!  pstat_from_pid
     101                 :             : !!
     102                 :             : !! FUNCTION
     103                 :             : !!   Init object from process identifier (main entry point for client code).
     104                 :             : !!
     105                 :             : !! SOURCE
     106                 :             : 
     107         [ -  + ]:        1448 : subroutine pstat_from_pid(pstat)
     108                 :             : 
     109                 :             : !Arguments ------------------------------------
     110                 :             :  class(pstat_t),intent(out) :: pstat
     111                 :             : 
     112                 :             : !Local variables-------------------------------
     113                 :             :  integer(c_int) :: pid
     114                 :             :  character(len=500) :: spid
     115                 :             : ! *************************************************************************
     116                 :             : 
     117                 :        1448 :  pid = clib_getpid()
     118                 :        1448 :  write(spid, "(i0)") pid
     119                 :        1448 :  spid = adjustl(spid)
     120         [ +  - ]:        1448 :  call pstat%from_file("/proc/"//trim(spid)//"/status")
     121                 :             : 
     122                 :        1448 : end subroutine pstat_from_pid
     123                 :             : !!***
     124                 :             : 
     125                 :             : !!****f* m_pstat/pstat_from_file
     126                 :             : !! NAME
     127                 :             : !!  pstat_from_file
     128                 :             : !!
     129                 :             : !! FUNCTION
     130                 :             : !! Init object from file (useful for debugging).
     131                 :             : !!
     132                 :             : !! SOURCE
     133                 :             : 
     134                 :       38168 : subroutine pstat_from_file(pstat, filepath)
     135                 :             : 
     136                 :             : !Arguments ------------------------------------
     137                 :             :  class(pstat_t),intent(inout) :: pstat
     138                 :             :  character(len=*),intent(in) :: filepath
     139                 :             : 
     140                 :             : !Local variables-------------------------------
     141                 :             :  integer :: unit, ierr
     142                 :             :  character(len=500) :: line
     143                 :             :  integer :: istart, istop, iostat
     144                 :             : ! *************************************************************************
     145                 :             : 
     146                 :       38168 :  pstat%ok = .False.
     147                 :       38168 :  pstat%filepath = filepath
     148                 :             : 
     149                 :       38168 :  open(newunit=unit, file=trim(pstat%filepath), action="read", status="old", iostat=ierr, iomsg=pstat%iomsg)
     150         [ -  + ]:       38168 :  if (ierr /= 0) then
     151                 :           0 :    close(unit); return
     152                 :             :  end if
     153                 :             : 
     154                 :             :  do
     155         [ +  + ]:     2251912 :    read(unit, "(a)", iostat=ierr, end=10, iomsg=pstat%iomsg) line
     156         [ -  + ]:     2213744 :    if (ierr > 0) then ! EOF
     157                 :           0 :      close(unit); return
     158                 :             :    end if
     159                 :             : 
     160                 :             :    ! Parse useful integers
     161         [ +  + ]:     2213744 :    if (index(line, "Pid:") == 1) call get_int(line, pstat%pid)
     162         [ +  + ]:     2213744 :    if (index(line, "Threads:") == 1) call get_int(line, pstat%threads)
     163         [ +  + ]:     2213744 :    if (index(line, "FDSize:") == 1) call get_int(line, pstat%fdsize)
     164                 :             : 
     165                 :             :    ! Parse memory entries
     166         [ +  + ]:     2213744 :    if (index(line, "VmRSS:") == 1) call get_mem_mb(line, pstat%vmrss_mb)
     167         [ +  + ]:     2213744 :    if (index(line, "VmPeak:") == 1) call get_mem_mb(line, pstat%vmpeak_mb)
     168         [ +  + ]:     2213744 :    if (index(line, "VmStk:") == 1) call get_mem_mb(line, pstat%vmstk_mb)
     169                 :             :  end do
     170                 :             : 
     171                 :       38168 : 10 close(unit)
     172                 :       38168 :   pstat%ok = .True.
     173         [ +  + ]:       76336 :   pstat%iomsg = ""
     174                 :             : 
     175                 :             : contains
     176                 :             : 
     177                 :      114504 : subroutine get_mem_mb(str, mem_mb)
     178                 :             : 
     179                 :             :  character(len=*),intent(in) :: str
     180                 :             :  real(dp),intent(out) :: mem_mb
     181                 :             : 
     182                 :             :  ! Generic mem entry has format `VmRSS: 2492 kB`
     183                 :             :  real(dp) :: mem_fact
     184                 :      114504 :  istart = index(str, ":") + 1
     185                 :             :  istop = find_and_select(str, &
     186                 :             :                         ["kB", "mB"], &
     187         [ +  + ]:      343512 :                         [one/1024._dp, one], mem_fact, pstat%iomsg) !default=one,
     188         [ -  + ]:      114504 :  ABI_CHECK(istop /= -1, pstat%iomsg)
     189                 :      114504 :  read(str(istart+1:istop-1), fmt=*, iostat=iostat, iomsg=pstat%iomsg) mem_mb
     190         [ -  + ]:      114504 :  ABI_CHECK(iostat == 0, pstat%iomsg)
     191                 :      114504 :  mem_mb = mem_mb * mem_fact
     192                 :             : 
     193                 :      114504 : end subroutine get_mem_mb
     194                 :             : 
     195                 :      114504 : subroutine get_int(str, out_ival)
     196                 :             : 
     197                 :             :  character(len=*),intent(in) :: str
     198                 :             :  integer,intent(out) :: out_ival
     199                 :      114504 :  istart = index(str, ":") + 1
     200                 :      114504 :  read(str(istart+1:), fmt=*, iostat=iostat, iomsg=pstat%iomsg) out_ival
     201                 :             :  !ABI_CHECK(iostat == 0, pstat%iomsg)
     202                 :             : 
     203                 :      114504 : end subroutine get_int
     204                 :             : 
     205                 :             : end subroutine pstat_from_file
     206                 :             : !!***
     207                 :             : 
     208                 :             : !!****f* m_pstat/pstat_print
     209                 :             : !! NAME
     210                 :             : !!  pstat_print
     211                 :             : !!
     212                 :             : !! FUNCTION
     213                 :             : !!  Print object in Yaml format to std_out
     214                 :             : !!
     215                 :             : !! SOURCE
     216                 :             : 
     217                 :       36720 : subroutine pstat_print(pstat, comm, file, line)
     218                 :             : 
     219                 :             :  class(pstat_t),intent(inout) :: pstat
     220                 :             :  character(len=*),optional,intent(in) :: file
     221                 :             :  integer,optional,intent(in) :: line, comm
     222                 :             : 
     223                 :             : !Local variables-------------------------------
     224                 :             :  integer :: units(1), ierr
     225                 :             :  integer :: f90line = 0
     226                 :             :  real(dp) :: min_mpicomm_vmrss_mb, max_mpicomm_vmrss_mb
     227                 :             :  character(len=500) :: f90name='Subroutine Unknown'
     228                 :             :  type(yamldoc_t) :: ydoc
     229                 :             : ! *************************************************************************
     230                 :             : 
     231                 :           0 :  if (pstat%pid == -1) return
     232                 :       36720 :  units(1) = std_out
     233         [ +  - ]:       36720 :  if (std_out < 1) return
     234                 :             : 
     235                 :       36720 :  call pstat%from_file(pstat%filepath)
     236                 :             : 
     237         [ +  - ]:       36720 :  if (present(line)) f90line = line
     238   [ +  -  +  - ]:       36720 :  if (present(file)) f90name = basename(file)
     239                 :             : 
     240                 :       36720 :  min_mpicomm_vmrss_mb = pstat%vmrss_mb
     241                 :       36720 :  max_mpicomm_vmrss_mb = pstat%vmrss_mb
     242         [ +  + ]:       36720 :  if (present(comm)) then
     243                 :        1432 :    call xmpi_min(pstat%vmrss_mb, min_mpicomm_vmrss_mb, comm, ierr)
     244                 :        1432 :    call xmpi_max(pstat%vmrss_mb, max_mpicomm_vmrss_mb, comm, ierr)
     245                 :             :  end if
     246                 :             : 
     247                 :             : #ifndef FC_NVHPC
     248                 :       36720 :  ydoc = yamldoc_open("PstatData")
     249                 :       36720 :  call ydoc%add_int("pid", pstat%pid)
     250                 :       36720 :  call ydoc%add_string("file", f90name)
     251                 :       36720 :  call ydoc%add_int("line", f90line)
     252                 :       36720 :  call ydoc%add_real("vmrss_mb", pstat%vmrss_mb)
     253                 :       36720 :  call ydoc%add_real("min_mpicomm_vmrss_mb", min_mpicomm_vmrss_mb)
     254                 :       36720 :  call ydoc%add_real("max_mpicomm_vmrss_mb", max_mpicomm_vmrss_mb)
     255                 :       36720 :  call ydoc%add_real("vmpeak_mb", pstat%vmpeak_mb)
     256                 :       36720 :  call ydoc%add_real("vmstk_mb", pstat%vmstk_mb)
     257   [ -  +  -  - ]:       36720 :  if (len_trim(pstat%iomsg) > 0) call ydoc%add_string("iomsg", trim(pstat%iomsg))
     258                 :       36720 :  call ydoc%write_units_and_free(units)
     259                 :             : #else
     260                 :             :  ! Yet another wild NVHPC bug (only on eos_nvhpc_23.9_elpa)
     261                 :             :  write(std_out, "(a)")"--- !PstatData"
     262                 :             :  write(std_out, *)"vmrss_mb: ", pstat%vmrss_mb
     263                 :             :  write(std_out, *)"min_mpicomm_vmrss: ", min_mpicomm_vmrss_mb
     264                 :             :  write(std_out, *)"max_mpicomm_vmrss: ", max_mpicomm_vmrss_mb
     265                 :             :  write(std_out, "(a)")"..."
     266                 :             : #endif
     267                 :             : 
     268         [ +  - ]:       36720 : end subroutine pstat_print
     269                 :             : !!***
     270                 :             : 
     271                 :             : !!****f* m_pstat/pstat_min_mem_mb_per_proc
     272                 :             : !! NAME
     273                 :             : !!  pstat_min_mem_mb_per_proc
     274                 :             : !!
     275                 :             : !! FUNCTION
     276                 :             : !!  This function estimates the available memory (in MB) per process, within the MPI communicator comm
     277                 :             : !!  based on process statistics (pstat).
     278                 :             : !!
     279                 :             : !! SOURCE
     280                 :             : 
     281                 :           0 : real(dp) function pstat_min_mem_mb_per_proc(pstat, comm) result(min_mem_mb)
     282                 :             : 
     283                 :             : !Arguments ------------------------------------
     284                 :             :  class(pstat_t),intent(inout) :: pstat
     285                 :             :  integer,intent(in) :: comm
     286                 :             : 
     287                 :             : !Local variables-------------------------------
     288                 :             :  integer :: ierr
     289                 :             :  logical :: all_ok
     290                 :             : ! *************************************************************************
     291                 :             : 
     292                 :           0 :  call pstat%from_file(pstat%filepath)
     293                 :             : 
     294                 :           0 :  all_ok = pstat%ok
     295                 :           0 :  call xmpi_land(all_ok, comm)
     296                 :             : 
     297         [ #  # ]:           0 :  if (.not. all_ok) then
     298                 :             :    ! Handle case in which pstat is not available or something went wrong when reading.
     299                 :           0 :    min_mem_mb = mem_per_cpu_mb * half
     300                 :           0 :    return
     301                 :             :  end if
     302                 :             : 
     303                 :             :  ! Compute min inside comm
     304                 :           0 :  call xmpi_min(pstat%vmrss_mb, min_mem_mb, comm, ierr)
     305                 :             : 
     306                 :           0 :  min_mem_mb = (mem_per_cpu_mb - min_mem_mb)
     307                 :             : 
     308                 :             :  ! Fallback for too small values
     309         [ #  # ]:           0 :  if (min_mem_mb <= tol1) min_mem_mb = mem_per_cpu_mb * half
     310                 :             : 
     311                 :           0 : end function pstat_min_mem_mb_per_proc
     312                 :             : !!***
     313                 :             : 
     314                 :           0 : end module m_pstat
     315                 :             : !!***
        

Generated by: LCOV version 2.3-1