LCOV - code coverage report
Current view: top level - src/base - machine.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:936074a) Lines: 75.1 % 181 136
Test Date: 2025-12-04 06:27:48 Functions: 90.5 % 21 19

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

Generated by: LCOV version 2.0-1