Como determinar o número máximo a ser passado para a opção make -j?

31

Eu quero compilar o mais rápido possível. Vai saber. E gostaria de automatizar a escolha do número após a -jopção. Como escolher programaticamente esse valor, por exemplo, em um script de shell?

A saída é nprocequivalente ao número de threads que tenho disponível para compilar?

make -j1 make -j16

tarabyte
fonte

Respostas:

34

nprocfornece o número de núcleos / threads de CPU disponíveis, por exemplo , 8 em uma CPU quad-core com suporte a SMT bidirecional.

O número de tarefas que você pode executar paralelamente ao makeuso da -jopção depende de vários fatores:

  • a quantidade de memória disponível
  • a quantidade de memória usada por cada maketrabalho
  • até que ponto os maketrabalhos são vinculados à E / S ou à CPU

make -j$(nproc) é um lugar decente para começar, mas geralmente você pode usar valores mais altos, desde que você não esgote a memória disponível e comece a debitar.

Para compilações muito rápidas, se você tiver memória suficiente, recomendo usar a tmpfs, assim, a maioria dos trabalhos será vinculada à CPU e make -j$(nproc)funcionará o mais rápido possível.

Stephen Kitt
fonte
3
e ccachepara mais tarde reconstruir, mas esta é OT
solstício de
11
Usar algo como o paralelo GNU vale a pena aqui?
terdon
Se eu usar a tmpfs, estarei limitado a um tamanho de diretório sempre menor que o tamanho da minha RAM física?
tarabyte
2
Não é uma ótima resposta, mas no espírito estrito da questão de determinar programaticamente o valor "j" mais rápido, você pode fazer um loop de j de 1 a um limite superior razoável (2x nproc ??) e encerrar a marca em uma timechamada. Limpe os resultados, ensaboe a repetição e acabe classificando os valores de tempos / j.
Jeff Schaller
3
@terdon Não. Make é sobre resolver dependências, o que significa que os trabalhos ainda precisam ser executados em uma determinada ordem. O paralelo GNU não se importa com isso. Em uma nota lateral, decidir quais trabalhos são seguros para serem executados em paralelo e quais não são é um problema difícil. Todos os programas de criação que ofereciam versões paralelas levaram anos até se tornarem um pouco utilizáveis.
Lcd047
6

Infelizmente, mesmo partes diferentes da mesma compilação podem ser ideais com valores conflitantes do fator j, dependendo do que está sendo construído, como, quais recursos do sistema são o gargalo naquele momento, o que mais está acontecendo na máquina de compilação, o que está acontecendo no a rede (se estiver usando técnicas de construção distribuídas), status / local / desempenho dos muitos sistemas de armazenamento em cache envolvidos em uma construção, etc.

Compilar 100 arquivos C minúsculos pode ser mais rápido do que compilar um único arquivo enorme, ou vice-versa. Criar um código pequeno e altamente complicado pode ser mais lento do que criar enormes quantidades de código direto / linear.

Mesmo o contexto da compilação é importante - usar o fator aj otimizado para compilações em servidores dedicados ajustados para compilações exclusivas e sem sobreposição pode gerar resultados muito decepcionantes quando usado por desenvolvedores que constroem paralelamente no mesmo servidor compartilhado (cada compilação pode levar mais tempo que todos eles combinados se serializados) ou em servidores com diferentes configurações de hardware ou virtualizados.

Há também o aspecto de correção da especificação de compilação. Construções muito complexas podem ter condições de corrida, causando falhas intermitentes de construção com taxas de ocorrência que podem variar bastante com o aumento ou diminuição do fator j.

Posso continuar por muito tempo. O ponto é que você precisa realmente avaliar sua construção no seu próprio contexto para o qual deseja que o fator j seja otimizado. O comentário de @Jeff Schaller se aplica: repita até encontrar o seu melhor ajuste. Pessoalmente, eu começaria com o valor nproc, tentaria para cima primeiro e para baixo apenas se as tentativas para cima mostrarem degradação imediata.

Pode ser uma boa ideia primeiro avaliar várias construções idênticas em contextos supostamente idênticos, apenas para ter uma idéia da variabilidade de suas medições - se muito alta, isso poderia prejudicar todo o seu esforço de otimização (uma variabilidade de 20% eclipsaria completamente uma melhoria de 10% / leitura de degradação na busca do fator j).

Por fim, o IMHO é melhor usar um servidor de trabalho (adaptável), se suportado e disponível, em vez de um fator j fixo - ele fornece consistentemente um melhor desempenho de construção em intervalos mais amplos de contextos.

Dan Cornilescu
fonte
bem colocado em relação às dependências da construção subjacente. você pode comentar sobre a passagem de nenhum número fixo com o -jparâmetro? por exemplo,make -j
tarabyte
4
make -jgerará tantos trabalhos quanto as dependências permitirem como uma bomba de forquilha ( superuser.com/questions/927836/… ); a compilação rastreará da melhor maneira possível gastando a maior parte da CPU no gerenciamento dos processos do que executá-los ( superuser.com/questions/934685/… ) e em compilações altamente paralelas, o sistema ficará sem memória / troca ou pid #s e a compilação falhará .
Dan Cornilescu
3

A maneira mais direta é usar nproco seguinte:

make -j`nproc`

O comando nprocretornará o número de núcleos em sua máquina. Envolvendo-o nos ticks, o nproccomando será executado primeiro, retornará um número e esse número será passado make.

Você pode ter alguma experiência anedótica em que a contagem principal + 1 resulta em tempos de compilação mais rápidos. Isso tem mais a ver com fatores como atrasos de E / S, outros atrasos de recursos e outra disponibilidade de restrições de recursos.

Para fazer isso nproc+1, tente o seguinte:

make -j$((`nproc`+1))
010110110101
fonte
0

Se você deseja escrever o makecomando para usar tantos trabalhadores paralelos quanto as CPUs virtuais, sugiro usar:

nproc | xargs -I % make -j%

Que pode ser gravado como um comando independente ou como RUNdiretiva dentro Dockerfile(como o Docker não suporta comandos aninhados)

Maksym Ganenko
fonte