IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Vous êtes nouveau sur Developpez.com ? Créez votre compte ou connectez-vous afin de pouvoir participer !

Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Vous n'avez pas encore de compte Developpez.com ? Créez-en un en quelques instants, c'est entièrement gratuit !

Si vous disposez déjà d'un compte et qu'il est bien activé, connectez-vous à l'aide du formulaire ci-dessous.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

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 , par Patrick Ruiz

109PARTAGES

18  0 
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 :

Code Rust : Sélectionner tout
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 : Sélectionner tout
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 ?

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

Une erreur dans cette actualité ? Signalez-le nous !

Avatar de Jeff_67
Membre éprouvé https://www.developpez.com
Le 06/01/2021 à 11:07
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).
6  0 
Avatar de
https://www.developpez.com
Le 06/01/2021 à 12:07
Citation Envoyé par Jeff_67 Voir le message
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).
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.
6  0 
Avatar de
https://www.developpez.com
Le 07/01/2021 à 18:08
Citation Envoyé par Mister Nono Voir le message
Mathématiques, science immuable depuis la fondation du monde.
C'est une blague ?
6  0 
Avatar de
https://www.developpez.com
Le 06/01/2021 à 10:02
Citation Envoyé par Patrick Ruiz Voir le message
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.
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.
5  0 
Avatar de Mimoza
Membre averti https://www.developpez.com
Le 06/01/2021 à 11:05
L'é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.
6  1 
Avatar de denis18
Membre habitué https://www.developpez.com
Le 06/01/2021 à 12:51
Il 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.
5  0 
Avatar de Nerothos
Membre régulier https://www.developpez.com
Le 06/01/2021 à 16:08
Le 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.
3  0 
Avatar de Aurelien.Regat-Barrel
Expert éminent sénior https://www.developpez.com
Le 07/01/2021 à 12:50
Citation Envoyé par Jeff_67 Voir le message
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.
Il 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é".
3  0 
Avatar de walfrat
Membre expérimenté https://www.developpez.com
Le 11/01/2021 à 22:15
Jusqu'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.
3  0 
Avatar de chrtophe
Responsable Systèmes https://www.developpez.com
Le 10/02/2021 à 19:57
on passe notre temps à apprendre de nouveaux langages
Beaucoup de nouveaux langages sont assez proches de la syntaxe du C.

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é ?
3  0