2009-03-27 4 views
7

Ich schreibe einige spezielle Datenstrukturen in Java, die für den Browser gedacht sind (kompiliert zu JavaScript mit GWT).GWT: Wie vermeidet man Aufrufe von dynamicCast und canCastUnsafe in generiertem JavaScript-Code?

Ich versuche, die Leistung einiger der eingebauten JDK-Klassen zu vergleichen. Ich merke, dass die Dinge ziemlich schnell laufen, aber wenn ich meinen Code-Trace mit einigen der emulierten JDK-Codes vergleiche, hat meins viele Aufrufe zu dynamicCast und canCastUnsafe, während die JDK-emulierten Klassen nicht. Und es geht nur um den Unterschied in der Leistung auch zu ...

Jeder GWT Gurus da draußen wissen, wie man das vermeidet? Es wird in Höhe von 20% Overhead :-(

Details:

Hier ist die Profilausgabe (erfaßt in Firebug) für 10.000 Einfügungen von Zufallszahlen zwischen 0 und 100.000 in zwei unterschiedliche Datenstrukturen:

Googles TreeMap Implementierung für java.util.TreeMap (ein rot-schwarz-Baum):

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 

My-Code (ein AVL-Baum):

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 

Weitere Beobachtungen:

  • Das gleiche Problem für eine andere Datenstruktur Ich habe (skiplist).
  • dynamicCast wird in der Vergleichsfunktion angewendet:

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

  • dynamicCast wird entfernt, wenn die Klasse Map nicht implementiert (dh: "implements Map" wird nur aus der Klasse entfernt. Es spielt keine Rolle, ob über die Schnittstelle oder direkt darauf zugegriffen wird.

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

Dies ist der entsprechende Abschnitt von Java-Quellcode von 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); 

      ... 
     } 
    } 
} 

Antwort

4

Leider bin ich noch nicht ganz klar auf die Ursache, aber aus meiner Erfahrung, so scheint es, von expliziten Abgüsse, wie:

((Comparable) obj).compareTo(other) 

Der Javascript erzeugt sieht aus wie:

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

Wo 1 ist eine generierte TypeId, die das Ziel der Besetzung darstellt. dynamicCast wiederum ruft canCastUnsafe auf und wenn false, wird eine ClassCastException ausgelöst. Der Wert davon war debated, da dies bereits im gehosteten Modus abgefangen werden würde.

Es kann mit JSNI wichen werden:

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

Does th Die Verwendung von Java 1.5 Generics und Wildcards könnte dies vermeiden?

+0

Eigentlich denke ich, dass es sollte, aber nicht .. Nach dem, was ich herausgefunden habe, scheint es ein Manko des Compilers zu sein. –

1

weiß nicht, ob Sie this thread in Forum GWT Profis gesehen haben ...

Grundsätzlich beginnt es mit dem gleichen Problem, das Sie identifiziert haben, schlägt einigen neuen Compiler-Flags, und geht zu zeigen, wie man verwendet etwas JSNI, um die Abgüsse zu umgehen.

Bearbeiten In der GWT Trunk gibt es eine neue Compiler-Flag. Siehe the wiki ...

+0

Coincendence, ich habe diesen Thread gestern gefunden, und das war eigentlich meine JSNI-Problemumgehung, die ich gestern entwickelt habe. –

1

Eine aktualisierte Antwort für GWT-Version 2.1 und höher:

Da GWT 2.1 (zumindest, dass die erste Erwähnung ist), der GWT-Compiler hat Ein neues Compiler-Argument mit dem Namen -XdisableCastChecking deaktiviert alle Laufzeitprüfungen von Umwandlungen. Beachten Sie, dass diese Option als experimentell markiert ist (wahrscheinlich, weil dadurch Ausnahmen für die Klassenübergabe sehr schwer zu debuggen wären).

In meiner App dynamicCast wurde Tausende Male in einem kurzen Profil ausgeführt, und waren die 3. zeitaufwendigste Methode in der Firebug Profiler. Durch die Verwendung dieses Compilerarguments wurde die Anzahl der "Long Duration Events" -Meldungen im Chrome Speed ​​Tracer erheblich reduziert.

Siehe GWT Compiler Options für dieses und andere Compiler-Argumente.

0

Es ist definitiv ein Problem mit dem Compiler: Ich habe das Problem auf der folgenden Zeile:

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

Ich weiß nicht wirklich, wie ich es umgehen kann: diese Zeile in einem Moment passiert, ich bin von einem Wechsel Modul zu einem anderen (es ist vielleicht mit dem Code-Splitter-Problem verwandt: obwohl ich Code-Split nicht verwende: Ich lade gerade eine andere Seite mit einem anderen Modul)

Verwandte Themen