From cb97f097d9e7b9bc338fdec8689b45ab40c905c4 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Tue, 6 Feb 2024 02:25:11 +0100 Subject: Find free interleaving indexes for the ACISM backend using a dedicated search. --- src/analysis/scan/patterns/backends/acism.c | 71 +++++-- src/common/bits.c | 279 ++++++++++++++++++++++++---- src/common/bits.h | 13 ++ 3 files changed, 318 insertions(+), 45 deletions(-) diff --git a/src/analysis/scan/patterns/backends/acism.c b/src/analysis/scan/patterns/backends/acism.c index d517168..aa462a7 100644 --- a/src/analysis/scan/patterns/backends/acism.c +++ b/src/analysis/scan/patterns/backends/acism.c @@ -813,13 +813,16 @@ static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend) size_t last_free_state; /* Dernier emplacement dispo. */ size_t full_size; /* Cartographie entière */ bitfield_t *global_usage; /* Cartographie des usages */ +#ifndef NDEBUG + size_t pops[3]; /* Décomptes individuels */ + size_t bsum; /* Somme de tous les bits */ +#endif bitfield_t *usage; /* Cartographie locale */ acism_trie_node_t *node; /* Noeud en cours de traitement*/ + size_t highest; /* Poids du bit le plus fort */ acism_trie_node_t *iter; /* Boucle de parcours #2 */ + size_t first_freedom_word; /* Premier mot avec des dispos.*/ size_t free_state; /* Emplacement libre trouvé */ - bool found; /* Bilan de recherche */ - - size_t bsum; /* Préparation de la liste de noeuds à inscrire */ @@ -841,8 +844,16 @@ static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend) full_size = last_free_state + 257; global_usage = create_bit_field(full_size, false); +#ifndef NDEBUG + + pops[0] = 0; + pops[1] = 0; + pops[2] = 0; + bsum = 0; +#endif + usage = create_bit_field(257, false); for (i = 0; i < backend->nodes_used; i++) @@ -855,26 +866,49 @@ static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend) /* Préparation du masque du noeud */ + truncate_bit_field(&usage, 257); + reset_all_in_bit_field(usage); set_in_bit_field(usage, 0, 1); +#ifndef NDEBUG + pops[0]++; +#endif + + highest = 0; + for (iter = node->child; iter != NULL; iter = iter->sibling) + { set_in_bit_field(usage, iter->code, 1); +#ifndef NDEBUG + pops[0]++; +#endif + + if (iter->code > highest) + highest = iter->code; + + } + +#ifndef NDEBUG + pops[1] += popcount_for_bit_field(usage); +#endif + assert(popcount_for_bit_field(usage) == (node->children_count + 1)); + truncate_bit_field(&usage, ++highest); + /* Recherche d'une position idéale */ if (i == 0) + { + first_freedom_word = 0; free_state = 0; + } else - for (free_state = 1; free_state < last_free_state; free_state++) - { - found = test_zeros_within_bit_field(global_usage, free_state, usage); - if (found) break; - } + free_state = find_interleaving_index_for_acism(global_usage, usage, &first_freedom_word); /* Suivi global */ @@ -882,8 +916,10 @@ static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend) or_bit_field_at(global_usage, usage, free_state); +#ifndef NDEBUG bsum += node->children_count + 1; assert(popcount_for_bit_field(global_usage) == bsum); +#endif node->state_index = free_state; @@ -898,6 +934,15 @@ static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend) /* Sotie encadrée */ +#ifndef NDEBUG + + pops[2] = popcount_for_bit_field(global_usage); + + assert(pops[0] == pops[1]); + assert(pops[0] == pops[2]); + +#endif + backend->bitmap_usage = global_usage; delete_bit_field(usage); @@ -934,10 +979,10 @@ static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend) bitfield_t *usage; /* Cartographie locale */ size_t rd_pos; /* Tête de lecture */ size_t wr_pos; /* Tête d'écriture */ + size_t first_freedom_word; /* Premier mot avec des dispos.*/ acism_trie_node_t *node; /* Noeud à traiter */ acism_trie_node_t *iter; /* Boucle de parcours */ size_t free_state; /* Emplacement libre trouvé */ - bool found; /* Bilan de recherche */ max_pos = backend->nodes_used; @@ -970,6 +1015,8 @@ static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend) rd_pos++; + first_freedom_word = 0; + /* Suivi des liens déjà en place */ while (rd_pos < max_pos) @@ -994,11 +1041,7 @@ static void g_acism_backend_prepare_interleave_array(GAcismBackend *backend) /* Recherche d'une position idéale */ - for (free_state = 1; free_state < last_free_state; free_state++) - { - found = test_zeros_within_bit_field(global_usage, free_state, usage); - if (found) break; - } + free_state = find_interleaving_index_for_acism(global_usage, usage, &first_freedom_word); /* Suivi global */ diff --git a/src/common/bits.c b/src/common/bits.c index a037078..1ded7a2 100644 --- a/src/common/bits.c +++ b/src/common/bits.c @@ -38,7 +38,9 @@ struct _bitfield_t { size_t length; /* Nombre de bits représentés */ - size_t requested; /* Nombre de mots alloués */ + + size_t allocated_words; /* Nombre de mots alloués */ + size_t used_words; /* Nombre de mots utilisés */ bool default_state; /* Etat d'initialisation */ @@ -73,18 +75,20 @@ static bool test_state_within_bit_field(const bitfield_t *, size_t, const bitfie static bitfield_t *_create_bit_field(size_t length) { bitfield_t *result; /* Création à retourner */ - size_t requested; /* Nombre de mots à allouer */ + size_t needed; /* Nombre de mots à allouer */ size_t base; /* Allocation de base en octets*/ - requested = length / (sizeof(unsigned long) * 8); - if (length % (sizeof(unsigned long) * 8) != 0) requested++; + needed = length / (sizeof(unsigned long) * 8); + if (length % (sizeof(unsigned long) * 8) != 0) needed++; - base = sizeof(bitfield_t) + requested * sizeof(unsigned long); + base = sizeof(bitfield_t) + needed * sizeof(unsigned long); result = (bitfield_t *)malloc(base); result->length = length; - result->requested = requested; + + result->allocated_words = needed; + result->used_words = needed; return result; @@ -140,7 +144,7 @@ bitfield_t *dup_bit_field(const bitfield_t *field) result = _create_bit_field(field->length); - memcpy(result->bits, field->bits, result->requested * sizeof(unsigned long)); + memcpy(result->bits, field->bits, result->used_words * sizeof(unsigned long)); return result; @@ -183,7 +187,45 @@ void copy_bit_field(bitfield_t *dest, const bitfield_t *src) { assert(dest->length == src->length); - memcpy(dest->bits, src->bits, dest->requested * sizeof(unsigned long)); + memcpy(dest->bits, src->bits, dest->used_words * sizeof(unsigned long)); + +} + + +/****************************************************************************** +* * +* Paramètres : field = champ de bits à modifier. [OUT] * +* length = nouveau nombre de bits du champ à représenter. * +* * +* Description : Réduit ou étend la taille d'un champ en évitant l'allocation.* +* * +* Retour : - * +* * +* Remarques : Les éventuels bits supplémentaires ou disparus ne sont pas * +* (ré)initialisés. * +* * +******************************************************************************/ + +void truncate_bit_field(bitfield_t **field, size_t length) +{ + bitfield_t *_field; /* Commodité d'accès */ + size_t needed; /* Nombre de mots à allouer */ + + _field = *field; + + needed = length / (sizeof(unsigned long) * 8); + if (length % (sizeof(unsigned long) * 8) != 0) needed++; + + if (needed <= _field->allocated_words) + { + _field->length = length; + + _field->used_words = needed; + + } + + else + resize_bit_field(field, length); } @@ -204,7 +246,7 @@ void copy_bit_field(bitfield_t *dest, const bitfield_t *src) void resize_bit_field(bitfield_t **field, size_t length) { bitfield_t *_field; /* Commodité d'accès */ - size_t requested; /* Nombre de mots à allouer */ + size_t needed; /* Nombre de mots à allouer */ size_t base; /* Allocation de base en octets*/ size_t remaining; /* Nombre de derniers bits */ size_t last; /* Dernier mot utilisé */ @@ -217,18 +259,18 @@ void resize_bit_field(bitfield_t **field, size_t length) { /* Redimensionnement */ - requested = length / (sizeof(unsigned long) * 8); - if (length % (sizeof(unsigned long) * 8) != 0) requested++; + needed = length / (sizeof(unsigned long) * 8); + if (length % (sizeof(unsigned long) * 8) != 0) needed++; - base = sizeof(bitfield_t) + requested * sizeof(unsigned long); - - *field = realloc(_field, base); - _field = *field; + base = sizeof(bitfield_t) + needed * sizeof(unsigned long); /* Initialisation, si nécessaire */ if (_field->length < length) { + *field = realloc(_field, base); + _field = *field; + last = _field->length / (sizeof(unsigned long) * 8); remaining = _field->length % (sizeof(unsigned long) * 8); @@ -245,7 +287,7 @@ void resize_bit_field(bitfield_t **field, size_t length) } - for (i = last; i < requested; i++) + for (i = last; i < needed; i++) { if (_field->default_state) _field->bits[i] = ~0ul; @@ -258,7 +300,9 @@ void resize_bit_field(bitfield_t **field, size_t length) /* Actualisation des tailles */ _field->length = length; - _field->requested = requested; + + _field->allocated_words = needed; + _field->used_words = needed; } @@ -326,12 +370,12 @@ int compare_bit_fields(const bitfield_t *a, const bitfield_t *b) else final = (1 << final) - 1; - for (i = 0; i < a->requested && result == 0; i++) + for (i = 0; i < a->used_words && result == 0; i++) { val_a = a->bits[i]; val_b = b->bits[i]; - if ((i + 1) == a->requested) + if ((i + 1) == a->used_words) { val_a &= final; val_b &= final; @@ -366,7 +410,7 @@ int compare_bit_fields(const bitfield_t *a, const bitfield_t *b) void reset_all_in_bit_field(bitfield_t *field) { - memset(field->bits, 0u, field->requested * sizeof(unsigned long)); + memset(field->bits, 0u, field->used_words * sizeof(unsigned long)); } @@ -385,7 +429,7 @@ void reset_all_in_bit_field(bitfield_t *field) void set_all_in_bit_field(bitfield_t *field) { - memset(field->bits, ~0u, field->requested * sizeof(unsigned long)); + memset(field->bits, ~0u, field->used_words * sizeof(unsigned long)); } @@ -483,7 +527,7 @@ void and_bit_field(bitfield_t *dest, const bitfield_t *src) assert(dest->length == src->length); - for (i = 0; i < dest->requested; i++) + for (i = 0; i < dest->used_words; i++) dest->bits[i] &= src->bits[i]; } @@ -508,7 +552,7 @@ void or_bit_field(bitfield_t *dest, const bitfield_t *src) assert(dest->length == src->length); - for (i = 0; i < dest->requested; i++) + for (i = 0; i < dest->used_words; i++) dest->bits[i] |= src->bits[i]; } @@ -545,14 +589,13 @@ void or_bit_field_at(bitfield_t *dest, const bitfield_t *src, size_t first) remaining = (first + src->length) % (sizeof(unsigned long) * 8); if ((first + src->length) % (sizeof(unsigned long) * 8) > 0) - last_iter = src->requested; + last_iter = src->used_words; else - last_iter = src->requested - 1; - + last_iter = src->used_words - 1; for (i = 0; i <= last_iter; i++) { - if (i < src->requested) + if (i < src->used_words) word = src->bits[i] << offset; else word = 0; @@ -736,7 +779,7 @@ static bool test_state_within_bit_field(const bitfield_t *field, size_t first, c else finalcut = (1lu << remaining) - 1; - for (i = 0; i < mask->requested && result; i++) + for (i = 0; i < mask->used_words && result; i++) { windex = start + i; @@ -746,7 +789,7 @@ static bool test_state_within_bit_field(const bitfield_t *field, size_t first, c else { word = field->bits[windex] >> offset; - if ((windex + 1) < field->requested) + if ((windex + 1) < field->used_words) word |= field->bits[windex + 1] << (sizeof(unsigned long) * 8 - offset); } @@ -756,7 +799,7 @@ static bool test_state_within_bit_field(const bitfield_t *field, size_t first, c test &= bitmask; - if ((i + 1) == mask->requested) + if ((i + 1) == mask->used_words) { bitmask &= finalcut; test &= finalcut; @@ -824,6 +867,128 @@ bool test_ones_within_bit_field(const bitfield_t *field, size_t first, const bit /****************************************************************************** * * * Paramètres : field = champ de bits à consulter. * +* extra = champ de bits à placer. * +* * +* Description : Recherche l'indice idéal pour placer un champ dans un autre. * +* * +* Retour : Position du premier bit à insérer. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t find_interleaving_index_for_acism(const bitfield_t *field, const bitfield_t *extra, size_t *first) +{ + size_t result; /* Dimension à retourner */ + size_t i; /* Boucle de parcours #1 */ + const unsigned long *bits; /* Itérateurs sur les bits */ + size_t init_k; /* Point de départ optimal */ + size_t k; /* Boucle de parcours #2 */ + unsigned long mask; /* Valeur à comparer */ + size_t j; /* Boucle de parcours #3 */ + + /** + * La procédure s'appuie sur deux particularité du contexte d'exécution (scan ACISM) : + * - il y a toujours au moins 257 bits (taille maximale du champs "extra") libres + * en fin de champs "field" ; + * - le premier bit du champ "extra" est toujours fixé à 1. + */ + + result = 0; + + for (i = *first; i < field->used_words; i++) + { + /* S'il ne reste plus aucune place */ + if (field->bits[i] != ~0lu) + break; + } + + *first = i; + + bits = field->bits + i; + + for (; i < field->used_words; i++, bits++) + { + /* S'il ne reste plus aucune place */ + if (*bits == ~0lu) + continue; + + init_k = __builtin_ffsl(~*bits) - 1; + + for (k = init_k; k < __WORDSIZE; k++) + { + /** + * Le champs de bits à placer ne comporte pas forcément au moins + * 32/64 bits, mais les bits non comptabilisés du mot sont toujours + * initialisés à zéro. + * + * Aucune prise en compte particulière d'un champ de petite taille + * n'est donc à réaliser ici. + */ + + mask = (extra->bits[0] << k); + + /* Si tous les bits nécessaires au début sont libres... */ + if ((*bits & mask) == 0) + { + for (j = 1; j < extra->used_words; j++) + { + if (k == 0) + mask = extra->bits[j]; + + else + { + /* Portion du mot courant */ + mask = (extra->bits[j] << k); + + /* Relicat du mot précédent */ + mask |= (extra->bits[j - 1] >> (__WORDSIZE - k)); + + } + + if (mask == 0) + continue; + + if ((bits[j] & mask) != 0) + break; + + } + + if (j == extra->used_words) + { + /* Eventuelle dernière bribe débordant sur un dernier mot ? */ + if (k > 0) + { + mask = (extra->bits[j - 1] >> (__WORDSIZE - k)); + + if ((bits[j] & mask) != 0) + continue; + + } + + result = i * __WORDSIZE + k; + goto found; + + } + + } + + } + + } + + found: + + assert(result > 0); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : field = champ de bits à consulter. * * * * Description : Détermine le nombre de bits à 1 dans un champ. * * * @@ -844,7 +1009,7 @@ size_t popcount_for_bit_field(const bitfield_t *field) remaining = field->length; - for (i = 0; i < field->requested; i++) + for (i = 0; i < field->used_words; i++) { value = field->bits[i]; @@ -866,3 +1031,55 @@ size_t popcount_for_bit_field(const bitfield_t *field) return result; } + + +#if 0 + +/****************************************************************************** +* * +* Paramètres : field = champ de bits à consulter. * +* * +* Description : Imprime sur la sortie standard la valeur représentée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void output_bit_field(const bitfield_t *field) +{ + size_t i; /* Boucle de parcours #1 */ + unsigned long value; /* Valeur masquée à traiter */ + size_t k; /* Boucle de parcours #2 */ + + printf("[len=%zu] \n", field->length); + +#define MAX_BITS (sizeof(unsigned long) * 8) + + for (i = 0; i < field->used_words; i++) + { + value = field->bits[i]; + + if (i > 0) + printf("| "); + + for (k = 0; k < MAX_BITS; k++) + { + if ((i * MAX_BITS + k) >= field->length) + break; + + printf("%c", value & (1lu << k) ? '1' : '.'); + + if ((k + 1) % 8 == 0) + printf(" "); + + } + + } + + printf("\n"); + +} + +#endif diff --git a/src/common/bits.h b/src/common/bits.h index 58fa0fe..8f67d3d 100644 --- a/src/common/bits.h +++ b/src/common/bits.h @@ -45,6 +45,9 @@ void delete_bit_field(bitfield_t *); /* Copie un champ de bits dans un autre. */ void copy_bit_field(bitfield_t *, const bitfield_t *); +/* Réduit ou étend la taille d'un champ en évitant l'allocation. */ +void truncate_bit_field(bitfield_t **, size_t); + /* Redimensionne un champ de bits. */ void resize_bit_field(bitfield_t **, size_t); @@ -90,9 +93,19 @@ bool test_zeros_within_bit_field(const bitfield_t *, size_t, const bitfield_t *) /* Teste l'état à 1 de bits selon un masque de bits. */ bool test_ones_within_bit_field(const bitfield_t *, size_t, const bitfield_t *); +/* Recherche l'indice idéal pour placer un champ dans un autre. */ +size_t find_interleaving_index_for_acism(const bitfield_t *, const bitfield_t *, size_t *); + /* Détermine le nombre de bits à 1 dans un champ. */ size_t popcount_for_bit_field(const bitfield_t *); +#if 0 + +/* Imprime sur la sortie standard la valeur représentée. */ +void output_bit_field(const bitfield_t *); + +#endif + #endif /* _COMMON_BITS_H */ -- cgit v0.11.2-87-g4458