2016-08-16 2 views
0

Je vois des résultats étranges de profilage avec gcc -pg et gprof.mauvais résultats gprof avec gcc -Ofast -pg

Je ne trouve pas de moyen de reproduction meilleur/plus petit, donc je suis en train de lier le code réel où je vois le problème.

J'utilise le code here, la construction gprof résultats de profilage avec make prof

Je remarque plusieurs erreurs, principalement:

  1. Une fonction shape_stream_test qui ne devrait jamais même être appelé est présentée comme étant appelée fortement par ai_best_move_rec et prenant jusqu'à 15% du temps d'exécution total en temps libre
  2. Autres fonctions légitimement appelé par ai_best_move_rec comme grid_block_remove, grid_cpy, grid_new ne même pas montrer que les enfants

Statistiques prof Actual:

Flat profile: 

Each sample counts as 0.01 seconds. 
    % cumulative self    self  total   
time seconds seconds calls ms/call ms/call name  
53.92  4.00  4.00 4231936  0.00  0.00 grid_eval 
13.62  5.01  1.01 4467368  0.00  0.00 shape_stream_test 
    6.88  5.52  0.51 4690742  0.00  0.00 grid_block_center_top 
    6.07  5.97  0.45 4521016  0.00  0.00 grid_block_valid 
    5.80  6.40  0.43 4467368  0.00  0.00 grid_block_add 
    3.37  6.65  0.25 4467368  0.00  0.00 grid_block_drop 
    2.02  6.80  0.15  35  4.29 209.20 ai_best_move_rec 
    1.95  6.95  0.15 235469  0.00  0.00 grid_init 
    1.75  7.08  0.13 9212461  0.00  0.00 block_extreme 
    1.48  7.19  0.11 4467402  0.00  0.00 block_move 
    0.94  7.26  0.07 1654899  0.00  0.00 block_get 
    0.54  7.30  0.04        block_crust_get 
    0.40  7.33  0.03        grid_block_set_color 
    0.27  7.35  0.02 4467368  0.00  0.00 grid_block_remove 
    0.27  7.37  0.02 235501  0.00  0.00 block_new 
    0.27  7.39  0.02        grid_block_intersects 
    0.20  7.40  0.02 235469  0.00  0.00 grid_new 
    0.13  7.41  0.01 235467  0.00  0.00 shape_stream_peek 
    0.13  7.42  0.01        drop_amount 
    0.00  7.42  0.00  621  0.00  0.00 grid_clear_lines 
    0.00  7.42  0.00  587  0.00  0.00 grid_cpy 
    0.00  7.42  0.00  35  0.00  0.00 grid_print 
    0.00  7.42  0.00  34  0.00  0.00 block_init 
    0.00  7.42  0.00  34  0.00  0.00 block_print 
    0.00  7.42  0.00  34  0.00  0.00 game_move_print 
    0.00  7.42  0.00  34  0.00  0.00 grid_apply_moves 
    0.00  7.42  0.00  34  0.00  0.00 shape_stream_pop 
    0.00  7.42  0.00  7  0.00  0.00 shape_new 
    0.00  7.42  0.00  1  0.00  0.00 shape_stream_new 

%   the percentage of the total running time of the 
time  program used by this function. 

cumulative a running sum of the number of seconds accounted 
seconds for by this function and those listed above it. 

self  the number of seconds accounted for by this 
seconds function alone. This is the major sort for this 
      listing. 

calls  the number of times this function was invoked, if 
      this function is profiled, else blank. 

self  the average number of milliseconds spent in this 
ms/call function per call, if this function is profiled, 
     else blank. 

total  the average number of milliseconds spent in this 
ms/call function and its descendents per call, if this 
     function is profiled, else blank. 

name  the name of the function. This is the minor sort 
      for this listing. The index shows the location of 
     the function in the gprof listing. If the index is 
     in parenthesis it shows where it would appear in 
     the gprof listing if it were to be printed. 

Copyright (C) 2012-2014 Free Software Foundation, Inc. 

Copying and distribution of this file, with or without modification, 
are permitted in any medium without royalty provided the copyright 
notice and this notice are preserved. 

      Call graph (explanation follows) 


granularity: each sample hit covers 2 byte(s) for 0.13% of 7.42 seconds 

index % time self children called  name 
               <spontaneous> 
[1]  98.7 0.00 7.32     ai_test [1] 
       0.15 7.17  35/35   ai_best_move_rec [2] 
       0.00 0.00  34/34   grid_apply_moves [21] 
       0.00 0.00  2/235469  grid_new [9] 
       0.00 0.00  35/35   grid_print [24] 
       0.00 0.00  34/34   game_move_print [27] 
       0.00 0.00  34/34   shape_stream_pop [28] 
       0.00 0.00  1/1   shape_stream_new [30] 
----------------------------------------------- 
           235432    ai_best_move_rec [2] 
       0.15 7.17  35/35   ai_test [1] 
[2]  98.7 0.15 7.17  35+235432 ai_best_move_rec [2] 
       4.00 0.00 4231936/4231936  grid_eval [3] 
       1.01 0.00 4467368/4467368  shape_stream_test [4] 
       0.51 0.11 4690742/4690742  grid_block_center_top [5] 
       0.45 0.09 4521016/4521016  grid_block_valid [6] 
       0.43 0.00 4467368/4467368  grid_block_add [7] 
       0.25 0.00 4467368/4467368  grid_block_drop [8] 
       0.02 0.15 235467/235469  grid_new [9] 
       0.11 0.00 4467368/4467402  block_move [12] 
       0.02 0.00 4467368/4467368  grid_block_remove [16] 
       0.02 0.00 235467/235501  block_new [17] 
       0.01 0.00 235467/235467  shape_stream_peek [19] 
       0.00 0.00  587/587   grid_cpy [23] 
       0.00 0.00  587/621   grid_clear_lines [22] 
           235432    ai_best_move_rec [2] 
----------------------------------------------- 
       4.00 0.00 4231936/4231936  ai_best_move_rec [2] 
[3]  53.9 4.00 0.00 4231936   grid_eval [3] 
----------------------------------------------- 
       1.01 0.00 4467368/4467368  ai_best_move_rec [2] 
[4]  13.6 1.01 0.00 4467368   shape_stream_test [4] 
----------------------------------------------- 
       0.51 0.11 4690742/4690742  ai_best_move_rec [2] 
[5]  8.4 0.51 0.11 4690742   grid_block_center_top [5] 
       0.07 0.00 4690742/9212461  block_extreme [11] 
       0.04 0.00 1056160/1654899  block_get [13] 
----------------------------------------------- 
       0.45 0.09 4521016/4521016  ai_best_move_rec [2] 
[6]  7.3 0.45 0.09 4521016   grid_block_valid [6] 
       0.06 0.00 4521016/9212461  block_extreme [11] 
       0.03 0.00 598739/1654899  block_get [13] 
----------------------------------------------- 
       0.43 0.00 4467368/4467368  ai_best_move_rec [2] 
[7]  5.8 0.43 0.00 4467368   grid_block_add [7] 
----------------------------------------------- 
       0.25 0.00 4467368/4467368  ai_best_move_rec [2] 
[8]  3.4 0.25 0.00 4467368   grid_block_drop [8] 
       0.00 0.00  635/9212461  block_extreme [11] 
----------------------------------------------- 
       0.00 0.00  2/235469  ai_test [1] 
       0.02 0.15 235467/235469  ai_best_move_rec [2] 
[9]  2.2 0.02 0.15 235469   grid_new [9] 
       0.15 0.00 235469/235469  grid_init [10] 
----------------------------------------------- 
       0.15 0.00 235469/235469  grid_new [9] 
[10]  2.0 0.15 0.00 235469   grid_init [10] 
----------------------------------------------- 
       0.00 0.00  68/9212461  grid_apply_moves [21] 
       0.00 0.00  635/9212461  grid_block_drop [8] 
       0.06 0.00 4521016/9212461  grid_block_valid [6] 
       0.07 0.00 4690742/9212461  grid_block_center_top [5] 
[11]  1.8 0.13 0.00 9212461   block_extreme [11] 
----------------------------------------------- 
       0.00 0.00  34/4467402  grid_apply_moves [21] 
       0.11 0.00 4467368/4467402  ai_best_move_rec [2] 
[12]  1.5 0.11 0.00 4467402   block_move [12] 
----------------------------------------------- 
       0.03 0.00 598739/1654899  grid_block_valid [6] 
       0.04 0.00 1056160/1654899  grid_block_center_top [5] 
[13]  0.9 0.07 0.00 1654899   block_get [13] 
----------------------------------------------- 
               <spontaneous> 
[14]  0.5 0.04 0.00     block_crust_get [14] 
----------------------------------------------- 
               <spontaneous> 
[15]  0.4 0.03 0.00     grid_block_set_color [15] 
----------------------------------------------- 
       0.02 0.00 4467368/4467368  ai_best_move_rec [2] 
[16]  0.3 0.02 0.00 4467368   grid_block_remove [16] 
----------------------------------------------- 
       0.00 0.00  34/235501  grid_apply_moves [21] 
       0.02 0.00 235467/235501  ai_best_move_rec [2] 
[17]  0.3 0.02 0.00 235501   block_new [17] 
----------------------------------------------- 
               <spontaneous> 
[18]  0.3 0.02 0.00     grid_block_intersects [18] 
----------------------------------------------- 
       0.01 0.00 235467/235467  ai_best_move_rec [2] 
[19]  0.1 0.01 0.00 235467   shape_stream_peek [19] 
----------------------------------------------- 
               <spontaneous> 
[20]  0.1 0.01 0.00     drop_amount [20] 
----------------------------------------------- 
       0.00 0.00  34/34   ai_test [1] 
[21]  0.0 0.00 0.00  34   grid_apply_moves [21] 
       0.00 0.00  34/235501  block_new [17] 
       0.00 0.00  68/9212461  block_extreme [11] 
       0.00 0.00  34/4467402  block_move [12] 
       0.00 0.00  34/34   block_init [25] 
       0.00 0.00  34/621   grid_clear_lines [22] 
----------------------------------------------- 
       0.00 0.00  34/621   grid_apply_moves [21] 
       0.00 0.00  587/621   ai_best_move_rec [2] 
[22]  0.0 0.00 0.00  621   grid_clear_lines [22] 
----------------------------------------------- 
       0.00 0.00  587/587   ai_best_move_rec [2] 
[23]  0.0 0.00 0.00  587   grid_cpy [23] 
----------------------------------------------- 
       0.00 0.00  35/35   ai_test [1] 
[24]  0.0 0.00 0.00  35   grid_print [24] 
----------------------------------------------- 
       0.00 0.00  34/34   grid_apply_moves [21] 
[25]  0.0 0.00 0.00  34   block_init [25] 
----------------------------------------------- 
       0.00 0.00  34/34   game_move_print [27] 
[26]  0.0 0.00 0.00  34   block_print [26] 
----------------------------------------------- 
       0.00 0.00  34/34   ai_test [1] 
[27]  0.0 0.00 0.00  34   game_move_print [27] 
       0.00 0.00  34/34   block_print [26] 
----------------------------------------------- 
       0.00 0.00  34/34   ai_test [1] 
[28]  0.0 0.00 0.00  34   shape_stream_pop [28] 
----------------------------------------------- 
       0.00 0.00  7/7   shapes_read [68] 
[29]  0.0 0.00 0.00  7   shape_new [29] 
----------------------------------------------- 
       0.00 0.00  1/1   ai_test [1] 
[30]  0.0 0.00 0.00  1   shape_stream_new [30] 
----------------------------------------------- 

This table describes the call tree of the program, and was sorted by 
the total amount of time spent in each function and its children. 

Each entry in this table consists of several lines. The line with the 
index number at the left hand margin lists the current function. 
The lines above it list the functions that called this function, 
and the lines below it list the functions this one called. 
This line lists: 
    index A unique number given to each element of the table. 
     Index numbers are sorted numerically. 
     The index number is printed next to every function name so 
     it is easier to look up where the function is in the table. 

    % time This is the percentage of the `total' time that was spent 
     in this function and its children. Note that due to 
     different viewpoints, functions excluded by options, etc, 
     these numbers will NOT add up to 100%. 

    self This is the total amount of time spent in this function. 

    children This is the total amount of time propagated into this 
     function by its children. 

    called This is the number of times the function was called. 
     If the function called itself recursively, the number 
     only includes non-recursive calls, and is followed by 
     a `+' and the number of recursive calls. 

    name The name of the current function. The index number is 
     printed after it. If the function is a member of a 
     cycle, the cycle number is printed between the 
     function's name and the index number. 


For the function's parents, the fields have the following meanings: 

    self This is the amount of time that was propagated directly 
     from the function into this parent. 

    children This is the amount of time that was propagated from 
     the function's children into this parent. 

    called This is the number of times this parent called the 
     function `/' the total number of times the function 
     was called. Recursive calls to the function are not 
     included in the number after the `/'. 

    name This is the name of the parent. The parent's index 
     number is printed after it. If the parent is a 
     member of a cycle, the cycle number is printed between 
     the name and the index number. 

If the parents of the function cannot be determined, the word 
`<spontaneous>' is printed in the `name' field, and all the other 
fields are blank. 

For the function's children, the fields have the following meanings: 

    self This is the amount of time that was propagated directly 
     from the child into the function. 

    children This is the amount of time that was propagated from the 
     child's children to the function. 

    called This is the number of times the function called 
     this child `/' the total number of times the child 
     was called. Recursive calls by the child are not 
     listed in the number after the `/'. 

    name This is the name of the child. The child's index 
     number is printed after it. If the child is a 
     member of a cycle, the cycle number is printed 
     between the name and the index number. 

If there are any cycles (circles) in the call graph, there is an 
entry for the cycle-as-a-whole. This entry shows who called the 
cycle (as parents) and the members of the cycle (as children.) 
The `+' recursive calls entry shows the number of function calls that 
were internal to the cycle, and the calls entry for each member shows, 
for that member, how many times it was called from other members of 
the cycle. 

Copyright (C) 2012-2014 Free Software Foundation, Inc. 

Copying and distribution of this file, with or without modification, 
are permitted in any medium without royalty provided the copyright 
notice and this notice are preserved. 

Index by function name 

    [2] ai_best_move_rec  [21] grid_apply_moves  [3] grid_eval 
    [14] block_crust_get   [7] grid_block_add   [10] grid_init 
    [11] block_extreme   [5] grid_block_center_top [9] grid_new 
    [13] block_get    [8] grid_block_drop  [24] grid_print 
    [25] block_init    [18] grid_block_intersects [29] shape_new 
    [12] block_move    [16] grid_block_remove  [30] shape_stream_new 
    [17] block_new    [15] grid_block_set_color [19] shape_stream_peek 
    [26] block_print    [6] grid_block_valid  [28] shape_stream_pop 
    [20] drop_amount   [22] grid_clear_lines  [4] shape_stream_test 
    [27] game_move_print  [23] grid_cpy 

wrong call graph with -Ofast Plus tard, je découvre que je les drapeaux -Ofast combinant et -pg, et la suppression de ces questions -Ofast arrange ci-dessus.

enter image description here

Mes questions sont les suivantes:

  1. -ce que ces deux drapeaux incompatibles? Si je ne pouvais pas trouver un tel avertissement dans les docs

  2. Si elles ne sont pas incompatibles, est-ce un bug de gcc?

  3. Comment puis-je contourner ce problème pour voir les résultats de profilage correspondant aux optimisations les plus agressives afin de ne pas perdre de temps à optimiser le mauvais code?

Répondre

1

Vous voulez de la vitesse, non? -Ofast seulement les questions au bas de la pile d'appel. Il ne peut pas réparer les choses que vous seul pouvez réparer. Cela ne peut que les rendre plus difficiles à trouver. Commencez par désactiver l'optimiseur et corrigez les problèmes que vous pouvez résoudre. Here's an example of how some people do it. Lorsque vous êtes allé aussi loin que possible, allumez l'optimiseur et laissez-le faire sa magie.

Petite flamme :) Beaucoup de gens disent que c'est une perte de temps pour profiler le code non optimisé, mais ils ne disent jamais pourquoi. Ils l'ont entendu dans un amphithéâtre, l'ont lu sur un blog, ou à partir de stackoverflow, de quelqu'un dont l'autorité claire sur le sujet évite le besoin de donner une raison.

Je pense que c'est un cas de vœu pieux: Mon code est fondamentalement parfait, donc les seules façons dont il pourrait être accéléré sont d'exécuter l'optimiseur du compilateur. Ensuite, quand le profiler ne montre aucun moyen de l'accélérer - c'est évidemment juste et hourra pour moi!

Ajoutée en réponse aux commentaires: Permettez-moi de digresser un peu (désolé). Je comprends que l'on peut passer en revue le code attentivement, investir des efforts dans les représentations de données, intégrer certaines fonctions, effectuer d'autres optimisations de haut niveau et mesurer les excès de vitesse. Génial. Mais si la raison de chaque changement de code est de regarder et de simplement penser au code, alors aussi éduqué que votre pensée est, c'est encore une supposition. Une supposition peut être juste, mais la question que vous devriez vous poser est: "Qu'est-ce que j'ai manqué?" et "Comment puis-je le trouver?"

La méthode que beaucoup de gens et j'utilise est random pausing. Le seul outil dont il a besoin est un débogueur, comme GDB ou tout IDE. Il diffère du profilage en ce qu'il localise le calcul inutile directement, plutôt que de prendre des mesures et de compter sur vous pour les déchiffrer, filtrer le bruit, regarder des routines particulières, et chasser à l'intérieur. Il vous indique les lignes de code particulières, et les données particulières, ce que le programme fait et pourquoi il le fait. Ensuite, vous pouvez demander s'il y a un moyen moins coûteux de le faire, et il y a des chances qu'il y en ait. Ce qu'il fait pas ne vous dit la fraction précise de temps - vous obtenez seulement une mesure très grossière. Qu'est-ce que fait est d'identifier le problème. Vous pourriez penser que vous ne pouvez certainement pas dépendre d'une telle méthode inexacte, et c'est vrai si vous ne voyez que le problème sur un échantillon un. Mais si vous le voyez sur plus d'un échantillon, vous savez qu'il est grand, et le moins d'échantillons globaux que vous avez pris pour le voir plus d'une fois, plus il est grand. Here are the statistics behind it. Et voici le kicker: il trouvera tout problème rencontré par un profileur, et plus encore.

Ensuite, lorsque vous trouvez et corrigez un problème, vous pouvez tout recommencer, car la suppression d'un problème amplifie les problèmes restants. De cette façon, vous pouvez "échelonner" les accélérations jusqu'à ce que vous ne pouvez plus. Voilà comment vous obtenez la vitesse maximale as in this example. Ensuite, par tous les moyens, utilisez -Ofast.

+0

Je pense que par «les choses que vous pouvez réparer», vous parlez d'optimisations de niveau supérieur. Mais dans ce cas, je suis intéressé à faire manuellement des optimisations de bas niveau. C'est pourquoi sans -je ne pense pas que je reçois une représentation précise des parties du code qui méritent mon attention. Je suis également très intéressé à comprendre pourquoi cette fonction non apparentée, non appelée, apparaît dans les statistiques, si les drapeaux sont incompatibles ou s'il s'agit d'un bug. – erjoalgo

+0

@erjoalgo: Gosh, plusieurs points. Tout d'abord, même si gprof n'avait pas de bugs, [* il a beaucoup de problèmes *] (http://stackoverflow.com/a/1779343/23771), les gens pourraient se demander pourquoi vous prenez la peine de lutter avec lui. Deuxièmement, si la vitesse est votre objectif, pourquoi les optimisations de haut niveau ne valent-elles pas votre attention? Troisièmement, tout ce que vous pourriez faire pour accélérer le code de bas niveau est évident dans un code non optimisé. Si le compilateur optimise un peu de code de bas niveau, cela ne fait pas que les choses que vous * * * pourraient faire plus évidentes (même si * * * montraient toutes les fonctions). Si vous voulez, je vais essayer d'expliquer cela plus en détail. –

+0

Sur ce projet particulier, j'ai investi suffisamment d'efforts dans la représentation des données et les algorithmes pour minimiser la complexité. J'ai donc déjà consacré beaucoup d'efforts à des optimisations de haut niveau, et j'aimerais attraper les fruits à portée de main. Par exemple, j'ai déjà gagné une accélération significative par le manuel en ligne de certains calculs, en s'éloignant d'une bibliothèque de tri, etc. – erjoalgo