LCOV - code coverage report
Current view: top level - src/base - machine.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:34ae921) Lines: 126 159 79.2 %
Date: 2024-09-13 19:57:57 Functions: 18 20 90.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !> \brief Machine interface based on Fortran 2003 and POSIX
      10             : !> \par History
      11             : !>      JGH (05.07.2001) : added G95 interface
      12             : !>      - m_flush added (12.06.2002,MK)
      13             : !>      - Missing print_memory added (24.09.2002,MK)
      14             : !>      - Migrate to generic implementation based on F2003 + POSIX (2014, Ole Schuett)
      15             : !> \author APSI, JGH, Ole Schuett
      16             : ! **************************************************************************************************
      17             : MODULE machine
      18             :    USE ISO_C_BINDING, ONLY: C_CHAR, &
      19             :                             C_INT, &
      20             :                             C_PTR, &
      21             :                             C_NULL_CHAR, &
      22             :                             C_ASSOCIATED
      23             :    USE ISO_FORTRAN_ENV, ONLY: input_unit, &
      24             :                               output_unit
      25             :    USE omp_lib, ONLY: omp_get_wtime
      26             :    USE kinds, ONLY: default_path_length, &
      27             :                     default_string_length, &
      28             :                     dp, &
      29             :                     int_8
      30             : #if defined(__LIBXSMM)
      31             : #include "libxsmm_version.h"
      32             : #if !defined(__LIBXSMM2) && (1 < __LIBXSMM || (1170000 < \
      33             :    (LIBXSMM_CONFIG_VERSION_MAJOR*1000000 + LIBXSMM_CONFIG_VERSION_MINOR*10000 + LIBXSMM_CONFIG_VERSION_UPDATE*100 + LIBXSMM_CONFIG_VERSION_PATCH)))
      34             : #define __LIBXSMM2
      35             : #endif
      36             :    USE libxsmm, ONLY: libxsmm_timer_tick, libxsmm_timer_duration, libxsmm_get_target_archid, &
      37             :                       LIBXSMM_TARGET_ARCH_GENERIC, LIBXSMM_X86_SSE4, LIBXSMM_X86_AVX, LIBXSMM_X86_AVX2, &
      38             : #if defined(__LIBXSMM2)
      39             :                       LIBXSMM_X86_AVX512_SKX, LIBXSMM_AARCH64_V81, LIBXSMM_AARCH64_SVE128
      40             : #else
      41             :    LIBXSMM_X86_AVX512_SKX => LIBXSMM_X86_AVX512_CORE
      42             : #endif
      43             : #endif
      44             : 
      45             :    IMPLICIT NONE
      46             : 
      47             :    ! Except for some error handling code, all code should
      48             :    ! get a unit number from the print keys or from the logger, in order
      49             :    ! to guarantee correct output behavior,
      50             :    ! for example in farming or path integral runs
      51             :    ! default_input_unit should never be used
      52             :    ! but we need to know what it is, as we should not try to open it for output
      53             :    INTEGER, PUBLIC, PARAMETER                   :: default_output_unit = output_unit, &
      54             :                                                    default_input_unit = input_unit
      55             : 
      56             : #include "machine_cpuid.h"
      57             :    ! Enumerates the target architectures or instruction set extensions.
      58             :    ! A feature is present if within range for the respective architecture.
      59             :    ! For example, to check for MACHINE_X86_AVX the following is true:
      60             :    ! MACHINE_X86_AVX <= m_cpuid() and MACHINE_X86 >= m_cpuid().
      61             :    ! For example, to check for MACHINE_ARM_SOME the following is true:
      62             :    ! MACHINE_ARM_SOME <= m_cpuid() and MACHINE_ARM >= m_cpuid().
      63             :    INTEGER, PUBLIC, PARAMETER :: &
      64             :       MACHINE_CPU_GENERIC = CP_MACHINE_CPU_GENERIC, &
      65             :       !
      66             :       MACHINE_X86_SSE4 = CP_MACHINE_X86_SSE4, &
      67             :       MACHINE_X86_AVX = CP_MACHINE_X86_AVX, &
      68             :       MACHINE_X86_AVX2 = CP_MACHINE_X86_AVX2, &
      69             :       MACHINE_X86_AVX512 = CP_MACHINE_X86_AVX512, &
      70             :       MACHINE_X86 = MACHINE_X86_AVX512, &
      71             :       !
      72             :       MACHINE_ARM_ARCH64 = CP_MACHINE_ARM_ARCH64, &
      73             :       MACHINE_ARM_SVE128 = CP_MACHINE_ARM_SVE128, &
      74             :       MACHINE_ARM_SVE256 = CP_MACHINE_ARM_SVE256, &
      75             :       MACHINE_ARM_SVE512 = CP_MACHINE_ARM_SVE512, &
      76             :       MACHINE_ARM = MACHINE_ARM_SVE512, &
      77             :       !
      78             :       ! other archs to be added as needed
      79             :       MACHINE_CPU_UNKNOWN = CP_MACHINE_UNKNOWN ! marks end of range
      80             : 
      81             :    PRIVATE
      82             : 
      83             :    PUBLIC :: m_walltime, m_datum, m_hostnm, m_flush, &
      84             :              m_getcwd, m_getlog, m_getpid, m_procrun, m_abort, &
      85             :              m_chdir, m_mov, m_memory, m_memory_details, m_energy, &
      86             :              m_cpuinfo, m_cpuid_static, m_cpuid, m_cpuid_name, &
      87             :              m_get_omp_stacksize
      88             : 
      89             :    INTERFACE
      90             :       ! **********************************************************************************************
      91             :       !> \brief Target architecture or instruction set extension according to compiler target flags.
      92             :       !> \return cpuid according to MACHINE_* integer-parameter.
      93             :       !> \par History
      94             :       !>      04.2019 created [Hans Pabst]
      95             :       ! **********************************************************************************************
      96             :       PURE FUNCTION m_cpuid_static() BIND(C)
      97             :          IMPORT :: C_INT
      98             :          INTEGER(C_INT) :: m_cpuid_static
      99             :       END FUNCTION m_cpuid_static
     100             :    END INTERFACE
     101             : 
     102             :    ! Flushing is enabled by default because without it crash reports can get lost.
     103             :    ! For performance reasons it can be disabled via the input in &GLOBAL.
     104             :    LOGICAL, SAVE, PUBLIC :: flush_should_flush = .TRUE.
     105             : 
     106             :    INTEGER(KIND=int_8), SAVE, PUBLIC :: m_memory_max = 0
     107             : 
     108             : CONTAINS
     109             : 
     110             : ! **************************************************************************************************
     111             : !> \brief flushes units if the &GLOBAL flag is set accordingly
     112             : !> \param lunit ...
     113             : !> \par History
     114             : !>      10.2008 created [Joost VandeVondele]
     115             : !> \note
     116             : !>      flushing might degrade performance significantly (30% and more)
     117             : ! **************************************************************************************************
     118      291735 :    SUBROUTINE m_flush(lunit)
     119             :       INTEGER, INTENT(IN)                                :: lunit
     120             : 
     121      291735 :       IF (flush_should_flush) FLUSH (lunit)
     122             : 
     123      291735 :    END SUBROUTINE
     124             : 
     125             : ! **************************************************************************************************
     126             : !> \brief returns time from a real-time clock, protected against rolling
     127             : !>      early/easily
     128             : !> \return ...
     129             : !> \par History
     130             : !>      03.2006 created [Joost VandeVondele]
     131             : !> \note
     132             : !>      same implementation for all machines.
     133             : !>      might still roll, if not called multiple times per count_max/count_rate
     134             : ! **************************************************************************************************
     135  3098812730 :    FUNCTION m_walltime() RESULT(wt)
     136             :       REAL(KIND=dp)                                      :: wt
     137             : 
     138             : #if defined(__LIBXSMM)
     139  3098812730 :       wt = libxsmm_timer_duration(0_int_8, libxsmm_timer_tick())
     140             : #else
     141             :       wt = omp_get_wtime()
     142             : #endif
     143  3098812730 :    END FUNCTION m_walltime
     144             : 
     145             : ! **************************************************************************************************
     146             : !> \brief reads /proc/cpuinfo if it exists (i.e. Linux) to return relevant info
     147             : !> \param model_name as obtained from the 'model name' field, UNKNOWN otherwise
     148             : ! **************************************************************************************************
     149        4620 :    SUBROUTINE m_cpuinfo(model_name)
     150             :       CHARACTER(LEN=default_string_length)               :: model_name
     151             : 
     152             :       INTEGER, PARAMETER                                 :: bufferlen = 2048
     153             : 
     154             :       CHARACTER(LEN=bufferlen)                           :: buffer
     155             :       INTEGER                                            :: i, icol, iline, imod, stat
     156             : 
     157        4620 :       model_name = "UNKNOWN"
     158        4620 :       buffer = ""
     159        4620 :       OPEN (121245, FILE="/proc/cpuinfo", ACTION="READ", STATUS="OLD", ACCESS="STREAM", IOSTAT=stat)
     160        4620 :       IF (stat == 0) THEN
     161     9466380 :          DO i = 1, bufferlen
     162     9466380 :             READ (121245, END=999) buffer(I:I)
     163             :          END DO
     164        4620 : 999      CLOSE (121245)
     165        4620 :          imod = INDEX(buffer, "model name")
     166        4620 :          IF (imod > 0) THEN
     167        4620 :             icol = imod - 1 + INDEX(buffer(imod:), ":")
     168        4620 :             iline = icol - 1 + INDEX(buffer(icol:), NEW_LINE('A'))
     169        4620 :             IF (iline == icol - 1) iline = bufferlen + 1
     170        4620 :             model_name = buffer(icol + 1:iline - 1)
     171             :          END IF
     172             :       END IF
     173        4620 :    END SUBROUTINE m_cpuinfo
     174             : 
     175             : ! **************************************************************************************************
     176             : !> \brief Target architecture or instruction set extension according to CPU-check at runtime.
     177             : !> \return cpuid according to MACHINE_* integer-parameter.
     178             : !> \par History
     179             : !>      04.2019 created [Hans Pabst]
     180             : !>      09.2024 update+arm [Hans Pabst]
     181             : ! **************************************************************************************************
     182       13459 :    PURE FUNCTION m_cpuid() RESULT(cpuid)
     183             :       INTEGER :: cpuid
     184             : #if defined(__LIBXSMM)
     185       13459 :       cpuid = libxsmm_get_target_archid()
     186       13459 :       IF (LIBXSMM_X86_SSE4 <= cpuid .AND. cpuid < LIBXSMM_X86_AVX) THEN
     187             :          cpuid = MACHINE_X86_SSE4
     188       13459 :       ELSE IF (LIBXSMM_X86_AVX <= cpuid .AND. cpuid < LIBXSMM_X86_AVX2) THEN
     189             :          cpuid = MACHINE_X86_AVX
     190       13459 :       ELSE IF (LIBXSMM_X86_AVX2 <= cpuid .AND. cpuid < LIBXSMM_X86_AVX512_SKX) THEN
     191             :          cpuid = MACHINE_X86_AVX2
     192           0 :       ELSE IF (LIBXSMM_X86_AVX512_SKX <= cpuid .AND. cpuid <= 1999) THEN
     193             :          cpuid = MACHINE_X86_AVX512
     194             : #if defined(__LIBXSMM2)
     195           0 :       ELSE IF (LIBXSMM_AARCH64_V81 <= cpuid .AND. cpuid < LIBXSMM_AARCH64_SVE128) THEN
     196             :          cpuid = MACHINE_ARM_ARCH64
     197           0 :       ELSE IF (LIBXSMM_AARCH64_SVE128 <= cpuid .AND. cpuid < 2401) THEN ! LIBXSMM_AARCH64_SVE512
     198             :          cpuid = MACHINE_ARM_SVE256
     199           0 :       ELSE IF (2401 <= cpuid .AND. cpuid <= 2999) THEN
     200             :          cpuid = MACHINE_ARM_SVE512
     201             : #endif
     202           0 :       ELSE IF (LIBXSMM_TARGET_ARCH_GENERIC <= cpuid .AND. cpuid <= 2999) THEN
     203             :          cpuid = MACHINE_CPU_GENERIC
     204             :       ELSE
     205           0 :          cpuid = MACHINE_CPU_UNKNOWN
     206             :       END IF
     207             : #else
     208             :       cpuid = m_cpuid_static()
     209             : #endif
     210       13459 :    END FUNCTION m_cpuid
     211             : 
     212             : ! **************************************************************************************************
     213             : !> \brief Determine name of target architecture for a given CPUID.
     214             : !> \param cpuid integer value (MACHINE_*)
     215             : !> \return name or short name.
     216             : !> \par History
     217             : !>      06.2019 created [Hans Pabst]
     218             : !>      09.2024 update+arm [Hans Pabst]
     219             : ! **************************************************************************************************
     220           0 :    FUNCTION m_cpuid_name(cpuid)
     221             :       INTEGER                                            :: cpuid
     222             :       CHARACTER(len=default_string_length), POINTER      :: m_cpuid_name
     223             : 
     224             :       CHARACTER(len=default_string_length), SAVE, TARGET :: name_arm_arch64 = "arm_arch64", &
     225             :                                                             name_arm_sve128 = "arm_sve128", &
     226             :                                                             name_arm_sve256 = "arm_sve256", &
     227             :                                                             name_arm_sve512 = "arm_sve512", &
     228             :                                                             name_generic = "generic", &
     229             :                                                             name_unknown = "unknown", &
     230             :                                                             name_x86_avx = "x86_avx", &
     231             :                                                             name_x86_avx2 = "x86_avx2", &
     232             :                                                             name_x86_avx512 = "x86_avx512", &
     233             :                                                             name_x86_sse4 = "x86_sse4"
     234             : 
     235           0 :       SELECT CASE (cpuid)
     236             :       CASE (MACHINE_CPU_GENERIC)
     237           0 :          m_cpuid_name => name_generic
     238             :       CASE (MACHINE_X86_SSE4)
     239           0 :          m_cpuid_name => name_x86_sse4
     240             :       CASE (MACHINE_X86_AVX)
     241           0 :          m_cpuid_name => name_x86_avx
     242             :       CASE (MACHINE_X86_AVX2)
     243           0 :          m_cpuid_name => name_x86_avx2
     244             :       CASE (MACHINE_X86_AVX512)
     245           0 :          m_cpuid_name => name_x86_avx512
     246             :       CASE (MACHINE_ARM_ARCH64)
     247           0 :          m_cpuid_name => name_arm_arch64
     248             :       CASE (MACHINE_ARM_SVE128)
     249           0 :          m_cpuid_name => name_arm_sve128
     250             :       CASE (MACHINE_ARM_SVE256)
     251           0 :          m_cpuid_name => name_arm_sve256
     252             :       CASE (MACHINE_ARM_SVE512)
     253           0 :          m_cpuid_name => name_arm_sve512
     254             :       CASE DEFAULT
     255           0 :          m_cpuid_name => name_unknown
     256             :       END SELECT
     257           0 :    END FUNCTION m_cpuid_name
     258             : 
     259             : ! **************************************************************************************************
     260             : !> \brief returns the energy used since some time in the past.
     261             : !>        The precise meaning depends on the infrastructure is available.
     262             : !>        In the cray_pm_energy case, this is the energy used by the node in kJ.
     263             : !> \return ...
     264             : !> \par History
     265             : !>      09.2013 created [Joost VandeVondele, Ole Schuett]
     266             : ! **************************************************************************************************
     267  3092200027 :    FUNCTION m_energy() RESULT(wt)
     268             :       REAL(KIND=dp)                            :: wt
     269             : 
     270             : #if defined(__CRAY_PM_ENERGY)
     271             :       wt = read_energy("/sys/cray/pm_counters/energy")
     272             : #elif defined(__CRAY_PM_ACCEL_ENERGY)
     273             :       wt = read_energy("/sys/cray/pm_counters/accel_energy")
     274             : #else
     275  3092200027 :       wt = 0.0 ! fallback default
     276             : #endif
     277             : 
     278  3092200027 :    END FUNCTION m_energy
     279             : 
     280             : #if defined(__CRAY_PM_ACCEL_ENERGY) || defined(__CRAY_PM_ENERGY)
     281             : ! **************************************************************************************************
     282             : !> \brief reads energy values from the sys-filesystem
     283             : !> \param filename ...
     284             : !> \return ...
     285             : !> \par History
     286             : !>      09.2013 created [Joost VandeVondele, Ole Schuett]
     287             : ! **************************************************************************************************
     288             :    FUNCTION read_energy(filename) RESULT(wt)
     289             :       CHARACTER(LEN=*)                                   :: filename
     290             :       REAL(KIND=dp)                                      :: wt
     291             : 
     292             :       CHARACTER(LEN=80)                                  :: DATA
     293             :       INTEGER                                            :: i, iostat
     294             :       INTEGER(KIND=int_8)                                :: raw
     295             : 
     296             :       OPEN (121245, FILE=filename, ACTION="READ", STATUS="OLD", ACCESS="STREAM")
     297             :       DO I = 1, 80
     298             :          READ (121245, END=999) DATA(I:I)
     299             :       END DO
     300             : 999   CLOSE (121245)
     301             :       DATA(I:80) = ""
     302             :       READ (DATA, *, IOSTAT=iostat) raw
     303             :       IF (iostat .NE. 0) THEN
     304             :          wt = 0.0_dp
     305             :       ELSE
     306             :          ! convert from J to kJ
     307             :          wt = raw/1000.0_dp
     308             :       END IF
     309             :    END FUNCTION read_energy
     310             : #endif
     311             : 
     312             : ! **************************************************************************************************
     313             : !> \brief returns a datum in human readable format using a standard Fortran routine
     314             : !> \param cal_date ...
     315             : !> \par History
     316             : !>      10.2009 created [Joost VandeVondele]
     317             : ! **************************************************************************************************
     318       21428 :    SUBROUTINE m_datum(cal_date)
     319             :       CHARACTER(len=*), INTENT(OUT)                      :: cal_date
     320             : 
     321             :       CHARACTER(len=10)                                  :: time
     322             :       CHARACTER(len=8)                                   :: date
     323             : 
     324       21428 :       CALL DATE_AND_TIME(date=date, time=time)
     325       21428 :       cal_date = date(1:4)//"-"//date(5:6)//"-"//date(7:8)//" "//time(1:2)//":"//time(3:4)//":"//time(5:10)
     326             : 
     327       21428 :    END SUBROUTINE m_datum
     328             : 
     329             : ! **************************************************************************************************
     330             : !> \brief Can be used to get a nice core
     331             : ! **************************************************************************************************
     332           0 :    SUBROUTINE m_abort()
     333             :       INTERFACE
     334             :          SUBROUTINE abort() BIND(C, name="abort")
     335             :          END SUBROUTINE
     336             :       END INTERFACE
     337             : 
     338           0 :       CALL abort()
     339           0 :    END SUBROUTINE m_abort
     340             : 
     341             : ! **************************************************************************************************
     342             : !> \brief Returns if a process is running on the local machine
     343             : !>        1 if yes and 0 if not
     344             : !> \param pid ...
     345             : !> \return ...
     346             : ! **************************************************************************************************
     347           2 :    FUNCTION m_procrun(pid) RESULT(run_on)
     348             :       INTEGER, INTENT(IN)       ::   pid
     349             :       INTEGER                   ::   run_on
     350             : #if defined(__MINGW)
     351             :       run_on = 0
     352             : #else
     353             :       INTEGER                   ::   istat
     354             : 
     355             :       INTERFACE
     356             :          FUNCTION kill(pid, sig) BIND(C, name="kill") RESULT(errno)
     357             :             IMPORT
     358             :             INTEGER(KIND=C_INT), VALUE                :: pid, sig
     359             :             INTEGER(KIND=C_INT)                      :: errno
     360             :          END FUNCTION
     361             :       END INTERFACE
     362             : 
     363             :       ! If sig is 0, then no signal is sent, but error checking is still
     364             :       ! performed; this can be used to check for the existence of a process
     365             :       ! ID or process group ID.
     366             : 
     367           2 :       istat = kill(pid=pid, sig=0)
     368           2 :       IF (istat == 0) THEN
     369             :          run_on = 1 ! no error, process exists
     370             :       ELSE
     371           0 :          run_on = 0 ! error, process probably does not exist
     372             :       END IF
     373             : #endif
     374           2 :    END FUNCTION m_procrun
     375             : 
     376             : ! **************************************************************************************************
     377             : !> \brief Returns the total amount of memory [bytes] in use, if known, zero otherwise
     378             : !> \param mem ...
     379             : ! **************************************************************************************************
     380     2080488 :    SUBROUTINE m_memory(mem)
     381             : 
     382             :       INTEGER(KIND=int_8), OPTIONAL, INTENT(OUT)         :: mem
     383             :       INTEGER(KIND=int_8)                      :: mem_local
     384             : 
     385             :       !
     386             :       ! __NO_STATM_ACCESS can be used to disable the stuff, if getpagesize
     387             :       ! lead to linking errors or /proc/self/statm can not be opened
     388             :       !
     389             : #if defined(__NO_STATM_ACCESS)
     390             :       mem_local = 0
     391             : #else
     392             :       INTEGER(KIND=int_8)                      :: m1, m2, m3
     393             :       CHARACTER(LEN=80) :: DATA
     394             :       INTEGER :: iostat, i
     395             : 
     396             :       ! the size of a page, might not be available everywhere
     397             :       INTERFACE
     398             :          FUNCTION getpagesize() BIND(C, name="getpagesize") RESULT(RES)
     399             :             IMPORT
     400             :             INTEGER(C_INT) :: RES
     401             :          END FUNCTION
     402             :       END INTERFACE
     403             : 
     404             :       !
     405             :       ! reading from statm
     406             :       !
     407     2080488 :       mem_local = -1
     408     2080488 :       DATA = ""
     409     2080488 :       OPEN (121245, FILE="/proc/self/statm", ACTION="READ", STATUS="OLD", ACCESS="STREAM")
     410    78957975 :       DO I = 1, 80
     411    78957975 :          READ (121245, END=999) DATA(I:I)
     412             :       END DO
     413     2080488 : 999   CLOSE (121245)
     414     2080488 :       DATA(I:80) = ""
     415             :       ! m1 = total
     416             :       ! m2 = resident
     417             :       ! m3 = shared
     418     2080488 :       READ (DATA, *, IOSTAT=iostat) m1, m2, m3
     419     2080488 :       IF (iostat .NE. 0) THEN
     420             :          mem_local = 0
     421             :       ELSE
     422     2080488 :          mem_local = m2
     423             : #if defined(__STATM_TOTAL)
     424             :          mem_local = m1
     425             : #endif
     426             : #if defined(__STATM_RESIDENT)
     427             :          mem_local = m2
     428             : #endif
     429     2080488 :          mem_local = mem_local*getpagesize()
     430             :       END IF
     431             : #endif
     432             : 
     433     2080488 :       m_memory_max = MAX(mem_local, m_memory_max)
     434     2080488 :       IF (PRESENT(mem)) mem = mem_local
     435             : 
     436     2080488 :    END SUBROUTINE m_memory
     437             : 
     438             : ! **************************************************************************************************
     439             : !> \brief get more detailed memory info, all units are bytes.
     440             : !>         the only 'useful' option is MemLikelyFree which is an estimate of remaining memory
     441             : !>         assumed to give info like /proc/meminfo while MeMLikelyFree is the amount of
     442             : !>         memory we're likely to be able to allocate, but not necessarily in one chunk
     443             : !>         zero means not available...
     444             : !> \param MemTotal ...
     445             : !> \param MemFree ...
     446             : !> \param Buffers ...
     447             : !> \param Cached ...
     448             : !> \param Slab ...
     449             : !> \param SReclaimable ...
     450             : !> \param MemLikelyFree ...
     451             : ! **************************************************************************************************
     452        9033 :    SUBROUTINE m_memory_details(MemTotal, MemFree, Buffers, Cached, Slab, SReclaimable, MemLikelyFree)
     453             : 
     454             :       INTEGER(kind=int_8), OPTIONAL :: MemTotal, MemFree, Buffers, Cached, Slab, SReclaimable, MemLikelyFree
     455             : 
     456             :       INTEGER, PARAMETER :: Nbuffer = 10000
     457             :       CHARACTER(LEN=Nbuffer) :: meminfo
     458             : 
     459             :       INTEGER :: i
     460             : 
     461        9033 :       MemTotal = 0
     462        9033 :       MemFree = 0
     463        9033 :       Buffers = 0
     464        9033 :       Cached = 0
     465        9033 :       Slab = 0
     466        9033 :       SReclaimable = 0
     467        9033 :       MemLikelyFree = 0
     468        9033 :       meminfo = ""
     469             : 
     470        9033 :       OPEN (UNIT=8123, file="/proc/meminfo", ACCESS="STREAM", ERR=901)
     471        9033 :       i = 0
     472    13864565 :       DO
     473    13873598 :          i = i + 1
     474    13873598 :          IF (i > Nbuffer) EXIT
     475    13873598 :          READ (8123, END=900, ERR=900) meminfo(i:i)
     476             :       END DO
     477             : 900   CONTINUE
     478        9033 :       meminfo(i:Nbuffer) = ""
     479             : 901   CONTINUE
     480        9033 :       CLOSE (8123, ERR=902)
     481             : 902   CONTINUE
     482        9033 :       MemTotal = get_field_value_in_bytes('MemTotal:')
     483        9033 :       MemFree = get_field_value_in_bytes('MemFree:')
     484        9033 :       Buffers = get_field_value_in_bytes('Buffers:')
     485        9033 :       Cached = get_field_value_in_bytes('Cached:')
     486        9033 :       Slab = get_field_value_in_bytes('Slab:')
     487        9033 :       SReclaimable = get_field_value_in_bytes('SReclaimable:')
     488             :       ! opinions here vary but this might work
     489        9033 :       MemLikelyFree = MemFree + Buffers + Cached + SReclaimable
     490             : 
     491             :    CONTAINS
     492             : 
     493             : ! **************************************************************************************************
     494             : !> \brief ...
     495             : !> \param field ...
     496             : !> \return ...
     497             : ! **************************************************************************************************
     498       54198 :       INTEGER(int_8) FUNCTION get_field_value_in_bytes(field)
     499             :          CHARACTER(LEN=*)                                   :: field
     500             : 
     501             :          INTEGER                                            :: start
     502             :          INTEGER(KIND=int_8)                                :: value
     503             : 
     504       54198 :          get_field_value_in_bytes = 0
     505       54198 :          start = INDEX(meminfo, field)
     506       54198 :          IF (start .NE. 0) THEN
     507       54198 :             start = start + LEN_TRIM(field)
     508       54198 :             IF (start .LT. Nbuffer) THEN
     509       54198 :                READ (meminfo(start:), *, ERR=999, END=999) value
     510             :                ! XXXXXXX convert from Kb to bytes XXXXXXXX
     511       54198 :                get_field_value_in_bytes = value*1024
     512             : 999            CONTINUE
     513             :             END IF
     514             :          END IF
     515       54198 :       END FUNCTION
     516             :    END SUBROUTINE m_memory_details
     517             : 
     518             : ! **************************************************************************************************
     519             : !> \brief ...
     520             : !> \param hname ...
     521             : ! **************************************************************************************************
     522       13315 :    SUBROUTINE m_hostnm(hname)
     523             :       CHARACTER(len=*), INTENT(OUT)            :: hname
     524             : #if defined(__MINGW)
     525             :       ! While there is a gethostname in the Windows (POSIX) API, it requires that winsocks is
     526             :       ! initialised prior to using it via WSAStartup(..), respectively cleaned up at the end via WSACleanup().
     527             :       hname = "<unknown>"
     528             : #else
     529             :       INTEGER                                  :: istat, i
     530             :       CHARACTER(len=default_path_length)       :: buf
     531             : 
     532             :       INTERFACE
     533             :          FUNCTION gethostname(buf, buflen) BIND(C, name="gethostname") RESULT(errno)
     534             :             IMPORT
     535             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: buf
     536             :             INTEGER(KIND=C_INT), VALUE               :: buflen
     537             :             INTEGER(KIND=C_INT)                      :: errno
     538             :          END FUNCTION
     539             :       END INTERFACE
     540             : 
     541       26630 :       istat = gethostname(buf, LEN(buf))
     542       13315 :       IF (istat /= 0) THEN
     543           0 :          WRITE (*, *) "m_hostnm failed"
     544           0 :          CALL m_abort()
     545             :       END IF
     546       13315 :       i = INDEX(buf, c_null_char) - 1
     547       13315 :       hname = buf(1:i)
     548             : #endif
     549       13315 :    END SUBROUTINE m_hostnm
     550             : 
     551             : ! **************************************************************************************************
     552             : !> \brief ...
     553             : !> \param curdir ...
     554             : ! **************************************************************************************************
     555      129932 :    SUBROUTINE m_getcwd(curdir)
     556             :       CHARACTER(len=*), INTENT(OUT)            :: curdir
     557             :       TYPE(C_PTR)                              :: stat
     558             :       INTEGER                                  :: i
     559             :       CHARACTER(len=default_path_length), TARGET  :: tmp
     560             : 
     561             :       INTERFACE
     562             :          FUNCTION getcwd(buf, buflen) BIND(C, name="getcwd") RESULT(stat)
     563             :             IMPORT
     564             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: buf
     565             :             INTEGER(KIND=C_INT), VALUE               :: buflen
     566             :             TYPE(C_PTR)                              :: stat
     567             :          END FUNCTION
     568             :       END INTERFACE
     569             : 
     570      259864 :       stat = getcwd(tmp, LEN(tmp))
     571      129932 :       IF (.NOT. C_ASSOCIATED(stat)) THEN
     572           0 :          WRITE (*, *) "m_getcwd failed"
     573           0 :          CALL m_abort()
     574             :       END IF
     575      129932 :       i = INDEX(tmp, c_null_char) - 1
     576      129932 :       curdir = tmp(1:i)
     577      129932 :    END SUBROUTINE m_getcwd
     578             : 
     579             : ! **************************************************************************************************
     580             : !> \brief ...
     581             : !> \param dir ...
     582             : !> \param ierror ...
     583             : ! **************************************************************************************************
     584        2902 :    SUBROUTINE m_chdir(dir, ierror)
     585             :       CHARACTER(len=*), INTENT(IN)             :: dir
     586             :       INTEGER, INTENT(OUT)                     :: ierror
     587             : 
     588             :       INTERFACE
     589             :          FUNCTION chdir(path) BIND(C, name="chdir") RESULT(errno)
     590             :             IMPORT
     591             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: path
     592             :             INTEGER(KIND=C_INT)                      :: errno
     593             :          END FUNCTION
     594             :       END INTERFACE
     595             : 
     596        2902 :       ierror = chdir(TRIM(dir)//c_null_char)
     597        2902 :    END SUBROUTINE m_chdir
     598             : 
     599             : ! **************************************************************************************************
     600             : !> \brief ...
     601             : !> \param pid ...
     602             : ! **************************************************************************************************
     603       13315 :    SUBROUTINE m_getpid(pid)
     604             :       INTEGER, INTENT(OUT)                     :: pid
     605             : 
     606             :       INTERFACE
     607             :          FUNCTION getpid() BIND(C, name="getpid") RESULT(pid)
     608             :             IMPORT
     609             :             INTEGER(KIND=C_INT)              :: pid
     610             :          END FUNCTION
     611             :       END INTERFACE
     612             : 
     613       13315 :       pid = getpid()
     614       13315 :    END SUBROUTINE m_getpid
     615             : 
     616             : ! **************************************************************************************************
     617             : !> \brief ...
     618             : !> \param path ...
     619             : !> \return ...
     620             : ! **************************************************************************************************
     621       11447 :    FUNCTION m_unlink(path) RESULT(istat)
     622             : 
     623             :       CHARACTER(LEN=*), INTENT(IN)             :: path
     624             : 
     625             :       INTEGER                                  :: istat
     626             : 
     627             :       INTERFACE
     628             :          FUNCTION unlink(path) BIND(C, name="unlink") RESULT(errno)
     629             :             IMPORT
     630             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: path
     631             :             INTEGER(KIND=C_INT)                      :: errno
     632             :          END FUNCTION
     633             :       END INTERFACE
     634             : 
     635       11447 :       istat = unlink(TRIM(path)//c_null_char)
     636       11447 :    END FUNCTION m_unlink
     637             : 
     638             : ! **************************************************************************************************
     639             : !> \brief ...
     640             : !> \param source ...
     641             : !> \param TARGET ...
     642             : ! **************************************************************************************************
     643       11447 :    SUBROUTINE m_mov(source, TARGET)
     644             : 
     645             :       CHARACTER(LEN=*), INTENT(IN)             :: source, TARGET
     646             : 
     647             :       INTEGER                                  :: istat
     648             : 
     649             :       INTERFACE
     650             :          FUNCTION rename(src, dest) BIND(C, name="rename") RESULT(errno)
     651             :             IMPORT
     652             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: src, dest
     653             :             INTEGER(KIND=C_INT)                      :: errno
     654             :          END FUNCTION
     655             :       END INTERFACE
     656             : 
     657       11447 :       IF (TARGET == source) THEN
     658           0 :          WRITE (*, *) "Warning: m_mov ", TRIM(TARGET), " equals ", TRIM(source)
     659           0 :          RETURN
     660             :       END IF
     661             : 
     662             :       ! first remove target (needed on windows / mingw)
     663       11447 :       istat = m_unlink(TARGET)
     664             :       ! ignore istat of unlink
     665             : 
     666             :       ! now move
     667       11447 :       istat = rename(TRIM(source)//c_null_char, TRIM(TARGET)//c_null_char)
     668       11447 :       IF (istat .NE. 0) THEN
     669           0 :          WRITE (*, *) "Trying to move "//TRIM(source)//" to "//TRIM(TARGET)//"."
     670           0 :          WRITE (*, *) "rename returned status: ", istat
     671           0 :          WRITE (*, *) "Problem moving file"
     672           0 :          CALL m_abort()
     673             :       END IF
     674             :    END SUBROUTINE m_mov
     675             : 
     676             : ! **************************************************************************************************
     677             : !> \brief ...
     678             : !> \param user ...
     679             : ! **************************************************************************************************
     680       13090 :    SUBROUTINE m_getlog(user)
     681             : 
     682             :       CHARACTER(LEN=*), INTENT(OUT) :: user
     683             : 
     684             :       INTEGER                       :: istat
     685             : 
     686             :       ! on a posix system LOGNAME should be defined
     687       13090 :       CALL get_environment_variable("LOGNAME", value=user, status=istat)
     688             :       ! nope, check alternative
     689       13090 :       IF (istat /= 0) &
     690       13090 :          CALL get_environment_variable("USER", value=user, status=istat)
     691             :       ! nope, check alternative
     692       13090 :       IF (istat /= 0) &
     693       13090 :          CALL get_environment_variable("USERNAME", value=user, status=istat)
     694             :       ! fall back
     695       13090 :       IF (istat /= 0) &
     696       13090 :          user = "<unknown>"
     697             : 
     698       13090 :    END SUBROUTINE m_getlog
     699             : 
     700             : ! **************************************************************************************************
     701             : !> \brief Retrieve environment variable OMP_STACKSIZE
     702             : !> \param omp_stacksize Value of OMP_STACKSIZE
     703             : ! **************************************************************************************************
     704        4620 :    SUBROUTINE m_get_omp_stacksize(omp_stacksize)
     705             :       CHARACTER(LEN=*), INTENT(OUT)                      :: omp_stacksize
     706             : 
     707             :       INTEGER                                            :: istat
     708             : 
     709        4620 :       omp_stacksize = ""
     710        4620 :       CALL get_environment_variable("OMP_STACKSIZE", value=omp_stacksize, status=istat)
     711             :       ! Fall back, if OMP_STACKSIZE is not set
     712        4620 :       IF (istat /= 0) omp_stacksize = "default"
     713             : 
     714        4620 :    END SUBROUTINE m_get_omp_stacksize
     715             : 
     716             : END MODULE machine

Generated by: LCOV version 1.15