Rust returning SISGEV on large operation (C++ static lib)

I tried to summarize the whole situation in the title but the thing is that I need rust as lib to perform an array multiplication calling it from C++, and it works fine, but if I increase the size up to 1024 x 1024 (i64) rust crashes immediately.

The matrices are harcoded in a C file, there are A, B and Result matrices (to check the result).
I'm using flat matrices with an inline "index" function to access them like index(i,j).
The matrices are inside the "InputVectorType" as a struct, and all structs are inside an array (defined in C headers).
The code doesn't fail if I comment line 53 (Res[ii * SIZE + jj] += aux; //FAILS) or if the size is smaller.

Here is my lib.rs

#![allow(non_snake_case)]
pub const SIZE:usize = 1024;
pub const BLOCK_SIZE:usize = SIZE;//8-128

#[inline(always)]
fn index(i: usize, j: usize) -> usize {
    i * SIZE + j
}

#[repr(C)]
pub struct InputVectorType {
    pub AMatrix: [i64;SIZE*SIZE],
    pub BMatrix: [i64;SIZE*SIZE],
    pub RMatrix: [i64;SIZE*SIZE],
}
#[repr(C)]
pub struct OutputVectorType {
    pub errors: i64,
}

#[no_mangle]
pub extern "C" fn rust_function(
    input_vector: *const InputVectorType,
    output_vector: *mut OutputVectorType,
) {
    if input_vector.is_null() || output_vector.is_null() {
        return;
    }

    let A:[i64; SIZE*SIZE];
    let B:[i64; SIZE*SIZE];
    let GOLD:[i64; SIZE*SIZE];
    let mut Res:[i64; SIZE*SIZE] = [0;SIZE*SIZE];

    unsafe{
        A = (*input_vector).AMatrix;
        B = (*input_vector).BMatrix;
        GOLD = (*input_vector).RMatrix;
    }
    Res.iter_mut().for_each(|e| *e = 0);

    for i in (0..SIZE).step_by(BLOCK_SIZE) {
        for j in (0..SIZE).step_by(BLOCK_SIZE) {
            for k in (0..SIZE).step_by(BLOCK_SIZE) {
                // Multiply blocks
                for ii in i..(i+BLOCK_SIZE) {
                    for jj in j..(j+BLOCK_SIZE) {
                        let mut aux = 0;
                        for kk in k..(k+BLOCK_SIZE) {
                            aux += A[index(ii, kk)] * B[index(kk, jj)];
                        }
                        //println!("{}",ii*SIZE+jj); //Good
                        Res[ii * SIZE + jj] += aux; //FAILS
                    }
                }
            }
        }
    }
    let res = Res[4];
    unsafe {
        (*output_vector).errors = res;
    }
}

Thank you in advance.

My best guess is that you’re getting something like a stack overflow: If you never write into Res, the optimizer can spot that and skip the allocation.

3 Likes

You are storing 8MB of arrays on the stack, are you sure it's big enough for them?

5 Likes

In any case, it’s probably better to read from the input vectors directly instead of copying them onto the stack first:

-    let A:[i64; SIZE*SIZE];
-    let B:[i64; SIZE*SIZE];
-    let GOLD:[i64; SIZE*SIZE];
+    let A:&[i64; SIZE*SIZE];
+    let B:&[i64; SIZE*SIZE];
+    let GOLD:&[i64; SIZE*SIZE];
     let mut Res:[i64; SIZE*SIZE] = [0;SIZE*SIZE];

     unsafe{
-        A = (*input_vector).AMatrix;
-        B = (*input_vector).BMatrix;
-        GOLD = (*input_vector).RMatrix;
+        A = &(*input_vector).AMatrix;
+        B = &(*input_vector).BMatrix;
+        GOLD = &(*input_vector).RMatrix;
     }
1 Like

This explains the strange behavior. Thank you :slight_smile:

That's true, I like the idea but I did the changes to the lib.rs and it didn't fix it. Maybe I need to change anything more?

Should I dereference the A and B pointers in the multiplication? (Althoug rust should do it automatically)

Or I'll have to box the slice maybe

As everybody guessed it was a stack overflow, I fixed it using Box on the Res array and adding the changes from 2e71828.

Thank you fr your help :3

1 Like