LCOV - code coverage report
Current view: top level - src/base - machine.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:4c33f95) Lines: 135 180 75.0 %
Date: 2025-01-30 06:53:08 Functions: 19 21 90.5 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2025 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_cpuid_vlen, 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      247751 :    SUBROUTINE m_flush(lunit)
     130             :       INTEGER, INTENT(IN)                                :: lunit
     131             : 
     132      247751 :       IF (flush_should_flush) FLUSH (lunit)
     133             : 
     134      247751 :    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  3146159407 :    FUNCTION m_walltime() RESULT(wt)
     147             :       REAL(KIND=dp)                                      :: wt
     148             : 
     149             : #if defined(__LIBXSMM)
     150  3146159407 :       wt = libxsmm_timer_duration(0_int_8, libxsmm_timer_tick())
     151             : #else
     152             :       wt = omp_get_wtime()
     153             : #endif
     154  3146159407 :    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        5004 :    SUBROUTINE m_cpuinfo(model_name)
     161             :       CHARACTER(LEN=default_string_length), INTENT(OUT)  :: model_name
     162             : 
     163             :       INTEGER, PARAMETER                                 :: bufferlen = 2048
     164             : 
     165             :       CHARACTER(LEN=bufferlen)                           :: buffer
     166             :       INTEGER                                            :: i, icol, iline, stat
     167             : 
     168        5004 :       model_name = "UNKNOWN"
     169        5004 :       buffer = ""
     170        5004 :       OPEN (121245, FILE="/proc/cpuinfo", ACTION="READ", STATUS="OLD", ACCESS="STREAM", IOSTAT=stat)
     171        5004 :       IF (stat == 0) THEN
     172    10253196 :          DO i = 1, bufferlen
     173    10253196 :             READ (121245, END=999) buffer(I:I)
     174             :          END DO
     175        5004 : 999      CLOSE (121245)
     176        5004 :          i = INDEX(buffer, "model name")
     177        5004 :          IF (i > 0) THEN
     178        5004 :             icol = i - 1 + INDEX(buffer(i:), ":")
     179        5004 :             iline = icol - 1 + INDEX(buffer(icol:), NEW_LINE('A'))
     180        5004 :             IF (iline == icol - 1) iline = bufferlen + 1
     181        5004 :             model_name = buffer(icol + 1:iline - 1)
     182             :          END IF
     183             :       END IF
     184        5004 :    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      456242 :    PURE FUNCTION m_cpuid()
     194             :       INTEGER :: m_cpuid
     195             : #if defined(__LIBXSMM)
     196      456242 :       m_cpuid = libxsmm_get_target_archid()
     197      456242 :       IF (LIBXSMM_X86_SSE4 <= m_cpuid .AND. m_cpuid < LIBXSMM_X86_AVX) THEN
     198             :          m_cpuid = MACHINE_X86_SSE4
     199      456242 :       ELSE IF (LIBXSMM_X86_AVX <= m_cpuid .AND. m_cpuid < LIBXSMM_X86_AVX2) THEN
     200             :          m_cpuid = MACHINE_X86_AVX
     201      456242 :       ELSE IF (LIBXSMM_X86_AVX2 <= m_cpuid .AND. m_cpuid < LIBXSMM_X86_AVX512_SKX) THEN
     202             :          m_cpuid = MACHINE_X86_AVX2
     203           0 :       ELSE IF (LIBXSMM_X86_AVX512_SKX <= m_cpuid .AND. m_cpuid <= 1999) THEN
     204             :          m_cpuid = MACHINE_X86_AVX512
     205             : #if defined(__LIBXSMM2)
     206           0 :       ELSE IF (LIBXSMM_AARCH64_V81 <= m_cpuid .AND. m_cpuid < LIBXSMM_AARCH64_SVE128) THEN
     207             :          m_cpuid = MACHINE_ARM_ARCH64
     208           0 :       ELSE IF (LIBXSMM_AARCH64_SVE128 <= m_cpuid .AND. m_cpuid < 2401) THEN ! LIBXSMM_AARCH64_SVE512
     209             :          m_cpuid = MACHINE_ARM_SVE256
     210           0 :       ELSE IF (2401 <= m_cpuid .AND. m_cpuid <= 2999) THEN
     211             :          m_cpuid = MACHINE_ARM_SVE512
     212             : #endif
     213           0 :       ELSE IF (LIBXSMM_TARGET_ARCH_GENERIC <= m_cpuid .AND. m_cpuid <= 2999) THEN
     214             :          m_cpuid = MACHINE_CPU_GENERIC
     215             :       ELSE
     216           0 :          m_cpuid = MACHINE_CPU_UNKNOWN
     217             :       END IF
     218             : #else
     219             :       m_cpuid = m_cpuid_static()
     220             : #endif
     221      456242 :    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 short name of ISA extension.
     227             : !> \par History
     228             : !>      06.2019 created [Hans Pabst]
     229             : !>      09.2024 update+arm [Hans Pabst]
     230             : ! **************************************************************************************************
     231           0 :    PURE FUNCTION m_cpuid_name(cpuid)
     232             :       INTEGER, OPTIONAL, INTENT(IN)         :: cpuid
     233             :       CHARACTER(len=default_string_length)  :: m_cpuid_name
     234             : 
     235             :       INTEGER                               :: isa
     236             : 
     237           0 :       IF (PRESENT(cpuid)) THEN
     238           0 :          isa = cpuid
     239             :       ELSE
     240           0 :          isa = m_cpuid()
     241             :       END IF
     242             : 
     243           0 :       SELECT CASE (isa)
     244             :       CASE (MACHINE_CPU_GENERIC)
     245           0 :          m_cpuid_name = "generic"
     246             :       CASE (MACHINE_X86_SSE4)
     247           0 :          m_cpuid_name = "x86_sse4"
     248             :       CASE (MACHINE_X86_AVX)
     249           0 :          m_cpuid_name = "x86_avx"
     250             :       CASE (MACHINE_X86_AVX2)
     251           0 :          m_cpuid_name = "x86_avx2"
     252             :       CASE (MACHINE_X86_AVX512)
     253           0 :          m_cpuid_name = "x86_avx512"
     254             :       CASE (MACHINE_ARM_ARCH64)
     255           0 :          m_cpuid_name = "arm_arch64"
     256             :       CASE (MACHINE_ARM_SVE128)
     257           0 :          m_cpuid_name = "arm_sve128"
     258             :       CASE (MACHINE_ARM_SVE256)
     259           0 :          m_cpuid_name = "arm_sve256"
     260             :       CASE (MACHINE_ARM_SVE512)
     261           0 :          m_cpuid_name = "arm_sve512"
     262             :       CASE DEFAULT
     263           0 :          m_cpuid_name = "unknown"
     264             :       END SELECT
     265           0 :    END FUNCTION m_cpuid_name
     266             : 
     267             : ! **************************************************************************************************
     268             : !> \brief Determine vector-length for a given CPUID.
     269             : !> \param cpuid integer value (MACHINE_*)
     270             : !> \param typesize number of bytes of scalar type
     271             : !> \return vector-length in number of elements.
     272             : !> \par History
     273             : !>      12.2024 created [Hans Pabst]
     274             : ! **************************************************************************************************
     275      452238 :    PURE FUNCTION m_cpuid_vlen(cpuid, typesize)
     276             :       INTEGER, OPTIONAL, INTENT(IN) :: cpuid, typesize
     277             : 
     278             :       INTEGER                       :: isa, m_cpuid_vlen, nbytes
     279             : 
     280      452238 :       IF (PRESENT(typesize)) THEN
     281           0 :          nbytes = typesize
     282             :       ELSE
     283             :          nbytes = 8 ! double-precision
     284             :       END IF
     285             : 
     286      452238 :       IF (0 < nbytes .AND. nbytes <= 16) THEN ! sanity check
     287      452238 :          IF (PRESENT(cpuid)) THEN
     288       10008 :             isa = cpuid
     289             :          ELSE
     290      442230 :             isa = m_cpuid()
     291             :          END IF
     292             : 
     293           0 :          SELECT CASE (isa)
     294             :          CASE (MACHINE_X86_SSE4)
     295           0 :             m_cpuid_vlen = 16/nbytes
     296             :          CASE (MACHINE_ARM_ARCH64) ! NEON
     297           0 :             m_cpuid_vlen = 16/nbytes
     298             :          CASE (MACHINE_ARM_SVE128)
     299           0 :             m_cpuid_vlen = 16/nbytes
     300             :          CASE (MACHINE_X86_AVX)
     301           0 :             m_cpuid_vlen = 32/nbytes
     302             :          CASE (MACHINE_X86_AVX2)
     303      452238 :             m_cpuid_vlen = 32/nbytes
     304             :          CASE (MACHINE_ARM_SVE256)
     305           0 :             m_cpuid_vlen = 32/nbytes
     306             :          CASE (MACHINE_X86_AVX512)
     307           0 :             m_cpuid_vlen = 64/nbytes
     308             :          CASE (MACHINE_ARM_SVE512)
     309           0 :             m_cpuid_vlen = 64/nbytes
     310             :          CASE DEFAULT ! unknown or generic
     311      452238 :             m_cpuid_vlen = 1 ! scalar
     312             :          END SELECT
     313             :       ELSE ! fallback
     314             :          m_cpuid_vlen = 1 ! scalar
     315             :       END IF
     316      452238 :    END FUNCTION m_cpuid_vlen
     317             : 
     318             : ! **************************************************************************************************
     319             : !> \brief returns the energy used since some time in the past.
     320             : !>        The precise meaning depends on the infrastructure is available.
     321             : !>        In the cray_pm_energy case, this is the energy used by the node in kJ.
     322             : !> \return ...
     323             : !> \par History
     324             : !>      09.2013 created [Joost VandeVondele, Ole Schuett]
     325             : ! **************************************************************************************************
     326  3139585875 :    FUNCTION m_energy() RESULT(wt)
     327             :       REAL(KIND=dp)                            :: wt
     328             : 
     329             : #if defined(__CRAY_PM_ENERGY)
     330             :       wt = read_energy("/sys/cray/pm_counters/energy")
     331             : #elif defined(__CRAY_PM_ACCEL_ENERGY)
     332             :       wt = read_energy("/sys/cray/pm_counters/accel_energy")
     333             : #else
     334  3139585875 :       wt = 0.0 ! fallback default
     335             : #endif
     336             : 
     337  3139585875 :    END FUNCTION m_energy
     338             : 
     339             : #if defined(__CRAY_PM_ACCEL_ENERGY) || defined(__CRAY_PM_ENERGY)
     340             : ! **************************************************************************************************
     341             : !> \brief reads energy values from the sys-filesystem
     342             : !> \param filename ...
     343             : !> \return ...
     344             : !> \par History
     345             : !>      09.2013 created [Joost VandeVondele, Ole Schuett]
     346             : ! **************************************************************************************************
     347             :    FUNCTION read_energy(filename) RESULT(wt)
     348             :       CHARACTER(LEN=*)                                   :: filename
     349             :       REAL(KIND=dp)                                      :: wt
     350             : 
     351             :       CHARACTER(LEN=80)                                  :: DATA
     352             :       INTEGER                                            :: i, iostat
     353             :       INTEGER(KIND=int_8)                                :: raw
     354             : 
     355             :       OPEN (121245, FILE=filename, ACTION="READ", STATUS="OLD", ACCESS="STREAM")
     356             :       DO I = 1, 80
     357             :          READ (121245, END=999) DATA(I:I)
     358             :       END DO
     359             : 999   CLOSE (121245)
     360             :       DATA(I:80) = ""
     361             :       READ (DATA, *, IOSTAT=iostat) raw
     362             :       IF (iostat .NE. 0) THEN
     363             :          wt = 0.0_dp
     364             :       ELSE
     365             :          ! convert from J to kJ
     366             :          wt = raw/1000.0_dp
     367             :       END IF
     368             :    END FUNCTION read_energy
     369             : #endif
     370             : 
     371             : ! **************************************************************************************************
     372             : !> \brief returns a datum in human readable format using a standard Fortran routine
     373             : !> \param cal_date ...
     374             : !> \par History
     375             : !>      10.2009 created [Joost VandeVondele]
     376             : ! **************************************************************************************************
     377       22580 :    SUBROUTINE m_datum(cal_date)
     378             :       CHARACTER(len=*), INTENT(OUT)                      :: cal_date
     379             : 
     380             :       CHARACTER(len=10)                                  :: time
     381             :       CHARACTER(len=8)                                   :: date
     382             : 
     383       22580 :       CALL DATE_AND_TIME(date=date, time=time)
     384       22580 :       cal_date = date(1:4)//"-"//date(5:6)//"-"//date(7:8)//" "//time(1:2)//":"//time(3:4)//":"//time(5:10)
     385             : 
     386       22580 :    END SUBROUTINE m_datum
     387             : 
     388             : ! **************************************************************************************************
     389             : !> \brief Can be used to get a nice core
     390             : ! **************************************************************************************************
     391           0 :    SUBROUTINE m_abort()
     392             :       INTERFACE
     393             :          SUBROUTINE abort() BIND(C, name="abort")
     394             :          END SUBROUTINE
     395             :       END INTERFACE
     396             : 
     397           0 :       CALL abort()
     398           0 :    END SUBROUTINE m_abort
     399             : 
     400             : ! **************************************************************************************************
     401             : !> \brief Returns if a process is running on the local machine
     402             : !>        1 if yes and 0 if not
     403             : !> \param pid ...
     404             : !> \return ...
     405             : ! **************************************************************************************************
     406           2 :    FUNCTION m_procrun(pid) RESULT(run_on)
     407             :       INTEGER, INTENT(IN)       ::   pid
     408             :       INTEGER                   ::   run_on
     409             : #if defined(__MINGW)
     410             :       run_on = 0
     411             : #else
     412             :       INTEGER                   ::   istat
     413             : 
     414             :       INTERFACE
     415             :          FUNCTION kill(pid, sig) BIND(C, name="kill") RESULT(errno)
     416             :             IMPORT
     417             :             INTEGER(KIND=C_INT), VALUE                :: pid, sig
     418             :             INTEGER(KIND=C_INT)                      :: errno
     419             :          END FUNCTION
     420             :       END INTERFACE
     421             : 
     422             :       ! If sig is 0, then no signal is sent, but error checking is still
     423             :       ! performed; this can be used to check for the existence of a process
     424             :       ! ID or process group ID.
     425             : 
     426           2 :       istat = kill(pid=pid, sig=0)
     427           2 :       IF (istat == 0) THEN
     428             :          run_on = 1 ! no error, process exists
     429             :       ELSE
     430           0 :          run_on = 0 ! error, process probably does not exist
     431             :       END IF
     432             : #endif
     433           2 :    END FUNCTION m_procrun
     434             : 
     435             : ! **************************************************************************************************
     436             : !> \brief Returns the total amount of memory [bytes] in use, if known, zero otherwise
     437             : !> \param mem ...
     438             : ! **************************************************************************************************
     439     2116343 :    SUBROUTINE m_memory(mem)
     440             : 
     441             :       INTEGER(KIND=int_8), OPTIONAL, INTENT(OUT)         :: mem
     442             :       INTEGER(KIND=int_8)                      :: mem_local
     443             : 
     444             :       ! __NO_STATM_ACCESS can be used to disable the stuff, if getpagesize
     445             :       ! lead to linking errors or /proc/self/statm can not be opened
     446             :       !
     447             : #if defined(__NO_STATM_ACCESS)
     448             :       mem_local = 0
     449             : #else
     450             :       INTEGER(KIND=int_8)                      :: m1, m2, m3
     451             :       CHARACTER(LEN=80) :: DATA
     452             :       INTEGER :: iostat, i
     453             : 
     454             :       ! the size of a page, might not be available everywhere
     455             :       INTERFACE
     456             :          FUNCTION getpagesize() BIND(C, name="getpagesize") RESULT(RES)
     457             :             IMPORT
     458             :             INTEGER(C_INT) :: RES
     459             :          END FUNCTION
     460             :       END INTERFACE
     461             : 
     462             :       ! reading from statm
     463             :       !
     464     2116343 :       mem_local = -1
     465     2116343 :       DATA = ""
     466     2116343 :       OPEN (121245, FILE="/proc/self/statm", ACTION="READ", STATUS="OLD", ACCESS="STREAM")
     467    78251923 :       DO I = 1, 80
     468    78251923 :          READ (121245, END=999) DATA(I:I)
     469             :       END DO
     470     2116343 : 999   CLOSE (121245)
     471     2116343 :       DATA(I:80) = ""
     472             :       ! m1 = total
     473             :       ! m2 = resident
     474             :       ! m3 = shared
     475     2116343 :       READ (DATA, *, IOSTAT=iostat) m1, m2, m3
     476     2116343 :       IF (iostat .NE. 0) THEN
     477             :          mem_local = 0
     478             :       ELSE
     479     2116343 :          mem_local = m2
     480             : #if defined(__STATM_TOTAL)
     481             :          mem_local = m1
     482             : #endif
     483             : #if defined(__STATM_RESIDENT)
     484             :          mem_local = m2
     485             : #endif
     486     2116343 :          mem_local = mem_local*getpagesize()
     487             :       END IF
     488             : #endif
     489             : 
     490     2116343 :       m_memory_max = MAX(mem_local, m_memory_max)
     491     2116343 :       IF (PRESENT(mem)) mem = mem_local
     492             : 
     493     2116343 :    END SUBROUTINE m_memory
     494             : 
     495             : ! **************************************************************************************************
     496             : !> \brief get more detailed memory info, all units are bytes.
     497             : !>         the only 'useful' option is MemLikelyFree which is an estimate of remaining memory
     498             : !>         assumed to give info like /proc/meminfo while MeMLikelyFree is the amount of
     499             : !>         memory we're likely to be able to allocate, but not necessarily in one chunk
     500             : !>         zero means not available...
     501             : !> \param MemTotal ...
     502             : !> \param MemFree ...
     503             : !> \param Buffers ...
     504             : !> \param Cached ...
     505             : !> \param Slab ...
     506             : !> \param SReclaimable ...
     507             : !> \param MemLikelyFree ...
     508             : ! **************************************************************************************************
     509        9801 :    SUBROUTINE m_memory_details(MemTotal, MemFree, Buffers, Cached, Slab, SReclaimable, MemLikelyFree)
     510             : 
     511             :       INTEGER(kind=int_8), OPTIONAL :: MemTotal, MemFree, Buffers, Cached, Slab, SReclaimable, MemLikelyFree
     512             : 
     513             :       INTEGER, PARAMETER :: Nbuffer = 10000
     514             :       CHARACTER(LEN=Nbuffer) :: meminfo
     515             : 
     516             :       INTEGER :: i
     517             : 
     518        9801 :       MemTotal = 0
     519        9801 :       MemFree = 0
     520        9801 :       Buffers = 0
     521        9801 :       Cached = 0
     522        9801 :       Slab = 0
     523        9801 :       SReclaimable = 0
     524        9801 :       MemLikelyFree = 0
     525        9801 :       meminfo = ""
     526             : 
     527        9801 :       OPEN (UNIT=8123, file="/proc/meminfo", ACCESS="STREAM", ERR=901)
     528        9801 :       i = 0
     529    15044155 :       DO
     530    15053956 :          i = i + 1
     531    15053956 :          IF (i > Nbuffer) EXIT
     532    15053956 :          READ (8123, END=900, ERR=900) meminfo(i:i)
     533             :       END DO
     534             : 900   CONTINUE
     535        9801 :       meminfo(i:Nbuffer) = ""
     536             : 901   CONTINUE
     537        9801 :       CLOSE (8123, ERR=902)
     538             : 902   CONTINUE
     539        9801 :       MemTotal = get_field_value_in_bytes('MemTotal:')
     540        9801 :       MemFree = get_field_value_in_bytes('MemFree:')
     541        9801 :       Buffers = get_field_value_in_bytes('Buffers:')
     542        9801 :       Cached = get_field_value_in_bytes('Cached:')
     543        9801 :       Slab = get_field_value_in_bytes('Slab:')
     544        9801 :       SReclaimable = get_field_value_in_bytes('SReclaimable:')
     545             :       ! opinions here vary but this might work
     546        9801 :       MemLikelyFree = MemFree + Buffers + Cached + SReclaimable
     547             : 
     548             :    CONTAINS
     549             : 
     550             : ! **************************************************************************************************
     551             : !> \brief ...
     552             : !> \param field ...
     553             : !> \return ...
     554             : ! **************************************************************************************************
     555       58806 :       INTEGER(int_8) FUNCTION get_field_value_in_bytes(field)
     556             :          CHARACTER(LEN=*)                                   :: field
     557             : 
     558             :          INTEGER                                            :: start
     559             :          INTEGER(KIND=int_8)                                :: value
     560             : 
     561       58806 :          get_field_value_in_bytes = 0
     562       58806 :          start = INDEX(meminfo, field)
     563       58806 :          IF (start .NE. 0) THEN
     564       58806 :             start = start + LEN_TRIM(field)
     565       58806 :             IF (start .LT. Nbuffer) THEN
     566       58806 :                READ (meminfo(start:), *, ERR=999, END=999) value
     567             :                ! XXXXXXX convert from Kb to bytes XXXXXXXX
     568       58806 :                get_field_value_in_bytes = value*1024
     569             : 999            CONTINUE
     570             :             END IF
     571             :          END IF
     572       58806 :       END FUNCTION
     573             :    END SUBROUTINE m_memory_details
     574             : 
     575             : ! **************************************************************************************************
     576             : !> \brief ...
     577             : !> \param hname ...
     578             : ! **************************************************************************************************
     579       14808 :    SUBROUTINE m_hostnm(hname)
     580             :       CHARACTER(len=*), INTENT(OUT)            :: hname
     581             : #if defined(__MINGW)
     582             :       ! While there is a gethostname in the Windows (POSIX) API, it requires that winsocks is
     583             :       ! initialised prior to using it via WSAStartup(..), respectively cleaned up at the end via WSACleanup().
     584             :       hname = "<unknown>"
     585             : #else
     586             :       INTEGER                                  :: istat, i
     587             :       CHARACTER(len=default_path_length)       :: buf
     588             : 
     589             :       INTERFACE
     590             :          FUNCTION gethostname(buf, buflen) BIND(C, name="gethostname") RESULT(errno)
     591             :             IMPORT
     592             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: buf
     593             :             INTEGER(KIND=C_INT), VALUE               :: buflen
     594             :             INTEGER(KIND=C_INT)                      :: errno
     595             :          END FUNCTION
     596             :       END INTERFACE
     597             : 
     598       29616 :       istat = gethostname(buf, LEN(buf))
     599       14808 :       IF (istat /= 0) THEN
     600           0 :          WRITE (*, *) "m_hostnm failed"
     601           0 :          CALL m_abort()
     602             :       END IF
     603       14808 :       i = INDEX(buf, c_null_char) - 1
     604       14808 :       hname = buf(1:i)
     605             : #endif
     606       14808 :    END SUBROUTINE m_hostnm
     607             : 
     608             : ! **************************************************************************************************
     609             : !> \brief ...
     610             : !> \param curdir ...
     611             : ! **************************************************************************************************
     612      134267 :    SUBROUTINE m_getcwd(curdir)
     613             :       CHARACTER(len=*), INTENT(OUT)            :: curdir
     614             :       TYPE(C_PTR)                              :: stat
     615             :       INTEGER                                  :: i
     616             :       CHARACTER(len=default_path_length), TARGET  :: tmp
     617             : 
     618             :       INTERFACE
     619             :          FUNCTION getcwd(buf, buflen) BIND(C, name="getcwd") RESULT(stat)
     620             :             IMPORT
     621             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: buf
     622             :             INTEGER(KIND=C_INT), VALUE               :: buflen
     623             :             TYPE(C_PTR)                              :: stat
     624             :          END FUNCTION
     625             :       END INTERFACE
     626             : 
     627      268534 :       stat = getcwd(tmp, LEN(tmp))
     628      134267 :       IF (.NOT. C_ASSOCIATED(stat)) THEN
     629           0 :          WRITE (*, *) "m_getcwd failed"
     630           0 :          CALL m_abort()
     631             :       END IF
     632      134267 :       i = INDEX(tmp, c_null_char) - 1
     633      134267 :       curdir = tmp(1:i)
     634      134267 :    END SUBROUTINE m_getcwd
     635             : 
     636             : ! **************************************************************************************************
     637             : !> \brief ...
     638             : !> \param dir ...
     639             : !> \param ierror ...
     640             : ! **************************************************************************************************
     641        2914 :    SUBROUTINE m_chdir(dir, ierror)
     642             :       CHARACTER(len=*), INTENT(IN)             :: dir
     643             :       INTEGER, INTENT(OUT)                     :: ierror
     644             : 
     645             :       INTERFACE
     646             :          FUNCTION chdir(path) BIND(C, name="chdir") RESULT(errno)
     647             :             IMPORT
     648             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: path
     649             :             INTEGER(KIND=C_INT)                      :: errno
     650             :          END FUNCTION
     651             :       END INTERFACE
     652             : 
     653        2914 :       ierror = chdir(TRIM(dir)//c_null_char)
     654        2914 :    END SUBROUTINE m_chdir
     655             : 
     656             : ! **************************************************************************************************
     657             : !> \brief ...
     658             : !> \param pid ...
     659             : ! **************************************************************************************************
     660       14808 :    SUBROUTINE m_getpid(pid)
     661             :       INTEGER, INTENT(OUT)                     :: pid
     662             : 
     663             :       INTERFACE
     664             :          FUNCTION getpid() BIND(C, name="getpid") RESULT(pid)
     665             :             IMPORT
     666             :             INTEGER(KIND=C_INT)              :: pid
     667             :          END FUNCTION
     668             :       END INTERFACE
     669             : 
     670       14808 :       pid = getpid()
     671       14808 :    END SUBROUTINE m_getpid
     672             : 
     673             : ! **************************************************************************************************
     674             : !> \brief ...
     675             : !> \param path ...
     676             : !> \return ...
     677             : ! **************************************************************************************************
     678       11591 :    FUNCTION m_unlink(path) RESULT(istat)
     679             : 
     680             :       CHARACTER(LEN=*), INTENT(IN)             :: path
     681             : 
     682             :       INTEGER                                  :: istat
     683             : 
     684             :       INTERFACE
     685             :          FUNCTION unlink(path) BIND(C, name="unlink") RESULT(errno)
     686             :             IMPORT
     687             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: path
     688             :             INTEGER(KIND=C_INT)                      :: errno
     689             :          END FUNCTION
     690             :       END INTERFACE
     691             : 
     692       11591 :       istat = unlink(TRIM(path)//c_null_char)
     693       11591 :    END FUNCTION m_unlink
     694             : 
     695             : ! **************************************************************************************************
     696             : !> \brief ...
     697             : !> \param source ...
     698             : !> \param TARGET ...
     699             : ! **************************************************************************************************
     700       11591 :    SUBROUTINE m_mov(source, TARGET)
     701             : 
     702             :       CHARACTER(LEN=*), INTENT(IN)             :: source, TARGET
     703             : 
     704             :       INTEGER                                  :: istat
     705             : 
     706             :       INTERFACE
     707             :          FUNCTION rename(src, dest) BIND(C, name="rename") RESULT(errno)
     708             :             IMPORT
     709             :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: src, dest
     710             :             INTEGER(KIND=C_INT)                      :: errno
     711             :          END FUNCTION
     712             :       END INTERFACE
     713             : 
     714       11591 :       IF (TARGET == source) THEN
     715           0 :          WRITE (*, *) "Warning: m_mov ", TRIM(TARGET), " equals ", TRIM(source)
     716           0 :          RETURN
     717             :       END IF
     718             : 
     719             :       ! first remove target (needed on windows / mingw)
     720       11591 :       istat = m_unlink(TARGET)
     721             :       ! ignore istat of unlink
     722             : 
     723             :       ! now move
     724       11591 :       istat = rename(TRIM(source)//c_null_char, TRIM(TARGET)//c_null_char)
     725       11591 :       IF (istat .NE. 0) THEN
     726           0 :          WRITE (*, *) "Trying to move "//TRIM(source)//" to "//TRIM(TARGET)//"."
     727           0 :          WRITE (*, *) "rename returned status: ", istat
     728           0 :          WRITE (*, *) "Problem moving file"
     729           0 :          CALL m_abort()
     730             :       END IF
     731             :    END SUBROUTINE m_mov
     732             : 
     733             : ! **************************************************************************************************
     734             : !> \brief ...
     735             : !> \param user ...
     736             : ! **************************************************************************************************
     737       14242 :    SUBROUTINE m_getlog(user)
     738             : 
     739             :       CHARACTER(LEN=*), INTENT(OUT) :: user
     740             : 
     741             :       INTEGER                       :: istat
     742             : 
     743             :       ! on a posix system LOGNAME should be defined
     744       14242 :       CALL get_environment_variable("LOGNAME", value=user, status=istat)
     745             :       ! nope, check alternative
     746       14242 :       IF (istat /= 0) &
     747       14242 :          CALL get_environment_variable("USER", value=user, status=istat)
     748             :       ! nope, check alternative
     749       14242 :       IF (istat /= 0) &
     750       14242 :          CALL get_environment_variable("USERNAME", value=user, status=istat)
     751             :       ! fall back
     752       14242 :       IF (istat /= 0) &
     753       14242 :          user = "<unknown>"
     754             : 
     755       14242 :    END SUBROUTINE m_getlog
     756             : 
     757             : ! **************************************************************************************************
     758             : !> \brief Retrieve environment variable OMP_STACKSIZE
     759             : !> \param omp_stacksize Value of OMP_STACKSIZE
     760             : ! **************************************************************************************************
     761        5004 :    SUBROUTINE m_omp_get_stacksize(omp_stacksize)
     762             :       CHARACTER(LEN=*), INTENT(OUT)                      :: omp_stacksize
     763             : 
     764             :       INTEGER                                            :: istat
     765             : 
     766        5004 :       omp_stacksize = ""
     767        5004 :       CALL get_environment_variable("OMP_STACKSIZE", value=omp_stacksize, status=istat)
     768             :       ! Fall back, if OMP_STACKSIZE is not set
     769        5004 :       IF (istat /= 0) omp_stacksize = "default"
     770             : 
     771        5004 :    END SUBROUTINE m_omp_get_stacksize
     772             : 
     773             : END MODULE machine

Generated by: LCOV version 1.15