Performance de Reflaction vs blocos Switch

4 respostas
dreampeppers99

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:

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

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?

4 Respostas

luistiagos

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…

T

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();
          ...
     }
}
}
Aldrin_Leal

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.

dreampeppers99

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

Criado 18 de julho de 2007
Ultima resposta 19 de jul. de 2007
Respostas 4
Participantes 4