LCOV - code coverage report
Current view: top level - src/base - machine.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:262480d) Lines: 126 159 79.2 %
Date: 2024-11-22 07:00:40 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_omp_get_stacksize, m_omp_trace_issues
      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             : 
     101             :       ! **********************************************************************************************
     102             :       !> \brief Trace OpenMP constructs if ennvironment variable CP2K_OMP_TRACE=1.
     103             :       !> \return Number of OpenMP issues encountered (negative if OMPT disabled).
     104             :       !> \par History
     105             :       !>      11.2024 created [Hans Pabst]
     106             :       ! **********************************************************************************************
     107             :       FUNCTION m_omp_trace_issues() BIND(C, name="openmp_trace_issues")
     108             :          IMPORT :: C_INT
     109             :          INTEGER(C_INT) :: m_omp_trace_issues
     110             :       END FUNCTION m_omp_trace_issues
     111             :    END INTERFACE
     112             : 
     113             :    ! Flushing is enabled by default because without it crash reports can get lost.
     114             :    ! For performance reasons it can be disabled via the input in &GLOBAL.
     115             :    LOGICAL, SAVE, PUBLIC :: flush_should_flush = .TRUE.
     116             : 
     117             :    INTEGER(KIND=int_8), SAVE, PUBLIC :: m_memory_max = 0
     118             : 
     119             : CONTAINS
     120             : 
     121             : ! **************************************************************************************************
     122             : !> \brief flushes units if the &GLOBAL flag is set accordingly
     123             : !> \param lunit ...
     124             : !> \par History
     125             : !>      10.2008 created [Joost VandeVondele]
     126             : !> \note
     127             : !>      flushing might degrade performance significantly (30% and more)
     128             : ! **************************************************************************************************
     129      243807 :    SUBROUTINE m_flush(lunit)
     130             :       INTEGER, INTENT(IN)                                :: lunit
     131             : 
     132      243807 :       IF (flush_should_flush) FLUSH (lunit)
     133             : 
     134      243807 :    END SUBROUTINE
     135             : 
     136             : ! **************************************************************************************************
     137             : !> \brief returns time from a real-time clock, protected against rolling
     138             : !>      early/easily
     139             : !> \return ...
     140             : !> \par History
     141             : !>      03.2006 created [Joost VandeVondele]
     142             : !> \note
     143             : !>      same implementation for all machines.
     144             : !>      might still roll, if not called multiple times per count_max/count_rate
     145             : ! **************************************************************************************************
     146  3131786791 :    FUNCTION m_walltime() RESULT(wt)
     147             :       REAL(KIND=dp)                                      :: wt
     148             : 
     149             : #if defined(__LIBXSMM)
     150  3131786791 :       wt = libxsmm_timer_duration(0_int_8, libxsmm_timer_tick())
     151             : #else
     152             :       wt = omp_get_wtime()
     153             : #endif
     154  3131786791 :    END FUNCTION m_walltime
     155             : 
     156             : ! **************************************************************************************************
     157             : !> \brief reads /proc/cpuinfo if it exists (i.e. Linux) to return relevant info
     158             : !> \param model_name as obtained from the 'model name' field, UNKNOWN otherwise
     159             : ! **************************************************************************************************
     160        4667 :    SUBROUTINE m_cpuinfo(model_name)
     161             :       CHARACTER(LEN=default_string_length)               :: model_name
     162             : 
     163             :       INTEGER, PARAMETER                                 :: bufferlen = 2048
     164             : 
     165             :       CHARACTER(LEN=bufferlen)                           :: buffer
     166             :       INTEGER                                            :: i, icol, iline, imod, stat
     167             : 
     168        4667 :       model_name = "UNKNOWN"
     169        4667 :       buffer = ""
     170        4667 :       OPEN (121245, FILE="/proc/cpuinfo", ACTION="READ", STATUS="OLD", ACCESS="STREAM", IOSTAT=stat)
     171        4667 :       IF (stat == 0) THEN
     172     9562683 :          DO i = 1, bufferlen
     173     9562683 :             READ (121245, END=999) buffer(I:I)
     174             :          END DO
     175        4667 : 999      CLOSE (121245)
     176        4667 :          imod = INDEX(buffer, "model name")
     177        4667 :          IF (imod > 0) THEN
     178        4667 :             icol = imod - 1 + INDEX(buffer(imod:), ":")
     179        4667 :             iline = icol - 1 + INDEX(buffer(icol:), NEW_LINE('A'))
     180        4667 :             IF (iline == icol - 1) iline = bufferlen + 1
     181        4667 :             model_name = buffer(icol + 1:iline - 1)
     182             :          END IF
     183             :       END IF
     184        4667 :    END SUBROUTINE m_cpuinfo
     185             : 
     186             : ! **************************************************************************************************
     187             : !> \brief Target architecture or instruction set extension according to CPU-check at runtime.
     188             : !> \return cpuid according to MACHINE_* integer-parameter.
     189             : !> \par History
     190             : !>      04.2019 created [Hans Pabst]
     191             : !>      09.2024 update+arm [Hans Pabst]
     192             : ! **************************************************************************************************
     193       13600 :    PURE FUNCTION m_cpuid() RESULT(cpuid)
     194             :       INTEGER :: cpuid
     195             : #if defined(__LIBXSMM)
     196       13600 :       cpuid = libxsmm_get_target_archid()
     197       13600 :       IF (LIBXSMM_X86_SSE4 <= cpuid .AND. cpuid < LIBXSMM_X86_AVX) THEN
     198             :          cpuid = MACHINE_X86_SSE4
     199       13600 :       ELSE IF (LIBXSMM_X86_AVX <= cpuid .AND. cpuid < LIBXSMM_X86_AVX2) THEN
     200             :          cpuid = MACHINE_X86_AVX
     201       13600 :       ELSE IF (LIBXSMM_X86_AVX2 <= cpuid .AND. cpuid < LIBXSMM_X86_AVX512_SKX) THEN
     202             :          cpuid = MACHINE_X86_AVX2
     203           0 :       ELSE IF (LIBXSMM_X86_AVX512_SKX <= cpuid .AND. cpuid <= 1999) THEN
     204             :          cpuid = MACHINE_X86_AVX512
     205             : #if defined(__LIBXSMM2)
     206           0 :       ELSE IF (LIBXSMM_AARCH64_V81 <= cpuid .AND. cpuid < LIBXSMM_AARCH64_SVE128) THEN
     207             :          cpuid = MACHINE_ARM_ARCH64
     208           0 :       ELSE IF (LIBXSMM_AARCH64_SVE128 <= cpuid .AND. cpuid < 2401) THEN ! LIBXSMM_AARCH64_SVE512
     209             :          cpuid = MACHINE_ARM_SVE256
     210           0 :       ELSE IF (2401 <= cpuid .AND. cpuid <= 2999) THEN
     211             :          cpuid = MACHINE_ARM_SVE512
     212             : #endif
     213           0 :       ELSE IF (LIBXSMM_TARGET_ARCH_GENERIC <= cpuid .AND. cpuid <= 2999) THEN
     214             :          cpuid = MACHINE_CPU_GENERIC
     215             :       ELSE
     216           0 :          cpuid = MACHINE_CPU_UNKNOWN
     217             :       END IF
     218             : #else
     219             :       cpuid = m_cpuid_static()
     220             : #endif
     221       13600 :    END FUNCTION m_cpuid
     222             : 
     223             : ! **************************************************************************************************
     224             : !> \brief Determine name of target architecture for a given CPUID.
     225             : !> \param cpuid integer value (MACHINE_*)
     226             : !> \return name or short name.
     227             : !> \par History
     228             : !>      06.2019 created [Hans Pabst]
     229             : !>      09.2024 update+arm [Hans Pabst]
     230             : ! **************************************************************************************************
     231           0 :    FUNCTION m_cpuid_name(cpuid)
     232             :       INTEGER                                            :: cpuid
     233             :       CHARACTER(len=default_string_length), POINTER      :: m_cpuid_name
     234             : 
     235             :       CHARACTER(len=default_string_length), SAVE, TARGET :: name_arm_arch64 = "arm_arch64", &
     236             :                                                             name_arm_sve128 = "arm_sve128", &
     237             :                                                             name_arm_sve256 = "arm_sve256", &
     238             :                                                             name_arm_sve512 = "arm_sve512", &
     239             :                                                             name_generic = "generic", &
     240             :                                                             name_unknown = "unknown", &
     241             :                                                             name_x86_avx = "x86_avx", &
     242             :                                                             name_x86_avx2 = "x86_avx2", &
     243             :                                                             name_x86_avx512 = "x86_avx512", &
     244             :                                                             name_x86_sse4 = "x86_sse4"
     245             : 
     246           0 :       SELECT CASE (cpuid)
     247             :       CASE (MACHINE_CPU_GENERIC)
     248           0 :          m_cpuid_name => name_generic
     249             :       CASE (MACHINE_X86_SSE4)
     250           0 :          m_cpuid_name => name_x86_sse4
     251             :       CASE (MACHINE_X86_AVX)
     252           0 :          m_cpuid_name => name_x86_avx
     253             :       CASE (MACHINE_X86_AVX2)
     254           0 :          m_cpuid_name => name_x86_avx2
     255             :       CASE (MACHINE_X86_AVX512)
     256           0 :          m_cpuid_name => name_x86_avx512
     257             :       CASE (MACHINE_ARM_ARCH64)
     258           0 :          m_cpuid_name => name_arm_arch64
     259             :       CASE (MACHINE_ARM_SVE128)
     260           0 :          m_cpuid_name => name_arm_sve128
     261             :       CASE (MACHINE_ARM_SVE256)
     262           0 :          m_cpuid_name => name_arm_sve256
     263             :       CASE (MACHINE_ARM_SVE512)
     264           0 :          m_cpuid_name => name_arm_sve512
     265             :       CASE DEFAULT
     266           0 :          m_cpuid_name => name_unknown
     267             :       END SELECT
     268           0 :    END FUNCTION m_cpuid_name
     269             : 
     270             : ! **************************************************************************************************
     271             : !> \brief returns the energy used since some time in the past.
     272             : !>        The precise meaning depends on the infrastructure is available.
     273             : !>        In the cray_pm_energy case, this is the energy used by the node in kJ.
     274             : !> \return ...
     275             : !> \par History
     276             : !>      09.2013 created [Joost VandeVondele, Ole Schuett]
     277             : ! **************************************************************************************************
     278  3125135881 :    FUNCTION m_energy() RESULT(wt)
     279             :       REAL(KIND=dp)                            :: wt
     280             : 
     281             : #if defined(__CRAY_PM_ENERGY)
     282             :       wt = read_energy("/sys/cray/pm_counters/energy")
     283             : #elif defined(__CRAY_PM_ACCEL_ENERGY)
     284             :       wt = read_energy("/sys/cray/pm_counters/accel_energy")
     285             : #else
     286  3125135881 :       wt = 0.0 ! fallback default
     287             : #endif
     288             : 
     289  3125135881 :    END FUNCTION m_energy
     290             : 
     291             : #if defined(__CRAY_PM_ACCEL_ENERGY) || defined(__CRAY_PM_ENERGY)
     292             : ! **************************************************************************************************
     293             : !> \brief reads energy values from the sys-filesystem
     294             : !> \param filename ...
     295             : !> \return ...
     296             : !> \par History
     297             : !>      09.2013 created [Joost VandeVondele, Ole Schuett]
     298             : ! **************************************************************************************************
     299             :    FUNCTION read_energy(filename) RESULT(wt)
     300             :       CHARACTER(LEN=*)                                   :: filename
     301             :       REAL(KIND=dp)                                      :: wt
     302             : 
     303             :       CHARACTER(LEN=80)                                  :: DATA
     304             :       INTEGER                                            :: i, iostat
     305             :       INTEGER(KIND=int_8)                                :: raw
     306             : 
     307             :       OPEN (121245, FILE=filename, ACTION="READ", STATUS="OLD", ACCESS="STREAM")
     308             :       DO I = 1, 80
     309             :          READ (121245, END=999) DATA(I:I)
     310             :       END DO
     311             : 999   CLOSE (121245)
     312             :       DATA(I:80) = ""
     313             :       READ (DATA, *, IOSTAT=iostat) raw
     314             :       IF (iostat .NE. 0) THEN
     315             :          wt = 0.0_dp
     316             :       ELSE
     317             :          ! convert from J to kJ
     318             :          wt = raw/1000.0_dp
     319             :       END IF
     320             :    END FUNCTION read_energy
     321             : #endif
     322             : 
     323             : ! **************************************************************************************************
     324             : !> \brief returns a datum in human readable format using a standard Fortran routine
     325             : !> \param cal_date ...
     326             : !> \par History
     327             : !>      10.2009 created [Joost VandeVondele]
     328             : ! **************************************************************************************************
     329       21570 :    SUBROUTINE m_datum(cal_date)
     330             :       CHARACTER(len=*), INTENT(OUT)                      :: cal_date
     331             : 
     332             :       CHARACTER(len=10)                                  :: time
     333             :       CHARACTER(len=8)                                   :: date
     334             : 
     335       21570 :       CALL DATE_AND_TIME(date=date, time=time)
     336       21570 :       cal_date = date(1:4)//"-"//date(5:6)//"-"//date(7:8)//" "//time(1:2)//":"//time(3:4)//":"//time(5:10)
     337             : 
     338       21570 :    END SUBROUTINE m_datum
     339             : 
     340             : ! **************************************************************************************************
     341             : !> \brief Can be used to get a nice core
     342             : ! **************************************************************************************************
     343           0 :    SUBROUTINE m_abort()
     344             :       INTERFACE
     345             :          SUBROUTINE abort() BIND(C, name="abort")
     346             :          END SUBROUTINE
     347             :       END INTERFACE
     348             : 
     349           0 :       CALL abort()
     350           0 :    END SUBROUTINE m_abort
     351             : 
     352             : ! **************************************************************************************************
     353             : !> \brief Returns if a process is running on the local machine
     354             : !>        1 if yes and 0 if not
     355             : !> \param pid ...
     356             : !> \return ...
     357             : ! **************************************************************************************************
     358           2 :    FUNCTION m_procrun(pid) RESULT(run_on)
     359             :       INTEGER, INTENT(IN)       ::   pid
     360             :       INTEGER                   ::   run_on
     361             : #if defined(__MINGW)
     362             :       run_on = 0
     363             : #else
     364             :       INTEGER                   ::   istat
     365             : 
     366             :       INTERFACE
     367             :          FUNCTION kill(pid, sig) BIND(C, name="kill") RESULT(errno)
     368             :             IMPORT
     369             :             INTEGER(KIND=C_INT), VALUE                :: pid, sig
     370             :             INTEGER(KIND=C_INT)                      :: errno
     371             :          END FUNCTION
     372             :       END INTERFACE
     373             : 
     374             :       ! If sig is 0, then no signal is sent, but error checking is still
     375             :       ! performed; this can be used to check for the existence of a process
     376             :       ! ID or process group ID.
     377             : 
     378           2 :       istat = kill(pid=pid, sig=0)
     379           2 :       IF (istat == 0) THEN
     380             :          run_on = 1 ! no error, process exists
     381             :       ELSE
     382           0 :          run_on = 0 ! error, process probably does not exist
     383             :       END IF
     384             : #endif
     385           2 :    END FUNCTION m_procrun
     386             : 
     387             : ! **************************************************************************************************
     388             : !> \brief Returns the total amount of memory [bytes] in use, if known, zero otherwise
     389             : !> \param mem ...
     390             : ! **************************************************************************************************
     391     2113370 :    SUBROUTINE m_memory(mem)
     392             : 
     393             :       INTEGER(KIND=int_8), OPTIONAL, INTENT(OUT)         :: mem
     394             :       INTEGER(KIND=int_8)                      :: mem_local
     395             : 
     396             :       !
     397             :       ! __NO_STATM_ACCESS can be used to disable the stuff, if getpagesize
     398             :       ! lead to linking errors or /proc/self/statm can not be opened
     399             :       !
     400             : #if defined(__NO_STATM_ACCESS)
     401             :       mem_local = 0
     402             : #else
     403             :       INTEGER(KIND=int_8)                      :: m1, m2, m3
     404             :       CHARACTER(LEN=80) :: DATA
     405             :       INTEGER :: iostat, i
     406             : 
     407             :       ! the size of a page, might not be available everywhere
     408             :       INTERFACE
     409             :          FUNCTION getpagesize() BIND(C, name="getpagesize") RESULT(RES)
     410             :             IMPORT
     411             :             INTEGER(C_INT) :: RES
     412             :          END FUNCTION
     413             :       END INTERFACE
     414             : 
     415             :       !
     416             :       ! reading from statm
     417             :       !
     418     2113370 :       mem_local = -1
     419     2113370 :       DATA = ""
     420     2113370 :       OPEN (121245, FILE="/proc/self/statm", ACTION="READ", STATUS="OLD", ACCESS="STREAM")
     421    80207762 :       DO I = 1, 80
     422    80207762 :          READ (121245, END=999) DATA(I:I)
     423             :       END DO
     424     2113370 : 999   CLOSE (121245)
     425     2113370 :       DATA(I:80) = ""
     426             :       ! m1 = total
     427             :       ! m2 = resident
     428             :       ! m3 = shared
     429     2113370 :       READ (DATA, *, IOSTAT=iostat) m1, m2, m3
     430     2113370 :       IF (iostat .NE. 0) THEN
     431             :          mem_local = 0
     432             :       ELSE
     433     2113370 :          mem_local = m2
     434             : #if defined(__STATM_TOTAL)
     435             :          mem_local = m1
     436             : #endif
     437             : #if defined(__STATM_RESIDENT)
     438             :          mem_local = m2
     439             : #endif
     440     2113370 :          mem_local = mem_local*getpagesize()
     441             :       END IF
     442             : #endif
     443             : 
     444     2113370 :       m_memory_max = MAX(mem_local, m_memory_max)
     445     2113370 :       IF (PRESENT(mem)) mem = mem_local
     446             : 
     447     2113370 :    END SUBROUTINE m_memory
     448             : 
     449             : ! **************************************************************************************************
     450             : !> \brief get more detailed memory info, all units are bytes.
     451             : !>         the only 'useful' option is MemLikelyFree which is an estimate of remaining memory
     452             : !>         assumed to give info like /proc/meminfo while MeMLikelyFree is the amount of
     453             : !>         memory we're likely to be able to allocate, but not necessarily in one chunk
     454             : !>         zero means not available...
     455             : !> \param MemTotal ...
     456             : !> \param MemFree ...
     457             : !> \param Buffers ...
     458             : !> \param Cached ...
     459             : !> \param Slab ...
     460             : !> \param SReclaimable ...
     461             : !> \param MemLikelyFree ...
     462             : ! **************************************************************************************************
     463        9127 :    SUBROUTINE m_memory_details(MemTotal, MemFree, Buffers, Cached, Slab, SReclaimable, MemLikelyFree)
     464             : 
     465             :       INTEGER(kind=int_8), OPTIONAL :: MemTotal, MemFree, Buffers, Cached, Slab, SReclaimable, MemLikelyFree
     466             : 
     467             :       INTEGER, PARAMETER :: Nbuffer = 10000
     468             :       CHARACTER(LEN=Nbuffer) :: meminfo
     469             : 
     470             :       INTEGER :: i
     471             : 
     472        9127 :       MemTotal = 0
     473        9127 :       MemFree = 0
     474        9127 :       Buffers = 0
     475        9127 :       Cached = 0
     476        9127 :       Slab = 0
     477        9127 :       SReclaimable = 0
     478        9127 :       MemLikelyFree = 0
     479        9127 :       meminfo = ""
     480             : 
     481        9127 :       OPEN (UNIT=8123, file="/proc/meminfo", ACCESS="STREAM", ERR=901)
     482        9127 :       i = 0
     483    14009945 :       DO
     484    14019072 :          i = i + 1
     485    14019072 :          IF (i > Nbuffer) EXIT
     486    14019072 :          READ (8123, END=900, ERR=900) meminfo(i:i)
     487             :       END DO
     488             : 900   CONTINUE
     489        9127 :       meminfo(i:Nbuffer) = ""
     490             : 901   CONTINUE
     491        9127 :       CLOSE (8123, ERR=902)
     492             : 902   CONTINUE
     493        9127 :       MemTotal = get_field_value_in_bytes('MemTotal:')
     494        9127 :       MemFree = get_field_value_in_bytes('MemFree:')
     495        9127 :       Buffers = get_field_value_in_bytes('Buffers:')
     496        9127 :       Cached = get_field_value_in_bytes('Cached:')
     497        9127 :       Slab = get_field_value_in_bytes('Slab:')
     498        9127 :       SReclaimable = get_field_value_in_bytes('SReclaimable:')
     499             :       ! opinions here vary but this might work
     500        9127 :       MemLikelyFree = MemFree + Buffers + Cached + SReclaimable
     501             : 
     502             :    CONTAINS
     503             : 
     504             : ! **************************************************************************************************
     505             : !> \brief ...
     506             : !> \param field ...
     507             : !> \return ...
     508             : ! **************************************************************************************************
     509       54762 :       INTEGER(int_8) FUNCTION get_field_value_in_bytes(field)
     510             :          CHARACTER(LEN=*)                                   :: field
     511             : 
     512             :          INTEGER                                            :: start
     513             :          INTEGER(KIND=int_8)                                :: value
     514             : 
     515       54762 :          get_field_value_in_bytes = 0
     516       54762 :          start = INDEX(meminfo, field)
     517       54762 :          IF (start .NE. 0) THEN
     518       54762 :             start = start + LEN_TRIM(field)
     519       54762 :             IF (start .LT. Nbuffer) THEN
     520       54762 :                READ (meminfo(start:), *, ERR=999, END=999) value
     521             :                ! XXXXXXX convert from Kb to bytes XXXXXXXX
     522       54762 :                get_field_value_in_bytes = value*1024
     523             : 999            CONTINUE
     524             :             END IF
     525             :          END IF
     526       54762 :       END FUNCTION
     527             :    END SUBROUTINE m_memory_details
     528             : 
     529             : ! **************************************************************************************************
     530             : !> \brief ...
     531             : !> \param hname ...
     532             : ! **************************************************************************************************
     533       13477 :    SUBROUTINE m_hostnm(hname)
     534             :       CHARACTER(len=*), INTENT(OUT)            :: hname
     535             : #if defined(__MINGW)
     536             :       ! While there is a gethostname in the Windows (POSIX) API, it requires that winsocks is
     537             :       ! initialised prior to using it via WSAStartup(..), respectively cleaned up at the end via WSACleanup().
     538             :       hname = "<unknown>"
     539             : #else
     540             :       INTEGER                                  :: istat, i
     541             :       CHARACTER(len=default_path_length)       :: buf
     542             : 
     543             :       INTERFACE
     544             :          FUNCTION gethostname(buf, buflen) BIND(C, name="gethostname") RESULT(errno)
     545             :             IMPORT
     546             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: buf
     547             :             INTEGER(KIND=C_INT), VALUE               :: buflen
     548             :             INTEGER(KIND=C_INT)                      :: errno
     549             :          END FUNCTION
     550             :       END INTERFACE
     551             : 
     552       26954 :       istat = gethostname(buf, LEN(buf))
     553       13477 :       IF (istat /= 0) THEN
     554           0 :          WRITE (*, *) "m_hostnm failed"
     555           0 :          CALL m_abort()
     556             :       END IF
     557       13477 :       i = INDEX(buf, c_null_char) - 1
     558       13477 :       hname = buf(1:i)
     559             : #endif
     560       13477 :    END SUBROUTINE m_hostnm
     561             : 
     562             : ! **************************************************************************************************
     563             : !> \brief ...
     564             : !> \param curdir ...
     565             : ! **************************************************************************************************
     566      130324 :    SUBROUTINE m_getcwd(curdir)
     567             :       CHARACTER(len=*), INTENT(OUT)            :: curdir
     568             :       TYPE(C_PTR)                              :: stat
     569             :       INTEGER                                  :: i
     570             :       CHARACTER(len=default_path_length), TARGET  :: tmp
     571             : 
     572             :       INTERFACE
     573             :          FUNCTION getcwd(buf, buflen) BIND(C, name="getcwd") RESULT(stat)
     574             :             IMPORT
     575             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: buf
     576             :             INTEGER(KIND=C_INT), VALUE               :: buflen
     577             :             TYPE(C_PTR)                              :: stat
     578             :          END FUNCTION
     579             :       END INTERFACE
     580             : 
     581      260648 :       stat = getcwd(tmp, LEN(tmp))
     582      130324 :       IF (.NOT. C_ASSOCIATED(stat)) THEN
     583           0 :          WRITE (*, *) "m_getcwd failed"
     584           0 :          CALL m_abort()
     585             :       END IF
     586      130324 :       i = INDEX(tmp, c_null_char) - 1
     587      130324 :       curdir = tmp(1:i)
     588      130324 :    END SUBROUTINE m_getcwd
     589             : 
     590             : ! **************************************************************************************************
     591             : !> \brief ...
     592             : !> \param dir ...
     593             : !> \param ierror ...
     594             : ! **************************************************************************************************
     595        2914 :    SUBROUTINE m_chdir(dir, ierror)
     596             :       CHARACTER(len=*), INTENT(IN)             :: dir
     597             :       INTEGER, INTENT(OUT)                     :: ierror
     598             : 
     599             :       INTERFACE
     600             :          FUNCTION chdir(path) BIND(C, name="chdir") RESULT(errno)
     601             :             IMPORT
     602             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: path
     603             :             INTEGER(KIND=C_INT)                      :: errno
     604             :          END FUNCTION
     605             :       END INTERFACE
     606             : 
     607        2914 :       ierror = chdir(TRIM(dir)//c_null_char)
     608        2914 :    END SUBROUTINE m_chdir
     609             : 
     610             : ! **************************************************************************************************
     611             : !> \brief ...
     612             : !> \param pid ...
     613             : ! **************************************************************************************************
     614       13477 :    SUBROUTINE m_getpid(pid)
     615             :       INTEGER, INTENT(OUT)                     :: pid
     616             : 
     617             :       INTERFACE
     618             :          FUNCTION getpid() BIND(C, name="getpid") RESULT(pid)
     619             :             IMPORT
     620             :             INTEGER(KIND=C_INT)              :: pid
     621             :          END FUNCTION
     622             :       END INTERFACE
     623             : 
     624       13477 :       pid = getpid()
     625       13477 :    END SUBROUTINE m_getpid
     626             : 
     627             : ! **************************************************************************************************
     628             : !> \brief ...
     629             : !> \param path ...
     630             : !> \return ...
     631             : ! **************************************************************************************************
     632       11472 :    FUNCTION m_unlink(path) RESULT(istat)
     633             : 
     634             :       CHARACTER(LEN=*), INTENT(IN)             :: path
     635             : 
     636             :       INTEGER                                  :: istat
     637             : 
     638             :       INTERFACE
     639             :          FUNCTION unlink(path) BIND(C, name="unlink") RESULT(errno)
     640             :             IMPORT
     641             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: path
     642             :             INTEGER(KIND=C_INT)                      :: errno
     643             :          END FUNCTION
     644             :       END INTERFACE
     645             : 
     646       11472 :       istat = unlink(TRIM(path)//c_null_char)
     647       11472 :    END FUNCTION m_unlink
     648             : 
     649             : ! **************************************************************************************************
     650             : !> \brief ...
     651             : !> \param source ...
     652             : !> \param TARGET ...
     653             : ! **************************************************************************************************
     654       11472 :    SUBROUTINE m_mov(source, TARGET)
     655             : 
     656             :       CHARACTER(LEN=*), INTENT(IN)             :: source, TARGET
     657             : 
     658             :       INTEGER                                  :: istat
     659             : 
     660             :       INTERFACE
     661             :          FUNCTION rename(src, dest) BIND(C, name="rename") RESULT(errno)
     662             :             IMPORT
     663             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: src, dest
     664             :             INTEGER(KIND=C_INT)                      :: errno
     665             :          END FUNCTION
     666             :       END INTERFACE
     667             : 
     668       11472 :       IF (TARGET == source) THEN
     669           0 :          WRITE (*, *) "Warning: m_mov ", TRIM(TARGET), " equals ", TRIM(source)
     670           0 :          RETURN
     671             :       END IF
     672             : 
     673             :       ! first remove target (needed on windows / mingw)
     674       11472 :       istat = m_unlink(TARGET)
     675             :       ! ignore istat of unlink
     676             : 
     677             :       ! now move
     678       11472 :       istat = rename(TRIM(source)//c_null_char, TRIM(TARGET)//c_null_char)
     679       11472 :       IF (istat .NE. 0) THEN
     680           0 :          WRITE (*, *) "Trying to move "//TRIM(source)//" to "//TRIM(TARGET)//"."
     681           0 :          WRITE (*, *) "rename returned status: ", istat
     682           0 :          WRITE (*, *) "Problem moving file"
     683           0 :          CALL m_abort()
     684             :       END IF
     685             :    END SUBROUTINE m_mov
     686             : 
     687             : ! **************************************************************************************************
     688             : !> \brief ...
     689             : !> \param user ...
     690             : ! **************************************************************************************************
     691       13231 :    SUBROUTINE m_getlog(user)
     692             : 
     693             :       CHARACTER(LEN=*), INTENT(OUT) :: user
     694             : 
     695             :       INTEGER                       :: istat
     696             : 
     697             :       ! on a posix system LOGNAME should be defined
     698       13231 :       CALL get_environment_variable("LOGNAME", value=user, status=istat)
     699             :       ! nope, check alternative
     700       13231 :       IF (istat /= 0) &
     701       13231 :          CALL get_environment_variable("USER", value=user, status=istat)
     702             :       ! nope, check alternative
     703       13231 :       IF (istat /= 0) &
     704       13231 :          CALL get_environment_variable("USERNAME", value=user, status=istat)
     705             :       ! fall back
     706       13231 :       IF (istat /= 0) &
     707       13231 :          user = "<unknown>"
     708             : 
     709       13231 :    END SUBROUTINE m_getlog
     710             : 
     711             : ! **************************************************************************************************
     712             : !> \brief Retrieve environment variable OMP_STACKSIZE
     713             : !> \param omp_stacksize Value of OMP_STACKSIZE
     714             : ! **************************************************************************************************
     715        4667 :    SUBROUTINE m_omp_get_stacksize(omp_stacksize)
     716             :       CHARACTER(LEN=*), INTENT(OUT)                      :: omp_stacksize
     717             : 
     718             :       INTEGER                                            :: istat
     719             : 
     720        4667 :       omp_stacksize = ""
     721        4667 :       CALL get_environment_variable("OMP_STACKSIZE", value=omp_stacksize, status=istat)
     722             :       ! Fall back, if OMP_STACKSIZE is not set
     723        4667 :       IF (istat /= 0) omp_stacksize = "default"
     724             : 
     725        4667 :    END SUBROUTINE m_omp_get_stacksize
     726             : 
     727             : END MODULE machine

Generated by: LCOV version 1.15