zeratax / yacx

Yet Another CudaExecutor - wrapper to easily compile and execute cuda kernels
https://zeratax.github.io/yacx
MIT License
8 stars 4 forks source link

instantiate for cuda/nvrtc exception enum #79

Closed zeratax closed 4 years ago

zeratax commented 4 years ago

https://github.com/ZerataX/yacx/blob/master/include/yacx/Exception.hpp#L149 can probably be done way shorter and then won't lead to problems with different cuda toolkits versions

visualJames commented 4 years ago

In nvrtc you can simply get the name with nvrtcGetErrorString. But in cuResult we first don't have such a function and second we also want to print out the description of the enumeration. But to simply put it in a array and convert the number i to int to get the string in the array[i] place is also not practical, because for example after enum 8 follows enum 100. But probably I will try this solution, because everything else is not a shorter or better understandable solution.

Which problems occour with different cuda toolkits versions? Could you please make a screenshot. Do you wish to have a solution with templates?

visualJames commented 4 years ago

templateCompileTime As I remember was one error that warning are printed out, because some CUresult are not in some cudaTookitVersions. But I have to work with switch, because all classes have to be interpreted at compile time. If I try it simply like above. I does not work, because a variable can never be constant and we simply don't know at the compile time which error could occour. To solve it in a different way I have probably to change the class structure. Then it would't work with templates and it won't exist different Exception classes for each enum, because I don't know how to do it then differently.

If the problem is that only in different cuda toolkits versions some CUresults aren't recognized. I could simply ask with #ifdef and #ifndef directives and with nvcc --version if it is the correct version. In this version it doesn't become simpler but it works.

zeratax commented 4 years ago

the latest cuda version has a way more errors which is why you had to remove so many to suppress warnings when running it on the server, which doesn't have the latest toolkit version.

There are specifically ways to instantiate whole enums for templates afaik. Meaning, that if two cuda toolkit versions have a different amount of errors in that enum the compiler should be able to take care of that, maybe something like this https://codereview.stackexchange.com/questions/166634/instantiating-a-c-class-based-on-an-enum-value

zeratax commented 4 years ago

for one there are macros to detect the version, e.g. __CUDACC_VER_MAJOR__

But this is not really what I want, though I have to admit I can't find any resources related to this myself rn

visualJames commented 4 years ago
// Copyright 2019 André Hodapp
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

#include <cuda.h>
#include <builtin_types.h>  // z.B. für dim3
#include <nvrtc.h>

// C++ Headers
#include <string>
#include <vector>
#include <exception>

/*
* this is the class of which nvrtcResultException and cudaResultException erben
*/
class nvidiaException : public std::exception {
private:
    std::string error;
public:
    void setError(std::string error){
        this->error = error;
    }
    const char * what () const throw () {
        return error.c_str();
    }
};

/*
*Template class for nvrtcResult Exceptions
*nvrtcResult name is the name and class_type of the exception
*/
template<nvrtcResult name = (nvrtcResult)0>
class nvrtcResultException : public nvidiaException {
public:
    nvrtcResultException(){
        printf("nvrtcResultException<%i> created\n", (int)name);
    }
};

/*
*Template class for nvrtcResult Exceptions
*nvrtcResult name is the name and class_type of the exception
*/
template<CUresult name = (CUresult)0>
class CUresultResultException : public nvidiaException {
public:
    CUresultResultException(){
        printf("CUresultResultException<%i> created\n", (int)name);
    }
};

constexpr nvrtcResult operator++ (const nvrtcResult& e)
{
    nvrtcResult neu = nvrtcResult(static_cast<std::underlying_type<nvrtcResult>::type>(e) + 1);
    return neu;
}

constexpr CUresult operator++ (const CUresult& e)
{
    CUresult neu = CUresult(static_cast<std::underlying_type<CUresult>::type>(e) + 1);
    return neu;
}

template<nvrtcResult res>
void addVector(std::vector<nvidiaException>& vec){
    vec.push_back(nvrtcResultException<res>());
    addVector<++res>(vec);
}

template <>
void addVector<NVRTC_ERROR_INTERNAL_ERROR>(std::vector<nvidiaException>& vec)
{
    vec.push_back(nvrtcResultException<NVRTC_ERROR_INTERNAL_ERROR>());
    return; //End of the template loop
}

template<CUresult res>
void addVector(std::vector<nvidiaException>& vec){
    vec.push_back(CUresultResultException<res>());
    addVector<++res>(vec);
}

template <>
void addVector</*CUDA_ERROR_UNKNOWN*/CUDA_ERROR_PROFILER_ALREADY_STOPPED>(std::vector<nvidiaException>& vec)
{
    vec.push_back(CUresultResultException</*CUDA_ERROR_UNKNOWN*/CUDA_ERROR_PROFILER_ALREADY_STOPPED>());
    return; //End of the template loop
}

// This will throw as an error the proper CUDA error strings
// in the event that a CUDA host call returns an error
#define checkNvrtcResultError(error)  __checkNvrtcResultError (error, __FILE__, __LINE__);
inline void __checkNvrtcResultError(const nvrtcResult error,
 const char *file, const int line ) {
    if( NVRTC_SUCCESS != error) {
       //create string for exception 
      std::string exception =
              nvrtcGetErrorString(error); //method to get the error name from NVIDIA
                exception = exception + "\n->occoured in file <" + file 
                +" in line " + std::to_string(line) + "\n";
      //choose which error to throw
      std::vector<nvidiaException> vec;
        /*for (nvrtcResult result = NVRTC_SUCCESS; result <= NVRTC_ERROR_INTERNAL_ERROR; ++result) {
            vec.push_back(nvrtcResultException<result>());
        }*/
        addVector<(nvrtcResult)0>(vec);
        vec.at(error).setError(exception.c_str());
      throw vec.at(error);
  }
 }

// This will throw as an error the proper CUDA error strings
// in the event that a CUDA host call returns an error
#define checkCUresultError(error)  __checkCUresultError (error, __FILE__, __LINE__);
inline void __checkCUresultError(const CUresult error,
                                    const char *file, const int line ) {
    if( CUDA_SUCCESS != error) {
        //create string for exception
        const char** name;
        cuGetErrorName(error, name); //method to get the error name from NVIDIA
        const char** description;
        cuGetErrorString(error, description); //method to get the error description from NVIDIA
        std::string exception = *name;
        exception = exception + "\n->occoured in file <" + file
                    +" in line " + std::to_string(line) + "\n" + *description + "\n";
        //choose which error to throw
        std::vector<nvidiaException> vec;
        /*for (nvrtcResult result = NVRTC_SUCCESS; result <= NVRTC_ERROR_INTERNAL_ERROR; ++result) {
            vec.push_back(nvrtcResultException<result>());
        }*/
        addVector<(CUresult)0>(vec);
        vec.at(error).setError(exception.c_str());
        throw vec.at(error);
    }
}

void testNvrtcResult() {
    nvrtcResult result = NVRTC_ERROR_INVALID_PROGRAM;
    char *r = (char *) nvrtcGetErrorString(result);
    //handle with nvtrtcGetErrorString
    printf("With nvrtcGetErrorString you can print out the following string:\n%s\n\n", r);

    printf("this is my new function, which returns a exception:\n");
    //handle with my function
    try {
        checkNvrtcResultError(result);
    } catch (nvrtcResultException<(nvrtcResult) 1> &e) {  // NVRTC_ERROR_OUT_OF_MEMORY
        std::cout << "Wrong Exception caught" << std::endl;
        std::cout << e.what() << std::endl;
    } catch (nvrtcResultException<NVRTC_ERROR_INVALID_PROGRAM> &e) {
        std::cout << "Correct Exception caught" << std::endl;
        std::cout << e.what() << std::endl;
    } catch (nvidiaException e) {
        std::cout << "almost correct Exception caught" << std::endl;
        std::cout << e.what() << std::endl;
    }catch (std::exception &e) {
            // Other errors
            std::cout << "anderer Error\n";
            std::cout << e.what() << std::endl;
        }
    }

void testCudaResult() {
    printf("ha");
    CUresult result = CUDA_ERROR_HARDWARE_STACK_ERROR;
    printf("ha");
    const char** name;
    cuGetErrorName(result, name); //method to get the error name from NVIDIA
    const char** description;
    cuGetErrorString(result, description); //method to get the error description from NVIDIA
    printf("With cuGetErrorName you can print out the following string:\n%s\n\n", *name);
    printf("With cuGetErrorString you can print out the following string:\n%s\n\n", *description);

    printf("this is my new function, which returns a exception:\n");
    //handle with my function
    try {
        checkCUresultError(result);
    } catch (CUresultResultException<CUDA_ERROR_HARDWARE_STACK_ERROR> &e) {
        std::cout << "Correct Exception caught" << std::endl;
        std::cout << e.what() << std::endl;
    } catch (nvidiaException e) {
        std::cout << "almost correct Exception caught" << std::endl;
        std::cout << e.what() << std::endl;
    }catch (std::exception &e) {
        // Other errors
        std::cout << "anderer Error\n";
        std::cout << e.what() << std::endl;
    }
}

void test(){
    printf("hi TEST\n");
}

    int main(void){
    printf("hello\n");
    testNvrtcResult();
        printf("hello\n");
        testNvrtcResult();
        test();
    testCudaResult();
    return 0;
}
cmake_minimum_required(VERSION 3.15)
project(enumNVRTC_result)

set(CMAKE_CXX_STANDARD 14)
link_libraries(cuda nvrtc)

add_executable(untitled main.cpp)

With nvrtcGetErrorString you can print out the following string: NVRTC_ERROR_INVALID_PROGRAM

this is my new function, which returns a exception:

nvrtcResultException<0> created
nvrtcResultException<1> created
nvrtcResultException<2> created
nvrtcResultException<3> created
nvrtcResultException<4> created
nvrtcResultException<5> created
nvrtcResultException<6> created
nvrtcResultException<7> created
nvrtcResultException<8> created
nvrtcResultException<9> created
nvrtcResultException<10> created
nvrtcResultException<11> created
almost correct Exception caught
NVRTC_ERROR_INVALID_PROGRAM
->occoured in file </home/samuelwiegner/Documents/Universität/7tesSemester/Projektseminar/CUDA/CudaDriverApi/checkCudaErrors/enumNVRTC_REsult/main.cpp in line 155

hi TEST
[1]    17849 segmentation fault (core dumped)  ./build/untitled

Ich habe mal ausprobiert, wie es funktionieren könnte. Es ist doch schwerer als gedacht und man konnte auch nicht direkt die Lösung von der verlinkten Seite anwenden. Die Probleme sind: 1. bisher packe ich es immer in einen Vektor, so das alle Sachen während der Compile Zeit initialisiert sind. Aber dadurch ist der Vektor mit der Oberklasse definiert, sodass man letztlich nicht die nvtrcException<1> wirft, sondern nvidiaException. Was man vielleicht lösen kann, aber ich kenne mich nicht so gut aus und dieser Fehler ist auch erstmal noch nicht der Schlimme. 2. Der schlimme Fehler ist, dass es für CUresult nicht funktioniert. Ich gehe einfach nur in die Funktion rein und direkt kommt ein Error. Ich mache nichts, sondern ganz oben wird direkt "Hello" ausgeprintet, aber es kommt nicht mal zu dieser ersten Zeile in der Funktion. Wenn ich andere Funktionen aufrufe, funktioniert alles. Es ist irgendwie das dort es mit den Präprozessor auseinanderfliegt. Z.B. könnte es sein, dass ich zu viel Speicher auf den Stack habe und durch einen Stackoverflow einen SIGSEGV bekomme

visualJames commented 4 years ago
// Copyright 2019 André Hodapp
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

#include <cuda.h>
#include <builtin_types.h>  // z.B. für dim3
#include <nvrtc.h>

// C++ Headers
#include <string>
#include <vector>
#include <exception>

/*
* this is the class of which nvrtcResultException and cudaResultException erben
*/
class nvidiaException : public std::exception {
protected:
    std::string error;
public:
    const char * what () const throw () {
        return error.c_str();
    }
};

/*
*class for nvrtcResult Exceptions
*nvrtcResult name is the name of the exception
*/
class nvrtcResultException : public nvidiaException {
public:
    nvrtcResult name;
    nvrtcResultException(nvrtcResult name, std::string error){
        this->name = name;
        this->error = error;
        printf("nvrtcResultException %i with description: '%s' created\n", (int)name , this->error.c_str());
    }
};

/*
*Template class for nvrtcResult Exceptions
*nvrtcResult name is the name and class_type of the exception
*/

class CUresultResultException : public nvidiaException {
public:
    CUresult name;
    CUresultResultException(CUresult name, std::string error){
        this->name = name;
        this->error = error;
        printf("CUresultResultException %i with description: '%s' created\n", (int)name, this->error.c_str());
    }
};

// This will throw as an error the proper CUDA error strings
// in the event that a CUDA host call returns an error
#define checkNvrtcResultError(error)  __checkNvrtcResultError (error, __FILE__, __LINE__);
inline void __checkNvrtcResultError(const nvrtcResult error,
 const char *file, const int line ) {
    if( NVRTC_SUCCESS != error) {
       //create string for exception
      std::string exception =
              nvrtcGetErrorString(error); //method to get the error name from NVIDIA
                exception = exception + "\n->occoured in file <" + file
                +" in line " + std::to_string(line) + "\n";
      throw nvrtcResultException(error, exception);
  }
 }

// This will throw as an error the proper CUDA error strings
// in the event that a CUDA host call returns an error
#define checkCUresultError(error)  __checkCUresultError (error, __FILE__, __LINE__);
inline void __checkCUresultError(const CUresult error,
                                    const char *file, const int line ) {
    if( CUDA_SUCCESS != error) {
        //create string for exception
        const char* name;
        cuGetErrorName(error, &name); //method to get the error name from NVIDIA
        const char* description;
        cuGetErrorString(error, &description); //method to get the error description from NVIDIA
        std::string exception = name;
        exception = exception + "\n->occoured in file <" + file
                    +" in line " + std::to_string(line) + "\n" + description + "\n";
        //choose which error to throw
        throw CUresultResultException(error, exception);
    }
}

void testNvrtcResult() {
    nvrtcResult result = NVRTC_ERROR_INVALID_PROGRAM;
    char *r = (char *) nvrtcGetErrorString(result);
    //handle with nvtrtcGetErrorString
    printf("With nvrtcGetErrorString you can print out the following string:\n%s\n\n", r);

    printf("this is my new function, which returns a exception:\n");
    //handle with my function
    try {
        checkNvrtcResultError(result);
    } catch (nvrtcResultException &e) {
      switch(e.name){
        case NVRTC_ERROR_INVALID_PROGRAM:
                std::cout << "Correct Exception caught" << std::endl;
                std::cout << e.what() << std::endl;
                break;
        case (nvrtcResult) 1 :  // NVRTC_ERROR_OUT_OF_MEMORY
            std::cout << "Wrong Exception caught" << std::endl;
            std::cout << e.what() << std::endl;
            break;
        default:
          std::cout << "Not Correct Exception caught" << std::endl;
          std::cout << e.what() << std::endl;
          break;
      }
    } catch (nvidiaException& e) {
        std::cout << "almost correct Exception caught" << std::endl;
        std::cout << e.what() << std::endl;
    }catch (std::exception &e) {
            // Other errors
            std::cout << "anderer Error\n";
            std::cout << e.what() << std::endl;
        }
    }

void testCudaResult() {
    printf("ha\n");
    CUresult result = CUDA_ERROR_DEINITIALIZED;
    printf("ha%i\n", (int) result);
    const char* name;
    cuGetErrorName(result, &name); //method to get the error name from NVIDIA
    const char* description;
    cuGetErrorString(result, &description); //method to get the error description from NVIDIA
    printf("With cuGetErrorName you can print out the following string:\n%s\n\n", name);
    printf("With cuGetErrorString you can print out the following string:\n%s\n\n", description);

    printf("this is my new function, which returns a exception:\n");
    //handle with my function
    try {
        checkCUresultError(result);
    } catch (CUresultResultException &e) {
      switch(e.name){
        case CUDA_ERROR_DEINITIALIZED:
                std::cout << "Correct Exception caught" << std::endl;
                std::cout << e.what() << std::endl;
                break;
        default:
          std::cout << "Not Correct Exception caught" << std::endl;
          std::cout << e.what() << std::endl;
          break;
        }
      }catch (nvidiaException &e) {
        std::cout << "almost correct Exception caught" << std::endl;
        std::cout << e.what() << std::endl;
    }catch (std::exception &e) {
        // Other errors
        std::cout << "anderer Error\n";
        std::cout << e.what() << std::endl;
    }
}

int main(void){
    printf("Anfang\n");
    //test1();
    testCudaResult();
    printf("hello\n");
    testNvrtcResult();
    printf("hello\n");
    testNvrtcResult();
    return 0;
}

Meine neue Lösung ist, dass wir Templates komplett rausschmeißen Bitte lass uns morgen deswegen nochmal austauschen

zeratax commented 4 years ago

@hadis1000 would you do this similarly?

zeratax commented 4 years ago

fixed with #94