2009-03-27 5 views
7

J'écris des structures de données spéciales en Java, destinées à être utilisées dans le navigateur (compilées en JavaScript avec GWT). J'essaie de faire correspondre les performances de certaines classes JDK intégrées Je remarque que les choses vont assez vite, mais quand je compare ma trace de code à une partie du code JDK émulé, le mien a beaucoup d'appels à dynamicCast et canCastUnsafe, alors que les classes émulées JDK ne le font pas. Et c'est juste à propos de la différence de performance aussi ...GWT: Comment éviter les appels à dynamicCast et canCastUnsafe dans le code JavaScript généré?

Les gourous GWT savent comment éviter cela? Il est d'un montant de frais généraux de 20% :-(

Détails:

est ici la sortie de profil (capturé dans Firebug) pour 10.000 insertions d'entiers aléatoires, entre 0 et 100 000 en deux structures de données différentes:

la mise en œuvre de TreeMap de Google pour java.util.TreeMap (un arbre rouge-noir):

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 

Mon code (un arbre 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 

Observations complémentaires:

  • Même problème pour une autre structure de données que j'ai fait (SkipList).
  • dynamicCast est appliquée à la fonction de comparaison:

    cmp = dynamicCast (right.key, 4) .compareTo $ (clé); DynamicCast s'en va si la classe n'implémente pas Map (c'est-à-dire: en supprimant simplement "implémente Map" de la classe.) Cela n'a pas d'importance si l'on accède directement à l'interface.

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

Ceci est la section pertinente de la source Java à partir 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); 

      ... 
     } 
    } 
} 

Répondre

4

Malheureusement, je ne suis toujours pas très clair sur la cause, mais de mon expérience, il semble à partir de moulages explicites, comme:

((Comparable) obj).compareTo(other) 

Le Javascript généré ressemble:

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

Où 1 est un typeId généré représentant la cible de la distribution. dynamicCast appelle à son tour canCastUnsafe et si false, il lève une exception ClassCastException. La valeur de ceci a été debated, puisque cela serait déjà pris en mode hébergé.

Il peut être contournée avec JSNI:

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

est-e L'utilisation de génériques et de jokers java 1.5 pourrait-elle éviter cela?

+0

En fait je pense que ça devrait, mais pas .. D'après ce que j'ai découvert, cela semble être un défaut du compilateur. –

1

J'sais si vous avez vu this thread dans le forum de GWT Contributeur ...

Fondamentalement, il commence par le même problème que vous avez identifié, propose de nouveaux drapeaux du compilateur, et continue de montrer comment utiliser certains JSNI pour contourner les moulages.

Édition Dans la jonction GWT, il existe un nouvel indicateur de compilateur. Voir the wiki ...

+0

Coïncidence, j'ai trouvé ce fil hier, et c'était en fait ma solution de contournement JSNI que j'ai inventé hier. –

1

Une réponse mise à jour pour la version GWT 2.1 et versions ultérieures:

Depuis GWT 2.1 (au moins c'est la première mention), le compilateur GWT a un nouvel argument de compilation appelé -XdisableCastChecking qui désactive toutes les vérifications d'exécution des castings. Notez que cette option est marquée comme expérimentale (probablement parce que cela rendrait très difficile le débogage des exceptions de distribution).

Dans mon application, dynamicCast a été appelée des milliers de fois dans une exécution de profil court, et était la 3ème méthode la plus consommatrice de temps dans le profileur Firebug. L'utilisation de cet argument de compilation a considérablement réduit le nombre de messages «Long Duration Events» dans le Chrome Speed ​​Tracer. Voir GWT Compiler Options pour cela et d'autres arguments du compilateur

0

Il est certainement un problème de compilateur: J'ai le problème sur la ligne suivante:

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

Je ne sais pas vraiment comment je peux contourner ce: cette ligne arrive dans un moment je change d'un module à un autre (c'est peut-être lié au problème du séparateur de code: même si je n'utilise pas le split: je charge juste une autre page avec un autre module)

Questions connexes