Вопрос

I have a c++ class which contains structs representing vectors of preset length and matrices of preset size as well. Each vector is just an array of doubles and each matrix is an array of vectors. I chose not to use the Vector class that C++ provides since I don't need to resize the vectors at all and won't be using any of the instance methods of a vector. I was just looking for a wrapper around my double arrays.

The goal of this class is to perform matrix multiplication of 2 big matrices (512x512) by breaking the matrix into smaller blocks and then performing the multiplication across several nodes on our local computing cluster using MPI. I had an issue with stack overflow exceptions when just trying to break the matrix into the smaller blocks. Here is some code:

// Vector Structs
struct Vec512 { double values[512]; };
struct Vec256 { double values[256]; };
struct Vec128 { double values[128]; };
struct Vec64 { double values[64]; };

// Matrix Structs
struct Mat512 { 
    Vec512 rows[512]; 
    Mat512(){}
    Mat512(MatrixInitEnum e){
        switch(e){
            case Empty:
                for(int row = 0; row < 512; row++){
                Vec512 temp;
                for(int col = 0; col < 512; col++){
                    temp.values[col] = 0;
                }
                rows[row] = temp;
            }
            break;
            case Random:
                for(int row = 0; row < 512; row++){
                    Vec512 temp;
                    for(int col = 0; col < 512; col++){
                        temp.values[col] = myRandom();
                    }
                    rows[row] = temp;
                }
                break;
            }
    }
    Vec512 GetRow(int row){
        return rows[row];
    }
    Vec512 GetColumn(int col){
        Vec512 column;
        for(int i = 0; i < 512; i++){
            column.values[i] = rows[i].values[col];
        }
        return column;
    }
    void SetValue(int row, int col, double value){
        rows[row].values[col] = value;
    }
    double GetValue(int row, int col){
        return rows[row].values[col];
    }
};
// Analogous structs for Mat256, Mat128, Mat64

/*Decomposes the big matrix into 4 256x256 matrices in row-major fashion*/
Mat256* DecomposeMatrix256(Mat512 *bigMat){
    Mat256 matArray[4];
    int beginRow, endRow, beginCol, endCol, rowOffset, colOffset;

    for(int it = 0; it < 4; it++){
        beginRow = (it/2) * 256;
        endRow = beginRow + 256;
        beginCol = (it % 2) * 256; 
        endCol = beginCol + 256;
        rowOffset = (it / 2) * 256;
        colOffset = (it % 2) * 256;

        for(int row = beginRow; row < endRow; row++){
            for(int col = beginCol; col < endCol; col++){
                double val = bigMat->GetValue(row, col);
                matArray[it].SetValue(row - rowOffset, col - colOffset, val);
            }
        }
    }

    return matArray;
}

// Analogous methods for breaking into 16 128x128 Mat128s and 64 64x64 Mat64s

Then my main method was simply

int main(int argc, char* argv[])
{
    cout << "Welcome, the program is now initializing the matrices.\n";

    Mat512* bigMat = new Mat512(Random);     // Creates this just fine
    Mat256* mats256 = DecomposeMatrix256(bigMat);    // Gets here and can step to the signature of the method above without issue

    // MPI code to split up the multiplication and to 
    // wait until user is ready to exit

    return 0;
}

Here is what my issue was/is: I could create the big Mat512 my my random values no problem. I set a break point at the point where the big matrix was created and verified that it was being created successfully. Then I stepped into the call to DecomposeMatrix256(Mat512 * bigMat) and saw that I was getting to the method no problem. Also, when hovering over the bigMat object, visual studio showed me that it was indeed receiving the big matrix. When I tried to step into the method, I got a stack overflow exception immediately.

What I am confused about is why I would get the stack overflow before I even create another new object (like the array of 4 256x256 matrices). I am pretty sure I am passing the matrix by reference and not by value (I am used to C# and not C++ so I would be happy to hear that I am simply doing it wrong on the reference passing) so I thought that there wouldn't be a big overhead in simply passing a reference to the big matrix.

I was able to resolve my issue by going into the project configuration settings and increasing the stack reserve size from 1MB (the default) to 8MB (possibly overkill but I just wanted it to work for my debugging purposes).

Can someone explain why I would be getting the overflow when I am simply passing a reference to the big matrix and not the matrix itself (by value)? Again, I got it to work by increasing the stack size but I don't see why this would be necessary when I am passing the object by reference and not by value.

Thanks for reading and for the input. I'd be happy to post anything else that is relevant to helping understand my issue.

Это было полезно?

Решение 2

This is because in method DecomposeMatrix256 you are creating automatic variable on stack with:

Mat256* DecomposeMatrix256(Mat512 *bigMat){
    Mat256 matArray[4];

the size of this is 4*256*256*sizeof(double) which is 4*256*256*8 on x64 bit machine. 2 097 152 bytes is just too much to put on stack, thus overflow.

Другие советы

DecomposeMatrix256() creates an array of four Mat256 objects on the stack. This is most probably causing the overflow, since it will require a lot of stack space. The parameter you are passing is not the reason of the overflow.

As another issue, the function is returning a pointer to a local variable that will go out of scope at the end of the function. This pointer will then not longer point to a valid object.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top