Estou tentando otimizar um aplicativo MPI com um padrão de comunicação altamente assíncrono. Cada classificação possui uma lista de itens a serem calculados e envia mensagens conforme necessário, se as entradas ou saídas residirem em uma classificação diferente. Além disso, cada classificação é encadeada (atualmente com um encadeamento de comunicação e 5 trabalhadores).
Eu instrumentei o código com timers em torno das diferentes partes críticas de desempenho, o que me fornece uma lista de triplos (início, fim, tipo) para cada thread. Traçados de maneira óbvia, com o tempo como eixo horizontal, a classificação e a linha como a vertical e a cor indicando o que cada linha está fazendo atualmente, recebo uma imagem como essa para 16 fileiras com 6 linhas / classificação:
Minha pergunta é: quais são outras maneiras de visualizar esses dados que podem ajudar a identificar problemas de desempenho? Alguém tem um tipo favorito de plot que eles usam ao criar um perfil de aplicativos assíncronos?
Esse conjunto de dados é limitado por não conhecer a estrutura do fluxo de dados, mas eu gostaria de obter o máximo de informações possível antes de tentar coletar algo mais complicado.
A imagem não compactada está aqui , caso alguém queira olhar em volta (falha ao fazer o upload pela rota normal). Infelizmente, o Firefox não aceita, mesmo que eu acredite que seja válido, possivelmente porque é muito grande.
fonte
Respostas:
Passo muito tempo escrevendo e depurando código paralelo, com memória compartilhada e / ou distribuída, mas sem conhecer seu problema específico, só posso lhe dizer o que funciona melhor para mim.
Sabendo que rotinas tomar quanto tempo é uma coisa importante, se você está olhando para a eficiência computacional, mas se você está preocupado com a eficiência paralela, então você deve estar mais preocupado com o que o seu código está fazendo quando é não fazer qualquer cálculo. É como se preocupar com o que as crianças estão fazendo quando está muito quieto ...
Como você está usando uma abordagem híbrida de memória compartilhada / distribuída, acho que seu código está, nos espaços em branco, aguardando uma chamada MPI ou uma variável mutex / condition. Você também pode agrupar essas chamadas em timers, e isso lhe dará uma imagem melhor do que está atrasando você, por exemplo, se é sempre a mesma condicional ou sempre a mesma em
MPI_REDUCE
que seus threads ficam presos.Um software que uso com bastante frequência é o Intel Vtune Amplifier XE . Ele possui um bom recurso / opção de plotagem que visualiza a simultaneidade do encadeamento. O programa desenhará um gráfico muito semelhante ao seu, mas quando um encadeamento aguarda uma variável mutex ou condição, ele desenha uma linha diagonal do encadeamento em espera, no momento em que começou a aguardar, para o encadeamento que realmente liberou o mutex ou sinalizou a condição que estava aguardando, no momento em que foi liberada / sinalizada. Isso pode ser bastante confuso, mas faz com que gargalos apareçam imediatamente.
Finalmente, também coleciono estatísticas em massa, por exemplo, para cada chamada mutex / sinal / MPI, quais foram os tempos médio e máximo de espera? Qual é o histograma dos tempos de espera coletados? Enquanto o enredo fornece uma boa visão geral, ele pode ficar bastante confuso quando se trata de detalhes finos.
Finalmente, uma pergunta que não deve ser subestimada: como você está coletando seus horários? O seu timer não é intrusivo o suficiente para não influenciar o seu código? Eu uso a contagem de instruções da CPU sempre que possível, ou seja,
RDTSC
em arquiteturas x86. Isso geralmente adiciona apenas uma única instrução ao seu código.fonte
constant_tsc
sinalizador definido (verificação/proc/cpuinfo
) e se você usar cada trava para um núcleo específico, ou seja, cada segmento sempre lê o mesmo registro do mesmo núcleo, por exemplo, usandopthread_setaffinity_np
. Observe que o último é específico do Linux e, portanto, não é portátil.MPI_Waitsome
, ainda poderá registrar quais solicitações realmente chegaram e de onde. Esta informação pode ou não ser de uso ...Às vezes, você pode obter uma visão alternativa dos problemas de desempenho por meio de uma análise de recursos de alto nível: Existe um gargalo relevante, como a largura de banda da memória? Todo segmento de trabalho faz a mesma quantidade de trabalho? Esses dados podem ser coletados facilmente com o likwid-perfctr do projeto de código do Google LIKWID do conjunto de ferramentas LIKWID . Se o perfil é tal que existem muitos pontos de acesso diferentes, pode ser necessário enfrentá-los um por um. Também pode haver problemas diferentes, dependendo de quantos threads / processos são usados.
fonte
Quando tenho um problema em uma rede de processos altamente assíncronos governados por mensagens ou eventos, uso um método que não é fácil, mas é eficaz. Isso envolvia obter registros dos processos com registro de data e hora, mesclá-los em uma linha do tempo comum e rastrear o progresso de algumas mensagens à medida que desencadeiam atividades, desencadeando outras mensagens. O que estou procurando é um atraso entre o momento em que uma mensagem é recebida e a hora em que é respondida, e a compreensão do motivo do atraso. Quando um problema é encontrado, ele é corrigido e o processo é repetido. Dessa forma, você pode obter um desempenho realmente satisfatório.
É importante ver como isso difere das abordagens em que você mede, mede, mede. A única coisa que a medição pode lhe dizer é para onde não procurar. O ajuste de desempenho real requer uma análise cuidadosa dos detalhes, de uma perspectiva temporal. O que você está procurando não é onde o tempo é gasto, mas onde é gasto desnecessariamente.
Boa sorte.
fonte