IdentifiantMot de passe
Loading...
Mot de passe oubli� ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les r�ponses en temps r�el, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

aider l'optimiseur pour floor_log_2(n)


Sujet :

C++

Vue hybride

Message pr�c�dent Message pr�c�dent   Message suivant Message suivant
  1. #1
    Membre tr�s actif

    Profil pro
    �tudiant
    Inscrit en
    D�cembre 2004
    Messages
    499
    D�tails du profil
    Informations personnelles :
    �ge : 39
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : D�cembre 2004
    Messages : 499
    Par d�faut aider l'optimiseur pour floor_log_2(n)
    bonjour,

    avez-vous une solution pour aider l'optimiseur � faire du "loop unwinding" ?

    J'ai code qui avec un "while" fait une recherche dichotomique du nombre de bit qu'il faut pour stocker un certain entier (donc qui calcule floor(log2(n)) ),

    et j'aimerais que l'optimiseur me produise un code assembleur dans ce style :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    private static int floorLog2(int i)    //do you see the binary tree? 5 comparisions
        {
            return
            i < 1 << 15 ? i < 1 << 07 ? i < 1 << 03 ? i < 1 << 01 ? i < 1 << 00 ? -1 : 00 :
                                                                    i < 1 << 02 ? 01 : 02 :
                                                      i < 1 << 05 ? i < 1 << 04 ? 03 : 04 :
                                                                    i < 1 << 06 ? 05 : 06 :
                                        i < 1 << 11 ? i < 1 << 09 ? i < 1 << 08 ? 07 : 08 :
                                                                    i < 1 << 10 ? 09 : 10 :
                                                      i < 1 << 13 ? i < 1 << 12 ? 11 : 12 :
                                                                    i < 1 << 14 ? 13 : 14 :
                          i < 1 << 23 ? i < 1 << 19 ? i < 1 << 17 ? i < 1 << 16 ? 15 : 16 :
                                                                    i < 1 << 18 ? 17 : 18 :
                                                      i < 1 << 21 ? i < 1 << 20 ? 19 : 20 :
                                                                    i < 1 << 22 ? 21 : 22 :
                                        i < 1 << 27 ? i < 1 << 25 ? i < 1 << 24 ? 23 : 24 :
                                                                    i < 1 << 26 ? 25 : 26 :
                                                      i < 1 << 29 ? i < 1 << 28 ? 27 : 28 :
                                                                    i < 1 << 30 ? 29 : 30;
    }
    mon code :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
     
    #include <iostream>
    template <typename T> T floor_log_2(T n) {
    	T nb_bit_for_type = sizeof(T) * 8;
    	T M = nb_bit_for_type/4;
    	T d = nb_bit_for_type/2;
    	T res = 0;
     
     
    	while(M) {
    		T tmp = 1 << d;
     
                    if (n < tmp) {
    			d -= M;
    		} else {
    		        d += M;
                    }
    	}
     
    	T tmp = 1 << d;
    	if (n >= tmp) {
    		d += 1;
    	}
     
    	return d ;
    }
     
     
    int main() {
    	int res;
    	res = floor_log_2<unsigned char>(8); // 4
    	res = floor_log_2<unsigned char>(3); // 2
    	res = floor_log_2<unsigned char>(128); // 8
    	res = floor_log_2<unsigned char>(127); // 7
    	res = floor_log_2<unsigned char>(17); // 5
    	res = floor_log_2<unsigned char>(24); // 5
    	res = floor_log_2<unsigned char>(60); // 6
     
    	res = floor_log_2<unsigned char>(1); // 1
    	res = floor_log_2<unsigned char>(0); // 1 (oui)
    	res = floor_log_2<unsigned char>(-1); // 8
     
    	return 0;
    }
    en fait je ne comprends pas bien pourquoi visual 2013 il n'arrive pas � le faire direct (je n'ai pas la derni�re version de gcc si quelqu'un voudrait bien regarder ce que �a donne ?)

    et avec un template r�cursif (M et d comme param�tres template ?) �a peut l'aider ?

  2. #2
    Membre tr�s actif

    Profil pro
    �tudiant
    Inscrit en
    D�cembre 2004
    Messages
    499
    D�tails du profil
    Informations personnelles :
    �ge : 39
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : D�cembre 2004
    Messages : 499
    Par d�faut
    ok avec des templates �a marche nickel il a bien "unwind�" les appels r�cursifs, mais bon �a serait plus cool qu'il arrive � le faire sans qu'on lui pr�m�che le travail.

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    #include <iostream>
     
     
    template <typename T, T d, T M> __inline T floor_log_2_bisT(T n) {
    	T tmp = (1 << d);
    	// int _d = d; int  _res = M; // pour voir les params
    	if (M != 0) {
    		if (n < tmp) {
    			return floor_log_2_bisT<T,d - M, M / 2>(n);
    		} else {
    			return floor_log_2_bisT<T, d + M, M / 2>(n);
    		}
    	} else {
    		if (n < tmp) {
    			return d;
    		} else {
    			return d + 1;
    		}
    	}
    }
     
     
    template <typename T> T _floor_log_2(T n) {
    	T res = floor_log_2_bisT<T,sizeof(T)* 4, sizeof(T)* 2>(n);
    	return res;
    }
    int global;
    unsigned int floor_log_2(unsigned int n) {
            global++; // pour mettre un breakpoint ici en release
    	return _floor_log_2<unsigned int>(n);
    }
     
    int main()
    {
    	int res;
     
    	res = floor_log_2(127); std::cout << res << "\n";
    	res = floor_log_2(128); std::cout << res << "\n";
    	res = floor_log_2(-1); std::cout << res << "\n";
    	res = floor_log_2((1 << 13) + (1 << 15) + 27); std::cout << res << "\n";
    	res = floor_log_2(3); std::cout << res << "\n";
    	res = floor_log_2(1); std::cout << res << "\n";
    	res = floor_log_2(0); std::cout << res << "\n";
    	return 0;
    }

  3. #3
    Membre Expert

    Inscrit en
    Mai 2008
    Messages
    1 014
    D�tails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Par d�faut
    Bonjour,

    Citation Envoy� par acx01b
    en fait je ne comprends pas bien pourquoi visual 2013 il n'arrive pas � le faire direct"
    C'est quand m�me loin d'�tre trivial comme optimisation... l'utilisation des template pour forcer la g�n�ration compl�te de l'arbre binaire me parait �tre une tr�s bonne id�e.

    Cependant si tu recherches des perf maximales je pense que le mieux reste quand m�me d'utiliser l'intrins�que _BitScanReverse qui renvoie justement la position du premier bit � 1 (pour gcc voir __builtin_ctz pour une fonction assez similaire), avec �a tu auras l'assurance que la recherche du bit le plus significatif se fera en une seule instruction, "bsr" sur x86.

    J'ai fait un programme de bench :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
     
    #include <chrono>
    #include <random>
    #include <iostream>
    #include <iomanip>
    #include <vector>
    #include <string>
    #include <intrin.h>
    #pragma intrinsic(_BitScanReverse)
     
    int prevent_optimization = 0;
     
    template <typename T, T d, T M> __forceinline T floor_log_2_bisT(T n)
    {
        T tmp = (1 << d);
        // int _d = d; int  _res = M; // pour voir les params
        if (M != 0) {
            if (n < tmp) {
                return floor_log_2_bisT<T, d - M, M / 2>(n);
            }
            else {
                return floor_log_2_bisT<T, d + M, M / 2>(n);
            }
        }
        else {
            if (n < tmp) {
                return d;
            }
            else {
                return d + 1;
            }
        }
    }
     
     
    template <typename T> T _floor_log_2(T n) {
        T res = floor_log_2_bisT<T, sizeof(T)* 4, sizeof(T)* 2>(n);
        return res;
    }
     
     
    unsigned int floor_log_2_binary_unroll(unsigned int n) {
        return _floor_log_2<unsigned int>(n);
    }
     
     
    int floor_log_2_binary_naive(unsigned int n) {
        int nb_bit_for_type = sizeof(int)* 8;
        int M = nb_bit_for_type / 4;
        int d = nb_bit_for_type / 2;
        int res = 0;
     
     
        while (M) {
            int tmp = 1 << d;
     
            if (n < tmp) {
                d -= M;
            }
            else {
                d += M;
            }
            M = M / 2;
        }
     
        int tmp = 1 << d;
        if (n >= tmp) {
            d += 1;
        }
     
        return d;
    }
     
    int floor_log_2_naive(unsigned int t)
    {
        int r = 1;
        while (t >>= 1)
        {
            r++;
        }
        return r;
    }
     
     
    int floor_log_2_intrinsic(unsigned int t)
    {
        if (t == 0)
            return 1;
     
        unsigned long r;
        _BitScanReverse(&r, t);
        return r + 1;
    }
     
     
    int floor_log_2_intrinsic_noz(unsigned int t)
    {
        // give random result if t == 0
        unsigned long r = 0;
        _BitScanReverse(&r, t);
        return r + 1;
    }
     
     
    template <class Rep, class Period>
    int to_ms(const std::chrono::duration<Rep, Period>& d)
    {
        return std::chrono::duration_cast<std::chrono::milliseconds>(d).count();
    }
     
    template <typename Func>
    void Do(const std::string& desc, const std::vector<int>& v, Func f)
    {
        std::chrono::system_clock clock;
        int res = 0;
     
        auto start = clock.now();
        for (int i : v)
        {
            res += f(i);
        }
        auto end = clock.now();
        prevent_optimization += res;
        std::cout << std::left << std::setw(25) << desc;
        std::cout << " : " << to_ms(end - start) << " ms" << std::endl;
    }
     
    int pick_a_number(int min, int max)
    {
        static std::default_random_engine rng;
        std::uniform_int_distribution<> d(min, max);
        return d(rng);
    }
     
    void test(int nbint, int min, int max)
    {
        std::cout << min << " " << max << std::endl;
        std::vector<int> v;
     
        for (int i = 0; i < nbint; i++)
        {
            v.push_back(pick_a_number(min, max));
        }
     
        Do("floor_log_2_naive", v, &floor_log_2_naive);
        Do("floor_log_2_binary_naive", v, &floor_log_2_binary_naive);
        Do("floor_log_2_binary_unroll", v, &floor_log_2_binary_unroll);
        Do("floor_log_2_intrinsic", v, &floor_log_2_intrinsic);
        Do("floor_log_2_intrinsic_noz", v, &floor_log_2_intrinsic_noz);
        std::cout << std::endl;
    }
     
    int main()
    {
        int nbitem = 100000000;
     
        for (int i = 0; i < 31; i++)
            test(nbitem, 0, 1 << i);
     
        std::cout << prevent_optimization;
     
        return 0;
    }
    Et voici les r�sultats :
    Il est int�ressant de constater que la m�thode dichotomique, m�me avec l'unroll, n'apporte pas un gain si puissant que �a. Au maximum, sur les grands nombres on gagne x4, par contre sur les petits nombres c'est du x1, pas de gain.

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
     
    0 1
    floor_log_2_naive         : 77 ms
    floor_log_2_binary_naive  : 667 ms
    floor_log_2_binary_unroll : 244 ms
    floor_log_2_intrinsic     : 417 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 2
    floor_log_2_naive         : 334 ms
    floor_log_2_binary_naive  : 918 ms
    floor_log_2_binary_unroll : 244 ms
    floor_log_2_intrinsic     : 344 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 4
    floor_log_2_naive         : 497 ms
    floor_log_2_binary_naive  : 1062 ms
    floor_log_2_binary_unroll : 369 ms
    floor_log_2_intrinsic     : 255 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 8
    floor_log_2_naive         : 488 ms
    floor_log_2_binary_naive  : 1158 ms
    floor_log_2_binary_unroll : 550 ms
    floor_log_2_intrinsic     : 192 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 16
    floor_log_2_naive         : 507 ms
    floor_log_2_binary_naive  : 1086 ms
    floor_log_2_binary_unroll : 479 ms
    floor_log_2_intrinsic     : 152 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 32
    floor_log_2_naive         : 541 ms
    floor_log_2_binary_naive  : 1164 ms
    floor_log_2_binary_unroll : 618 ms
    floor_log_2_intrinsic     : 125 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 64
    floor_log_2_naive         : 580 ms
    floor_log_2_binary_naive  : 1101 ms
    floor_log_2_binary_unroll : 478 ms
    floor_log_2_intrinsic     : 110 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 128
    floor_log_2_naive         : 626 ms
    floor_log_2_binary_naive  : 1118 ms
    floor_log_2_binary_unroll : 600 ms
    floor_log_2_intrinsic     : 101 ms
    floor_log_2_intrinsic_noz : 97 ms
     
    0 256
    floor_log_2_naive         : 679 ms
    floor_log_2_binary_naive  : 1049 ms
    floor_log_2_binary_unroll : 486 ms
    floor_log_2_intrinsic     : 97 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 512
    floor_log_2_naive         : 729 ms
    floor_log_2_binary_naive  : 1145 ms
    floor_log_2_binary_unroll : 632 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 1024
    floor_log_2_naive         : 818 ms
    floor_log_2_binary_naive  : 1105 ms
    floor_log_2_binary_unroll : 490 ms
    floor_log_2_intrinsic     : 93 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 2048
    floor_log_2_naive         : 877 ms
    floor_log_2_binary_naive  : 1122 ms
    floor_log_2_binary_unroll : 652 ms
    floor_log_2_intrinsic     : 93 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 4096
    floor_log_2_naive         : 937 ms
    floor_log_2_binary_naive  : 1067 ms
    floor_log_2_binary_unroll : 534 ms
    floor_log_2_intrinsic     : 91 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 8192
    floor_log_2_naive         : 1000 ms
    floor_log_2_binary_naive  : 1121 ms
    floor_log_2_binary_unroll : 674 ms
    floor_log_2_intrinsic     : 93 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 16384
    floor_log_2_naive         : 1110 ms
    floor_log_2_binary_naive  : 1093 ms
    floor_log_2_binary_unroll : 539 ms
    floor_log_2_intrinsic     : 92 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 32768
    floor_log_2_naive         : 1114 ms
    floor_log_2_binary_naive  : 1093 ms
    floor_log_2_binary_unroll : 691 ms
    floor_log_2_intrinsic     : 92 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 65536
    floor_log_2_naive         : 1190 ms
    floor_log_2_binary_naive  : 1047 ms
    floor_log_2_binary_unroll : 584 ms
    floor_log_2_intrinsic     : 93 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 131072
    floor_log_2_naive         : 1217 ms
    floor_log_2_binary_naive  : 1166 ms
    floor_log_2_binary_unroll : 691 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 262144
    floor_log_2_naive         : 1281 ms
    floor_log_2_binary_naive  : 1100 ms
    floor_log_2_binary_unroll : 498 ms
    floor_log_2_intrinsic     : 93 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 524288
    floor_log_2_naive         : 1352 ms
    floor_log_2_binary_naive  : 1104 ms
    floor_log_2_binary_unroll : 626 ms
    floor_log_2_intrinsic     : 93 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 1048576
    floor_log_2_naive         : 1383 ms
    floor_log_2_binary_naive  : 1055 ms
    floor_log_2_binary_unroll : 492 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 2097152
    floor_log_2_naive         : 1440 ms
    floor_log_2_binary_naive  : 1135 ms
    floor_log_2_binary_unroll : 631 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 4194304
    floor_log_2_naive         : 1522 ms
    floor_log_2_binary_naive  : 1075 ms
    floor_log_2_binary_unroll : 490 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 8388608
    floor_log_2_naive         : 1568 ms
    floor_log_2_binary_naive  : 1072 ms
    floor_log_2_binary_unroll : 621 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 16777216
    floor_log_2_naive         : 1615 ms
    floor_log_2_binary_naive  : 1025 ms
    floor_log_2_binary_unroll : 508 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 33554432
    floor_log_2_naive         : 1651 ms
    floor_log_2_binary_naive  : 1139 ms
    floor_log_2_binary_unroll : 637 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 67108864
    floor_log_2_naive         : 1705 ms
    floor_log_2_binary_naive  : 1097 ms
    floor_log_2_binary_unroll : 494 ms
    floor_log_2_intrinsic     : 95 ms
    floor_log_2_intrinsic_noz : 95 ms
     
    0 134217728
    floor_log_2_naive         : 1777 ms
    floor_log_2_binary_naive  : 1092 ms
    floor_log_2_binary_unroll : 651 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 268435456
    floor_log_2_naive         : 1858 ms
    floor_log_2_binary_naive  : 1070 ms
    floor_log_2_binary_unroll : 535 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 536870912
    floor_log_2_naive         : 1913 ms
    floor_log_2_binary_naive  : 1116 ms
    floor_log_2_binary_unroll : 673 ms
    floor_log_2_intrinsic     : 93 ms
    floor_log_2_intrinsic_noz : 96 ms
     
    0 1073741824
    floor_log_2_naive         : 1989 ms
    floor_log_2_binary_naive  : 1072 ms
    floor_log_2_binary_unroll : 536 ms
    floor_log_2_intrinsic     : 94 ms
    floor_log_2_intrinsic_noz : 96 ms

  4. #4
    Membre tr�s actif

    Profil pro
    �tudiant
    Inscrit en
    D�cembre 2004
    Messages
    499
    D�tails du profil
    Informations personnelles :
    �ge : 39
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : D�cembre 2004
    Messages : 499
    Par d�faut
    salut,

    Merci ! Je ne connaissais pas l'existence de ces built-in dans visual (et gcc) !

    http://msdn.microsoft.com/fr-fr/libr...(v=vs.90).aspx

    J'ai regard� _BitScanReverse qui effectivement ne fait que l'instruction assembleur bsr.
    Pourtant partout dans la doc de bsr il disent que le r�sultat est 2^(floor(log_2(n))+1) et non pas floor(log_2(n))+1 (quand on trouve un bit � 1 dans src, le bit correspondant est mis � 1 dans dst).
    La doc de _BitScanReverse elle est correcte.

    Sinon je ne sais pas trop pourquoi ce serait une optimisation non-triviale : � voir.

  5. #5
    Expert �minent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activit� : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par d�faut
    Salut,

    Par habitude, je me m�fies comme de la peste des instructions qui commencent par _ ou par __ : ce sont, typiquement, des instructions propres � une impl�mentation donn�e (microsoft, ou gcc en l'occurrence), qui risquent soit de rendre le code non portable, soit de nous obliger � jouer avec un maximume de directives pr�processeurs
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
     #ifdef WIN32 #elif defined(GCC)
    (ou similaires, bien sur
    A m�diter: La solution la plus simple est toujours la moins compliqu�e
    Ce qui se con�oit bien s'�nonce clairement, et les mots pour le dire vous viennent ais�ment. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 f�vrier 2014
    mon tout nouveau blog

  6. #6
    Membre tr�s actif

    Profil pro
    �tudiant
    Inscrit en
    D�cembre 2004
    Messages
    499
    D�tails du profil
    Informations personnelles :
    �ge : 39
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : D�cembre 2004
    Messages : 499
    Par d�faut
    � mon avis ce type de boucle est triviale � d�plier pour l'optimiseur :

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    int uneFonction(int n) {
    	const int M = une constante;
            int res = 0;
    	while(M) {
                    k opérations simples sur (n,M,res) où k est une constante
    		M /= 2;
    	}
    	return res;
    }
    c'est �quivalent avec M /= cst o� cst > 1 � la place de M/=2 (par contre si cst = 1.0001 la taille du code d�pli� peut devenir beaucoup trop importante et �tre plus lent � cause du cache donc c'est � l'optimiseur d'estimer ce qui est acceptable en taille et le plus rapide).

    Je vais faire quelques tests pour voir si visual et gcc trouvent �a trivial ou non.

  7. #7
    Membre Expert
    Homme Profil pro
    �tudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par d�faut
    Citation Envoy� par Arzar Voir le message
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    0 1
    floor_log_2_intrinsic     : 417 ms
    floor_log_2_intrinsic_noz : 96 ms
    �a co�te tellement cher les branch mispredict :/

    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int floor_log_2_intrinsic(unsigned int t)
    {
        unsigned long r;
        _BitScanReverse(&r, t);
        if(t == 0) {
            r = 0; // cmovz normalement ici
        }
        return r + 1;
    }
    Peut �tre qu'avec �a le compilo virera la branche pour mettre un cmovz.

  8. #8
    Membre tr�s actif

    Profil pro
    �tudiant
    Inscrit en
    D�cembre 2004
    Messages
    499
    D�tails du profil
    Informations personnelles :
    �ge : 39
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : D�cembre 2004
    Messages : 499
    Par d�faut
    salut, comment tu expliques ces perfs juste pour faire un x4 pour t = 0 ou 1
    x2.5 pour t <= 4
    x1 pour t <= 2^16 (le if n'est plus perceptible au niveau perf)


    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    int floor_log_2_intrinsic(unsigned int t) { // 0 <= t < 4
        /** si on décommente ça change les perfs dans certain cas
        if (t == 0) {
            return 1;
        } **/
     
        unsigned long r;
        _BitScanReverse(&r, t);
        return r + 1;
    }
    une hypoth�se "plausible" :

    tu ne crois pas que c'est juste que pour t tr�s petit le proc arrive � faire 5 instructions en m�me temps dont le _BitScanReverse,
    alors que pour t tr�s grand il n'arrive pas � g�rer le _BitScanReverse en parall�le et fait les instructions s�quentiellement ?

    donc si on met le if c'est n�gligeable sauf dans le cas o� il a un r�sultat pr�cabl� pour _BitScanReverse (genre t < 8 ?) qui lui permet d'utiliser ses autres circuits pour faire le prologue/�pilogue de la fonction tant qu'il n'y a pas de if au milieu ?

  9. #9
    Membre Expert
    Homme Profil pro
    �tudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activit� : �tudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par d�faut
    Citation Envoy� par acx01b Voir le message
    salut, comment tu expliques ces perfs juste pour faire un
    C'est les branch mispredicts : mauvaise pr�diction = besoin de vider le pipeline et de recharger les bonnes instructions, et �a, c'est tr�s co�teux.
    Les nombres sont al�atoires, donc les branches impossibles � pr�dire. Pour t < 2, t == 0 sera vrai une fois sur 2 (mais sans suivre de pattern reconnaissable), et globalement le cpu se trompera en permanence, d'o� le surco�t.

    Pour t grand, on � t == 0 (quasiment) toujours faux, c'est facile � pr�dire et le cpu ne se trompera que tr�s rarement.

Discussions similaires

  1. Aider moi svp pour mon pfe
    Par sillimi18 dans le forum Servlets/JSP
    R�ponses: 0
    Dernier message: 19/05/2013, 17h15
  2. Quel optimiseur pour ce probl�me ?
    Par Ceubex dans le forum EDI et Outils pour Java
    R�ponses: 1
    Dernier message: 30/05/2011, 18h26
  3. Optimiseurs pour mod�lisation
    Par Ceubex dans le forum API standards et tierces
    R�ponses: 0
    Dernier message: 05/06/2010, 16h54
  4. R�ponses: 6
    Dernier message: 27/06/2006, 18h54
  5. Aider moi pour sql server et delphi
    Par aqs dans le forum Bases de donn�es
    R�ponses: 6
    Dernier message: 11/06/2005, 21h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo