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