Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
BlockIndexList.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2022 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/* BlockIndexList.cc (C) 2000-2023 */
9/* */
10/* Classe gérant un tableau d'indices sous la forme d'une liste de blocs. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/core/BlockIndexList.h"
15
16#include "arcane/utils/ArrayView.h"
17#include "arcane/utils/ITraceMng.h"
18#include "arcane/utils/String.h"
19#include "arcane/utils/FatalErrorException.h"
20
21#include <iomanip>
22#include <functional>
23
24/*---------------------------------------------------------------------------*/
25/*---------------------------------------------------------------------------*/
26
27namespace Arcane
28{
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32
33Real BlockIndexList::
34memoryRatio() const
35{
36 if (m_original_size == 0)
37 return 0.0;
38
39 Int32 new_size = m_indexes.size() + m_blocks_index_and_offset.size();
40 return (static_cast<Real>(new_size) / static_cast<Real>(m_original_size));
41}
42
43/*---------------------------------------------------------------------------*/
44/*---------------------------------------------------------------------------*/
45
46void BlockIndexList::
47fillArray(Array<Int32>& v)
48{
49 for (Int32 i = 0, n = m_nb_block; i < n; ++i) {
50 BlockIndex bi = block(i);
51 for (Int32 z = 0, nb_z = bi.size(); z < nb_z; ++z) {
52 v.add(bi[z]);
53 }
54 }
55}
56
57/*---------------------------------------------------------------------------*/
58/*---------------------------------------------------------------------------*/
59
60void BlockIndexList::
61reset()
62{
63 m_indexes.clear();
64 m_blocks_index_and_offset.clear();
65 m_original_size = 0;
66 m_block_size = 0;
67 m_nb_block = 0;
68 m_last_block_size = 0;
69}
70
71/*---------------------------------------------------------------------------*/
72/*---------------------------------------------------------------------------*/
73
74void BlockIndexList::
75_setBlockIndexAndOffset(Int32 block, Int32 index, Int32 offset)
76{
77 m_blocks_index_and_offset[block * 2] = index * m_block_size;
78 m_blocks_index_and_offset[(block * 2) + 1] = offset;
79}
80
81/*---------------------------------------------------------------------------*/
82/*---------------------------------------------------------------------------*/
83
84void BlockIndexList::
85_setNbBlock(Int32 nb_block)
86{
87 m_blocks_index_and_offset.resize(nb_block * 2);
88 m_nb_block = nb_block;
89}
90
91/*---------------------------------------------------------------------------*/
92/*---------------------------------------------------------------------------*/
93
94Int32 BlockIndexList::
95_currentIndexPosition() const
96{
97 return m_indexes.size();
98}
99
100/*---------------------------------------------------------------------------*/
101/*---------------------------------------------------------------------------*/
102
103void BlockIndexList::
104_addBlockInfo(const Int32* data, Int16 size)
105{
106 m_indexes.addRange(ConstArrayView<Int32>(size, data));
107}
108
109/*---------------------------------------------------------------------------*/
110/*---------------------------------------------------------------------------*/
111
112Int32 BlockIndexList::
113_computeNbContigusBlock() const
114{
115 // TODO: on doit pouvoir savoir automatiquement si un bloc est contigu
116 // en connaissant son hash et la taille du bloc.
117 if (m_block_size == 0)
118 return 0;
119
120 Int32 nb_reduced_block = m_indexes.size() / m_block_size;
121 const Int32 block_size = m_block_size;
122 // Numéro du bloc contenant les indices continus s'il y en a un
123 Int32 contigu_block_pos = -1;
124
125 for (Int32 i = 0; i < nb_reduced_block; ++i) {
126 bool is_contigu = true;
127 Int32 pos = i * block_size;
128 for (Int32 z = 1; z < block_size; ++z) {
129 if (m_indexes[pos + z] != z) {
130 is_contigu = false;
131 break;
132 }
133 }
134 if (is_contigu) {
135 contigu_block_pos = pos;
136 break;
137 }
138 }
139
140 if (contigu_block_pos < 0)
141 return 0;
142
143 // Le nombre de blocs contigu correspond au nombre de blocs pour
144 // lesquels l'index est 'contigu_block_pos'.
145 Int32 nb_contigu = 0;
146 for (Int32 i = 0, n = m_nb_block; i < n; ++i) {
147 if (m_blocks_index_and_offset[i * 2] == contigu_block_pos)
148 ++nb_contigu;
149 }
150
151 return nb_contigu;
152}
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
156
157/*---------------------------------------------------------------------------*/
158/*---------------------------------------------------------------------------*/
159
160void BlockIndexListBuilder::
161build(BlockIndexList& block_index_list, SmallSpan<const Int32> indexes, const String& name)
162{
163 block_index_list.reset();
164
165 bool is_verbose = m_is_verbose;
166
167 const Int16 block_size = (m_block_size > 0) ? m_block_size : 32;
168 const Int32 original_size = indexes.size();
169 const Int32 nb_fixed_block = original_size / block_size;
170 const Int16 remaining_size = static_cast<Int16>(original_size % block_size);
171 Int32 nb_block = nb_fixed_block;
172 Int16 last_block_size = block_size;
173 if (remaining_size != 0) {
174 ++nb_block;
175 last_block_size = remaining_size;
176 }
177
178 std::unordered_map<std::size_t, Int32> block_indexes;
179 std::hash<Int32> hasher;
180 std::ostringstream o;
181 block_index_list._setNbBlock(nb_block);
182 block_index_list.m_original_size = original_size;
183 block_index_list.m_block_size = block_size;
184 block_index_list.m_last_block_size = last_block_size;
185
186 UniqueArray<Int32> block_index_in_original_array;
187 block_index_in_original_array.reserve(nb_block);
188
189 for (Int32 i = 0; i < nb_fixed_block; ++i) {
190 Int32 iter_index = i * block_size;
191 Int32 first_value = indexes[iter_index];
192 size_t hash = hasher(0);
193
194 // TODO: faire une spécialisation en fonction de la taille de bloc.
195 for (Int32 z = 1; z < block_size; ++z) {
196 Int32 diff = indexes[iter_index + z] - first_value;
197 size_t hash2 = hasher(diff);
198 hash ^= hash2 + 0x9e3779b9 + (hash << 6) + (hash >> 2);
199 }
200
201 auto idx = block_indexes.find(hash);
202 Int32 block_index = -1;
203 if (idx == block_indexes.end()) {
204 // Nouveau bloc.
205 block_index = static_cast<Int32>(block_indexes.size());
206 block_indexes.insert(std::make_pair(hash, block_index));
207 block_index_in_original_array.add(iter_index);
208 }
209 else
210 block_index = idx->second;
211 block_index_list._setBlockIndexAndOffset(i, block_index, first_value);
212
213 if (is_verbose) {
214 o << "\nBlock i=" << std::setw(5) << i;
215 for (Int32 z = 1; z < block_size; ++z) {
216 Int32 diff = indexes[iter_index + z] - first_value;
217 o << " " << std::setw(4) << diff;
218 }
219 o << " H=" << std::hex << hash << std::setbase(0);
220 }
221 }
222
223 // Gère l'éventuel dernier bloc.
224 if (remaining_size != 0) {
225 Int32 iter_index = nb_fixed_block * block_size;
226 Int32 first_value = indexes[iter_index];
227 Int32 block_index = static_cast<Int32>(block_indexes.size());
228 block_index_in_original_array.add(iter_index);
229 block_index_list._setBlockIndexAndOffset(nb_fixed_block, block_index, first_value);
230 }
231
232 // Maintenant qu'on connait le nombre de blocs communs, alloue le tableau
233 // des blocs compressés et recopie les valeurs correspondantes
234 {
235 Int32 local_block_values[BlockIndex::MAX_BLOCK_SIZE];
236 local_block_values[0] = 0;
237 const Int32 nb_reduced_block = static_cast<Int32>(block_indexes.size());
238 block_index_list.m_indexes.reserve((block_size * nb_reduced_block) + remaining_size);
239 for (Int32 i = 0; i < nb_reduced_block; ++i) {
240 Int32 pos = block_index_in_original_array[i];
241 Int32 first_value = indexes[pos];
242 for (Int32 z = 1; z < block_size; ++z) {
243 Int32 diff = indexes[pos + z] - first_value;
244 local_block_values[z] = diff;
245 }
246 block_index_list.m_indexes.addRange(ConstArrayView<Int32>(block_size, local_block_values));
247 }
248 if (remaining_size != 0) {
249 Int32 pos = nb_fixed_block * block_size;
250 Int32 first_value = indexes[pos];
251 // TODO: regarder pour faire un padding jusqu'à la fin du bloc avec la dernière
252 // valeur (comme ce qui est fait pour les ItemGroup)
253 for (Int32 z = 1; z < remaining_size; ++z) {
254 Int32 diff = indexes[pos + z] - first_value;
255 local_block_values[z] = diff;
256 }
257 block_index_list.m_indexes.addRange(ConstArrayView<Int32>(remaining_size, local_block_values));
258 }
259 }
260
261 Int32 nb_contigu = block_index_list._computeNbContigusBlock();
262
263 if (is_verbose)
264 info() << o.str();
265 info() << "Group Name=" << name << " original_size = " << original_size << " nb_block = " << nb_block
266 << " nb_contigu=" << nb_contigu
267 << " reduced_nb_block=" << block_indexes.size()
268 << " ratio=" << block_index_list.memoryRatio();
269}
270
271/*---------------------------------------------------------------------------*/
272/*---------------------------------------------------------------------------*/
273
274BlockIndexListBuilder::
275BlockIndexListBuilder(ITraceMng* tm)
276: TraceAccessor(tm)
277{
278}
279
280/*---------------------------------------------------------------------------*/
281/*---------------------------------------------------------------------------*/
282
283void BlockIndexListBuilder::
284setBlockSizeAsPowerOfTwo(Int32 v)
285{
286 if (v < 0)
287 _throwInvalidBlockSize(v);
288 Int32 block_size = 1 << v;
289 if (block_size > BlockIndex::MAX_BLOCK_SIZE)
290 _throwInvalidBlockSize(block_size);
291 m_block_size = static_cast<Int16>(block_size);
292}
293
294/*---------------------------------------------------------------------------*/
295/*---------------------------------------------------------------------------*/
296
297void BlockIndexListBuilder::
298_throwInvalidBlockSize(Int32 block_size)
299{
300 ARCANE_FATAL("Bad value for block size v={0} min=1 max={1}",
301 block_size, BlockIndex::MAX_BLOCK_SIZE);
302}
303
304/*---------------------------------------------------------------------------*/
305/*---------------------------------------------------------------------------*/
306
307} // namespace Arcane
308
309/*---------------------------------------------------------------------------*/
310/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Integer size() const
Nombre d'éléments du vecteur.
void resize(Int64 s)
Change le nombre d'éléments du tableau à s.
void addRange(ConstReferenceType val, Int64 n)
Ajoute n élément de valeur val à la fin du tableau.
void clear()
Supprime les éléments du tableau.
TraceMessage info() const
Flot pour un message d'information.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
double Real
Type représentant un réel.