6
votes

Conversion de 64 bits doubles à la bytretring efficacement

J'ai écrit une fonction pour convertir un double de 64 bits à bytestring (la sécurité de l'architecture / type n'est pas vraiment un problème - supposons-nous maintenant que le double est de 64 bits). Bien que la fonction ci-dessous fonctionne bien, je me demande s'il y a un moyen plus rapide de convertir le double à la bytretring. Dans le code ci-dessous, il y a un débardement de Word64 dans la liste Word8, suivi d'inverse (pour en faire un petit format Endian), puis emballer en bytretring. Le code est ci-dessous: xxx pré>

un échantillon de sortie GHCI sur Mac x86: p> xxx pré>

tandis que le code semble fonctionner bien, je prévois de Utilisez-le pour encoder beaucoup de valeurs doubles dans la bytretring avant de l'envoyer sur IPC. Donc, j'apprécierai que les indicateurs restent plus rapides, s'il y en a. P>

Il me semble que le double doit être déballé dans Word8, puis emballé dans la bytretring. Donc, peut être l'algorithme général tel qu'il est, ne peut pas être amélioré beaucoup. Mais, en utilisant une fonction de déballage / pack plus efficace fera probablement une différence, s'il y en avait un. P>

Edit1: strong> Je viens de découvrir une autre complication sur Mac (GHC 7.0.3) - le code ci-dessus ne compilera pas dans GHC en raison de cette erreur - je testais à GHCI jusqu'à présent: p>

estimating cost of a clock call...
mean is 46.09080 ns (36 iterations)

benchmarking encodeDouble/78901.234
mean: 218.8732 ns, lb 218.4946 ns, ub 219.3389 ns, ci 0.950
std dev: 2.134809 ns, lb 1.757455 ns, ub 2.568828 ns, ci 0.950

benchmarking encodeDouble/789.01
mean: 219.5382 ns, lb 219.0744 ns, ub 220.1296 ns, ci 0.950
std dev: 2.675674 ns, lb 2.197591 ns, ub 3.451464 ns, ci 0.950


2 commentaires

Je suis curieux de savoir pourquoi vous ne voulez pas utiliser l'approche de céréales , ce qui réduit à une poignée de lignes dans le noyau que les notes de réponse liées. Dès que vous commencez à traiter avec des listes, vous allez vous retrouver avec quelque chose de beaucoup plus cher.


Acfolter, bon point. J'ai finalement compris ce que je devrais rechercher (mettre en œuvre Motsword64le). Ça a fait l'affaire. S'il vous plaît voir mon message ci-dessous. Si vous avez des suggestions sur les endroits où chercher une mise en œuvre de la liste rapide, merci de me le faire savoir.


3 Réponses :


1
votes

Notez que l'utilisation de Unfeceecoerce # est dangereuse ici, les documents disent

Casting d'un type de boîte de boîte à un autre type de la même taille ( mais pas des coercitions entre les types flottants et les types intégrés )

En ce qui concerne la vitesse, il peut être plus rapide d'éviter la liste intermédiaire et d'écrire directement à la mémoire via insecfecreate de data.bytestring.internal . .


1 commentaires

Oui, je pense que c'est exactement pourquoi l'erreur de compilation n'indique pas un bogue.



4
votes

J'ai récemment ajouté la prise en charge de l'IEEE-754 floatts à céréales , et vous pouvez trouver des fonctions similaires pour binaire dans DATA BINARY-IEEE754 . Voici un exemple à l'aide de la version de la version à la version aller -trip PI à un bytestring et arrière: xxx

il utilise une astuce avec des tableaux ST pour faire la conversion rapidement; Voir cette question précédente pour plus de détails.

mise à jour : d'oh, je devrais savoir comment utiliser des appels j'ai contribué à la bibliothèque ...

Mettre à jour x2 : concernant l'échec de la compilation, je ne pense pas que cela qualifie de bogue.

Je n'ai pas regardé trop soigneusement à l'assemblage généré pour ce code particulier, mais les opérandes vers une instruction MOVSD deviennent encadrés. De 14.4.1.1 du Intel X86 manuel :

Le transfert transfère le point de déplacement à virgule flottant de la mémoire à double précision de 64 bits de la mémoire au faible quadrudique d'un registre XMM ou vice versa ou entre les registres XMM.

dans le code non optimisé, vous avez des instructions fines telles que MOVSD LNTH (% RIP),% xmm0 , mais dans le code -O , vous voyez. Des choses telles que Movsd ln2cj (% RIP),% RAX , où % RAX est un registre à usage général, plutôt qu'un registre XMM.

L'optimiseur rend probablement des hypothèses sur les représentations de données qu'il doit se déplacer entre les registres en fonction du type de données impliquées. UNSEACECOERCE ET AMIS invalidez ces hypothèses, donc lorsque le sélecteur d'instructions pense qu'il choisit la bonne opération pour un D # , il émet un code qui tente de tracer ce D # < / code> où un w64 # serait bon.

Depuis la manipulation, cela demanderait à l'optimiseur d'abandonner de nombreuses hypothèses qui lui permettent d'émettre un meilleur code dans des circonstances normales, je suis enclin à dire que ce n'est pas un bug, mais plutôt une bonne histoire pour pourquoi dangereux fonctions supporter un avertissement de cavernation.


4 commentaires

Merci. Cela a été utile car je ne peux pas compiler mon code avec UNSADECOERCE (pls voir la modification ci-dessus pour la mise à jour)


Consultez ma mise à jour pour la raison pour laquelle vous ne pourrez probablement pas compiler avec Unfafecoerce dans un avenir prévisible :)


Bien sûr, comme allusion au billet lié, il pourrait y avoir des coercitions spécialisées construites dans GHC à l'avenir, mais non référière ne fonctionnera probablement jamais de cette façon


Le pointeur d'erreur de compilation était très utile. Je suis d'accord sur CAVEATER Emptor. Moi aussi je me demandais si c'était bien le cas sur les hypothèses violées de la largeur de données lors de l'insonorisation.



1
votes

Suite à la suggestion de ACFOLTER (Catégorie de source de céréales) et Daniel Fischer (Insececreate), j'ai écrit le code ci-dessous qui fonctionne bien pour mon étui d'utilisation, et est rapide aussi:

estimating cost of a clock call...
mean is 46.80361 ns (35 iterations)
found 5 outliers among 35 samples (14.3%)
  3 (8.6%) high mild
  2 (5.7%) high severe

benchmarking encodeDouble/78901.234
mean: 18.80689 ns, lb 18.73805 ns, ub 18.97247 ns, ci 0.950
std dev: 516.7499 ps, lb 244.8588 ps, ub 1.043685 ns, ci 0.950

benchmarking encodeDouble/789.01
mean: 18.96963 ns, lb 18.90986 ns, ub 19.06127 ns, ci 0.950
std dev: 374.2191 ps, lb 275.3313 ps, ub 614.4281 ps, ci 0.950


0 commentaires