A estrutura de automação de refinamento de instrumentação de desempenho PIRA aborda a tarefa demorada de gerar uma medida de desempenho razoável para uma base de código desconhecida ao usar o Score-P. Para mais informações consulte nossos artigos:
[PI18] | Jan-Patrick Lehr, Alexander Hück, Christian Bischof. PIRA: automação de refinamento de instrumentação de desempenho. No 5º Workshop Internacional ACM SIGPLAN sobre Inteligência Artificial e Métodos Empíricos para Engenharia de Software e Sistemas de Computação Paralela (AI-SEPS) , páginas 1-10, ACM, 2018. |
[PI19] | Jan-Patrick Lehr, Alexandru Calotoiu, Christian Bischof, Felix Wolf. Refinamento Automático de Instrumentação para Modelagem de Desempenho Empírico. No Workshop Internacional sobre Ferramentas de Programação e Visualização de Desempenho (ProTools) , páginas 40-47, IEEE, 2019. |
[PI21] | Peter Arzt, Yannic Fischler, Jan-Patrick Lehr, Christian Bischof. Detecção automática de desequilíbrio de carga de baixa sobrecarga em aplicações MPI. No Euro-Par 2021: Processamento Paralelo. Notas de aula em Ciência da Computação, vol 12820 , páginas 19-34, Springer, 2021. |
O PIRA executa as quatro fases a seguir (2-4 são iteradas):
O PIRA oferece suporte à filtragem de funções em tempo de compilação e em tempo de execução , incluindo filtragem em tempo de execução de funções MPI por meio de wrappers gerados automaticamente. Na filtragem em tempo de compilação, apenas as funções desejadas são instrumentadas em tempo de compilação, reduzindo significativamente a influência geral da medição. Por outro lado, na filtragem em tempo de execução, o compilador insere ganchos de instrumentação em cada função do aplicativo de destino, e a filtragem ocorre em tempo de execução.
PIRA requer CMake (>=3.16), Clang/LLVM 10, Python 3, Qt5 e OpenMPI 4. Ele (ou MetaCG) fará download (e compilação) posteriormente
Se você deseja construir o PIRA em um ambiente sem acesso à Internet, consulte o script resources/build_submodules.sh
e ajuste-o às suas necessidades.
Clone o repositório PIRA.
$> git clone https://github.com/tudasc/pira
$> cd pira
Segundo, construa os submódulos dependentes usando o script fornecido ou passe valores para as diferentes opções (consulte as informações de uso via -h
para as opções disponíveis). Todos os arquivos baixados e compilados serão colocados em external/src/
enquanto todas as instalações serão colocadas em external/install/
. Especifique o número de processos de compilação a serem gerados para a compilação de recursos externos do PIRA. O script baixará as dependências do PIRA em sua versão padrão. Essas versões também são testadas em nosso CI e espera-se que funcionem.
$> cd resources
$> ./build_submodules.sh -p <ncores>
Como etapa final, o script de construção gravará os caminhos de instalação dos submódulos no arquivo resources/setup_paths.sh
. Se você deseja reconstruir o PIRA, lembre-se de git restore
este arquivo.
Também fornecemos um Dockerfile
(experimental) para construir o PIRA e testá-lo.
$> podman build -t pira:master -f docker/Dockerfile .
Ao executar dentro do contêiner, por exemplo, os testes de integração, invoque os scripts como segue.
$> cd resources
$> . setup_paths.sh
$> cd ../test/integration/GameOfLife # Example test case
# By default PIRA will look into $HOME/.local, which is not currently existent in the docker
# XDG_DATA_HOME signals where to put the profiling data PIRA generates
$> XDG_DATA_HOME=/tmp ./run.sh
Para um exemplo completo de como usar o PIRA, verifique os scripts run.sh
na pasta /test/integration/*
. Um ponto de partida potencialmente bom é a pasta GameOfLife
e seu caso de teste.
Primeiro, configure os caminhos necessários obtendo o script na pasta resources
.
$> cd resources/
$> . setup_paths.sh
Em seguida, você pode executar um exemplo de aplicativo do PIRA em uma implementação muito simples do Game of Life de Conway usando o script run.sh
fornecido na pasta ./test/integration/GameOfLife
.
$> cd ./test/integration/GameOfLife
$> ./run.sh
O script executa todas as etapas necessárias desde o início, ou seja, prepara todos os componentes para um novo código alvo, para finalmente invocar o PIRA. Nas seções subsequentes, as etapas serão explicadas com mais detalhes. As etapas são:
config
Caminho para o arquivo de configuração (argumento obrigatório)--config-version [1,2]
Versão da configuração PIRA, 2 é o padrão e recomendado; 1 está obsoleto.--runtime-filter
Usa filtragem em tempo de execução, o padrão é falso. Na filtragem em tempo de compilação, as funções não são instrumentadas em tempo de compilação, reduzindo significativamente a influência geral da medição, mas exigindo que o alvo seja reconstruído em cada iteração. Por outro lado, com a filtragem de tempo de execução, o compilador insere ganchos de instrumentação em todas as funções do aplicativo de destino.--iterations [number]
Número de iterações do Pira, o valor padrão é 3.--repetitions [number]
Número de repetições de medição, o valor padrão é 3.--tape
Local onde uma fita de registro (um tanto extensa) deve ser gravada.--extrap-dir
O diretório base onde a estrutura de pastas Extra-p é colocada.--extrap-prefix
Prefixo extra-P, deve ser uma sequência de caracteres.--version
Imprime o número da versão da instalação do PIRA--analysis-parameters
Caminho para o arquivo de configuração contendo parâmetros de análise para PGIS. Necessário para o modo Extra-P e LIDe.--slurm-config [path to slurm cfg file]
Permite a execução do código de destino em um cluster slurm. É necessário um arquivo de configuração do slurm. Consulte esta seção para obter mais informações. --hybrid-filter-iters [number]
Recompile após [número] iterações, use a filtragem de tempo de execução entre elas.--export
Anexa os modelos Extra-P gerados e os tamanhos dos conjuntos de dados ao arquivo IPCG do destino.--export-runtime-only
Requer --export
; Anexa apenas o valor médio do tempo de execução de todas as repetições às funções. Disponível apenas quando não estiver usando Extra-P.--load-imbalance-detection [path to cfg file]
Habilita e configura o modo de detecção de desequilíbrio de carga. Por favor, leia esta seção para obter mais informações. O PIRA usa informações do código-fonte para construir uma instrumentação inicial e decidir quais funções adicionar a uma instrumentação durante o refinamento iterativo. Ele fornece uma ferramenta de gráfico de chamadas baseada em Clang que coleta todas as informações necessárias e as gera em um arquivo .json
. Você pode encontrar a ferramenta cgcollector
no subdiretório ./extern/src/metacg/cgcollector
. O PIRA exige que o arquivo callgraph esteja no formato de arquivo MetaCG na versão 2 (MetaCG v2).
Mais informações sobre o CGColector e seus componentes podem ser encontradas na documentação do MetaCG.
A aplicação do CGCollector geralmente acontece em duas etapas.
Inicialmente, cgc
é invocado em todos os arquivos de origem do projeto. por exemplo:
for f in $(find ./src -type f ( -iname "*.c" -o -iname "*.cpp" ) ); do
cgc --metacg-format-version=2 $f
done
Os arquivos .ipcg
criados na etapa 1 são então mesclados em um arquivo geral usando cgmerge
.
"null"
2. Se o seu projeto contém mais de uma função main
, mescle o arquivo apenas com a função main
correta. echo "null" > $IPCG_FILENAME
find ./src -name "*.ipcg" -exec cgmerge $IPCG_FILENAME $IPCG_FILENAME {} +
O gráfico final precisa ser colocado no diretório do analisador callgraph. Como o PGIS é usado atualmente para análise CG, todo o arquivo do programa gerado é copiado para o diretório PGIS. Atualmente é importante que o arquivo do diretório PGIS seja nomeado seguindo o padrão item_flavor.mcg
. Um item representa um aplicativo de destino. Mais sobre os termos sabor e item na próxima seção.
# Assuming $PIRA holds the top-level PIRA directory
$> cp my-app.mcg $PIRA/extern/install/pgis/bin/item_flavor.mcg
A configuração do PIRA contém todas as informações necessárias para que o PIRA execute o processo automático. Os vários diretórios que precisam ser especificados no arquivo de configuração podem ser caminhos absolutos ou caminhos relativos ao caminho de execução do pira . Os caminhos podem conter variáveis de ambiente, por exemplo, $HOME
. Os exemplos foram retirados do exemplo GameOfLife em ./test/integration/GameOfLife
.
O usuário especifica: o diretório no qual procurar itens definidos posteriormente; no exemplo, o diretório é ./gol/serial_non_template
. Esses diretórios recebem aliases, que são desreferenciados usando o sinal '%'. Um item no PIRA é uma aplicação alvo, construída de uma forma específica, razão pela qual está agrupada na configuração em builds .
{
"builds": {
"%gol": {
"items": {
"gol": {
...
}
}
}
}
"directories": {
"gol": "./gol/serial_non_template"
}
}
Cada item especifica qual analisador deve ser usado. O analisador padrão vem com o PIRA e as fontes podem ser encontradas em ./extern/src/metacg/pgis
ou a instalação em ./extern/install/pgis/bin
, respectivamente. O analisador é responsável por orientar o refinamento da instrumentação e é, portanto, uma parte essencial da estrutura PIRA.
O campo argmap especifica os diferentes argumentos que são passados para o aplicativo de destino ao executar os experimentos de desempenho. A forma como os argumentos são passados para o aplicativo de destino é definida por diferentes mapeadores . No exemplo, é usado um mapeador linear , que simplesmente itera os valores do parâmetro denominado tamanho na ordem dada na lista.
"argmap": {
"mapper": "Linear",
"size": [50, 80, 110, 150, 300, 500]
}
O campo dos cubos é o local onde o PIRA deve armazenar os perfis Score-P obtidos. Ele construirá uma árvore de diretórios naquele local, para que o usuário possa, após terminar o PIRA, também invocar facilmente a ferramenta de modelagem Extra-P simplesmente passando-lhe o respectivo local, ou seja, /tmp/pira no exemplo.
"cubes": "/tmp/pira"
O campo de sabores adiciona outro nível de distinção possível, pois os aplicativos alvo podem ser construídos em diferentes sabores . Um exemplo seria especificar diferentes bibliotecas matemáticas às quais o aplicativo de destino deve se vincular.
Finalmente, o diretório functors aponta o PIRA para o local onde ele procura as funções Python fornecidas pelo usuário que, em última análise, informam ao PIRA como construir, executar e analisar o aplicativo de destino. No exemplo, o PIRA é apontado para um diretório chamado functors relativo ao local da configuração.
"flavors": [
"ct"
],
"functors": "./functors",
"mode": "CT"
O campo mode , nesta versão do PIRA, é ignorado.
A partir de agora, o usuário precisa implementar cinco functores diferentes:
analyze_<ITEM>_<FLAVOR>.py
: invoca o analisador.clean_<ITEM>_<FLAVOR>.py
: limpa o diretório de construção.<ITEM>_<FLAVOR>.py
: cria a versão instrumentada.no_instr_<ITEM>_<FLAVOR>.py
: constrói a versão vanilla.runner_<ITEM>_<FLAVOR>.py
: executa o aplicativo de destino. Os functores, geralmente, suportam dois modos de invocação: ativo e passivo . O functor informa ao PIRA qual modo ele usa, definindo o respectivo valor como True
no dicionário retornado pela função get_method()
.
No modo ativo, o próprio functor invoca os comandos necessários, por exemplo, para construir o software. Quando invocado, o functor recebe um parâmetro **kwargs
contendo, por exemplo, o diretório atual e uma instância de um shell de subprocesso.
O modo passivo retorna apenas os comandos a serem executados, por exemplo, a string make
para invocar um Makefile simples no diretório de nível superior do item. Também é passado um parâmetro kwargs
que contém informações específicas, como valores predefinidos necessários para adicionar a CXXFLAGS ou sinalizadores de linker adicionais. Um exemplo de functor passivo pode ser encontrado nos diretórios de examples
e test
. Atualmente, todos os functores implementados utilizam o modo passivo.
O PIRA passa os seguintes argumentos de palavras-chave para todos os functores. Além disso, diferentes componentes do PIRA podem passar argumentos adicionais.
Importante : agora enviamos nossa própria versão Score-P. Assim, não é mais necessário ajustar os comandos de compilação no PIRA. Confira os functores em test/integration/AMG2013
para ver exemplos de uso das diferentes informações.
Atualmente, nenhuma informação é passada para todos os functores
[0]
acessa o primeiro argumento, [1]
o segundo, e assim por diante..so
que implementa as funções do wrapper MPI (crucial para a filtragem MPI). Parâmetros adicionais são necessários para alguns modos de análise. Especificamente, a análise de modelagem PIRA LIDe (veja abaixo) e Extra-P requerem parâmetros fornecidos pelo usuário. Crie um arquivo JSON e forneça seu caminho para o PIRA usando o --analysis-parameters
-switch. O exemplo a seguir contém parâmetros para o modo de modelagem Extra-P. As estratégias disponíveis para agregar múltiplos modelos Extra-P (quando uma função é chamada em diferentes contextos) são: FirstModel
, Sum
, Average
, Maximum
.
{
"Modeling": {
"extrapolationThreshold": 2.1,
"statementThreshold": 200,
"modelAggregationStrategy": "Sum"
}
}
Para obter mais detalhes sobre o recurso de detecção de desequilíbrio de carga, consulte [PI21]. Forneça à invocação do PIRA um caminho para um arquivo de configuração usando o parâmetro --load-imbalance-detection
. Este arquivo JSON deve ter a seguinte estrutura:
{
"metricType": "ImbalancePercentage",
"imbalanceThreshold": 0.05,
"relevanceThreshold": 0.05,
"contextStrategy": "None",
"contextStepCount": 5,
"childRelevanceStrategy": "RelativeToMain",
"childConstantThreshold": 1,
"childFraction": 0.001
}
Para executar o PIRA em um cluster com o gerenciador de carga de trabalho SLURM, invoque-o com o sinalizador --slurm-config
. Forneça o caminho para o arquivo de configuração do sistema em lote com ele. Veja os testes de integração com o sufixo _Slurm
( test/integration/*_Slurm/
). O PIRA atualmente oferece suporte a sistemas em lote com o gerenciador de carga de trabalho SLURM. O PIRA suporta o uso de um sistema module
, que pode ser encontrado em clusters slurm.
O arquivo de configuração do sistema em lote é um arquivo JSON, estruturado da seguinte forma:
{
"general": {
"backend": "slurm",
"interface": "pyslurm",
"timings": "subprocess"
},
"module-loads": [
{
"name": "gcc",
"version": "8.5"
},
{
"name": "llvm",
"version": "10.0.0",
"depends-on": [
{
"name": "gcc",
"version": "8.5"
}
]
}
],
"batch-settings": {
"time_str": "00:10:00",
"mem_per_cpu": 3800,
"number_of_tasks": 1,
"partition": null,
"reservation": null,
"account": "your_account_here",
"cpus_per_task": 96
}
}
Discriminação:
general
: Permite escolher de que forma o PIRA executará seu código no sistema em lote. Como todas as opções nesta seção são opcionais, você pode omitir a seção inteira, se concordar em usar os padrões:backend
: qual gerenciador de carga de trabalho usar. Opções: slurm
, para o gerenciador de carga de trabalho slurm. Padrão: slurm
, portanto opcional.interface
: De que forma o PIRA deve interagir com o gerenciador do sistema em lote. Para o backend SLURM, são: pyslurm
, para usar o PySlurm (isso requer a instalação do PySlurm, consulte esta seção; sbatch-wait
, para usar sbatch
padrão com o sinalizador --wait
; os
, para sbatch
padrão e chamadas de interação squeue
. Padrão: pyslurm
, portanto opcional.timings
: como o timing do código alvo deve ser feito. Escolhas: subprocess
, para cronometrar com um wrapper python e os.times
em um subprocesso (exatamente como o PIRA faz se for executado localmente); os
, para usar /usr/bin/time
. Padrão: subprocess
, portanto opcional.force-sequential
: Padrão false
. Defina como true
para forçar o PIRA/seu sistema em lote a fazer todas as execuções em ordem sequencial (apenas uma execução do código de destino por vez). Isso significa que o PIRA cuidará para que seu sistema em lote execute repetições, bem como diferentes trabalhos no dimensionamento de experimentos em ordem sequencial. Se definido como/esquerdo em false
o PIRA tentará instruir o sistema em lote para fazer tantas execuções quanto possível dentro de cada iteração em paralelo.module-loads
: Atualmente não em uso no PIRA, trabalho em andamento! Atualmente, você precisa carregar todos os módulos manualmente, antes de iniciar o PIRA! Refere-se a quais módulos devem ser carregados com o sistema module
. Isso requer que um esteja instalado (os comandos module load
e module purge
podem ser usados pelo PIRA). Se você não possui um sistema module
instalado ou não deseja usá-lo, omita esta seção completamente ou defina "module-loads": null
. Para especificar os módulos que o PIRA deve carregar, especifique uma lista de módulos, como no exemplo acima.name
.version
é opcional, se não for fornecida, dependerá do que o sistema module
carrega como versão padrão do módulo. Recomenda-se sempre fornecer versões explicitamente.depends-on
também é opcional. Forneça uma lista de módulos dos quais este módulo depende. Esses módulos devem ter um name
e podem opcionalmente ter uma version
fornecida. As dependências definidas aqui são usadas pelo PIRA para determinar a ordem em que os módulos devem ser carregadosnull
, presume-se que este módulo não possui dependências.depends-on
o PIRA irá (tentar) carregar os módulos exatamente na ordem que foi fornecida no arquivo de configuração.batch-setting
: As opções reais de hardware e trabalho para o sistema em lote. Algumas opções da seção são obrigatórias, você não pode omitir esta seção.time
: A opção sbatch --time
, obrigatória.mem-per-cpu
: A opção sbatch --mem-per-cpu
, obrigatória.ntasks
: A opção sbatch --ntasks
, obrigatória.partition
, reservation
, account
(todos padrão como null
=não fornecido), cpus-per-task
(o padrão é 4
), exclusive
(o padrão é true
; não suportado com pyslurm
) e cpu-freq
(o padrão é null
).sbatch
que você não pode definir nesta configuração. Isto se deve a algumas opções usadas internamente pelo PIRA, por exemplo a opção --array
, para mapear as repetições para matrizes de tarefas. Como e qual versão do PySlurm instalar em seu cluster depende muito de sua versão SLURM e de sua instalação SLURM. A solução de instalação e embalagem do pyslurm com PIRA está em andamento. Consulte o README deles. Você pode tentar alguns dos seguintes:
include
e lib
.python3 setup.py build --slurm-lib=/opt/slurm/21.08.6/lib --slurm-inc=/opt/slurm/21.08.6/include
python3 setup.py install --slurm-lib=/opt/slurm/21.08.6/lib --slurm-inc=/opt/slurm/21.08.6/include
.