在 C++/CLI 和 C# 中调用 cublas 时出现意外结果
Unexpected results when calling cublas in C++/CLI and C#
我用 Visual Studio 在 C++11/CLI 中编写了一个包装器以使用 CUDA 的 CuBLAS。我正在使用 CUDA 工具包 7.0。
这是我的包装器的源代码:
#pragma once
#include "stdafx.h"
#include "BLAS.h"
#include "cuBLAS.h"
namespace lab
{
namespace Mathematics
{
namespace CUDA
{
void BLAS::DAXPY(int n, double alpha, const array<double> ^x, int incx, array<double> ^y, int incy)
{
pin_ptr<double> xPtr = &(x[0]);
pin_ptr<double> yPtr = &(y[0]);
pin_ptr<double> alphaPtr = α
cuBLAS::DAXPY(n, alphaPtr, xPtr, incx, yPtr, incy);
}
}
}
}
为了测试这段代码,我用 C# 编写了以下测试:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using lab.Mathematics.CUDA;
namespace lab.Mathematics.CUDA.Test
{
[TestClass]
public class TestBLAS
{
[TestMethod]
public void TestDAXPY()
{
var count = 10;
var alpha = 1.0;
var a = Enumerable.Range(0, count).Select(x => Convert.ToDouble(x)).ToArray();
var b = Enumerable.Range(0, count).Select(x => Convert.ToDouble(x)).ToArray();
// Call CUDA
BLAS.DAXPY(count, alpha, a, 1, b, 1);
// Validate results
for (int i = 0; i < count; i++)
{
Assert.AreEqual(i + i, b[i]);
}
}
}
}
程序使用x64架构编译没有错误。但是我每次 运行 测试得到的结果都不一样。更准确地说,数组 b
是结果,它每次都有不同的值。我也不知道为什么。
我也可能在那里添加我的 cuda 代码,有人可以找到问题。请注意,我在编译时没有收到任何错误和警告。我也想知道也许我必须在编译中做一些更改,而我什么也没做并使用默认选项。
void cuBLAS::DAXPY(int n, const double *alpha, const double *x, int incx, double *y, int incy)
{
cudaError_t cudaStat;
cublasStatus_t stat;
// Allocate GPU memory
double *devX, *devY;
cudastat = cudaMalloc((void **)&devX, (size_t)n*sizeof(*devX));
if (cudaStat != cudaSuccess) {
// throw exception
std::ostringstream msg;
msg << "device memory allocation failed: fail.Stat = " << cudaStat;
throw new std::exception(msg.str().c_str());
}
cudaMalloc((void **)&devY, (size_t)n*sizeof(*devY));
// Create cuBLAS handle
cublasHandle_t handle;
cublasCreate(&handle);
// Initialize the input matrix and vector
cublasSetVector(n, sizeof(*devX), x, incx, devX, incx);
cublasSetVector(n, sizeof(*devY), y, incy, devY, incy);
// Call cuBLAS function
cublasDaxpy(handle, n, alpha, devX, incx, devY, incy);
// Retrieve resulting vector
cublasGetVector(n, sizeof(*devY), devY, incy, y, incy);
// Free GPU resources
cudaFree(devX);
cudaFree(devY);
cublasDestroy(handle);
}
编辑:我添加了 David Yaw 的新建议,还添加了对所有 cuda 操作的错误检查。但为了可读性,我没有在这里写所有的错误检查。仍然无法正常工作。
你的错误在这几行。
// Initialize the input matrix and vector
cublasSetVector(n, sizeof(*devX), x, incx, devX, incx);
// Call cuBLAS function
cublasDaxpy(handle, n, alpha, devX, incx, devY, incy);
// Retrieve resulting vector
cublasGetVector(n, sizeof(*devY), devY, incy, y, incy);
引用 the documentation(强调我的):
This function multiplies the vector x by the scalar α and adds it to the vector y overwriting the latest vector with the result.
Y
既是输入又是输出,但您永远不会设置值,因此您会得到未初始化内存中的任何垃圾。在调用 cublasDaxpy
之前添加对 cublasSetVector
的调用以设置 devY
的初始值。
所以写的代码是完美的。我遇到的唯一问题是我没有正确编译它。根据 This Tutorial,每次您在 cuda 程序中进行更改(准确地说是 .cu 文件),您都必须重建整个项目,以便 Pralel Nsight 对其进行编译。否则会坚持上次编译。
这是一个很小的点,但可能会节省很多人,调试一整天却毫无结果。
我用 Visual Studio 在 C++11/CLI 中编写了一个包装器以使用 CUDA 的 CuBLAS。我正在使用 CUDA 工具包 7.0。
这是我的包装器的源代码:
#pragma once
#include "stdafx.h"
#include "BLAS.h"
#include "cuBLAS.h"
namespace lab
{
namespace Mathematics
{
namespace CUDA
{
void BLAS::DAXPY(int n, double alpha, const array<double> ^x, int incx, array<double> ^y, int incy)
{
pin_ptr<double> xPtr = &(x[0]);
pin_ptr<double> yPtr = &(y[0]);
pin_ptr<double> alphaPtr = α
cuBLAS::DAXPY(n, alphaPtr, xPtr, incx, yPtr, incy);
}
}
}
}
为了测试这段代码,我用 C# 编写了以下测试:
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using lab.Mathematics.CUDA;
namespace lab.Mathematics.CUDA.Test
{
[TestClass]
public class TestBLAS
{
[TestMethod]
public void TestDAXPY()
{
var count = 10;
var alpha = 1.0;
var a = Enumerable.Range(0, count).Select(x => Convert.ToDouble(x)).ToArray();
var b = Enumerable.Range(0, count).Select(x => Convert.ToDouble(x)).ToArray();
// Call CUDA
BLAS.DAXPY(count, alpha, a, 1, b, 1);
// Validate results
for (int i = 0; i < count; i++)
{
Assert.AreEqual(i + i, b[i]);
}
}
}
}
程序使用x64架构编译没有错误。但是我每次 运行 测试得到的结果都不一样。更准确地说,数组 b
是结果,它每次都有不同的值。我也不知道为什么。
我也可能在那里添加我的 cuda 代码,有人可以找到问题。请注意,我在编译时没有收到任何错误和警告。我也想知道也许我必须在编译中做一些更改,而我什么也没做并使用默认选项。
void cuBLAS::DAXPY(int n, const double *alpha, const double *x, int incx, double *y, int incy)
{
cudaError_t cudaStat;
cublasStatus_t stat;
// Allocate GPU memory
double *devX, *devY;
cudastat = cudaMalloc((void **)&devX, (size_t)n*sizeof(*devX));
if (cudaStat != cudaSuccess) {
// throw exception
std::ostringstream msg;
msg << "device memory allocation failed: fail.Stat = " << cudaStat;
throw new std::exception(msg.str().c_str());
}
cudaMalloc((void **)&devY, (size_t)n*sizeof(*devY));
// Create cuBLAS handle
cublasHandle_t handle;
cublasCreate(&handle);
// Initialize the input matrix and vector
cublasSetVector(n, sizeof(*devX), x, incx, devX, incx);
cublasSetVector(n, sizeof(*devY), y, incy, devY, incy);
// Call cuBLAS function
cublasDaxpy(handle, n, alpha, devX, incx, devY, incy);
// Retrieve resulting vector
cublasGetVector(n, sizeof(*devY), devY, incy, y, incy);
// Free GPU resources
cudaFree(devX);
cudaFree(devY);
cublasDestroy(handle);
}
编辑:我添加了 David Yaw 的新建议,还添加了对所有 cuda 操作的错误检查。但为了可读性,我没有在这里写所有的错误检查。仍然无法正常工作。
你的错误在这几行。
// Initialize the input matrix and vector
cublasSetVector(n, sizeof(*devX), x, incx, devX, incx);
// Call cuBLAS function
cublasDaxpy(handle, n, alpha, devX, incx, devY, incy);
// Retrieve resulting vector
cublasGetVector(n, sizeof(*devY), devY, incy, y, incy);
引用 the documentation(强调我的):
This function multiplies the vector x by the scalar α and adds it to the vector y overwriting the latest vector with the result.
Y
既是输入又是输出,但您永远不会设置值,因此您会得到未初始化内存中的任何垃圾。在调用 cublasDaxpy
之前添加对 cublasSetVector
的调用以设置 devY
的初始值。
所以写的代码是完美的。我遇到的唯一问题是我没有正确编译它。根据 This Tutorial,每次您在 cuda 程序中进行更改(准确地说是 .cu 文件),您都必须重建整个项目,以便 Pralel Nsight 对其进行编译。否则会坚持上次编译。
这是一个很小的点,但可能会节省很多人,调试一整天却毫无结果。