Line data Source code
1 : !--------------------------------------------------------------------------------------------------!
2 : ! CP2K: A general program to perform molecular dynamics simulations !
3 : ! Copyright 2000-2024 CP2K developers group <https://cp2k.org> !
4 : ! !
5 : ! SPDX-License-Identifier: GPL-2.0-or-later !
6 : !--------------------------------------------------------------------------------------------------!
7 :
8 : ! **************************************************************************************************
9 : !> \brief Swarm-framwork, provides a convenient master/worker architecture.
10 : !> \author Ole Schuett
11 : ! **************************************************************************************************
12 : MODULE swarm
13 : USE cp_log_handling, ONLY: cp_get_default_logger,&
14 : cp_logger_type
15 : USE cp_output_handling, ONLY: cp_print_key_unit_nr
16 : USE global_types, ONLY: global_environment_type
17 : USE input_section_types, ONLY: section_type,&
18 : section_vals_type,&
19 : section_vals_val_get
20 : USE kinds, ONLY: default_string_length
21 : USE message_passing, ONLY: mp_para_env_type
22 : USE swarm_master, ONLY: swarm_master_finalize,&
23 : swarm_master_init,&
24 : swarm_master_steer,&
25 : swarm_master_type
26 : USE swarm_message, ONLY: swarm_message_add,&
27 : swarm_message_free,&
28 : swarm_message_get,&
29 : swarm_message_type
30 : USE swarm_mpi, ONLY: swarm_mpi_finalize,&
31 : swarm_mpi_init,&
32 : swarm_mpi_recv_command,&
33 : swarm_mpi_recv_report,&
34 : swarm_mpi_send_command,&
35 : swarm_mpi_send_report,&
36 : swarm_mpi_type
37 : USE swarm_worker, ONLY: swarm_worker_execute,&
38 : swarm_worker_finalize,&
39 : swarm_worker_init,&
40 : swarm_worker_type
41 : #include "../base/base_uses.f90"
42 :
43 : IMPLICIT NONE
44 : PRIVATE
45 :
46 : CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'swarm'
47 :
48 : PUBLIC :: run_swarm
49 :
50 : CONTAINS
51 :
52 : ! **************************************************************************************************
53 : !> \brief Central driver routine of the swarm framework, called by cp2k_runs.F
54 : !> \param input_declaration ...
55 : !> \param root_section ...
56 : !> \param para_env ...
57 : !> \param globenv ...
58 : !> \param input_path ...
59 : !> \author Ole Schuett
60 : ! **************************************************************************************************
61 12 : SUBROUTINE run_swarm(input_declaration, root_section, para_env, globenv, input_path)
62 : TYPE(section_type), POINTER :: input_declaration
63 : TYPE(section_vals_type), POINTER :: root_section
64 : TYPE(mp_para_env_type), POINTER :: para_env
65 : TYPE(global_environment_type), POINTER :: globenv
66 : CHARACTER(LEN=*), INTENT(IN) :: input_path
67 :
68 : CHARACTER(len=*), PARAMETER :: routineN = 'run_swarm'
69 :
70 : INTEGER :: handle, iw, n_workers
71 : TYPE(cp_logger_type), POINTER :: logger
72 :
73 6 : CALL timeset(routineN, handle)
74 :
75 6 : logger => cp_get_default_logger()
76 : iw = cp_print_key_unit_nr(logger, root_section, &
77 6 : "SWARM%PRINT%MASTER_RUN_INFO", extension=".masterLog")
78 :
79 6 : IF (iw > 0) WRITE (iw, "(A)") " SWARM| Ready to roll :-)"
80 :
81 : CALL section_vals_val_get(root_section, "SWARM%NUMBER_OF_WORKERS", &
82 6 : i_val=n_workers)
83 :
84 6 : IF (n_workers == 1 .AND. para_env%num_pe == 1) THEN
85 0 : IF (iw > 0) WRITE (iw, "(A)") " SWARM| Running in single worker mode."
86 0 : CALL swarm_serial_driver(input_declaration, root_section, input_path, para_env, globenv)
87 : ELSE
88 6 : IF (iw > 0) WRITE (iw, "(A)") " SWARM| Running in master / workers mode."
89 : !printkey iw passed on for output from swarm_mpi_init()
90 6 : CALL swarm_parallel_driver(n_workers, input_declaration, root_section, input_path, para_env, globenv, iw)
91 : END IF
92 :
93 6 : CALL timestop(handle)
94 6 : END SUBROUTINE run_swarm
95 :
96 : ! **************************************************************************************************
97 : !> \brief Special driver for using only a single worker.
98 : !> \param input_declaration ...
99 : !> \param root_section ...
100 : !> \param input_path ...
101 : !> \param para_env ...
102 : !> \param globenv ...
103 : !> \author Ole Schuett
104 : ! **************************************************************************************************
105 0 : SUBROUTINE swarm_serial_driver(input_declaration, root_section, input_path, para_env, globenv)
106 : TYPE(section_type), POINTER :: input_declaration
107 : TYPE(section_vals_type), POINTER :: root_section
108 : CHARACTER(LEN=*), INTENT(IN) :: input_path
109 : TYPE(mp_para_env_type), POINTER :: para_env
110 : TYPE(global_environment_type), POINTER :: globenv
111 :
112 : INTEGER :: handle
113 : LOGICAL :: should_stop
114 : TYPE(swarm_master_type) :: master
115 : TYPE(swarm_message_type) :: cmd, report
116 : TYPE(swarm_worker_type) :: worker
117 :
118 0 : CALL swarm_master_init(master, para_env, globenv, root_section, n_workers=1)
119 : CALL swarm_worker_init(worker, para_env, input_declaration, root_section, &
120 0 : input_path, worker_id=1)
121 :
122 0 : CALL swarm_message_add(report, "worker_id", 1)
123 0 : CALL swarm_message_add(report, "status", "initial_hello")
124 :
125 0 : should_stop = .FALSE.
126 0 : DO WHILE (.NOT. should_stop)
127 0 : CALL timeset("swarm_worker_await_reply", handle)
128 0 : CALL swarm_master_steer(master, report, cmd)
129 0 : CALL timestop(handle)
130 0 : CALL swarm_message_free(report)
131 0 : CALL swarm_worker_execute(worker, cmd, report, should_stop)
132 0 : CALL swarm_message_free(cmd)
133 : END DO
134 :
135 0 : CALL swarm_message_free(report)
136 0 : CALL swarm_worker_finalize(worker)
137 0 : CALL swarm_master_finalize(master)
138 :
139 0 : END SUBROUTINE swarm_serial_driver
140 :
141 : ! **************************************************************************************************
142 : !> \brief Normal driver routine for parallelized runs.
143 : !> \param n_workers ...
144 : !> \param input_declaration ...
145 : !> \param root_section ...
146 : !> \param input_path ...
147 : !> \param para_env ...
148 : !> \param globenv ...
149 : !> \param iw ...
150 : !> \author Ole Schuett
151 : ! **************************************************************************************************
152 6 : SUBROUTINE swarm_parallel_driver(n_workers, input_declaration, root_section, input_path, para_env, globenv, iw)
153 : INTEGER, INTENT(IN) :: n_workers
154 : TYPE(section_type), POINTER :: input_declaration
155 : TYPE(section_vals_type), POINTER :: root_section
156 : CHARACTER(LEN=*), INTENT(IN) :: input_path
157 : TYPE(mp_para_env_type), POINTER :: para_env
158 : TYPE(global_environment_type), POINTER :: globenv
159 : INTEGER, INTENT(IN) :: iw
160 :
161 : INTEGER :: worker_id
162 6 : TYPE(swarm_mpi_type) :: swarm_mpi
163 :
164 6 : CALL swarm_mpi_init(swarm_mpi, para_env, root_section, n_workers, worker_id, iw)
165 :
166 6 : IF (ASSOCIATED(swarm_mpi%worker)) THEN
167 3 : CALL swarm_parallel_worker_driver(swarm_mpi, input_declaration, worker_id, root_section, input_path)
168 : ELSE
169 3 : CALL swarm_parallel_master_driver(swarm_mpi, n_workers, root_section, globenv)
170 : END IF
171 :
172 6 : CALL swarm_mpi_finalize(swarm_mpi, root_section)
173 :
174 6 : END SUBROUTINE swarm_parallel_driver
175 :
176 : ! **************************************************************************************************
177 : !> \brief Worker's driver routine for parallelized runs.
178 : !> \param swarm_mpi ...
179 : !> \param input_declaration ...
180 : !> \param worker_id ...
181 : !> \param root_section ...
182 : !> \param input_path ...
183 : !> \author Ole Schuett
184 : ! **************************************************************************************************
185 3 : SUBROUTINE swarm_parallel_worker_driver(swarm_mpi, input_declaration, worker_id, root_section, input_path)
186 : TYPE(swarm_mpi_type), INTENT(IN) :: swarm_mpi
187 : TYPE(section_type), POINTER :: input_declaration
188 : INTEGER, INTENT(IN) :: worker_id
189 : TYPE(section_vals_type), POINTER :: root_section
190 : CHARACTER(LEN=*), INTENT(IN) :: input_path
191 :
192 : INTEGER :: handle
193 : LOGICAL :: should_stop
194 : TYPE(swarm_message_type) :: cmd, report
195 : TYPE(swarm_worker_type) :: worker
196 :
197 : CALL swarm_worker_init(worker, swarm_mpi%worker, input_declaration, &
198 3 : root_section, input_path, worker_id=worker_id)
199 :
200 3 : CALL swarm_message_add(report, "worker_id", worker_id)
201 3 : CALL swarm_message_add(report, "status", "initial_hello")
202 :
203 3 : should_stop = .FALSE.
204 54 : DO WHILE (.NOT. should_stop)
205 51 : CALL timeset("swarm_worker_await_reply", handle)
206 51 : CALL swarm_mpi_send_report(swarm_mpi, report)
207 51 : CALL swarm_message_free(report)
208 51 : CALL swarm_mpi_recv_command(swarm_mpi, cmd)
209 51 : CALL timestop(handle)
210 51 : CALL swarm_worker_execute(worker, cmd, report, should_stop)
211 51 : CALL swarm_message_free(cmd)
212 : END DO
213 :
214 3 : CALL swarm_message_free(report)
215 3 : CALL swarm_worker_finalize(worker)
216 :
217 3 : END SUBROUTINE swarm_parallel_worker_driver
218 :
219 : ! **************************************************************************************************
220 : !> \brief Master's driver routine for parallelized runs.
221 : !> \param swarm_mpi ...
222 : !> \param n_workers ...
223 : !> \param root_section ...
224 : !> \param globenv ...
225 : !> \author Ole Schuett
226 : ! **************************************************************************************************
227 3 : SUBROUTINE swarm_parallel_master_driver(swarm_mpi, n_workers, root_section, globenv)
228 : TYPE(swarm_mpi_type), INTENT(IN) :: swarm_mpi
229 : INTEGER, INTENT(IN) :: n_workers
230 : TYPE(section_vals_type), POINTER :: root_section
231 : TYPE(global_environment_type), POINTER :: globenv
232 :
233 : CHARACTER(len=default_string_length) :: command
234 : INTEGER :: i_shutdowns, j, wid
235 6 : LOGICAL, DIMENSION(n_workers) :: is_waiting
236 : TYPE(swarm_master_type) :: master
237 : TYPE(swarm_message_type) :: cmd, report
238 :
239 6 : is_waiting(:) = .FALSE.
240 :
241 3 : CALL swarm_master_init(master, swarm_mpi%master, globenv, root_section, n_workers)
242 :
243 3 : i_shutdowns = 0
244 3 : j = 0
245 :
246 105 : DO WHILE (i_shutdowns < n_workers)
247 : ! Each iteration if the loop does s.th. different depending on j.
248 : ! First (j==0) it receives one report with (blocking) MPI,
249 : ! then it searches through the list is_waiting.
250 102 : j = MOD(j + 1, n_workers + 1)
251 102 : IF (j == 0) THEN
252 51 : CALL swarm_mpi_recv_report(swarm_mpi, report)
253 51 : ELSE IF (is_waiting(j)) THEN
254 0 : is_waiting(j) = .FALSE.
255 0 : CALL swarm_message_add(report, "worker_id", j)
256 0 : CALL swarm_message_add(report, "status", "wait_done")
257 : ELSE
258 : CYCLE
259 : END IF
260 :
261 51 : CALL swarm_master_steer(master, report, cmd)
262 51 : CALL swarm_message_free(report)
263 :
264 51 : CALL swarm_message_get(cmd, "command", command)
265 51 : IF (TRIM(command) == "wait") THEN
266 0 : CALL swarm_message_get(cmd, "worker_id", wid)
267 0 : is_waiting(wid) = .TRUE.
268 : ELSE
269 51 : CALL swarm_mpi_send_command(swarm_mpi, cmd)
270 51 : IF (TRIM(command) == "shutdown") i_shutdowns = i_shutdowns + 1
271 : END IF
272 102 : CALL swarm_message_free(cmd)
273 : END DO
274 :
275 3 : CALL swarm_master_finalize(master)
276 :
277 3 : END SUBROUTINE swarm_parallel_master_driver
278 :
279 : END MODULE swarm
280 :
|