Pergunta

Profiling algum número C ++ trituração de código com ambos gprof e kcachegrind dá resultados semelhantes para as funções que mais contribuem para o tempo de execução (50-80% dependendo da entrada), mas para funções entre 10-30% ambas essas ferramentas dão resultados diferentes . Será que isso significa um deles não é confiável? O que yo fazer aqui?

Foi útil?

Solução

gprof é realmente muito primitivo. Aqui está o que ele faz. 1) É amostras do contador de programa a uma taxa constante e registros de quantas amostras pousar em cada função (tempo exclusivo). 2) Ele conta quantas vezes qualquer função Uma chama qualquer função B. Desde que ele pode descobrir quantas vezes cada função foi chamada no total, e o que é o tempo médio exclusivo foi. Para obter o tempo médio inclusivo de cada função se propaga tempo exclusivo para cima no gráfico de chamadas.

Se você está esperando isso para ter algum tipo de precisão, você deve estar ciente de algumas questões. Primeiro, ele só conta CPU-time-in-process, o que significa que é cego para I / O ou outras chamadas de sistema. Em segundo lugar, a recursividade confunde. Em terceiro lugar, a premissa de que as funções sempre respeitar um tempo médio prazo, não importa quando eles são chamados ou que os chama, é muito suspeito. Forth, a noção de que funções (e seu gráfico de chamada) é o que você precisa saber sobre, ao invés de linhas de código, é simplesmente uma suposição popular, nada mais. Em quinto lugar, a noção de que a precisão da medição é mesmo relevantes para encontrar "gargalos" também é apenas uma suposição popular, nada mais.

Callgrind pode trabalhar no nível de linhas - isso é bom. Infelizmente ele compartilha os outros problemas.

Se o seu objetivo é encontrar "gargalos" (em oposição a obtenção de medidas gerais), você deve dar uma olhada na parede-relógio samplers pilha vez que o relatório por cento por linha, como Zoom . A razão é simples, mas possivelmente desconhecida.

Suponha que você tenha um programa com um monte de funções que chamam um ao outro que leva um total de 10 segundos. Além disso, há um sampler que as amostras, e não apenas o contador de programa, mas toda a pilha de chamadas, e ele faz isso o tempo todo a uma taxa constante, como 100 vezes por segundo. (Ignorar outros processos para agora.)

Assim, no final você tem 1000 amostras da pilha de chamadas. Escolha qualquer linha de código G que aparece em mais de um deles. Suponha que você pudesse de alguma forma otimizar essa linha, evitando-lo, removê-lo ou passá-lo fora a um processador realmente muito rápido.

O que aconteceria com essas amostras?

Uma vez que essa linha de código L agora leva (essencialmente) nenhum momento a todos, nenhuma amostra pode batê-lo, de modo que as amostras só iria desaparecer , reduzindo o número total de amostras, e, portanto, do total Tempo! Na verdade, o tempo total seria reduzido pela fração de tempo L tinha sido na pilha, que é aproximadamente a fração de amostras que continham-lo.

Eu não quero ficar muito estatística, mas muitas pessoas pensam que você precisa de um lote de amostras, porque eles acham que a precisão da medição é importante. Não é, se a razão que você está fazendo isso é para descobrir o que corrigir para obter aceleração. A ênfase está em encontrar o que correção, não no medição -lo. Linha L está na pilha alguma fração F do tempo, certo? Então cada amostra tem uma probabilidade F de bater-lo, certo? Assim como jogar uma moeda. Há uma teoria deste, o chamado regra de sucessão . Ela diz que (sob simplificando mas pressupostos gerais), se você jogar uma moeda N vezes, e ver "cabeças" S vezes, você pode estimar a equidade da moeda F como (em média) (S+1)/(N+2). Então, se você tomar como poucos como três amostras, e veja L em dois deles, você sabe o que F é? Claro que não. Mas você não sei em média é (2 + 1) / (3 + 2) ou 60% . Então, isso é quanto tempo você poderia economizar (em média) por "otimizar afastado" linha L. E, claro, as amostras pilha mostrou você exatamente , onde linha L (o "gargalo" **) é. Será que isso realmente importa that você não medi-lo a duas ou três casas decimais?

BTW, é imune a todos os outros problemas mencionados acima .

** I manter colocar aspas em torno de "gargalo", porque o que faz com que a maioria dos softwares lento não tem nada em comum com o gargalo de uma garrafa. Uma metáfora melhor é uma "fuga." - algo que apenas desnecessariamente desperdiça tempo

Outras dicas

dados o tempo de gprof é estatística (leia sobre isso em detalhes do perfil de docs ).

Por outro lado, KCacheGrind usa valgrind que realmente interpreta todo o código.

Assim KCacheGrind pode ser "mais preciso" (à custa de mais sobrecarga) se o CPU modelado por valgrind está perto de seu CPU real.

Qual escolher também depende de que tipo de sobrecarga que você pode manipular. Na minha experiência, gprof acrescenta menos sobrecarga runtime (tempo de execução que é), mas é mais intrusivo (ou seja -pg adiciona código para todos e cada um de seus funções). Assim, dependendo da situação, em ou outro é mais adequado.

Para "melhor" dados gprof, executar o código mais longo (e sobre a mais ampla gama de dados de teste que você pode). Quanto mais você tem, melhor as medidas serão estatisticamente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top