Performance de Reflaction vs blocos Switch

PS: se trata de emulação de uma cpu, portanto não estou seguindo muito os padrões e melhores práticas em função da performance.

Com o tópico http://guj.com.br/posts/list/64849.java já respondido.

Veio outra indagação

veja:
Com switch.

switch (opcode) { case 0x0001: method1(); case 0x0002: method2(); case 0x0003: method3(); ... case 0x00FF }

(essa coisa compilada provavelmente dará em um monte de if’s aninhados)

Com Reflection:

[quote]Method metodo = this.getClass().getMethod( “method” + opcode );
metodo.invoke();[/quote]

Mas ai veio a dúvida a cada chamada no Reflaction irá causar um I/O no disco ?

Se sim, então é bem menos rápido.
Estou certo?

Ele nao causara uma I/O no disco… pois ele não dispara uma IOException… ele usa a propria memoria para fazer isto provavelmente…
mas pelo que eu vejo e bem mais performatico usar blocos switch invez de reflection… e melhor ainda usar Interfaces para isto…

Usualmente você usaria “switch” mesmo para efetuar sua emulação. Ou então faria o seguinte:

interface Processavel {
    void processar();
}
class NOP implements Processavel {
    public void processar () {}
}
class ADD implements Processavel {
    private Contexto cont;
    public ADD (Contexto cont) {
        this.cont = cont;
    }
    void processar () { cont.registradorA = cont.registradorA + cont.registradorB; }
}
class SUB implements Processavel {
    private Contexto cont;
    public SUB (Contexto cont) {
        this.cont = cont;
    }
    void processar () { cont.registradorA = cont.registradorA - cont.registradorB; }
public class CPU {
     Contexto contexto = new Contexto();
     Processavel opcodes = new Processavel [] {
         new NOP(), // opcode 0x0000
         new ADD(cont),  // opcode 0x0001
         new SUB(cont),
         .... 
     };
     int instrucoes[] = ...;
     public void emular () {
          ...
          // Executando a instrução do array instrucoes
          // cuja posição está em "contexto.pc"
          opcodes[instrucoes[contexto.pc]].processar();
          ...
     }
}
}

Apenas três coisas:

a) Reflection incorre uma perda na ordem de 5%. O ideal é você poder usar algo como a nova API de Compiler do Java 6 ou o Janino para Compilar isto em uma classe que implemente uma interface, e/ou uma classe abstrata. Segue um exemplo de um código que implementei semana passada, utilizando o janino:

  /**
   * Compila/Instancia um Verifier a partir do código-fonte especificado
   * 
   * @param text
   *          codigo-fonte do verifier
   * @return verifier
   */
  private Verifier getVerifier(final String text) {
    try {
      final ClassBodyEvaluator classBodyEvaluator = new ClassBodyEvaluator();
      classBodyEvaluator.setDefaultImports(new String[] {
          SerializedDataVerifier.class.getCanonicalName(),
          Verifier.class.getCanonicalName(),
          AbstractVerifier.class.getCanonicalName() });
      classBodyEvaluator.setImplementedTypes(new Class[] { Verifier.class });
      classBodyEvaluator.setExtendedType(AbstractVerifier.class);
      classBodyEvaluator
          .cook(String
              .format(
                  "protected void verifyInternal(VerifierSource verifierSource) { %s }",
                  this.text));

      return (Verifier) classBodyEvaluator.getClazz().newInstance();
    } catch (final Exception e) {
      throw new IllegalArgumentException(String.format("getVerifier(text=%s)", text), e);
    }
  }

Este código me cria uma classe derivada de AbstractVerifier (que roteia para verifyInternal) e que implementa a interface Verifier, a partir do conteúdo de texto. Resumindo, é um Pattern de Command, de forma que possa ser usado em uma cadeia-de-responsabilidade maior.

No caso, a única coisa que faço é uma interpolação entre um template de código-fonte, de forma a construir os métodos. É uma boa idéia? Sem dúvida: Reavaliar periodicamente o mesmo bloco de código não é uma boa idéia, quando o que você quer é performance.

Mas lembre-se: Otimização prematura é a fonte de toda a maldade no mundo :slight_smile:

b) Existe um opcode específico, otimizado para switches. Este artigo pode te dar mais detalhes

c) Existe limite de 64KiB para comprimento do método.

Espero que ajude.

p/S: Pelo pouco que li do seu projeto, acho que você pode aprender algumas coisas lendo os artigos do NestedVM, que é um emulador de MIPS feito para executar sob uma JVM.

Muito obrigado !!!
Vou usar as informações citadas por vocês.