How to malloc an array in heap like C?

I want to malloc an array in heap instead of using Vector.

This is a similar C code:

int *arr = (int *)malloc(sizeof(int) * array_size);

Is there a good way to malloc an array in heap in rust ?

2 Likes

Vec uses the heap to store its values. You could use a Box with an array, e.g. Box<[u8; 32]>

I don't want use the heap in Vec as you say. I would rather use my own heap array which is malloced by myself.

But why. There's no need to reinvent the wheel.

If you want a growable array, use Vec, period! If you want a fixed size array, use [type; size] (e.g. [u8; 16]). If you want it on the heap use Box.

Because I want to test a vector production performance. I want to see which is better in C++ and rust. So I don't need any other data or operation which affects the result.

If I use Vec to test vector production in Rust, it is 1/3 slower than C++.

Have you used --release to compile your program?

Yes, of course. I compare Rust using --release and C++ using -O3

Please show the Rust code you are using, compared to the C++ one. I bet we can find something that can be optimized.

2 Likes

What's more, the assembly code which objdump -d from binary file compiled by cargo/rustc is 30000+ lines, while 500+ lines in C/C++.

Here is Rust and C++ code. Any help will be appreciated!


use std::io;
use std::time::{Duration, Instant};
use std::alloc::{alloc, dealloc, Layout};


fn mymalloc(size: usize) -> Box<[i32]> {
    (vec![0; size]).into_boxed_slice()
}

fn main() {

    let mut v1 = mymalloc(100_000_000); 
    let mut v2 = mymalloc(100_000_000); 
    let mut vsum = mymalloc(100_000_000);

    for i in 0..100_000_000 {
        v1[i]= (i + 2) as i32;
        v2[i] = (i - 1) as i32;
    }

    let now = Instant::now();

    for k in 0..1_000 {
        for i in 0..100_000_000 {
            vsum[i] += v1[i] * v2[i];
        }
    }

    println!("time = {}", now.elapsed().as_millis());

    // assert_eq!(vsum[10000], 10002 * 9999);
}

#include <stdio.h>
#include <time.h>
#include <vector>
#include <stdlib.h>

using std::vector;

int main() {
    auto a = vector<int>(100000000);
    auto b = vector<int>(100000000);
    auto c = vector<int>(100000000);
    for (int i = 0; i < 100000000; ++i) {
        a[i] = i + 2;
        b[i] = i - 1;
    }

    struct timespec tm, ts;
    clock_gettime(CLOCK_MONOTONIC, &tm);

    for (int k = 0; k < 1000; ++k)
    for (int i = 0; i < 100000000; ++i) {
        c[i] += a[i] * b[i];
    }

    clock_gettime(CLOCK_MONOTONIC, &ts);

    printf("time = %lf\n", (ts.tv_sec - tm.tv_sec) + (ts.tv_nsec - tm.tv_nsec)*1E-9);

    return 0;
}


Funny enough, replacing the Box<[i32]> with Vec<i32> decreased the time by 20s for me. It now outperforms C++ (I haven't changed anything else).

Rust: 80212
C++ : 82470

I don't see the problem you described.

In my machine (CPU: intel i5-9600K), the time of C++ is 59720 ms.

If I using Vec<i32>, the time of Rust is 82812 ms.
If I using Box<[i32]>, the time of Rust is 80763 ms.

I think I figure out it why Rust is slower. I use Vec::with_capacity(100_000_000) and vsum.resize(100_000_000, 0) to resize vsum vector. When I change to vec![0; 100_000_000], it is just a bit slower than C++( spend 2s more than C++). So can you explain why ?

I used vec![0; size] to create a Vec. That's what I meant, when I changed to replace Box by Vec. Sorry, I think I wasn't clear enough.

1 Like

I think I've got a funny situation again..



    use std::time::{Instant};


    fn main() {

        let mut v1 = vec![0; 100_000_000]; 
        let mut v2 = vec![0; 100_000_000]; 
        let mut vsum = vec![0; 100_000_000];


        for i in 0..100_000_000 {
            v1[i] = (i + 2) as i32;
            v2[i] = (i - 1) as i32;
        }

        let now = Instant::now();

        for _ in 0..1_000 {
            for i in 0..100_000_000 {
                vsum[i] += v1[i] * v2[i];
            }
        }
        
        println!("time = {}", now.elapsed().as_millis());



        // assert_eq!(vsum[10000], 10002 * 9999);
    }


The the performance of code above is good, just 2s slower than C++.

But if I add two statements to make v1, v2 immutable like this:


    use std::time::{Instant};


    fn main() {

        let mut v1 = vec![0; 100_000_000]; 
        let mut v2 = vec![0; 100_000_000]; 
        let mut vsum = vec![0; 100_000_000];


        for i in 0..100_000_000 {
            v1[i] = (i + 2) as i32;
            v2[i] = (i - 1) as i32;
        }

        let v1 = v1;
        let v2  = v2;

        let now = Instant::now();

        for _ in 0..1_000 {
            for i in 0..100_000_000 {
                vsum[i] += v1[i] * v2[i];
            }
        }
        
        println!("time = {}", now.elapsed().as_millis());



        // assert_eq!(vsum[10000], 10002 * 9999);
    }

It is 10s slower than C++.

You should start formatting your code by using rustfmt (rustup component add rustfmt and then you can do cargo fmt).
Next, please replace 100_000_000 by a constant. It's a pain to see that large number over and over again and squeeze my eyes to see if they are actually equal to each other.

It made it actually 6 seconds faster than C++. I had to ask this earlier, but which version of rust are you using? (rustc --version)

rustc 1.34.1 (fc50f328b 2019-04-24)
gcc (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0

Which version of your C++ compiler you are using?