2009-03-27 6 views
7

Estoy escribiendo algunas estructuras de datos de propósito especial en Java, destinadas para su uso en el navegador (compiladas a JavaScript con GWT).GWT: ¿Cómo evitar las llamadas a dynamicCast y canCastUnsafe en el código JavaScript generado?

Estoy tratando de hacer coincidir el rendimiento de algunas de las clases incorporadas de JDK. Me doy cuenta de que las cosas se ejecutan razonablemente rápido, pero cuando comparo mi código trazo a algunos del código JDK emulado, el mío tiene muchas llamadas a dynamicCast y canCastUnsafe, mientras que las clases emuladas JDK no lo hacen. Y también explica la diferencia en el rendimiento ...

¿Algún gurú de GWT sabe cómo evitar esto? Se asciende a una sobrecarga de 20% :-(

Detalles:

Aquí está la salida perfil (capturada en Firebug) para 10.000 inserciones de números enteros aleatorios, entre 0 y 100 000 en dos estructuras de datos diferentes:

aplicación de Google para TreeMap java.util.TreeMap (un árbol rojo-negro):

Profile (4058.602ms, 687545 calls) 
Function    Calls  Percent Own Time 
$insert_1    129809  41.87% 1699.367ms 
$compare_0   120290  16%  649.209ms 
$isRed    231166  13.33%  540.838ms 
compareTo_0   120290  8.96%  363.531ms 
$put_2     10000  6.02%  244.493ms 
wrapArray    10000  3.46%  140.478ms 
createFromSeed   10000  2.91%  118.038ms 
$TreeMap$Node   10000  2.38%  96.706ms 
initDim    10000  1.92%  77.735ms 
initValues    10000  1.49%  60.319ms 
$rotateSingle   5990  0.73%  29.55ms 
TreeMap$Node   10000  0.47%  18.92ms 

Mi código (un árbol AVL):

Profile (5397.686ms, 898603 calls) 
Function    Calls  Percent Own Time 
$insert    120899  25.06% 1352.827ms 
$compare    120899  17.94%  968.17ms 
dynamicCast   120899  14.12%  762.307ms <-------- 
$balanceTree   120418  13.64%  736.096ms 
$setHeight   126764  8.93%  482.018ms 
compareTo_0   120899  7.76%  418.716ms 
canCastUnsafe   120899  6.99%  377.518ms <-------- 
$put     10000  2.59%  139.936ms 
$AVLTreeMap$Node  9519  1.04%  56.403ms 
$moveLeft    2367  0.36%  19.602ms 
AVLTreeMap$State  9999  0.36%  19.429ms 
$moveRight    2378  0.34%  18.295ms 
AVLTreeMap$Node   9519  0.34%  18.252ms 
$swingRight    1605  0.26%  14.261ms 
$swingLeft    1539  0.26%  13.856ms 

observaciones adicionales:

  • El mismo problema para otra estructura de datos que hice (SkipList).
  • dynamicCast se está aplicando en la función de comparación:

    cmp = dynamicCast (right.key, 4) .compareTo $ (clave);

  • dynamicCast desaparece si la clase no implementa Map (es decir, simplemente eliminando "implementa Map" de la clase. No importa si se accede a través de la interfaz o directamente. Esto da como resultado la misma línea de compilación para:

    cmp = right.key.compareTo $ (clave);

Ésta es la sección correspondiente de la fuente de Java desde SkipList:

private int compare(Node a, Object o) { 
    if (comparator != null) 
     return comparator.compare((K) a.key, (K) o); 

    return ((Comparable<K>) a.key).compareTo((K) o); 
} 

public V get(Object k) { 
    K key = (K) k; 
    Node<K, V> current = head; 

    for (int i = head.height - 1; i >= 0; i--) { 
     Node<K, V> right; 

     while ((right = current.right[i]) != null) { 
      int cmp = compare(right, key); 

      ... 
     } 
    } 
} 

Respuesta

4

Lamentablemente todavía no estoy del todo claro de la causa, pero desde mi experiencia, parece de conversiones explícitas, como:

((Comparable) obj).compareTo(other) 

La JavaScript generado será similar a:

dynamicCast(obj, 1).compareTo(other); 

Dónde 1 es un tipo de letra generado que representa el objetivo del reparto. dynamicCast a su vez puede canCastUnsafe y si es falso, arroja una ClassCastException. El valor de esto ha sido debated, ya que esto quedaría atrapado en modo alojado.

Se puede eludió con JSNI:

public static native int compare(Object a, Object b) /*-{ 
    return [email protected]::compareTo(Ljava/lang/Object;)(b); 
}-*/; 
-1

¿el XX El uso de java 1.5 genéricos y comodines podría evitar esto?

+0

En realidad, creo que debería, pero no ... Por lo que he descubierto, parece ser una deficiencia del compilador. –

1

No sé si has visto this thread en el foro de la GWT colaborador ...

Básicamente, se inicia con el mismo problema que ha identificado, propone algunas nuevas opciones del compilador, y pasa a mostrar cómo utilizar algunos JSNI para sortear los moldes.

Editar En el tronco GWT hay una nueva bandera del compilador. Ver the wiki ...

+0

Coincendence, encontré ese hilo ayer, y esa fue en realidad mi solución JSNI que se me ocurrió ayer. –

1

Una respuesta actualizada para GWT versión 2.1 y posteriores:

Desde GWT 2.1 (al menos esa es la primera mención), el compilador GWT tiene un nuevo argumento del compilador llamado -XdisableCastChecking que deshabilita todas las revisiones de los lanzamientos en tiempo de ejecución. Tenga en cuenta que esta opción está marcada como experimental (probablemente porque esto haría que las excepciones de lanzamiento de clases fueran muy difíciles de depurar).

En mi aplicación dynamicCast se llamó miles de veces en una ejecución de perfil corto, y fue el tercer método más lento en el generador de perfiles de Firebug. El uso de este argumento del compilador redujo significativamente el número de mensajes de "Duración prolongada" en Chrome Speed ​​Tracer.

Consulte GWT Compiler Options para este y otros argumentos del compilador.

0

es sin duda un problema del compilador: Tengo el problema en la línea siguiente:

final DefaultIconedSuggestBox<SuggestValueProxy, IconedValueHolderItem<SuggestValueProxy>> fieldValueWidget = getCategoryWidget().getFieldValueWidget(); 

Realmente no sé cómo puedo solucionar es: esta línea que pasa en un momento voy a cambiar a partir de una módulo a otro (puede estar relacionado con el problema del divisor de código: aunque no estoy usando el código dividido: solo estoy cargando otra página con otro módulo)

Cuestiones relacionadas