• [^] # Re: Quitte à faire du branchless

    Posté par (site web personnel) . En réponse au journal Exercices de programmation et benchmarks. Évalué à 2.

    Tiens, dis-moi, j'essaye le même genre de truc sur la version indices, qui maintient une liste les indices des colonnes pertinentes :

    int matrix_elements_sum_indices_branchless
    (const std::vector<std::vector<int>>& matrix)
    {
     const int row_size(matrix[0].size());
     std::vector<int> usable_columns(row_size);
     const auto usable_columns_begin(usable_columns.begin());
     auto usable_columns_end(usable_columns.end());
     std::iota(usable_columns_begin, usable_columns_end, 0);
     int remaining_count(row_size);
     int result(0);
     for (const std::vector<int>& row : matrix)
     for (auto it(usable_columns_begin); it != usable_columns_end; )
     {
     const int i(*it);
     const int v(row[i]);
     result += v;
     const int keep_mask((v == 0) ? 0 : -1);
     usable_columns_end += ~keep_mask;
     // discussion ci-dessous sur le code d'ici...
     const int distance_to_last(usable_columns_end - it);
     const auto new_i_it(it + (distance_to_last & ~keep_mask));
     *it = *new_i_it;
     // ...à là.
     it += -keep_mask;
     }
     return result;
    }

    Ça ne fonctionne pas très bien et je pense que c'est à cause de l'écriture dans le bloc d'ici à là. Si je mets à la place de ce bloc la condition suivante :

     if (~keep_mask)
     *it = *usable_columns_end;

    Alors ça fonctionne très bien.

    Ma compréhension est grosso-modo que dans la première version on réécrit inconditionnellement dans la mémoire pointée par it, et bien qu'elle est probablement en cache (on vient juste d'y accéder) et que sa valeur ne change pas toujours, la ligne de cache devient toujours dirty et il faut la renvoyer en RAM. Du coup on paye une écriture à chaque itération, qui coûte bien plus cher qu'une misprediction occasionnelle. Qu'en penses tu ?