Arcane  v3.14.10.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
BitonicSortT.H
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* BitonicSortT.H (C) 2000-2024 */
9/* */
10/* Algorithme de tri bitonique parallèle */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/TraceAccessor.h"
15#include "arcane/utils/FatalErrorException.h"
16
17#include "arcane/core/IParallelMng.h"
18#include "arcane/core/parallel/BitonicSort.h"
19
20/*---------------------------------------------------------------------------*/
21/*---------------------------------------------------------------------------*/
22
23namespace Arcane::Parallel
24{
25
26/*---------------------------------------------------------------------------*/
27/*---------------------------------------------------------------------------*/
28
29template <typename KeyType, typename KeyTypeTraits> BitonicSort<KeyType, KeyTypeTraits>::
30BitonicSort(IParallelMng* parallel_mng)
31: TraceAccessor(parallel_mng->traceMng())
32, m_parallel_mng(parallel_mng)
33{
34}
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39template <typename KeyType, typename KeyTypeTraits> void BitonicSort<KeyType, KeyTypeTraits>::
40_init(ConstArrayView<KeyType> keys)
41{
42 m_init_size = keys.size();
43
44 // Il est indispensable que tout les procs aient la même valeur
45 // de m_size
46 m_size = m_parallel_mng->reduce(Parallel::ReduceMax, m_init_size);
47
48 m_keys.resize(m_size);
49 m_key_ranks.resize(m_size);
50 m_key_indexes.resize(m_size);
51
52 Int32 rank = m_parallel_mng->commRank();
53
54 // Les valeurs de la variable aux mailles tab sont stockées
55 // dans le tableau m_key
56 for (Integer i = 0; i < m_init_size; ++i) {
57 m_keys[i] = keys[i];
58 m_key_indexes[i] = i;
59 m_key_ranks[i] = rank;
60 }
61
62 // Remplit la fin du tableau avec des valeurs non significatives
63 // Afin que chaque processeur ait le meme nombre d'elements
64 KeyType max_value = KeyTypeTraits::maxValue();
65 for (Int64 i = m_init_size; i < m_size; i++) {
66 m_keys[i] = max_value;
67 m_key_indexes[i] = -1;
68 m_key_ranks[i] = rank;
69 }
70}
71
72/*---------------------------------------------------------------------------*/
73/*---------------------------------------------------------------------------*/
85template <typename KeyType, typename KeyTypeTraits> void
88{
89 _init(keys);
90
91 m_nb_merge = 0;
92
93 info() << "BITONIC_SORT (64bit) want_rank?=" << m_want_index_and_rank
94 << " size=" << m_size
95 << " memsize=" << sizeof(KeyType) * m_size
96 << " structsize=" << sizeof(KeyType);
97
98 // Appel au tri local des cles
99 _localHeapSort();
100
101 // Définition du nombre de niveaux pour l'algorithme
102 Int32 nb_level = 0;
103 Int32 test = 1;
104 Int32 nb_rank = m_parallel_mng->commSize();
105 while (nb_rank > test) {
106 nb_level++;
107 test *= 2;
108 }
109 Int32 size = 1;
110
111 // Boucle sur les niveaux de profondeurs de l'algorithme
112 for (Int32 ilevel = 0; ilevel < nb_level; ++ilevel) {
113 size *= 2;
114
115 // Boucle sur les groupes de processeurs à traiter
116 for (Int32 jproc = 0; jproc < nb_rank; jproc += size) {
117 _mergeLevels(jproc, size);
118 }
119 }
120
121 // Le nombre d'éléments valides de la liste peut-être inférieur
122 // au nombre d'éléments alloués. Dès qu'une valeur est invalide,
123 // on arrête la liste.
124 // TODO: partir de la fin
125 for (Integer i = 0; i < m_size; ++i) {
126 if (!KeyTypeTraits::isValid(m_keys[i])) {
127 m_size = i;
128 break;
129 }
130 }
131
132 info() << "END_BITONIC_SORT nb_merge=" << m_nb_merge;
133
134 m_keys.resize(m_size);
135 m_key_ranks.resize(m_size);
136 m_key_indexes.resize(m_size);
137}
138
139/*---------------------------------------------------------------------------*/
140/*---------------------------------------------------------------------------*/
151template <typename KeyType, typename KeyTypeTraits> void
153_mergeLevels(Int32 begin, Int32 size)
154{
155 //etage separateur
156 for (Int32 i = 0; i < size / 2; ++i)
157 _mergeProcessors(begin + i, begin + size - 1 - i);
158
159 if (size <= 2)
160 return;
161
162 // Application de la trieuse bitonique de niveau n/2
163 Int32 div_size = size;
164 while (div_size > 1) {
165 div_size /= 2;
166 for (Int32 iproc = 0; iproc < size; iproc += div_size)
167 _separator(begin + iproc, div_size);
168 }
169}
170
171/*---------------------------------------------------------------------------*/
172/*---------------------------------------------------------------------------*/
176template <typename KeyType, typename KeyTypeTraits> void BitonicSort<KeyType, KeyTypeTraits>::
177_separator(Int32 begin, Int32 size)
178{
179 for (Int32 i = 0; i < size / 2; ++i)
180 _mergeProcessors(begin + i, begin + i + size / 2);
181}
182
183/*---------------------------------------------------------------------------*/
184/*---------------------------------------------------------------------------*/
199template <typename KeyType, typename KeyTypeTraits> void BitonicSort<KeyType, KeyTypeTraits>::
200_mergeProcessors(Int32 iproc1, Int32 iproc2)
201{
202 if (iproc1 >= iproc2)
203 ARCANE_FATAL("Invalid merge iproc1={0} iproc2={1}", iproc1, iproc2);
204
205 Int32 my_rank = m_parallel_mng->commRank();
206
207 if (iproc2 >= m_parallel_mng->commSize())
208 return;
209
210 bool is_proc2 = (iproc2 == my_rank);
211 bool is_proc1 = (iproc1 == my_rank);
212
213 if (!is_proc1 && !is_proc2)
214 return;
215
216 info() << "SORT iproc1=" << iproc1 << " iproc2=" << iproc2;
217 ++m_nb_merge;
218
219 const Int64 buf_size = m_size;
220 const bool is_want_index_rank = m_want_index_and_rank;
222 //traitement du processeur 2
224
225 if (is_proc2) {
226 //envoi de la liste au proc 1
228 UniqueArray<Request> requests;
229 requests.add(KeyTypeTraits::send(m_parallel_mng, iproc1, send_keys));
230 if (is_want_index_rank) {
231 requests.add(m_parallel_mng->send(m_key_indexes, iproc1, false));
232 requests.add(m_parallel_mng->send(m_key_ranks, iproc1, false));
233 }
234 //reception de la fin de la liste fusionnee par le proc1
235 requests.add(KeyTypeTraits::recv(m_parallel_mng, iproc1, m_keys));
236 if (is_want_index_rank) {
237 requests.add(m_parallel_mng->recv(m_key_indexes, iproc1, false));
238 requests.add(m_parallel_mng->recv(m_key_ranks, iproc1, false));
239 }
240 m_parallel_mng->waitAllRequests(requests);
241 }
242
244 //traitement du processeur 1
246 if (is_proc1) {
247 //reception de la liste du proc2
248
252 //on alloue buf2 a la taille+1 afin de placer une sentinelle en
253 //buf2[size]
254 buf2.resize(buf_size);
255 if (is_want_index_rank) {
256 buf2_proc.resize(buf_size);
257 buf2_local_id.resize(buf_size);
258 }
259
260 Request recv_request = KeyTypeTraits::recv(m_parallel_mng, iproc2, buf2);
261 m_parallel_mng->waitAllRequests(ArrayView<Request>(1, &recv_request));
262 if (is_want_index_rank) {
263 m_parallel_mng->recv(buf2_local_id, iproc2);
264 m_parallel_mng->recv(buf2_proc, iproc2);
265 }
266
267 //à remplacer par le plus grand nombre representable par un Integer
268 buf2.add(KeyTypeTraits::maxValue());
269
270 // allocation d'un buffer de travail pour la fusion des deux listes
271 Int64 total_size = m_size + buf_size;
275 if (is_want_index_rank) {
278 }
279
280#if 0
281 info() << "SIZE=" << buf_size << " total=" << total_size << " m_size=" << m_size
282 << " proc2=" << iproc2 << " init-size=" << m_init_size;
283#endif
284
285 // Fusion des deux listes en partant du principe que chacune est
286 // déjà triée.
287 Int64 cursor1 = 0;
288 Int64 cursor2 = 0;
289 for (Int64 i = 0; i < total_size; ++i) {
290 if (cursor1 >= m_size || (KeyTypeTraits::compareLess(buf2[cursor2], m_keys[cursor1]) && cursor2 < buf_size)) {
291 buf_merge[i] = buf2[cursor2];
292 if (is_want_index_rank) {
295 }
296 ++cursor2;
297 }
298 else {
299 buf_merge[i] = m_keys[cursor1];
300 if (is_want_index_rank) {
301 buf_local_id_merge[i] = m_key_indexes[cursor1];
302 buf_proc_merge[i] = m_key_ranks[cursor1];
303 }
304 ++cursor1;
305 }
306 }
307 buf2.resize(buf_size);
308
309 // Recopie et envoi de la fin de la liste vers le proc2
310 for (Integer ii = 0; ii < buf_size; ii++) {
311 buf2[ii] = buf_merge[m_size + ii];
312 if (is_want_index_rank) {
314 buf2_proc[ii] = buf_proc_merge[m_size + ii];
315 }
316 }
317 Request send_request = KeyTypeTraits::send(m_parallel_mng, iproc2, buf2);
318 m_parallel_mng->waitAllRequests(ArrayView<Request>(1, &send_request));
319 if (is_want_index_rank) {
320 m_parallel_mng->send(buf2_local_id, iproc2);
321 m_parallel_mng->send(buf2_proc, iproc2);
322 }
323
324 // recopie du debut de la liste dans la variable m_work_unique_id
325 for (Integer i = 0; i < buf_size; i++) {
326 m_keys[i] = buf_merge[i];
327 if (is_want_index_rank) {
328 m_key_indexes[i] = buf_local_id_merge[i];
329 m_key_ranks[i] = buf_proc_merge[i];
330 }
331 }
332 }
333}
334
335/*---------------------------------------------------------------------------*/
336/*---------------------------------------------------------------------------*/
343template <typename KeyType, typename KeyTypeTraits> void BitonicSort<KeyType, KeyTypeTraits>::
345{
346 // Cas particulier d'une liste réduite à zero ou un element
347 if (m_size < 2)
348 return;
349
350 // Suivant du parent du dernier element
351 Int64 l = m_size / 2;
352 Int64 ir = m_size - 1;
353 KeyType rra;
354 Int64 i = 0;
355 Int64 j = 0;
356 Integer tmp_local_id = NULL_ITEM_LOCAL_ID;
357 Integer tmp_proc = A_NULL_RANK;
358
359 for (;;) {
360 if (l > 0) {
361 --l;
362 rra = m_keys[l];
363 tmp_local_id = m_key_indexes[l];
364 tmp_proc = m_key_ranks[l];
365 }
366 else {
367 rra = m_keys[ir];
368 tmp_local_id = m_key_indexes[ir];
369 tmp_proc = m_key_ranks[ir];
370
371 m_keys[ir] = m_keys[0];
372 m_key_indexes[ir] = m_key_indexes[0];
373 m_key_ranks[ir] = m_key_ranks[0];
374
375 if (--ir == 0) {
376 m_keys[0] = rra;
377 m_key_indexes[0] = tmp_local_id;
378 m_key_ranks[0] = tmp_proc;
379 break;
380 }
381 }
382 i = l;
383 j = l + l + 1;
384 while (j <= ir) {
385 if (j < ir && KeyTypeTraits::compareLess(m_keys[j], m_keys[j + 1]))
386 ++j;
387 if (KeyTypeTraits::compareLess(rra, m_keys[j])) {
388 m_keys[i] = m_keys[j];
389 m_key_indexes[i] = m_key_indexes[j];
390 m_key_ranks[i] = m_key_ranks[j];
391 i = j;
392 //enfant a gauche
393 j = j * 2 + 1;
394 }
395 else
396 j = ir + 1;
397 }
398 m_keys[i] = rra;
399 m_key_indexes[i] = tmp_local_id;
400 m_key_ranks[i] = tmp_proc;
401 }
402}
403
404/*---------------------------------------------------------------------------*/
405/*---------------------------------------------------------------------------*/
406
407} // namespace Arcane::Parallel
408
409/*---------------------------------------------------------------------------*/
410/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Algorithme de tri bitonique parallèle.
Requête d'un message.
Definition Request.h:77
Vecteur 1D de données avec sémantique par valeur (style STL).
Implémentation de la concurrence.