1 pontos por GN⁺ 4 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • O emulador x86-32 gerava código nativo por meio de tradução binária para executar código x86-32 em outros processadores, oferecendo um grande ganho de desempenho em relação à abordagem por interpretador
  • Esse emulador podia ser entendido como uma arquitetura que tratava o x86-32 como bytecode, fazendo o emulador funcionar como um compilador JIT
  • Um programa precisava alocar cerca de 64 KB de memória na pilha e inicializá-la; a forma comum era fazer primeiro uma sonda de pilha, depois reduzir o ponteiro da pilha e inicializar a memória com um pequeno loop
  • O compilador desse código gerou, em vez de um loop, 65.536 instruções individuais de escrita de byte, e como cada instrução tinha 4 bytes, foram necessários 256 KB de código para inicializar 64 KB de dados
  • A equipe do emulador adicionou ao tradutor um código especial para detectar essa função e substituí-la por um loop curto equivalente

Contexto: emulador x86-32 e tradução binária

  • O Windows já incluiu um emulador de processador x86-32 para sistemas executados em processadores que não eram x86-32
  • O texto original não especifica a qual processador esse caso se aplicava
  • Esse emulador usava tradução binária para gerar código nativo com comportamento equivalente ao código x86-32 original
  • Esse método oferecia uma melhora significativa de desempenho em comparação com a emulação baseada em interpretador
  • É possível entendê-lo tratando o x86-32 como bytecode e o emulador como um compilador JIT

O código problemático: inicialização de 64 KB de memória na pilha

  • Um programa precisava alocar cerca de 64 KB de memória na pilha e inicializá-la
  • A forma padrão era primeiro executar uma sonda de pilha para verificar se os 64 KB de memória podiam ser usados
  • Depois disso, o comum era subtrair 65.536 do ponteiro da pilha e inicializar a memória com um loop pequeno e enxuto

Desenrolamento excessivo de loop pelo compilador

  • O compilador que gerou esse código não produziu um loop para inicializar cada byte
  • Em vez disso, ele expandiu o loop em 65.536 instruções individuais de “escrita de byte na memória”
  • Cada instrução tinha 4 bytes de comprimento
  • Como resultado, foram necessários 256 KB de código para inicializar 64 KB de dados

A resposta da equipe do emulador

  • A equipe do emulador adicionou ao tradutor um código especial para detectar essa função
  • A função detectada era substituída por um loop curto que executava o mesmo comportamento
  • Em vez de traduzir o código original do programa exatamente como estava, esse tratamento trocava, durante a emulação, um padrão de código ineficiente por uma forma mais compacta

1 comentários

 
GN⁺ 4 시간 전
Opiniões no Lobste.rs
  • Gostei bastante do comentário que explicava loop unrolling para Raymond Chen

    • Aquele comentário pode ter sido escrito não só para o autor do blog, mas também para leitores em geral
      Entre as pessoas que leem esse tipo de texto, nem todo mundo conhece todo o contexto, então há quem agradeça pistas para aprender mais
    • Não vi esse comentário, mas acho que foi apagado. Ainda assim, se for Raymond Chen, esse sujeito é uma lenda viva
      https://joelonsoftware.com/2004/06/…
    • Isso me lembrou de quando, décadas atrás no Slashdot, alguém tentou explicar um assunto de Perl para larry@wall.org
  • Acho que isso deve ter sido no Alpha. Afinal, foi colocado muito trabalho no emulador x86 para essa plataforma