I am new to Rust and wrote a function for calculating exponential moving average in Rust and compared this to equivalent one in Julia for time taken to process a vector of 100,000 elements.
The Julia function gives me a time of approx 206 micro seconds whereas Rust gives me time of approx 2.27 milli seconds. Here is the Rust function -
use rand::Rng;
use std::time::Instant;
fn calculate_ema(prices: &[f64], alpha: f64) -> Vec<f64> {
if prices.is_empty() {
return vec![];
}
let mut ema = Vec::with_capacity(prices.len());
ema.push(prices[0]); // The first EMA value is just the first price.
for i in 1..prices.len() {
let new_ema = alpha * prices[i] + (1.0 - alpha) * ema[i - 1];
ema.push(new_ema);
}
ema
}
fn main() {
// Generate a vector of 50,000 random prices between 10 and 50
let mut rng = rand::thread_rng();
let prices: Vec<f64> = (0..100000).map(|_| rng.gen_range(10.0..=50.0)).collect();
// Define the period for the EMA
let period = 10.5;
// Measure the time taken to run the calculate_ema function
let start_time = Instant::now();
let _ema = calculate_ema(&prices, 2.0/(1.0 + period));
let elapsed_time = start_time.elapsed();
println!("Time taken to run calculate_ema: {:?}", elapsed_time);
}
And here is the equivalent Julia function -
using Random
using BenchmarkTools
function calculate_ema(prices, alpha)
ema = Vector{Float64}(undef, length(prices))
ema[1] = prices[1]
for i in 2:length(prices)
ema[i] = alpha * prices[i] + (1 - alpha) * ema[i-1]
end
return ema
end
prices = rand(10.0:0.1:50.0, 100000)
alpha = 2/(1 + 10.5)
# Measure the time taken to run the calculate_ema function
@btime calculate_ema(prices, alpha)
I was expecting Rust performance to be better than Julia or may be equal. I am wondering why Rust is 10 times slower here.
The main difference between the two pieces of code is that in rust you append to the vector on the fly, where in julia you first created the vector, and then updated the elements. The latter gives the optimizer (LLVM in both cases) a much better Idea of what you are doing, allowing for better code generation.
I adjusted your Rust code as follows, to make it do roughly the same thing as julia:
I get a runtime of 380us on the Rust playground . (down from 980us using the original version). For further optimization you could compare the assembly, maybe using the fantastic https://godbolt.org which supports both languages.