Share via


Compilação do ReadyToRun

A latência e o tempo de inicialização do aplicativo .NET podem ser aprimorados compilando os assemblies de aplicativo como o formato R2R (ReadyToRun). R2R é uma forma de compilação antecipada (AOT).

Os binários R2R melhoram o desempenho de inicialização reduzindo a quantidade de trabalho que o compilador just-in-time (JIT) precisa fazer à medida que seu aplicativo é carregado. Os binários contêm código nativo similar comparado ao que o JIT produziria. Entretanto, os binários R2R são maiores porque contêm código de IL (linguagem intermediária), que ainda é necessário para alguns cenários, e a versão nativa do mesmo código. O R2R só está disponível quando você publica um aplicativo direcionado a um RID (Runtime Environment) específico, como o Linux x64 ou o Windows x64.

Para compilar o projeto como ReadyToRun, o aplicativo precisa ser publicado com a propriedade PublishReadyToRun definida como true.

Há duas maneiras de publicar o aplicativo como ReadyToRun:

  1. Especificar o sinalizador PublishReadyToRun diretamente no comando dotnet publish. Confira dotnet publish para obter detalhes.

    dotnet publish -c Release -r win-x64 -p:PublishReadyToRun=true
    
  2. Especificar a propriedade no projeto.

    • Adicione a configuração <PublishReadyToRun> ao projeto.
    <PropertyGroup>
      <PublishReadyToRun>true</PublishReadyToRun>
    </PropertyGroup>
    
    • Publique o aplicativo sem parâmetros especiais.
    dotnet publish -c Release -r win-x64
    

Impacto do uso do recurso ReadyToRun

A compilação Ahead Of Time tem um impacto complexo no desempenho do aplicativo, o que pode ser difícil de prever. Em geral, o tamanho de um assembly aumentará de duas a três vezes. Esse aumento no tamanho físico do arquivo pode reduzir o desempenho do carregamento do assembly do disco e aumentar o conjunto de trabalho do processo. No entanto, em troca, o número de métodos compilados em tempo de execução normalmente é reduzido significativamente. O resultado é que a maioria dos aplicativos com códigos extensos conta com grandes benefícios de desempenho ao habilitar o ReadyToRun. Os aplicativos com pouco código talvez não tenham uma melhoria significativa ao habilitar o ReadyToRun, pois as bibliotecas de runtime do .NET já foram pré-compiladas com ReadyToRun.

O aprimoramento de inicialização discutido aqui se aplica não apenas à inicialização do aplicativo, mas também ao primeiro uso de qualquer código no aplicativo. Por exemplo, o ReadyToRun pode ser usado para reduzir a latência de resposta do primeiro uso da API Web em um aplicativo ASP.NET.

Interação com a compilação em camadas

O código Ahead Of Time não é tão otimizado quanto o código produzido por JIT. Para resolver esse problema, a compilação em camadas substituirá os métodos ReadyToRun que costumam ser usados por métodos gerados por JIT.

Como o conjunto de assemblies pré-compilados é escolhido?

O SDK pré-compilará os assemblies que são distribuídos com o aplicativo. Para aplicativos autossuficientes, esse conjunto de assemblies incluirá a estrutura. Os binários C++/CLI não estão qualificados para compilação ReadyToRun.

Para excluir assemblies específicos do processamento de ReadyToRun, use a lista <PublishReadyToRunExclude>.

<ItemGroup>
  <PublishReadyToRunExclude Include="Contoso.Example.dll" />
</ItemGroup>

Como o conjunto de métodos é escolhido para pré-compilação?

O compilador tentará pré-compilar o máximo de métodos possível. No entanto, por vários motivos, não é esperado que o uso do recurso ReadyToRun impeça a execução do JIT. Esses motivos podem incluir, mas não se limitam a:

  • Uso de tipos genéricos definidos em assemblies separados.
  • Interoperabilidade com código nativo.
  • O uso de tipos intrínsecos de hardware cuja segurança de uso em um computador de destino o compilador não consegue comprovar.
  • Certos padrões de IL incomuns.
  • Criação de método dinâmico por meio de reflexão ou LINQ.

Geração de símbolos para uso com criadores de perfil

Ao compilar um aplicativo com ReadyToRun, os criadores de perfil podem exigir símbolos para examinar os arquivos ReadyToRun gerados. Para habilitar a geração de símbolos, especifique a propriedade <PublishReadyToRunEmitSymbols>.

<PropertyGroup>
  <PublishReadyToRunEmitSymbols>true</PublishReadyToRunEmitSymbols>
</PropertyGroup>

Esses símbolos serão colocados no diretório de publicação e para Windows terão uma extensão de arquivo .ni.pdb e, para Linux, haverá uma extensão de arquivo .r2rmap. Esses arquivos geralmente não são redistribuídos para clientes finais, mas sim armazenados em um servidor de símbolos. Em geral, esses símbolos são úteis para depurar problemas de desempenho relacionados à inicialização de aplicativos, pois a compilação em camadas substituirá o código gerado por ReadyToRun pelo código gerado dinamicamente. No entanto, em caso de tentativa de criar o perfil de um aplicativo que desabilite a compilação em camadas, os símbolos serão úteis.

ReadyToRun composto

A compilação ReadyToRun normal produz binários que podem ser atendidos e manipulados individualmente. Do .NET 6 em diante, o suporte para a compilação de ReadyToRun composta foi adicionado. O ReadyToRun composto compila um conjunto de assemblies que precisam ser distribuídos juntos. Isso tem a vantagem de que o compilador pode executar otimizações melhores e reduz o conjunto de métodos que não podem ser compilados por meio do processo ReadyToRun. No entanto, como desvantagem, a velocidade de compilação é bem reduzida e o tamanho geral do arquivo do aplicativo é bem aumentado. Devido a essas desvantagens, o uso de ReadyToRun composto só é recomendado para aplicativos que desabilitam a compilação em camadas ou aplicativos em execução no Linux que buscam o melhor tempo de inicialização com uma implantação autossuficiente. Para habilitar a compilação ReadyToRun composta, especifique a propriedade <PublishReadyToRunComposite>.

<PropertyGroup>
  <PublishReadyToRunComposite>true</PublishReadyToRunComposite>
</PropertyGroup>

Observação

No .NET 6, o ReadyToRun composto só é compatível com a implantação autossuficiente.

Restrições de plataforma cruzada/arquitetura

Para algumas plataformas de SDK, o compilador ReadyToRun pode fazer a compilação entre outras plataformas de destino.

Os destinos de compilação com suporte são descritos na tabela abaixo para direcionamento ao .NET 6 e a versões posteriores.

Plataforma de SDK Plataformas de destino com suporte
Windows X64 Windows (X86, X64, Arm64), Linux (X64, Arm32, Arm64), macOS (X64, Arm64)
Windows X86 Windows (X86), Linux (Arm32)
Linux X64 Linux (X64, Arm32, Arm64), macOS (X64, Arm64)
Linux Arm32 Linux Arm32
Linux Arm64 Linux (X64, Arm32, Arm64), macOS (X64, Arm64)
macOS X64 Linux (X64, Arm32, Arm64), macOS (X64, Arm64)
macOS Arm64 Linux (X64, Arm32, Arm64), macOS (X64, Arm64)

Os destinos de compilação com suporte são descritos na tabela abaixo para direcionamento ao .NET 5 e abaixo.

Plataforma de SDK Plataformas de destino com suporte
Windows X64 Windows X86, Windows X64, Windows Arm64
Windows X86 Windows X86, Windows Arm32
Linux X64 Linux X86, Linux X64, Linux Arm32, Linux Arm64
Linux Arm32 Linux Arm32
Linux Arm64 Linux Arm64
macOS X64 macOS X64