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

Generated by: LCOV version 2.0-1