Les applications Rust sont-elles plus rapides que leurs équivalents en C ?
C'est ce que suggèrent plusieurs benchmarks qui comparent les deux langages de programmation de la filière système
Le 2021-01-06 09:28:32, par Patrick Ruiz, Chroniqueur Actualités
Rust de Mozilla Research est le type de langage de programmation auquel ceux qui écrivent du code pour des systèmes d’entrée/sortie de base (BIOS), des chargeurs d’amorce, des systèmes d’exploitation, etc. portent un intérêt. D’avis d’observateurs avertis, c’est le futur de la programmation système en lieu et place du langage C. En effet, des experts sont d’avis qu’il offre de meilleures garanties de sécurisation des logiciels que le couple C/C++. De récents benchmarcks suggèrent même que les applications Rust sont plus rapides que leurs équivalents C.
Les langages de programmation sont mis face à face sur plusieurs terrains dont l’allocation (et la désallocation) d’arbres binaires et la visualisation d’ensembles de Mandelbrot sur un Intel i5-3330 quatre cœurs cadencé à 3 gigahertz et doté de près de 16 Go de mémoire vive. Les benchmarks ne dévoilent des chiffres comparatifs que pour les versions les plus rapides de programmes pour un couple donné de langages. Les codes sources de ces derniers sont disponibles dans le cas du couple Rust/C pour ce qui est du benchmark Mandelbrot :
Les chiffres :
L’explication de l’intérêt grandissant d’acteurs de la filière programmation système repose sur ce type de constats. Au troisième trimestre de l’année 2019, on parlait déjà de la possible entrée au sein du noyau Linux d’un framework pour la mise sur pied de pilotes en langage de programmation Rust. Depuis l’année dernière, la communauté Linux est lancée sur des réflexions en lien à la façon d’intégrer la prise en charge du langage de Mozilla Research au système de build. « Nous devons adopter une approche de prise en charge identique à celle des compilateurs et procéder à la vérification de la disponibilité de divers drapeau de compilation à l’étape de configuration », a précisé Linus. La sortie du créateur du célèbre noyau open source marquait en principe son accord avec le principe de la prise en charge de plus en plus importante du langage Rust au sein de Linux.
Le fait avec le langage Rust est qu’il a obtenu la reconnaissance de « plus aimé » des développeurs habitués de la plateforme de questions-réponses sur des sujets liés à l’informatique – StackOverflow. Au terme de l’édition 2019 de son enquête qui a mobilisé près de 90 000 travailleurs de la filière programmation informatique, le langage a concentré 83,5 % de retours positifs. Ce sont donc près de 75 000 développeurs de ce sondage Stack Overflow qui ont fait savoir qu’ils utilisent le langage Rust et qu’ils vont continuer à en faire usage ; autrement dit, des développeurs qui, après quelques expériences avec le langage, en sont tombés amoureux. C’est une autre enquête cette fois menée par l’équipe de développement du langage et parue au premier trimestre de l’année précédente qui est venue mettre en lumière le fait que le langage reste encore principalement utilisé pour des projets personnels. Raison majeure : manque d’adoption par les entreprises.
Après, la donne est en train de changer puisque le langage commence à bénéficier de soutiens d’acteurs de l’industrie informatique et pas des moindres. À date, il existe une projection du langage Rust pour les API Windows Runtime. C’est une annonce de Microsoft parue au mois de mai de l'année précédente. Rust rejoint ainsi C++ avec la bibliothèque Rust/WinRT, ce qui ouvre la possibilité aux développeurs Rust les portes de la mise sur pied de composants et pilotes pour Windows.
Source : Debian
Et vous ?
Que pensez-vous de ces benchmarks ? Peuvent-ils constituer une base de référence pour la performance des programmes écrits en C et Rust ?
Votre entreprise a-t-elle adopté le langage Rust ? Si oui, sur des projets de quelle taille ?
Quels sont les ingrédients susceptibles de conduire à une adoption plus importante de Rust, mais qui lui font encore défaut de votre point de vue ?
Voir aussi :
Rust s'approche de sa première version stable, Mozilla publie une nouvelle préversion de son langage dérivé de C/C++
Linux : un framework pour la mise au point de drivers en langage Rust pourrait faire son entrée dans le noyau de l'OS
L'équipe de npm choisit Rust pour gérer les goulots d'étranglement liés au CPU au détriment de Go, C, C++ et Java, voici les raisons de ce choix
Les langages de programmation sont mis face à face sur plusieurs terrains dont l’allocation (et la désallocation) d’arbres binaires et la visualisation d’ensembles de Mandelbrot sur un Intel i5-3330 quatre cœurs cadencé à 3 gigahertz et doté de près de 16 Go de mémoire vive. Les benchmarks ne dévoilent des chiffres comparatifs que pour les versions les plus rapides de programmes pour un couple donné de langages. Les codes sources de ces derniers sont disponibles dans le cas du couple Rust/C pour ce qui est du benchmark Mandelbrot :
Code Rust : |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | // The Computer Language Benchmarks Game // https://salsa.debian.org/benchmarksgame-team/benchmarksgame/ // // contributed by Matt Watson // contributed by TeXitoi // contributed by Volodymyr M. Lisivka // contributed by Michael Cicotti extern crate generic_array; extern crate num_traits; extern crate numeric_array; extern crate rayon; use generic_array::typenum::consts::U8; use numeric_array::NumericArray as Arr; use rayon::prelude::*; use std::io::Write; // [f64;8] type Vecf64 = Arr<f64, U8>; type Constf64 = numeric_array::NumericConstant<f64>; const MAX_ITER: usize = 50; const VLEN: usize = 8; #[inline(always)] pub fn mbrot8(out: &mut u8, cr: Vecf64, ci: Constf64) { let mut zr = Arr::splat(0f64); let mut zi = Arr::splat(0f64); let mut tr = Arr::splat(0f64); let mut ti = Arr::splat(0f64); let mut absz = Arr::splat(0f64); for _ in 0..MAX_ITER / 5 { for _ in 0..5 { zi = (zr + zr) * zi + ci; zr = tr - ti + cr; tr = zr * zr; ti = zi * zi; } absz = tr + ti; if absz.iter().all(|&t| t > 4.) { return; } } *out = absz.iter().enumerate().fold(0, |accu, (i, &t)| { accu | if t <= 4. { 0x80 >> i } else { 0 } }); } fn main() { let size = std::env::args() .nth(1) .and_then(|n| n.parse().ok()) .unwrap_or(200); // Round size to multiple of 8 let size = size / VLEN * VLEN; let inv = 2. / size as f64; let mut xloc = vec![Arr::splat(0f64); size / VLEN]; for i in 0..size { xloc[i / VLEN][i % VLEN] = i as f64 * inv - 1.5; } let stdout_unlocked = std::io::stdout(); // Main thread only can print to stdout let mut stdout = stdout_unlocked.lock(); println!("P4\n{} {}", size, size); let mut rows = vec![0; size * size / VLEN]; rows.par_chunks_mut(size / VLEN) .enumerate() .for_each(|(y, out)| { let ci = numeric_array::NumericConstant(y as f64 * inv - 1.); out.iter_mut() .enumerate() .for_each(|(i, inner_out)| mbrot8(inner_out, xloc[i], ci)); }); let _ = stdout.write_all(&rows); } |
Code C : |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | // The Computer Language Benchmarks Game // https://salsa.debian.org/benchmarksgame-team/benchmarksgame/ // // Contributed by Kevin Miller // // ver 2: added a couple of optimizations // - Reduced number of times a vector of 8 was checked to see if // they had all escaped, similar to Dominic Letz's C #5 entry. // - Processed 64 pixels at a time if width was a multiple of 64, // thereby reducing writes to the bitmap. // // compile with following gcc flags // -pipe -Wall -O3 -ffast-math -fno-finite-math-only -march=native -mfpmath=sse -msse3 -fopenmp #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <emmintrin.h> long numDigits(long n) { long len = 0; while(n) { n=n/10; len++; } return len; } inline long vec_nle(__m128d *v, double f) { return (v[0][0] <= f || v[0][1] <= f || v[1][0] <= f || v[1][1] <= f || v[2][0] <= f || v[2][1] <= f || v[3][0] <= f || v[3][1] <= f) ? 0 : -1; } inline void clrPixels_nle(__m128d *v, double f, unsigned long * pix8) { if(!(v[0][0] <= f)) *pix8 &= 0x7f; if(!(v[0][1] <= f)) *pix8 &= 0xbf; if(!(v[1][0] <= f)) *pix8 &= 0xdf; if(!(v[1][1] <= f)) *pix8 &= 0xef; if(!(v[2][0] <= f)) *pix8 &= 0xf7; if(!(v[2][1] <= f)) *pix8 &= 0xfb; if(!(v[3][0] <= f)) *pix8 &= 0xfd; if(!(v[3][1] <= f)) *pix8 &= 0xfe; } inline void calcSum(__m128d *r, __m128d *i, __m128d *sum, __m128d *init_r, __m128d init_i) { for(long pair=0; pair<4; pair++) { __m128d r2 = r[pair] * r[pair]; __m128d i2 = i[pair] * i[pair]; __m128d ri = r[pair] * i[pair]; sum[pair] = r2 + i2; r[pair]=r2 - i2 + init_r[pair]; i[pair]=ri + ri + init_i; } } inline unsigned long mand8(__m128d *init_r, __m128d init_i) { __m128d r[4], i[4], sum[4]; for(long pair=0; pair<4; pair++) { r[pair]=init_r[pair]; i[pair]=init_i; } unsigned long pix8 = 0xff; for (long j = 0; j < 6; j++) { for(long k=0; k<8; k++) calcSum(r, i, sum, init_r, init_i); if (vec_nle(sum, 4.0)) { pix8 = 0x00; break; } } if (pix8) { calcSum(r, i, sum, init_r, init_i); calcSum(r, i, sum, init_r, init_i); clrPixels_nle(sum, 4.0, &pix8); } return pix8; } unsigned long mand64(__m128d *init_r, __m128d init_i) { unsigned long pix64 = 0; for(long byte=0; byte<8; byte++) { unsigned long pix8 = mand8(init_r, init_i); pix64 = (pix64 >> 8) | (pix8 << 56); init_r += 4; } return pix64; } int main(int argc, char ** argv) { // get width/height from arguments long wid_ht = 16000; if (argc >= 2) { wid_ht = atoi(argv[1]); } wid_ht = (wid_ht+7) & ~7; // allocate memory for header and pixels long headerLength = numDigits(wid_ht)*2+5; long pad = ((headerLength + 7) & ~7) - headerLength; // pad aligns pixels on 8 long dataLength = headerLength + wid_ht*(wid_ht>>3); unsigned char * const buffer = malloc(pad + dataLength); unsigned char * const header = buffer + pad; unsigned char * const pixels = header + headerLength; // generate the bitmap header sprintf((char *)header, "P4\n%ld %ld\n", wid_ht, wid_ht); // calculate initial values, store in r0, i0 __m128d r0[wid_ht/2]; double i0[wid_ht]; for(long xy=0; xy<wid_ht; xy+=2) { r0[xy>>1] = 2.0 / wid_ht * (__m128d){xy, xy+1} - 1.5; i0[xy] = 2.0 / wid_ht * xy - 1.0; i0[xy+1] = 2.0 / wid_ht * (xy+1) - 1.0; } // generate the bitmap long use8 = wid_ht%64; if (use8) { // process 8 pixels (one byte) at a time #pragma omp parallel for schedule(guided) for(long y=0; y<wid_ht; y++) { __m128d init_i = (__m128d){i0[y], i0[y]}; long rowstart = y*wid_ht/8; for(long x=0; x<wid_ht; x+=8) { pixels[rowstart + x/8] = mand8(r0+x/2, init_i); } } } else { // process 64 pixels (8 bytes) at a time #pragma omp parallel for schedule(guided) for(long y=0; y<wid_ht; y++) { __m128d init_i = (__m128d){i0[y], i0[y]}; long rowstart = y*wid_ht/64; for(long x=0; x<wid_ht; x+=64) { ((unsigned long *)pixels)[rowstart + x/64] = mand64(r0+x/2, init_i); } } } // write the data long ret = ret = write(STDOUT_FILENO, header, dataLength); free(buffer); return 0; } |
Les chiffres :
L’explication de l’intérêt grandissant d’acteurs de la filière programmation système repose sur ce type de constats. Au troisième trimestre de l’année 2019, on parlait déjà de la possible entrée au sein du noyau Linux d’un framework pour la mise sur pied de pilotes en langage de programmation Rust. Depuis l’année dernière, la communauté Linux est lancée sur des réflexions en lien à la façon d’intégrer la prise en charge du langage de Mozilla Research au système de build. « Nous devons adopter une approche de prise en charge identique à celle des compilateurs et procéder à la vérification de la disponibilité de divers drapeau de compilation à l’étape de configuration », a précisé Linus. La sortie du créateur du célèbre noyau open source marquait en principe son accord avec le principe de la prise en charge de plus en plus importante du langage Rust au sein de Linux.
Le fait avec le langage Rust est qu’il a obtenu la reconnaissance de « plus aimé » des développeurs habitués de la plateforme de questions-réponses sur des sujets liés à l’informatique – StackOverflow. Au terme de l’édition 2019 de son enquête qui a mobilisé près de 90 000 travailleurs de la filière programmation informatique, le langage a concentré 83,5 % de retours positifs. Ce sont donc près de 75 000 développeurs de ce sondage Stack Overflow qui ont fait savoir qu’ils utilisent le langage Rust et qu’ils vont continuer à en faire usage ; autrement dit, des développeurs qui, après quelques expériences avec le langage, en sont tombés amoureux. C’est une autre enquête cette fois menée par l’équipe de développement du langage et parue au premier trimestre de l’année précédente qui est venue mettre en lumière le fait que le langage reste encore principalement utilisé pour des projets personnels. Raison majeure : manque d’adoption par les entreprises.
Après, la donne est en train de changer puisque le langage commence à bénéficier de soutiens d’acteurs de l’industrie informatique et pas des moindres. À date, il existe une projection du langage Rust pour les API Windows Runtime. C’est une annonce de Microsoft parue au mois de mai de l'année précédente. Rust rejoint ainsi C++ avec la bibliothèque Rust/WinRT, ce qui ouvre la possibilité aux développeurs Rust les portes de la mise sur pied de composants et pilotes pour Windows.
Source : Debian
Et vous ?
Voir aussi :
-
Si on regarde le benchmark Rust vs C++, il y a à peu près autant de "victoires" en Rust qu'en C++ https://benchmarksgame-team.pages.de.../rust-gpp.html
Donc non, "les applications Rust ne sont pas plus rapides que leurs équivalents en C". C'est plutôt que ce benchmark mesure aussi à quel point les communautés veulent défendre leur langage. Et apparemment, ça n'intéresse pas la communauté C.le 06/01/2021 à 10:02 -
Les résultats des benchmarks sont dépendants de l'architecture, du matériel et des compilateurs utilisés, et pas intrinsèquement du langage de programmation. Les différences constatées en C et Rust ne sont pas significatives si bien qu'il est difficile de trancher.
Au-delà de ça, la précision est aussi un point clé dans les problèmes d'analyse numérique. Ce genre de benchmark ne l'aborde jamais.
J'ai personnellement une préférence pour Rust, non parce que le langage serait foncièrement meilleur que le C, mais parce qu'il intégré des fonctionnalités modernes tel enumerate et foreach pour reprendre le code cité en exemple, que les fonctions sont capables de retourner dès tuples (pas besoin de se dépatouiller avec des pointeurs), etc... Je trouve que ça amélioré la compacité et la lisibilité du code (85 lignes en Rust vs 200 en C pour l'exemple cité dans l'article).le 06/01/2021 à 11:07 -
MimozaMembre avertiL'écriture du code et son optimisation peux tellement influer sur les performance d'un programme que, a moins d'avoir de grosses différences de perf il est difficile de dire si un langage est plus rapide qu'un autre. Et même dans ce cas un bon codeur avec langage «lent» peux produire un programme plus véloce qu'un mauvais développeur avec un langage «rapide».
Bref, il est plus intéressant de choisir un langage pour ses qualités/caractéristiques intrasèque (sécurité mémoire, parallélisme, …) et qui est maitrisé que pour un éventuel gain de perf.le 06/01/2021 à 11:05 -
Ici la compacité du code Rust vient surtout du fait qu'il utilise des libs toutes faites pour gérer les tableaux optimisés (SIMD, multi-core). Dans le code C, tout est fait à la main donc même pour ce critère, la comparaison est injuste.le 06/01/2021 à 12:07
-
le 07/01/2021 à 18:08
-
denis18InactifIl n'y a pas toujours une seule solution à un problème donné. Les langages de programmation évoluent et deviennent parfois plus accessible pour résoudre certain problème. J'ai utilisé de nombreux Foreach en Turbo Pascal pour Windows TPW15 avec des notations objets dans un logiciel de dessin cadastrale que j'ai conçu dans les années 1990. Lors du passage en 32 bits le compilateur Delphi ne connaissait plus ces Foreach et j'ai dut tout remplacer à nouveau par des boucles for i, ceci pour expliquer que certaine évolutions récentes ont déjà était conçu mais ont disparu pour revenir à nouveau, mais aussi pour comprendre que l'évolution d'un nouveau langage demande sa persistance dans le temps et souvent quand un nouveau langage apparait ont se demande pour combien de temps ça va durer. D'autre part, le test aurais aussi était intéressant pour comparer d'autre compilateur C que Gcc, qui n'est peut être pas le mieux optimisé des compilateurs C.le 06/01/2021 à 12:51
-
chrtopheResponsable Systèmeson passe notre temps à apprendre de nouveaux langages
Maintenant y a t'il un réel intérêt à passer de C/C++ à RUST ? Je ne suis pas programmeur, mais pas convaincu non plus.
RUST existe depuis 10 ans je crois, a t'il vraiment persé ?le 10/02/2021 à 19:57 -
NerothosMembre régulierLe problème avec les benchmarks c'est que 99% du temps les codes sont ultra optimisés pour une tâche spécifique qui n'est pas représentative d'un code qui se retrouvera dans une application globale.le 06/01/2021 à 16:08
-
Aurelien.Regat-BarrelExpert éminent séniorIl y a un autre aspect très important que ces micro benchmarks n'évaluent pas c'est celui de l'organisation en mémoire des objets / variables utilisées : ce sont à chaque fois des benchmarks très orientés code de calcul. Or la performance ne se trouve pas uniquement dans les instructions assembleur loin de là. La bonne utilisation des caches est elle aussi très importante.
C'est ce qui distingue un bout de code qui tourne tout seul dans son benchmark d'une application beaucoup plus lourde qui manipule des giga octets de mémoire. Le CPU est optimisé pour fonctionner d'une certaine façon (accès linéaires et prédictibles à la mémoire), et la pénalité runtime peut être colossale si on ne permet pas au prefetcher de faire son boulot. Si la taille totale des données modifiées se limite à quelques Mo (ce qui est souvent le cas dans les benchmarks) ça se passe bien car tout tient dans les caches. Mais une fois qu'on déborde de leur capacité tout s'écroule.
Il se trouve que le langage C incite davantage à créer des structures de données compactes et sérialisées en mémoire, ce que le CPU adore. Là où un langage "objet" a davantage tendance à les éparpiller de façon quasi aléatoire. C'est encore plus vrai avec l'utilisation de listes chaînées et autres map, absentes du langage C.
Quand on connait ce genre de détails, il est assez facile de créer un benchmark tout bête qui parcourt un simple tableau et qui produit des variations de performance totalement incompréhensibles sur la base de modifications à priori insignifiantes. Ce qui nous amène à la phrase "ne fait pas confiance à un benchmark que tu n'as pas toi même truqué".le 07/01/2021 à 12:50 -
walfratMembre émériteJusqu'ici je n'ai pas entendu parler de beaucoup de langage qui semblait intéressant dès qu'on parlais de programmation système par les spécialistes du domaines. On finissait toujours par dire que le C faisait mieux le boulot.
Aujourd'hui avec Rust c'est pas le cas, beaucoup de personnes y compris les plus exigeantes (ou chiantes si tu préfères) genre Linus sont très intéressés par celui-ci. Etant donné qu'il faut être particulièrement pointu et rigoureux sur la programmation système, l'investissement pour maîtrisé ce que l'on fait est gros, et donc, ces experts ne switchent pas juste pour le plaisir de faire le dernier langage a la mode.
Enfin dire "ce que tu peux faire en Rust je peux le faire en C", et bien "tu peux aussi bien faire en assembleur tout ce que tu peux faire en C", bref cet argument vaut pas grand chose.
On peux faire des sites Web en C aussi, mais persos je me ferais pas chier à faire ça, a part peut-être pour faire le prochain site avec des centaines de millions de visites par jour.le 11/01/2021 à 22:15