Automatic Null Checks : mitigate null pointers exceptions

As every modern language, C# exposes the null reference billion dollar mistake. On the other hand, native languages such as CUDA or C/C++ expose null pointers. To mitigate that, latest versions of compilers tend to introduce some form of automatic null checks.
For example, Typescript recently added a --strictNullChecks option, and C#, following a proposal, will expose similar features.

When it comes to CUDA, null pointers can pop out virtually anywhere. You can explicitely return nullptr in some cases, and forget to check against it at some point in your code. You can also allocate local memory by using malloc which returns null when no more memory is available.

A example

For example, have a look at this simple toy code:

unsafe class Program
    {
        struct MyStruct
        {
            public fixed double large[1000001]; // 8 extra bytes
        }

        [IntrinsicFunction("malloc")]
        static void* malloc(int s)
        {
            return (void*)Marshal.AllocHGlobal(s);
        }

        [IntrinsicFunction("free")]
        static void free(void* ptr)
        {
            Marshal.FreeHGlobal(new IntPtr(ptr));
        }

        [EntryPoint]
        public static void Run(double[] output, double[] input)
        {
            MyStruct* ptr = (MyStruct*) malloc(sizeof(MyStruct));
            for (int k = 0; k < 1000001; ++k) {
                ptr->large[k] = input[k];
            }

            free(ptr);
        }

        static void Main(string[] args)
        {
            cudaDeviceProp prop;
            cuda.GetDeviceProperties(out prop, 0);
            HybRunner runner = HybRunner.Cuda("NullChecks_CUDA.dll").SetDistrib(1, 1);
            dynamic wrapped = runner.Wrap(new Program());

            int threadCount = 1;
            double[] output = new double[threadCount];
            double[] input = new double[1000001];
            wrapped.Run(output, input);
        }
    }

Since we allocate 8000008 bytes per thread, we exceed the cudaLimitMallocHeapSize limit of 8MB, and malloc will return NULL.

Running the above code in Release mode yields the following output:


System.ApplicationException: CUDA error occured before deserialization (most probably during kernel call): an illegal memory access was encountered
at Hybridizer.Runtime.CUDAImports.CudaSerializationState.CUDADeserializer.InitialVisit(Object param)
at Hybridizer.Runtime.CUDAImports.NativeSerializerState.UpdateManagedData(Object param)

Leverage automatic null checks

As of version 1.0.5923.8928, Hybridizer proposes automatic null checks with various behaviors:

Print

The good old printf debugging! Just add -DHYBRIDIZER_NULL_CHECKS_PRINT to Hybridizer Jitter Options, recompile, and you’ll get:

null pointer at directory\Program.cs:31
System.ApplicationException: CUDA error occured before deserialization (most probably during kernel call): an illegal memory access was encountered

handy isn’t it?

Break

Add -DHYBRIDIZER_NULL_CHECKS_BREAK to Hybridizer Jitter Options. Then recompile and start CUDA debugging, and debugger will stop just before the illegal memory access:
automatic null checks

Run C# code on GPU in a minute

We updated Hybridizer Essentials today.
We fixed numerous bugs, and added some new features:

  • Cublas, Cusparse and Nvblas are better supported in CUDA 9.0 and 9.1
  • We now support intrinsic includes
  • Visual studio integration should be faster, due to a large code refactoring and performance improvements
  • We added an Item template containing all the required boilerplate C# code. That should save you some precious time
  • Some users reported a freeze of Visual Studio 2017. This should be fixed
  • We had a time zone issue for PST users. Licenses now work immediately from their zone
  • cudaDeviceProperties are now correctly mapped in cuda 9.0 and 9.1
  • Generated CUDA projects now contain the -G option in debug
  • Binary is compiled for the machine’s GPU. That means it’s compiled with the best compute capability available, but can’t be run on another machine

Finally we updated Hybridizer Samples to integrate those changes.
Given those changes, it’s now possible to create a new C# project and run code on a GPU in less than a minute:

Stay tuned!

Hybridizer Essentials supports CUDA 9.1

cuda 9.1 on marketplace
Since the publication in parallelforall blog, we had 500 installations. We received both great and constructive feedbacks. The most important issue was the lack of CUDA 9.1 support. This is now done with version 1.1.5685.8524 of Hybridizer Essentials.

You can download it from Visual Studio Marketplace or from our release page on our github.

We also updated our SDK accordingly. We added four Visual Studio solutions, one for each Visual Studio version we support.

Be aware that version 15.5.3 of Visual Studio breaks CUDA support (even 9.1). Keep version 15.5.2 (or below) if you want CUDA with Visual Studio 2017.