Performance des langages C++ vs Machine virtuelle dans la finance haute fréquence

je pensais que la question de performance C/C++ vs C# / Java était bien piétinée, ce qui signifie que j'avais lu suffisamment de preuves pour suggérer que les langages VM ne sont pas nécessairement plus lents que les langages "proche du silicium". Surtout parce que le compilateur JIT peut faire des optimisations que les langages statiquement compilés ne peuvent pas faire.

cependant, j'ai récemment reçu un CV d'un gars qui prétend que le trading haute fréquence basé sur Java est toujours battu par C++, et qu'il avait été dans une situation où cela a été le cas.

un rapide coup d'oeil sur les sites d'emploi montre en effet que les candidats HFT ont besoin de connaissance du C++, et un regard sur Wilmott forum montre tous les praticiens qui parlent de c++.

y a-t-il une raison particulière à cela? J'aurais pensé qu'avec les affaires financières modernes étant un peu complexe, un langage VM avec la sécurité de type, la mémoire gérée, et une bibliothèque riche serait préférable. La productivité est plus élevée de cette façon. En Plus, JIT les compilateurs sont de mieux en mieux. Ils peuvent faire des optimisations pendant que le programme est en cours d'exécution, donc vous pensez qu'ils utilisent cette information d'exécution pour battre la performance du programme non géré.

peut-être que ces gars écrivent les bits critiques en C++ et les appellent depuis un environnement géré (P/Invoke etc)? Est-ce possible?

Enfin, quelqu'un a une expérience avec la question centrale dans cette, qui est pourquoi, dans ce domaine non géré le code est-il sans doute préférable à la gestion?

autant que je puisse dire, les gars HFT doivent réagir aussi vite que possible aux données entrantes du marché, mais ce n'est pas nécessairement un dur en temps réel exigence. Vous êtes pire si vous êtes lent, c'est sûr, mais vous n'avez pas besoin de garantir une certaine vitesse pour chaque réponse, vous avez juste besoin d'un moyen rapide.

EDIT

droite, quelques bonnes réponses jusqu'à présent, mais assez général (sentier). Permettez-moi de préciser quel genre de programme les gars de HFT seraient en cours d'exécution.

le critère principal est la réactivité. Quand une commande arrive sur le marché, vous voulez être le premier à être en mesure de réagir. Si vous êtes en retard, quelqu'un d'autre pourrait le prendre avant vous, mais chaque entreprise a une stratégie légèrement différente, donc vous pourriez être OK si une itération est un peu lente.

le programme fonctionne toute la journée, avec presque aucune intervention de l'utilisateur. Quelle que soit la fonction manipulée chaque nouvelle donnée du marché est exécutée des douzaines (voire des centaines) de fois par seconde.

ces entreprises n'ont généralement pas de limite quant au coût du matériel.

29
demandé sur Carlos 2010-07-04 19:02:59

15 réponses

tout D'abord, 1 ms est une éternité en HFT. Si vous pensez qu'il n'est pas alors il serait bon de faire un peu plus de lecture sur le domaine. (C'est comme être à 100 kilomètres de l'échange.) Le débit et la latence sont profondément imbriquées les formules élémentaire théorie des files d'attente manuel vous dira. Les mêmes formules montreront des valeurs de jitter (souvent dominées par l'écart-type du délai de file D'attente CPU si le tissu réseau est bon et que vous n'avez pas configuré assez de cœurs).

L'un des problèmes avec l'arbitrage HFT est qu'une fois que vous décidez de capturer un spread, il y a deux jambes (ou plus) pour réaliser le profit. Si vous ne réussissez pas à frapper toutes les jambes, vous pouvez être laissé avec une position que vous ne voulez vraiment pas (et une perte subséquente) - après tout, vous arbitragez pas investir.

vous ne voulez pas de postes à moins que votre stratégie ne prévoie le (très proche terme!!!) avenir (et cela, croyez-le ou non, est fait avec beaucoup de succès). Si vous êtes 1 ms loin de l'échange alors une fraction significative de vos ordres ne seront pas exécutés et ce que vous vouliez sera retiré. Très probablement ceux qui ont exécuté une jambe finira par perdants ou au moins pas rentable.

quelle que soit votre stratégie pour le bien de l'argument disons qu'il se termine par un 55%/45% win/loss ratio. Même un petit changement dans le rapport des gains/pertes peut avoir un grand changement dans la rentabilité.

re: "exécuter des dizaines (voire des centaines)" semble par commandes de l'ampleur même en regardant 20000 tiques par seconde semble faible, bien que ce pourrait être la moyenne pour toute la journée pour l'ensemble d'instruments qu'il regarde.

il y a une grande variabilité dans les taux observés à chaque seconde. Je vais donner un exemple. Dans certains de mes tests, je regarde 7 stocks de gré à gré (CSCO,GOOG,MSFT,EBAY,AAPL,INTC,DELL) au milieu de la journée les taux par seconde pour ce flux peut varier de 0 mps (très très rare) à près de 2000 devis et les métiers par pic de la seconde. (voir pourquoi je pense que les 20000 ci-dessus est faible.)

je construis l'infrastructure et le logiciel de mesure pour ce domaine et les nombres dont nous parlons sont de 100000 et des millions par seconde. J'ai des bibliothèques d'infrastructure c++ producteur/consommateur qui peuvent envoyer presque 5000000 (5 millions) messages/seconde entre producteur et consommateur, (32 bits,noyaux 2,4 GHz). Ce sont des messages de 64 octets avec nouveau, à construire, à mettre en file d'attente, synchroniser, sur le producteur et synchroniser,file d'attente,touchez chaque octet,exécutez destructeur virtuel,gratuit du côté des consommateurs. Il s'agit là, il est vrai, d'un simple point de repère sans emboîtement IO (et l'emboîtement IO peut être laid), comme ce serait le cas aux extrémités des étages de la conduite terminale. C'est toutes les classes de synchronisation personnalisées qui ne se synchronisent qu'en cas de vide, d'allocateurs personnalisés, de listes et de files d'attente libres personnalisées, de STL occasionnelle(avec des allocateurs personnalisés) mais plus souvent de collections intrusives personnalisées (dont j'ai un important bibliothèque.) Plus d'une fois, j'ai donné à un vendeur dans ce domaine un quadruple (et plus) de débit sans augmentation de batching aux points d'extrémité socket.

j'ai OrderBook et OrderBook:: classes D'univers qui prennent moins de 2us pour new, insert, find, partial fill, find, second fill, erase, delete sequence lorsqu'on fait la moyenne sur 22000 instruments. Le benchmark itère sur tous les 22000 instruments en série entre le premier et le dernier remplissage de sorte qu'il n'y a pas de astuces de mise en cache bon marché impliquer. Les opérations dans le même livre sont séparées par des accès de 22000 livres différents. Ce ne sont pas les caractéristiques de mise en cache des données réelles. Les données réelles sont beaucoup plus localisées dans le temps et les métiers consécutifs frappent souvent le même livre.

Tout ce travail implique un examen minutieux des constantes et des caractéristiques de mise en cache dans n'importe lequel des coûts algorithmiques des collections utilisées. (Parfois, il semble que le K est en K O (n) K O (N * log n) etc., etc., etc. sont écartés un peu trop avec aisance)

je travaille sur l'aspect infrastructure des données du marché. Il est inconcevable de penser même à utiliser java ou un environnement géré pour ce travail. Et quand vous pouvez obtenir ce genre de performance avec C++ et je pense qu'il est assez difficile d'obtenir des performances millions+/mps avec un environnement managé) Je ne peux pas imaginer aucune des banques d'investissement importantes ou des fonds spéculatifs (pour qui un salaire de 250000 $pour un programmeur C++ de premier ordre n'est rien) ne va pas avec le C++.

Est ce que quelqu'un y arriver vraiment 2000000+/mps performances d'un environnement géré? Je connais quelques personnes dans cette arène et personne ne s'en est vanté devant moi. Et je pense que 2mm dans un environnement géré aurait quelques droits de vantardise.

je connais un décodeur D'ordre de correction d'un joueur important qui fait 12000000 décodes de champ/ sec. (3GHz CPU) c'est C++ et le gars qui l'a écrit a presque défié n'importe qui de trouver quelque chose dans un environnement géré c'est même la moitié de cette vitesse.

technologiquement, C'est un domaine intéressant avec beaucoup de défis amusants de performance. Considérez le marché des options lorsque la sécurité sous-jacente change - il pourrait y avoir par exemple 6 points de prix en circulation avec 3 ou 4 dates d'expiration différentes. Pour chaque métier, il y avait probablement 10 à 20 devis. Ces citations peuvent déclencher des changements de prix dans les options. Ainsi, pour chaque commerce, il pourrait y avoir 100 ou 200 changements dans les propositions d'options. C'est juste une tonne de données - pas un Grand Hadron Collider collision-détecteur de collision-comme la quantité de données, mais un peu d'un défi. C'est un peu différent de traiter avec des touches.

même le débat sur la FPGA continue. Beaucoup de gens prennent la position qu'un analyseur bien codé tournant sur 3GHz marchandise HW peut battre un FPGA 500MHz. Mais même si un tout petit peu plus lent (ne pas dire qu'ils sont) les systèmes basés sur FPGA peuvent avoir tendance à avoir des distributions de retard plus serrées. (Lire "tendance" - ce n'est pas un énoncé général) bien sûr, si vous avez un grand analyseur C++ que vous poussez à travers un Cfront et puis pousser cela à travers le générateur D'image FPGA... Mais que d'un autre débat...

34
répondu pgast 2010-07-12 03:22:20

il s'agit en grande partie d'une simple différence entre les faits et la théorie. Les gens ont avancé théories pour expliquer pourquoi Java devrait être (ou du moins pourrait être) plus rapide que C++. La plupart des arguments ont peu à voir avec Java ou C++ soi, mais à la compilation dynamique versus statique, avec Java et C++ étant en fait un peu plus que des exemples des deux (bien que, bien sûr, il est possible de compiler Java statically, ou c++ dynamiquement). La plupart de ces personnes ont repères pour "prouver" leur demande. Lorsque ces critères sont examiné dans le détail, il devient vite évident que, dans quelques cas, ils ont plutôt des mesures extrêmes pour obtenir les résultats qu'ils voulaient (par exemple, un certain nombre activer optimisation lors de la compilation du Java, mais spécifiquement désactivé optimisation lors de la compilation du C++).

comparez ceci à la Ordinateur Language Benchmarks Jeu, où quasiment personne pouvez soumettre une entrée, de sorte que tout le code a tendance à être optimisé pour un degré raisonnable (et, dans quelques cas, même déraisonnable degré). Il semble assez clair qu'un bon nombre de personnes considèrent cela comme essentiellement une compétition, les défenseurs de chaque langue faisant de leur mieux pour "prouver" que leur langue préférée est la meilleure. Puisque n'importe qui peut soumettre une mise en oeuvre de n'importe quel problème, une soumission particulièrement mauvaise a peu d'effet sur les résultats globaux. Dans cette situation, C et c++ apparaissent comme claire dirigeants.

Pire, si quoi que ce soit à ces résultats, probablement montrer Java mieux léger que ce qui est tout à fait exact. En particulier, quelqu'un qui utilise C ou C++ et qui se soucie vraiment des performances peut (et le fera souvent) utiliser le compilateur D'Intel au lieu de g++. Ce sera généralement donner au moins 20% d'amélioration de vitesse par rapport à g++.

éditer (en réponse à quelques points soulevés par jalf, mais vraiment trop long pour s'intégrer raisonnablement dans les commentaires):

  1. pointeurs un optimiseur écrivains cauchemar. C'est vraiment exagérer les choses (tout à fait) un peu. Les pointeurs conduisent à la possibilité d'aliasing, qui empêche certaines optimisations dans certaines circonstances. Cela dit, l'incrustation prévient les effets néfastes de la plupart du temps (c.-à-d., le compilateur peut détecter s'il y a aliasing plutôt que toujours générer du code sous l'hypothèse qu'il pourrait y en avoir). Même si le code doit supposer l'aliasing, la mise en cache minimise les performances de ce type de cache (c'est-à-dire que les données dans le cache L1 ne sont que très plus lent que les données dans un registre). Empêcher l'aliasing aiderait les performances en C++, mais pas autant que vous pourriez le penser.

  2. Allocation étant beaucoup plus rapide avec un éboueur. Il est certainement vrai que l' par défaut allocator dans de nombreuses implémentations C++ est plus lent que ce que la plupart des allocateurs (courants) de déchets collectés fournir. Ceci est équilibré (au moins dans une certaine mesure) par le fait que les allocations en C++ ont tendance à être sur la pile, ce qui est aussi rapide, alors que dans un langage GC presque toutes les allocations sont habituellement sur le tas. Pire encore, dans un langage managé, vous attribuez généralement de l'espace pour chaque objet individuellement, alors qu'en C++ vous attribuez normalement de l'espace pour tous les objets d'une même portée.

il est également vrai que C++ supporte directement le remplacement des allocateurs à la fois globalement et sur un classe par classe, donc quand / si la vitesse d'allocation est vraiment un problème, il est généralement assez facile à résoudre.

finalement, jalf a raison: ces deux points sans doute favoriser les implémentations "gérées". Le degré de cette amélioration devrait être maintenu dans la perspective cependant: ils ne sont pas assez pour permettre aux implémentations compilées dynamiquement de fonctionner plus rapidement sur beaucoup de code -- pas même des benchmarks conçus dès le début pour les favoriser autant que possible.

Edit2: je vois que Jon Harrop a essayé d'insérer sa valeur de deux (milliardièmes de cent). Pour ceux qui ne le connaissent pas, Jon a été un homme!--45-->notoire troll et spammeur ans