LCOV - code coverage report
Current view: top level - src/base - machine.F (source / functions) Coverage Total Hit
Test: CP2K Regtests (git:ca6acae) Lines: 75.1 % 181 136
Test Date: 2026-01-02 06:29:53 Functions: 90.5 % 21 19

            Line data    Source code
       1              : !--------------------------------------------------------------------------------------------------!
       2              : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3              : !   Copyright 2000-2026 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       254991 :    SUBROUTINE m_flush(lunit)
     136              :       INTEGER, INTENT(IN)                                :: lunit
     137              : 
     138       254991 :       IF (flush_should_flush) FLUSH (lunit)
     139              : 
     140       254991 :    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   3293714383 :    FUNCTION m_walltime() RESULT(wt)
     153              :       REAL(KIND=dp)                                      :: wt
     154              : 
     155              : #if defined(__LIBXSMM)
     156   3293714383 :       wt = libxsmm_timer_duration(0_int_8, libxsmm_timer_tick())
     157              : #else
     158              :       wt = omp_get_wtime()
     159              : #endif
     160   3293714383 :    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         5050 :    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         5050 :       model_name = "UNKNOWN"
     175         5050 :       buffer = ""
     176         5050 :       OPEN (121245, FILE="/proc/cpuinfo", ACTION="READ", STATUS="OLD", ACCESS="STREAM", IOSTAT=stat)
     177         5050 :       IF (stat == 0) THEN
     178     10347450 :          DO i = 1, bufferlen
     179     10347450 :             READ (121245, END=999) buffer(I:I)
     180              :          END DO
     181         5050 : 999      CLOSE (121245)
     182         5050 :          i = INDEX(buffer, "model name")
     183         5050 :          IF (i > 0) THEN
     184         5050 :             icol = i - 1 + INDEX(buffer(i:), ":")
     185         5050 :             iline = icol - 1 + INDEX(buffer(icol:), NEW_LINE('A'))
     186         5050 :             IF (iline == icol - 1) iline = bufferlen + 1
     187         5050 :             model_name = buffer(icol + 1:iline - 1)
     188              :          END IF
     189              :       END IF
     190         5050 :    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       485211 :    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       485211 :       m_cpuid = MACHINE_CPU_UNKNOWN
     207       485211 :       archid = libxsmm_get_target_archid()
     208       485211 :       IF (LIBXSMM_X86_SSE4 <= archid .AND. archid < LIBXSMM_X86_AVX) THEN
     209              :          m_cpuid = MACHINE_X86_SSE4
     210       485211 :       ELSE IF (LIBXSMM_X86_AVX <= archid .AND. archid < LIBXSMM_X86_AVX2) THEN
     211              :          m_cpuid = MACHINE_X86_AVX
     212       485211 :       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       485211 :    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       481165 :    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       481165 :       IF (PRESENT(typesize)) THEN
     295            0 :          nbytes = typesize
     296              :       ELSE
     297              :          nbytes = 8 ! double-precision
     298              :       END IF
     299              : 
     300       481165 :       IF (0 < nbytes .AND. nbytes <= 16) THEN ! sanity check
     301       481165 :          IF (PRESENT(cpuid)) THEN
     302        10100 :             isa = cpuid
     303              :          ELSE
     304       471065 :             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       481165 :             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       481165 :             m_cpuid_vlen = 1 ! scalar
     326              :          END SELECT
     327              :       ELSE ! fallback
     328              :          m_cpuid_vlen = 1 ! scalar
     329              :       END IF
     330       481165 :    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   3286754813 :    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   3286754813 :       wt = 0.0 ! fallback default
     349              : #endif
     350              : 
     351   3286754813 :    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        22839 :    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        22839 :       CALL DATE_AND_TIME(date=date, time=time)
     399              :       timestamp = date(1:4)//"-"//date(5:6)//"-"//date(7:8)//" "// &
     400        22839 :                   time(1:2)//":"//time(3:4)//":"//time(5:10)
     401              : 
     402        22839 :    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         9893 :    FUNCTION m_procrun(pid) RESULT(run_on)
     423              :       INTEGER, INTENT(IN)                                :: pid
     424              :       INTEGER                                            :: run_on
     425              : 
     426              :       INTEGER                                            :: istat
     427              :       INTERFACE
     428              :          FUNCTION kill(pid, sig) RESULT(errno) BIND(C, name="kill")
     429              :             IMPORT
     430              :             INTEGER(KIND=C_INT), VALUE                :: pid, sig
     431              :             INTEGER(KIND=C_INT)                      :: errno
     432              :          END FUNCTION kill
     433              :       END INTERFACE
     434              : 
     435              :       ! If sig is 0, then no signal is sent, but error checking is still
     436              :       ! performed; this can be used to check for the existence of a process
     437              :       ! ID or process group ID.
     438              : 
     439         9893 :       istat = kill(pid=pid, sig=0)
     440         9893 :       IF (istat == 0) THEN
     441              :          run_on = 1 ! no error, process exists
     442              :       ELSE
     443            0 :          run_on = 0 ! error, process probably does not exist
     444              :       END IF
     445         9893 :    END FUNCTION m_procrun
     446              : 
     447              : ! **************************************************************************************************
     448              : !> \brief Returns the total amount of memory [bytes] in use, if known, zero otherwise
     449              : !> \param mem ...
     450              : ! **************************************************************************************************
     451      2231372 :    SUBROUTINE m_memory(mem)
     452              : 
     453              :       INTEGER(KIND=int_8), OPTIONAL, INTENT(OUT)         :: mem
     454              :       INTEGER(KIND=int_8)                      :: mem_local
     455              : 
     456              :       ! __NO_STATM_ACCESS can be used to disable the stuff, if getpagesize
     457              :       ! lead to linking errors or /proc/self/statm can not be opened
     458              :       !
     459              : #if defined(__NO_STATM_ACCESS)
     460              :       mem_local = 0
     461              : #else
     462              :       INTEGER(KIND=int_8)                      :: m1, m2, m3
     463              :       CHARACTER(LEN=80) :: DATA
     464              :       INTEGER :: iostat, i
     465              : 
     466              :       ! the size of a page, might not be available everywhere
     467              :       INTERFACE
     468              :          FUNCTION getpagesize() BIND(C, name="getpagesize") RESULT(RES)
     469              :             IMPORT
     470              :             INTEGER(C_INT) :: RES
     471              :          END FUNCTION getpagesize
     472              :       END INTERFACE
     473              : 
     474              :       ! reading from statm
     475              :       !
     476      2231372 :       mem_local = -1
     477      2231372 :       DATA = ""
     478      2231372 :       OPEN (121245, FILE="/proc/self/statm", ACTION="READ", STATUS="OLD", ACCESS="STREAM")
     479     78199895 :       DO I = 1, 80
     480     78199895 :          READ (121245, END=999) DATA(I:I)
     481              :       END DO
     482      2231372 : 999   CLOSE (121245)
     483      2231372 :       DATA(I:80) = ""
     484              :       ! m1 = total
     485              :       ! m2 = resident
     486              :       ! m3 = shared
     487      2231372 :       READ (DATA, *, IOSTAT=iostat) m1, m2, m3
     488      2231372 :       IF (iostat /= 0) THEN
     489              :          mem_local = 0
     490              :       ELSE
     491      2231372 :          mem_local = m2
     492              : #if defined(__STATM_TOTAL)
     493              :          mem_local = m1
     494              : #endif
     495              : #if defined(__STATM_RESIDENT)
     496              :          mem_local = m2
     497              : #endif
     498      2231372 :          mem_local = mem_local*getpagesize()
     499              :       END IF
     500              : #endif
     501              : 
     502      2231372 :       m_memory_max = MAX(mem_local, m_memory_max)
     503      2231372 :       IF (PRESENT(mem)) mem = mem_local
     504              : 
     505      2231372 :    END SUBROUTINE m_memory
     506              : 
     507              : ! **************************************************************************************************
     508              : !> \brief get more detailed memory info, all units are bytes.
     509              : !>         the only 'useful' option is MemLikelyFree which is an estimate of remaining memory
     510              : !>         assumed to give info like /proc/meminfo while MeMLikelyFree is the amount of
     511              : !>         memory we're likely to be able to allocate, but not necessarily in one chunk
     512              : !>         zero means not available...
     513              : !> \param MemTotal ...
     514              : !> \param MemFree ...
     515              : !> \param Buffers ...
     516              : !> \param Cached ...
     517              : !> \param Slab ...
     518              : !> \param SReclaimable ...
     519              : !> \param MemLikelyFree ...
     520              : ! **************************************************************************************************
     521         9893 :    SUBROUTINE m_memory_details(MemTotal, MemFree, Buffers, Cached, Slab, SReclaimable, MemLikelyFree)
     522              : 
     523              :       INTEGER(kind=int_8), OPTIONAL :: MemTotal, MemFree, Buffers, Cached, Slab, SReclaimable, MemLikelyFree
     524              : 
     525              :       INTEGER, PARAMETER :: Nbuffer = 10000
     526              :       CHARACTER(LEN=Nbuffer) :: meminfo
     527              : 
     528              :       INTEGER :: i
     529              : 
     530         9893 :       MemTotal = 0
     531         9893 :       MemFree = 0
     532         9893 :       Buffers = 0
     533         9893 :       Cached = 0
     534         9893 :       Slab = 0
     535         9893 :       SReclaimable = 0
     536         9893 :       MemLikelyFree = 0
     537         9893 :       meminfo = ""
     538              : 
     539         9893 :       OPEN (UNIT=8123, file="/proc/meminfo", ACCESS="STREAM", ERR=901)
     540         9893 :       i = 0
     541     15175993 :       DO
     542     15185886 :          i = i + 1
     543     15185886 :          IF (i > Nbuffer) EXIT
     544     15185886 :          READ (8123, END=900, ERR=900) meminfo(i:i)
     545              :       END DO
     546              : 900   CONTINUE
     547         9893 :       meminfo(i:Nbuffer) = ""
     548              : 901   CONTINUE
     549         9893 :       CLOSE (8123, ERR=902)
     550              : 902   CONTINUE
     551         9893 :       MemTotal = get_field_value_in_bytes('MemTotal:')
     552         9893 :       MemFree = get_field_value_in_bytes('MemFree:')
     553         9893 :       Buffers = get_field_value_in_bytes('Buffers:')
     554         9893 :       Cached = get_field_value_in_bytes('Cached:')
     555         9893 :       Slab = get_field_value_in_bytes('Slab:')
     556         9893 :       SReclaimable = get_field_value_in_bytes('SReclaimable:')
     557              :       ! opinions here vary but this might work
     558         9893 :       MemLikelyFree = MemFree + Buffers + Cached + SReclaimable
     559              : 
     560              :    CONTAINS
     561              : 
     562              : ! **************************************************************************************************
     563              : !> \brief ...
     564              : !> \param field ...
     565              : !> \return ...
     566              : ! **************************************************************************************************
     567        59358 :       INTEGER(int_8) FUNCTION get_field_value_in_bytes(field)
     568              :       CHARACTER(LEN=*)                                   :: field
     569              : 
     570              :       INTEGER                                            :: start
     571              :       INTEGER(KIND=int_8)                                :: value
     572              : 
     573        59358 :          get_field_value_in_bytes = 0
     574        59358 :          start = INDEX(meminfo, field)
     575        59358 :          IF (start /= 0) THEN
     576        59358 :             start = start + LEN_TRIM(field)
     577        59358 :             IF (start < Nbuffer) THEN
     578        59358 :                READ (meminfo(start:), *, ERR=999, END=999) value
     579              :                ! XXXXXXX convert from Kb to bytes XXXXXXXX
     580        59358 :                get_field_value_in_bytes = value*1024
     581              : 999            CONTINUE
     582              :             END IF
     583              :          END IF
     584        59358 :       END FUNCTION get_field_value_in_bytes
     585              :    END SUBROUTINE m_memory_details
     586              : 
     587              : ! **************************************************************************************************
     588              : !> \brief ...
     589              : !> \param hname ...
     590              : ! **************************************************************************************************
     591        14947 :    SUBROUTINE m_hostnm(hname)
     592              :       CHARACTER(len=*), INTENT(OUT)            :: hname
     593              :       INTEGER                                  :: istat, i
     594              :       CHARACTER(len=default_path_length)       :: buf
     595              : 
     596              :       INTERFACE
     597              :          FUNCTION gethostname(buf, buflen) BIND(C, name="gethostname") RESULT(errno)
     598              :             IMPORT
     599              :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: buf
     600              :             INTEGER(KIND=C_INT), VALUE               :: buflen
     601              :             INTEGER(KIND=C_INT)                      :: errno
     602              :          END FUNCTION gethostname
     603              :       END INTERFACE
     604              : 
     605        29894 :       istat = gethostname(buf, LEN(buf))
     606        14947 :       IF (istat /= 0) THEN
     607            0 :          WRITE (*, *) "m_hostnm failed"
     608            0 :          CALL m_abort()
     609              :       END IF
     610        14947 :       i = INDEX(buf, c_null_char) - 1
     611        14947 :       hname = buf(1:i)
     612        14947 :    END SUBROUTINE m_hostnm
     613              : 
     614              : ! **************************************************************************************************
     615              : !> \brief ...
     616              : !> \param curdir ...
     617              : ! **************************************************************************************************
     618       134723 :    SUBROUTINE m_getcwd(curdir)
     619              :       CHARACTER(len=*), INTENT(OUT)            :: curdir
     620              :       TYPE(C_PTR)                              :: stat
     621              :       INTEGER                                  :: i
     622              :       CHARACTER(len=default_path_length), TARGET  :: tmp
     623              : 
     624              :       INTERFACE
     625              :          FUNCTION getcwd(buf, buflen) BIND(C, name="getcwd") RESULT(stat)
     626              :             IMPORT
     627              :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: buf
     628              :             INTEGER(KIND=C_INT), VALUE               :: buflen
     629              :             TYPE(C_PTR)                              :: stat
     630              :          END FUNCTION getcwd
     631              :       END INTERFACE
     632              : 
     633       269446 :       stat = getcwd(tmp, LEN(tmp))
     634       134723 :       IF (.NOT. C_ASSOCIATED(stat)) THEN
     635            0 :          WRITE (*, *) "m_getcwd failed"
     636            0 :          CALL m_abort()
     637              :       END IF
     638       134723 :       i = INDEX(tmp, c_null_char) - 1
     639       134723 :       curdir = tmp(1:i)
     640       134723 :    END SUBROUTINE m_getcwd
     641              : 
     642              : ! **************************************************************************************************
     643              : !> \brief ...
     644              : !> \param dir ...
     645              : !> \param ierror ...
     646              : ! **************************************************************************************************
     647         2966 :    SUBROUTINE m_chdir(dir, ierror)
     648              :       CHARACTER(len=*), INTENT(IN)             :: dir
     649              :       INTEGER, INTENT(OUT)                     :: ierror
     650              : 
     651              :       INTERFACE
     652              :          FUNCTION chdir(path) BIND(C, name="chdir") RESULT(errno)
     653              :             IMPORT
     654              :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: path
     655              :             INTEGER(KIND=C_INT)                      :: errno
     656              :          END FUNCTION chdir
     657              :       END INTERFACE
     658              : 
     659         2966 :       ierror = chdir(TRIM(dir)//c_null_char)
     660         2966 :    END SUBROUTINE m_chdir
     661              : 
     662              : ! **************************************************************************************************
     663              : !> \brief ...
     664              : !> \param pid ...
     665              : ! **************************************************************************************************
     666        14947 :    SUBROUTINE m_getpid(pid)
     667              :       INTEGER, INTENT(OUT)                     :: pid
     668              : 
     669              :       INTERFACE
     670              :          FUNCTION getpid() BIND(C, name="getpid") RESULT(pid)
     671              :             IMPORT
     672              :             INTEGER(KIND=C_INT)              :: pid
     673              :          END FUNCTION getpid
     674              :       END INTERFACE
     675              : 
     676        14947 :       pid = getpid()
     677        14947 :    END SUBROUTINE m_getpid
     678              : 
     679              : ! **************************************************************************************************
     680              : !> \brief ...
     681              : !> \param path ...
     682              : !> \return ...
     683              : ! **************************************************************************************************
     684        11908 :    FUNCTION m_unlink(path) RESULT(istat)
     685              : 
     686              :       CHARACTER(LEN=*), INTENT(IN)             :: path
     687              : 
     688              :       INTEGER                                  :: istat
     689              : 
     690              :       INTERFACE
     691              :          FUNCTION unlink(path) BIND(C, name="unlink") RESULT(errno)
     692              :             IMPORT
     693              :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: path
     694              :             INTEGER(KIND=C_INT)                      :: errno
     695              :          END FUNCTION unlink
     696              :       END INTERFACE
     697              : 
     698        11908 :       istat = unlink(TRIM(path)//c_null_char)
     699        11908 :    END FUNCTION m_unlink
     700              : 
     701              : ! **************************************************************************************************
     702              : !> \brief ...
     703              : !> \param source ...
     704              : !> \param TARGET ...
     705              : ! **************************************************************************************************
     706        11908 :    SUBROUTINE m_mov(source, TARGET)
     707              : 
     708              :       CHARACTER(LEN=*), INTENT(IN)             :: source, TARGET
     709              : 
     710              :       INTEGER                                  :: istat
     711              : 
     712              :       INTERFACE
     713              :          FUNCTION rename(src, dest) BIND(C, name="rename") RESULT(errno)
     714              :             IMPORT
     715              :             CHARACTER(KIND=C_CHAR), DIMENSION(*)     :: src, dest
     716              :             INTEGER(KIND=C_INT)                      :: errno
     717              :          END FUNCTION rename
     718              :       END INTERFACE
     719              : 
     720        11908 :       IF (TARGET == source) THEN
     721            0 :          WRITE (*, *) "Warning: m_mov ", TRIM(TARGET), " equals ", TRIM(source)
     722            0 :          RETURN
     723              :       END IF
     724              : 
     725              :       ! first remove target (needed on windows)
     726        11908 :       istat = m_unlink(TARGET)
     727              :       ! ignore istat of unlink
     728              : 
     729              :       ! now move
     730        11908 :       istat = rename(TRIM(source)//c_null_char, TRIM(TARGET)//c_null_char)
     731        11908 :       IF (istat /= 0) THEN
     732            0 :          WRITE (*, *) "Trying to move "//TRIM(source)//" to "//TRIM(TARGET)//"."
     733            0 :          WRITE (*, *) "rename returned status: ", istat
     734            0 :          WRITE (*, *) "Problem moving file"
     735            0 :          CALL m_abort()
     736              :       END IF
     737              :    END SUBROUTINE m_mov
     738              : 
     739              : ! **************************************************************************************************
     740              : !> \brief ...
     741              : !> \param user ...
     742              : ! **************************************************************************************************
     743        14380 :    SUBROUTINE m_getlog(user)
     744              : 
     745              :       CHARACTER(LEN=*), INTENT(OUT) :: user
     746              : 
     747              :       INTEGER                       :: istat
     748              : 
     749              :       ! on a posix system LOGNAME should be defined
     750        14380 :       CALL get_environment_variable("LOGNAME", value=user, status=istat)
     751              :       ! nope, check alternative
     752        14380 :       IF (istat /= 0) &
     753        14380 :          CALL get_environment_variable("USER", value=user, status=istat)
     754              :       ! nope, check alternative
     755        14380 :       IF (istat /= 0) &
     756        14380 :          CALL get_environment_variable("USERNAME", value=user, status=istat)
     757              :       ! fall back
     758        14380 :       IF (istat /= 0) &
     759        14380 :          user = "<unknown>"
     760              : 
     761        14380 :    END SUBROUTINE m_getlog
     762              : 
     763              : ! **************************************************************************************************
     764              : !> \brief Retrieve environment variable OMP_STACKSIZE
     765              : !> \param omp_stacksize Value of OMP_STACKSIZE
     766              : ! **************************************************************************************************
     767         5050 :    SUBROUTINE m_omp_get_stacksize(omp_stacksize)
     768              :       CHARACTER(LEN=*), INTENT(OUT)                      :: omp_stacksize
     769              : 
     770              :       INTEGER                                            :: istat
     771              : 
     772         5050 :       omp_stacksize = ""
     773         5050 :       CALL get_environment_variable("OMP_STACKSIZE", value=omp_stacksize, status=istat)
     774              :       ! Fall back, if OMP_STACKSIZE is not set
     775         5050 :       IF (istat /= 0) omp_stacksize = "default"
     776              : 
     777         5050 :    END SUBROUTINE m_omp_get_stacksize
     778              : 
     779              : END MODULE machine
        

Generated by: LCOV version 2.0-1