MPI-SCATCI  2.0
An MPI version of SCATCI
MemoryManager_module.f90
Go to the documentation of this file.
1 ! Copyright 2019
2 !
3 ! For a comprehensive list of the developers that contributed to these codes
4 ! see the UK-AMOR website.
5 !
6 ! This file is part of UKRmol-in (UKRmol+ suite).
7 !
8 ! UKRmol-in is free software: you can redistribute it and/or modify
9 ! it under the terms of the GNU General Public License as published by
10 ! the Free Software Foundation, either version 3 of the License, or
11 ! (at your option) any later version.
12 !
13 ! UKRmol-in is distributed in the hope that it will be useful,
14 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ! GNU General Public License for more details.
17 !
18 ! You should have received a copy of the GNU General Public License
19 ! along with UKRmol-in (in source/COPYING). Alternatively, you can also visit
20 ! <https://www.gnu.org/licenses/>.
21 
32 
33  use precisn, only: longint, wp
34  use const_gbl, only: stdout
35 
36  implicit none
37 
38  public master_memory
39 
40  private
41 
46  type :: memorymanager
47  private
48  integer(longint) :: total_local_memory = 0
49  integer(longint) :: available_local_memory = 0
50  integer(longint) :: cached_tracked_memory = 0
51  logical :: initialized = .false.
52  contains
53  private
54  procedure, public :: construct => memorymanager_ctor
55  procedure, public :: init_memory
56  procedure, public :: track_memory
57  procedure, public :: free_memory
58  procedure, public :: get_available_memory
59  procedure, public :: get_scaled_available_memory
60  procedure, public :: print_memory_report
61  end type memorymanager
62 
70 
71 contains
72 
80  subroutine memorymanager_ctor (this, total_memory)
81  class(memorymanager) :: this
82  integer(longint), intent(in) :: total_memory
83 
84  this % total_local_memory = total_memory
85  this % available_local_memory = this % total_local_memory
86  this % initialized = .true.
87  this % available_local_memory = this % available_local_memory - this % cached_tracked_memory
88 
89  end subroutine memorymanager_ctor
90 
91 
99  subroutine init_memory (this, total_memory)
100  class(memorymanager) :: this
101  integer(longint), intent(in) :: total_memory
102 
103  this % total_local_memory = total_memory
104  this % available_local_memory = this % total_local_memory
105  this % available_local_memory = this % available_local_memory - this % cached_tracked_memory
106  this % initialized = .true.
107 
108  end subroutine init_memory
109 
110 
121  subroutine track_memory (this, elem_size, nelem, stat, array_name)
122  class(memorymanager) :: this
123  character(len=*), intent(in) :: array_name
124  integer, intent(in) :: elem_size,nelem,stat
125  integer(longint) :: total_mem
126 
127  !Check if allocation was successfull
128  if (stat /= 0) then
129  !If not print name and error stats
130  write (stdout, "('Array : ',a)") array_name
131  write (stdout, "('stat returned error ',i16,' when trying to allocate nelems ',i16,' of size ', i16)") &
132  stat, nelem, elem_size
133  !Halt the program
134  stop "[Memory manager] Memory allocation error"
135  end if
136 
137  ! calculate in bytes total memory used
138  total_mem = elem_size * nelem
139 
140  !Remove from available memory
141  !$OMP ATOMIC
142  this % cached_tracked_memory = this % cached_tracked_memory + total_mem
143  if (.not. this % initialized) return
144  !$OMP ATOMIC
145  this % available_local_memory = this % available_local_memory - total_mem
146 
147  !If we've hit negative then throw error
148  if (this % available_local_memory < 0) then
149  call this % print_memory_report()
150  write (stdout, "('Array : ',a)") array_name
151  write (stdout, "('Overrun allowed memory space when trying to allocate nelems ',i16,' of size ', 2i16,' vs',i16)") &
152  nelem, elem_size, total_mem, this % get_available_memory()
153  stop "[Memory manager] Overrun space"
154  end if
155  end subroutine track_memory
156 
157 
166  subroutine free_memory (this, elem_size, nelem)
167  class(memorymanager) :: this
168  integer, intent(in) :: elem_size, nelem
169  integer(longint) :: total_mem
170 
171  ! Calculate total deallocated
172  total_mem = elem_size * nelem
173  !$OMP ATOMIC
174  this % cached_tracked_memory = this % cached_tracked_memory - total_mem
175  !Add memory back to pool
176  if (.not. this % initialized) return
177  !$OMP ATOMIC
178  this % available_local_memory = this % available_local_memory + total_mem
179 
180  !If we have more memory than available then flag as there is a mismatching of track and free
181  if (this % available_local_memory > this % total_local_memory) then
182  stop "Memory mismatch"
183  end if
184 
185  end subroutine free_memory
186 
187 
194  integer(longint) function get_available_memory (this)
195  class(memorymanager) :: this
196 
197  get_available_memory = this % available_local_memory
198 
199  end function get_available_memory
200 
201 
213  integer(longint) function get_scaled_available_memory (this, scale_)
214  class(memorymanager) :: this
215  real(wp), intent(in) :: scale_
216  real(wp) :: s
217 
218  !Clamp scale between 0.0 ad 1.0
219  s = min(abs(scale_), 1.0_wp)
220 
221  !Return scaled
222  get_scaled_available_memory = int(real(this % available_local_memory) * s, longint)
223 
224  end function get_scaled_available_memory
225 
226 
231  subroutine print_memory_report (this)
232  class(memorymanager) :: this
233  real(wp) :: mem_total, mem_avail, percentage
234 
235  !Compute total in gibibytes
236  mem_total = real(this % total_local_memory) / real(1024**3)
237 
238  !Compute available in gibibytes
239  mem_avail = real(this % available_local_memory) / real(1024**3)
240 
241  !Compute percentage available
242  percentage = mem_avail * 100.0 / mem_total
243  write (stdout, "('Currently we have ',f18.8,'GB / ',f18.8,'GiB available')") mem_avail, mem_total
244  write (stdout, "('Memory availability at ',f6.1,'%')") percentage
245 
246  end subroutine print_memory_report
247 
248 end module memorymanager_module
memorymanager_module
Memory manager module.
Definition: MemoryManager_module.f90:31
memorymanager_module::get_scaled_available_memory
integer(longint) function get_scaled_available_memory(this, scale_)
Get currently available memory scaled.
Definition: MemoryManager_module.f90:214
memorymanager_module::memorymanager_ctor
subroutine memorymanager_ctor(this, total_memory)
Constructor, used to initialize total available memory.
Definition: MemoryManager_module.f90:81
memorymanager_module::init_memory
subroutine init_memory(this, total_memory)
Same as constructor, used to reinitialize te memory again (not really used)
Definition: MemoryManager_module.f90:100
memorymanager_module::free_memory
subroutine free_memory(this, elem_size, nelem)
Tracks memory deallocation, usually called before a deallocation.
Definition: MemoryManager_module.f90:167
memorymanager_module::print_memory_report
subroutine print_memory_report(this)
Prints a very simple memory report.
Definition: MemoryManager_module.f90:232
memorymanager_module::memorymanager
This is a simple class to handle memory management tracking.
Definition: MemoryManager_module.f90:46
memorymanager_module::get_available_memory
integer(longint) function get_available_memory(this)
Get currently available memory.
Definition: MemoryManager_module.f90:195
memorymanager_module::track_memory
subroutine track_memory(this, elem_size, nelem, stat, array_name)
Tracks memory allocation, usually called after an allocation.
Definition: MemoryManager_module.f90:122
memorymanager_module::master_memory
type(memorymanager), public master_memory
This is the global memory manager.
Definition: MemoryManager_module.f90:69