GPU调用

时间:2016-01-13 14:53:09

标签: c++ cuda

在我看来,我有一个相当奇怪的问题。我有一段代码,首先使用GPU创建四个矩阵,需要0.15秒,然后将矩阵复制到主机并放入cv::Mat矩阵。此后,使用两个嵌套的for循环来迭代图像并执行一些计算。

for循环完全在CPU上运行,如果我之前使用GPU计算矩阵,则需要14秒才能完成。如果我改为一直使用CPU,那么在计算四个矩阵时,计算矩阵需要2秒,但运行for循环只需要1.2秒。

为什么在for-loop之前使用GPU需要很长时间。 GPU与GPU无关。

另一件奇怪的事情是,如果我之后我调用了GPU并在CPU上创建了cv::Mat矩阵,我会想象出这样的图像

    cv::imshow("Error", Error * 100);
    cv::waitKey(0);
在循环之前

,循环只需1.4秒。

另一个奇怪的事情是,如果我将诊断程序作为管理员运行,它运行得更好,速度更快。此外,在分析代码时运行速度要快得多。

我在64位计算机上使用Visual Studio 2013。

以下是代码:

void ModelTracker::computeAnalyticLSqRay(const Eigen::VectorXd &Xi, const cv::Mat &depthImg){
LieAlgebra::LieAlgebra lie;
Eigen::MatrixXd A = Eigen::MatrixXd::Zero(6, 6);
Eigen::VectorXd b = Eigen::VectorXd::Zero(6);

// Vectors for rotation and translation
Eigen::Vector3d xi(Xi(0), Xi(1), Xi(2));
Eigen::Vector3d t(Xi(3), Xi(4), Xi(5));

// Vectors for outer derivative
double delta = DELTADERIV;

Eigen::VectorXd XiDX = Xi;
Eigen::VectorXd XiDY = Xi;
Eigen::VectorXd XiDZ = Xi;

XiDX(3) += delta;
XiDY(4) += delta;
XiDZ(5) += delta;

//cv::Mat Error = rayCast(Xi, depthImg);
//cv::Mat ErrorDX = rayCast(XiDX, depthImg);
//cv::Mat ErrorDY = rayCast(XiDY, depthImg);
//cv::Mat ErrorDZ = rayCast(XiDZ, depthImg);

// Here the GPU is called from the function GPURayCast

double t1 = omp_get_wtime();
cv::Mat Error = GPUrayCast(Xi, depthImg);
cv::Mat ErrorDX = GPUrayCast(XiDX, depthImg);
cv::Mat ErrorDY = GPUrayCast(XiDY, depthImg);
cv::Mat ErrorDZ = GPUrayCast(XiDZ, depthImg);
double t2 = omp_get_wtime();
std::cout << t2 - t1 << std::endl;
std::cout << "GPURayCast Done" << std::endl;
cv::imshow("Error", Error * 100);
cv::waitKey(0);
Eigen::MatrixXd Atmp = Eigen::MatrixXd::Zero(6, 6);
Eigen::VectorXd btmp = Eigen::VectorXd::Zero(6, 1);

t1 = omp_get_wtime();
for (int i = 0; i < depthImg.rows; i++){
    for (int j = 0; j < depthImg.cols; ++j){
        double z = depthImg.at<double>(i, j);
        if (!isnan(z)){
            double V0 = Error.at<double>(i, j);
            if (!isnan(V0)){
                Eigen::Vector3d pLocal = reproject3p(j, i, z);
                double V0Dx = ErrorDX.at<double>(i, j);
                double V0Dy = ErrorDY.at<double>(i, j);
                double V0Dz = ErrorDZ.at<double>(i, j);

                if (!isnan(V0Dx) && !isnan(V0Dy) && !isnan(V0Dz)){
                    Eigen::VectorXd grad = getRayAnalyticGradient(xi, t, pLocal, V0, V0Dx, V0Dy, V0Dz, delta, i, j, z);

                    bool gradCheck = checkGradient(grad);

                    if (gradCheck){
                        Atmp += grad*grad.transpose();
                        btmp += V0*grad;
                    }

                }
            }
        }
    }
}
t2 = omp_get_wtime();
std::cout << "Time for computing matrices: " << t2 - t1<< std::endl;
//std::cout << btmp << std::endl;
ALsq = Atmp;
bLsq = btmp;
}

GPUrayCast:

cv::Mat ModelTracker::GPUrayCast(const Eigen::VectorXd &Xi, const cv::Mat &depthImg){
LieAlgebra::LieAlgebra lie;
double *error = new double[depthImg.rows*depthImg.cols];
memset(error, 0, depthImg.cols*depthImg.rows);
Eigen::Matrix4d camera = lie.getTransfMatrix(Xi);
double ptrCamera[12] = { 0 };
cpyToCamera(ptrCamera, camera);
double3 gridStart = { start(0), start(1), start(2) };
GPURayCast(error, depthImg.rows, depthImg.cols, fx, fy, cx, cy, RESOLUTION, step, MAXITR, gridStart, MAXDISTANCE, RAYTHRESHOLD, ptrCamera);
cv::Mat tmp =  getErrorMatrix(error, depthImg.rows, depthImg.cols);
delete [] error;
return tmp;
}

GPURayCast :(在.cu文件中)

extern "C" void GPURayCast(double *target, const int rows, const int cols, const double fx, const double fy, const double cx, const double cy, const int resolution, const double gridStep, const int maxItr, const double3 gridStart, const int maxDistance, const double rayThreshold, double *camera){
uploadGlobalCamera(camera);

const int nbrOfBlocksX = (rows) / L + ((rows) % L != 0 ? 1 : 0);
const int nbrOfBlocksY = cols / L + (cols % L != 0 ? 1 : 0);
const int BXBY = nbrOfBlocksX * nbrOfBlocksY;

dim3 Blocks(nbrOfBlocksX, nbrOfBlocksY);
dim3 Threads(L, L);


CudaSafeCall(cudaMemset(devTarget, 0, rows*cols*sizeof(double)));

rayCast << <Blocks, Threads >> >(devGrid, devDepthImg, rows, cols, fx, fy, cx, cy, resolution, devTarget, gridStep, maxItr, gridStart, maxDistance, rayThreshold);
CudaSafeCall(cudaThreadSynchronize());
CudaCheckError();
CudaSafeCall(cudaMemcpy(target, devTarget, rows*cols*sizeof(double), cudaMemcpyDeviceToHost));
}

在CPU上执行所有操作(请注意,for循环与上面的void ModelTracker::computeAnalyticLSqRay中的完全相同):

void ModelTracker::CPUcomputeAnalyticLSqRay(const Eigen::VectorXd &Xi, const cv::Mat &depthImg){
LieAlgebra::LieAlgebra lie;
Eigen::MatrixXd A = Eigen::MatrixXd::Zero(6, 6);
Eigen::VectorXd b = Eigen::VectorXd::Zero(6);

// Vectors for rotation and translation
Eigen::Vector3d xi(Xi(0), Xi(1), Xi(2));
Eigen::Vector3d t(Xi(3), Xi(4), Xi(5));

// Vectors for outer derivative
double delta = DELTADERIV;

Eigen::VectorXd XiDX = Xi;
Eigen::VectorXd XiDY = Xi;
Eigen::VectorXd XiDZ = Xi;

//Eigen::VectorXd XiRX = Xi;
//Eigen::VectorXd XiRY = Xi;
//Eigen::VectorXd XiRZ = Xi;


XiDX(3) += delta;
XiDY(4) += delta;
XiDZ(5) += delta;

double t1 = omp_get_wtime();
cv::Mat Error = rayCast(Xi, depthImg);
cv::Mat ErrorDX = rayCast(XiDX, depthImg);
cv::Mat ErrorDY = rayCast(XiDY, depthImg);
cv::Mat ErrorDZ = rayCast(XiDZ, depthImg);
double t2 = omp_get_wtime();
std::cout << t2 - t1 << std::endl;
//double t1 = omp_get_wtime();
//cv::Mat Error = GPUrayCast(Xi, depthImg);
//cv::Mat ErrorDX = GPUrayCast(XiDX, depthImg);
//cv::Mat ErrorDY = GPUrayCast(XiDY, depthImg);
//cv::Mat ErrorDZ = GPUrayCast(XiDZ, depthImg);
//double t2 = omp_get_wtime();
//std::cout << t2 - t1 << std::endl;
//std::cout << "GPURayCast Done" << std::endl;
//cv::imshow("Error", Error * 100);
//cv::waitKey(0);
Eigen::MatrixXd Atmp = Eigen::MatrixXd::Zero(6, 6);
Eigen::VectorXd btmp = Eigen::VectorXd::Zero(6, 1);

t1 = omp_get_wtime();
for (int i = 0; i < depthImg.rows; i++){
    for (int j = 0; j < depthImg.cols; ++j){
        double z = depthImg.at<double>(i, j);
        if (!isnan(z)){
            double V0 = Error.at<double>(i, j);
            if (!isnan(V0)){
                Eigen::Vector3d pLocal = reproject3p(j, i, z);
                double V0Dx = ErrorDX.at<double>(i, j);
                double V0Dy = ErrorDY.at<double>(i, j);
                double V0Dz = ErrorDZ.at<double>(i, j);

                if (!isnan(V0Dx) && !isnan(V0Dy) && !isnan(V0Dz)){
                    Eigen::VectorXd grad = getRayAnalyticGradient(xi, t, pLocal, V0, V0Dx, V0Dy, V0Dz, delta, i, j, z);

                    bool gradCheck = checkGradient(grad);

                    if (gradCheck){
                        Atmp += grad*grad.transpose();
                        btmp += V0*grad;
                    }

                }
            }
        }
    }
}
t2 = omp_get_wtime();
std::cout << "Time for computing matrices: " << t2 - t1 << std::endl;
//std::cout << btmp << std::endl;
ALsq = Atmp;
bLsq = btmp;
}

getErrorMatrix():

cv::Mat ModelTracker::getErrorMatrix(double *error, const int rows, const int cols){
cv::Mat tmp = cv::Mat::zeros(rows, cols, CV_64FC1);
for (int i = 0; i < rows; ++i){
    for (int j = 0; j < cols; ++j){
        tmp.at<double>(i, j) = error[j + i*cols];
    }
}
return tmp;
}

2 个答案:

答案 0 :(得分:1)

由于这种奇怪的行为,我开始怀疑它与Visual Studio 2013中的设置有关。事实证明,即使我使用Release版本构建,当我启动程序时,它也在进行调试。添加按钮&#34;启动而不调试&#34;做了诀窍,(或ctrl-F5)。换句话说,我只是一个愚蠢的错误。

答案 1 :(得分:0)

我不知道您的代码中哪些调用可能会这样做,但您的GPU计算似乎包括将数据移动到VRAM中的步骤,然后您的GPU有一个共享而不是复制结果-address编程模型,它只是将VRAM映射到CPU代码的地址空间,这样每次后续访问都需要PCI事务处理。

或许GPU驱动程序正在更改传入的缓冲区上的页表标记,例如将页面标记为不可缓存,以使其可用于DMA。

尝试通过立即将整个数据克隆到一个全新的缓冲区(完全在CPU内存中,并且GPU驱动程序从未见过)来尝试遵循GPU操作,并将该副本用于后续计算。