kunzmi / managedCuda

ManagedCUDA aims an easy integration of NVidia's CUDA in .net applications written in C#, Visual Basic or any other .net language.
Other
440 stars 79 forks source link

NVML: nvmlDeviceGetName doesn't seem to work #31

Closed mgravell closed 7 years ago

mgravell commented 7 years ago

The actual device name wouldn't come back; I'm not an expert in C/C++ bindings, so I don't know what the right attributes etc should be - but it works OK if you implement it as a byte* (and presumably as byte[] - untested). I ended up hacking it to byte* and using it this way, which worked for me:

            const int MAX_NAME_LEN = 64;
            byte* buffer = stackalloc byte[MAX_NAME_LEN];
            if(NvmlNativeMethods.nvmlDeviceGetName(device, buffer, MAX_NAME_LEN) == nvmlReturn.Success)
            {
                int len = 0; // find the nul terminator
                for(int i = 0; i < MAX_NAME_LEN;i++)
                {
                    if(buffer[i] == 0)
                    {
                        len = i;
                        break;
                    }
                }
                if(len != 0)
                {  // interpret as ASCII directly into char - small length, so fine
                    char* ascii = stackalloc char[len];
                    for (int i = 0; i < len; i++)
                        ascii[i] = (char)buffer[i];
                    name = new string(ascii, 0, len);
                }
            }

(as a side note, there's a nvmlConstants::NVML_DEVICE_NAME_BUFFER_SIZE (64) that it may be beneficial to expose in the API)

kunzmi commented 7 years ago

String handling in p/invoke is ugly... Sometimes it works, sometimes not... The safest way to do this, is using IntPtr and Marshal, as done for the error string of the same API using a public converter method and an internal p/invoke call:

[DllImport(NVML_API_DLL_NAME, EntryPoint = "nvmlErrorString")]
internal static extern IntPtr nvmlErrorStringInternal(nvmlReturn result);

/// <summary>
/// Helper method for converting NVML error codes into readable strings.
/// For all products.
/// </summary>
/// <param name="result">NVML error code to convert</param>
/// <returns>
/// String representation of the error.
/// </returns>
public static string nvmlErrorString(nvmlReturn result)
{
    IntPtr ptr = nvmlErrorStringInternal(result);
    string error;
    error = Marshal.PtrToStringAnsi(ptr);
    return error;
}

NVML library ist just "as is", so only a simple wrapper of the C++ header file and not tested. If the string value for device name doesn't work, all the other string parameters in other functions won't work, too.

kunzmi commented 7 years ago

Fixed all functions returning strings