rust code lent

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Hello, je refais en rust le programme présenté ici et mon programme est hyper lent, l’animation est saccadée et je saisis pas vraiment pourquoi, je me dis que c’est les nombreux sin et cos qui pourraient causer ceci. Mais j’ai vu que faire une table de lookup ne va pas forcément améliorer mes perfs.
Je comprends pas comment afficher 5 cercles et 5 lignes peut être si gourmand.

Et la j’ai pas commencé à implémenter le graph. Je compte le faire de cette manière : je retiens la position y de l’epicycle le plus petit et je graph tout les y a dt d’interval en x.

Mais bon ça saccade beaucoup trop déjà maintenant avant d’avoir un graph qui fonctionne. Je m’y prend peut-être mal.

Actuellement je pose un cercle centré en (x;y)(x;y), trace une ligne de (x;y) aˋ(x+radiuscos(angle);y+radiussin(angle))(x;y) \ à (x + radius * cos(angle) ; y + radius * sin(angle)) et je pose un autre cercle + ligne au bout de la ligne du cercle précédent.

j’update tout mes cercles avec la position du cercles précédent et avec le dt pour qu’il calcule le nouvelle angle Je sais pas s’il y a une meilleur méthode ou si c’est juste que mon code est hyper mal conçu.

Si vous avez des idée pour améliorer tout ça :

use piston_window::*;
use std::time::Instant;

#[derive(Debug)]
struct Epi {
    radius: f64,
    color: [f32; 4],
    x: f64,
    y: f64,
    angular_speed: f64,
    angle: f64,
}
impl Epi {
    fn new() -> Epi {
        Epi {
            radius: 100.0,
            color: color::BLACK,
            x: 300.0,
            y: 512.0 / 2.0,
            angular_speed: 1.0,
            angle: 0.0,
        }
    }
    fn draw(&mut self, e: &Event, window: &mut PistonWindow) {
        window.draw_2d(e, |c, g, _| {
            let border = Ellipse::new_border(self.color, 1.0);
            border.draw(
                rectangle::centered_square(self.x, self.y, self.radius),
                &c.draw_state,
                c.transform,
                g,
            );
            line(
                color::BLACK,
                1.0,
                [self.x, self.y, self.x + self.cos(), self.y + self.sin()],
                c.transform,
                g,
            ); //draw a line
        });
    }
    fn update(&mut self, dt: u128, pos: (f64, f64)) {
        self.angle += (self.angular_speed * 2.0 * std::f64::consts::PI * dt as f64) / (1000.0);
        self.angle %= 2.0 * std::f64::consts::PI;
        self.x = pos.0;
        self.y = pos.1;
    }
    fn cos(&self) -> f64 {
        self.radius as f64 * self.angle.cos()
    }
    fn sin(&self) -> f64 {
        self.radius as f64 * self.angle.sin()
    }
    fn get_absolute_pos(&self) -> (f64, f64) {
        (self.get_absolute_x(), self.get_absolute_y())
    }
    fn get_absolute_x(&self) -> f64 {
        self.x + self.cos()
    }
    fn get_absolute_y(&self) -> f64 {
        self.y + self.sin()
    }
}

fn main() {
    let opengl = OpenGL::V4_5;
    let mut window: PistonWindow = WindowSettings::new("Square fourrier", [1024, 512])
        .exit_on_esc(true)
        .graphics_api(opengl)
        .build()
        .unwrap();

    let mut epis = vec![Epi::new()];
    let mut now = Instant::now();
  
    //https://fr.wikipedia.org/wiki/Signal_carr%C3%A9
    //4/pi [sin( (2k+1) 2*pi*dt)/(2k + 1)]
    let n_epicycle = 5;
    for k in 1..n_epicycle {
        epis.push(Epi {
            radius: 4.0 / (std::f64::consts::PI * (2 * k + 1) as f64) * 100.0,
            color: [0.0, 0.0, 0.0, 0.5],
            x: epis[k - 1].get_absolute_x(),
            y: epis[k - 1].get_absolute_y(),
            angular_speed: (2 * k + 1) as f64,
            angle: 0.0,
        });
    }

    while let Some(e) = window.next() {
        window.draw_2d(&e, |_c, g, _| {
            clear([1.0; 4], g); //clear screen
        });
        let dt = now.elapsed().as_millis();
        epis[0].draw(&e, &mut window);
        epis[0].update(dt, (250.0, 512.0 / 2.0));

        for i in 1..epis.len() {
            epis[i].draw(&e, &mut window);
            let pos_of_previous_epi = epis[i - 1].get_absolute_pos();
            epis[i].update(dt, pos_of_previous_epi);
        }
        now = Instant::now(); //init timer for next frame
    }
}

conseil: le thé est meilleur avec un zeste de citron

+0 -0

Quelle est la commande cargo que tu utilises pour compiler ton programme ? Tu restes en mode debug ou bien en mode release (beaucoup plus performant) ?

Je me suis déjà fait avoir avec ça. Les performances en mode release étaient considérablement meilleures sur un code déjà optimisé d’un point de vue algorithmique.

+0 -0

Salut,

Pour étendre un peu ce que dit @sgble, il peut être intéressant de compiler les dépendances externes avec des optimisations en mode dev, voir ici.

EDIT : au fait tu as des trucs un peu curieux dans ton code, comme des self.radius as f64 alors que tu as définit Epi.radius comme étant f64. C’est pas grave en soi, mais ça alourdit ton code pour rien.

Édité par adri1

I don’t mind that you think slowly, but I do mind that you are publishing faster. — W. Pauli

+0 -0
Auteur du sujet

j’utilise cargo run —release ou cargo build —release && ./target/app

Et franchement je vois pas de différence, c’est toujours saccadé. Ce qui me choque c’est que dans le vidéo le gars le fait en javascript sans souci, je me suis dit que j’aurais pas besoins de faire d’optimisation et là je suis déjà bloqué.

En ce qui concerne les nombreux as f64, c’est que rust me laisse pas multiplier différent type de scalar entre eux. Donc à la base j’avais des f32, et je suis passé en f64 car les fonctions trigo retourne des f64 et pi est définis en f64 et j’ai oublié d’enlever mes as f64.

Je remarque aussi que la vitesse angulaire du premier epicycle est proportionnelle au nombre d’epicycles, alors que ça devrait pas puisque je le crée avec une vitesse de 1 cf, la methode new, et je le modifie jamais

conseil: le thé est meilleur avec un zeste de citron

+0 -0

Je pense que c’est que tu utilises mal piston_window du coup, un truc du genre faire un refresh total au lieu de simplement ce qui est nécessaire peut faire mal aux perfs.

Ce qui me choque c’est que dans le vidéo le gars le fait en javascript sans souci, je me suis dit que j’aurais pas besoins de faire d’optimisation

JS est optimisé à mort dans les interpréteurs, notamment au niveau du rendu. Si tu ne te sers pas correctement de ton moteur de rendu (ou que ce dernier est lui-même mal foutu), ça va te plomber. C’est pas calculer quelques sinus et cosinus qui va faire boiter ton ordi de toute façon.

I don’t mind that you think slowly, but I do mind that you are publishing faster. — W. Pauli

+0 -0

Salut,

J’ai l’impression que tes problèmes de saccades ne viennent pas d’un problème de performances, mais plutôt d’une mauvaise utilisation du timer. D’abord parce que tu utilises la fonction as_millis qui renvoie un entier, donc tu ne peux pas mesurer d’intervalles de temps plus petits que la milliseconde. Ensuite parce que tu réinitialises ton timer bien après avoir lu sa valeur, donc tout le temps passé entre ces deux opérations n’est pas pris en compte.

Mais de toute façon, tu ne devrais pas avoir à gérer de timer manuellement. Je ne connais pas Piston, mais d’après ce que j’ai pu voir ici, si tu matches correctement sur la variable e de ta boucle, tu as accès à l’intervalle de temps écoulé depuis la dernière update.

+1 -0
Auteur du sujet

Hello,
Merci pour vos réponses, je pense que j’utilisais mal piston, j’ai refait le programme en utilisant ggez (avec l’affichage du graphique) Il se peut aussi que le problème viennent du timer, mais bon comme mon programme fonctionne désormais avec ggez, je vais pas debugger l’autre.

Et tout fonctionne sans souci sans rien opti. Merci de votre aide

conseil: le thé est meilleur avec un zeste de citron

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte