Download code/llmc_training/llmc/cuda_common.h from SciCode/MileTone_2: direct link, hf CLI and curl.
- Browser
- Download file 8.39 kB
-
https://huggingface.co/SciCode/MileTone_2/resolve/main/code/llmc_training/llmc/cuda_common.h
- Command line
-
hf download hf://SciCode/MileTone_2/code/llmc_training/llmc/cuda_common.h
-
curl -L -o cuda_common.h https://huggingface.co/SciCode/MileTone_2/resolve/main/code/llmc_training/llmc/cuda_common.h
8.39 kB
| /* | |
| Common utilities for CUDA code. | |
| */ | |
| // ---------------------------------------------------------------------------- | |
| // Global defines and settings | |
| // Device properties of the CUDA device used in this process | |
| // defined as extern here because the individual kernels wish to use it | |
| // but it is actually created and instantiated in the main program file | |
| extern cudaDeviceProp deviceProp; | |
| // WarpSize is not a compile time constant | |
| // Defining here like this possibly allows the compiler to optimize better | |
| // try to make sure that 2 blocks fit on A100/H100 to maximise latency tolerance | |
| // this needs to be defines rather than queried to be used for __launch_bounds__ | |
| // convenience macro for calculating grid/block dimensions for kernels | |
| // short-cuts for compile-time boolean values that can be used as function arguments | |
| constexpr std::bool_constant<true> True; | |
| constexpr std::bool_constant<true> False; | |
| // ---------------------------------------------------------------------------- | |
| // Error checking | |
| // CUDA error checking. Underscore added so this function can be called directly not just via macro | |
| inline void cudaCheck_(cudaError_t error, const char *file, int line) { | |
| if (error != cudaSuccess) { | |
| printf("[CUDA ERROR] at file %s:%d:\n%s\n", file, line, cudaGetErrorString(error)); | |
| exit(EXIT_FAILURE); | |
| } | |
| }; | |
| // like cudaFree, but checks for errors _and_ resets the pointer. | |
| template<class T> | |
| inline void cudaFreeCheck(T** ptr, const char *file, int line) { | |
| cudaError_t error = cudaFree(*ptr); | |
| if (error != cudaSuccess) { | |
| printf("[CUDA ERROR] at file %s:%d:\n%s\n", file, line, cudaGetErrorString(error)); | |
| exit(EXIT_FAILURE); | |
| } | |
| *ptr = nullptr; | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // CUDA Precision settings and defines | |
| enum PrecisionMode { | |
| PRECISION_FP32, | |
| PRECISION_FP16, | |
| PRECISION_BF16 | |
| }; | |
| // Specific configurations based on the enabled precision | |
| typedef float floatX; | |
| // use fp16 (note: this may require gradient scaler, currently not implemented!) | |
| typedef half floatX; | |
| typedef __nv_bfloat16 floatX; | |
| // ---------------------------------------------------------------------------- | |
| // Load and store with streaming cache hints | |
| // Older nvcc does not provide __ldcs and __stcs for bfloat16, despite these | |
| // actually just being unsigned shorts. We need to be careful here to only define | |
| // our own versions if none already exist, otherwise the compiler will complain. | |
| // If not, you easily get "no viable overload" (for sm52) and "function already exists" (sm_80) | |
| __device__ floatX __ldcs(const floatX* address) { | |
| unsigned short bf = __ldcs(reinterpret_cast<const unsigned short*>(address)); | |
| return __nv_bfloat16_raw{bf}; | |
| } | |
| __device__ void __stcs(floatX* address, floatX value) { | |
| __stcs(reinterpret_cast<unsigned short*>(address), ((__nv_bfloat16_raw)value).x); | |
| } | |
| // ---------------------------------------------------------------------------- | |
| // Profiler utils | |
| class NvtxRange { | |
| public: | |
| NvtxRange(const char* s) { nvtxRangePush(s); } | |
| NvtxRange(const std::string& base_str, int number) { | |
| std::string range_string = base_str + " " + std::to_string(number); | |
| nvtxRangePush(range_string.c_str()); | |
| } | |
| ~NvtxRange() { nvtxRangePop(); } | |
| }; | |
| // ---------------------------------------------------------------------------- | |
| // Utilities to Read & Write between CUDA memory <-> files | |
| // copy num_bytes from device pointer src into file dest, using double buffering running on the given stream. | |
| inline void device_to_file(FILE* dest, void* src, size_t num_bytes, size_t buffer_size, cudaStream_t stream) { | |
| // allocate pinned buffer for faster, async transfer | |
| char* buffer_space; | |
| cudaCheck(cudaMallocHost(&buffer_space, 2*buffer_size)); | |
| // split allocation in two | |
| void* read_buffer = buffer_space; | |
| void* write_buffer = buffer_space + buffer_size; | |
| // prime the read buffer; first copy means we have to wait | |
| char* gpu_read_ptr = (char*)src; | |
| size_t copy_amount = std::min(buffer_size, num_bytes); | |
| cudaCheck(cudaMemcpyAsync(read_buffer, gpu_read_ptr, copy_amount, cudaMemcpyDeviceToHost, stream)); | |
| cudaCheck(cudaStreamSynchronize(stream)); | |
| size_t rest_bytes = num_bytes - copy_amount; | |
| size_t write_buffer_size = copy_amount; | |
| gpu_read_ptr += copy_amount; | |
| std::swap(read_buffer, write_buffer); | |
| // now the main loop; as long as there are bytes left | |
| while(rest_bytes > 0) { | |
| // initiate next read | |
| copy_amount = std::min(buffer_size, rest_bytes); | |
| cudaCheck(cudaMemcpyAsync(read_buffer, gpu_read_ptr, copy_amount, cudaMemcpyDeviceToHost, stream)); | |
| // while this is going on, transfer the write buffer to disk | |
| fwriteCheck(write_buffer, 1, write_buffer_size, dest); | |
| cudaCheck(cudaStreamSynchronize(stream)); // wait for both buffers to be ready. | |
| std::swap(read_buffer, write_buffer); | |
| rest_bytes -= copy_amount; | |
| write_buffer_size = copy_amount; | |
| gpu_read_ptr += copy_amount; | |
| } | |
| // make sure to write the last remaining write buffer | |
| fwriteCheck(write_buffer, 1, write_buffer_size, dest); | |
| cudaCheck(cudaFreeHost(buffer_space)); | |
| } | |
| // copy num_bytes from file src into device pointer dest, using double buffering running on the given stream. | |
| inline void file_to_device(void* dest, FILE* src, size_t num_bytes, size_t buffer_size, cudaStream_t stream) { | |
| // allocate pinned buffer for faster, async transfer | |
| // from the docs (https://developer.download.nvidia.com/compute/DevZone/docs/html/C/doc/html/group__CUDART__HIGHLEVEL_ge439496de696b166ba457dab5dd4f356.html) | |
| // WC memory is a good option for buffers that will be written by the CPU and read by the device via mapped pinned memory or host->device transfers. | |
| char* buffer_space; | |
| cudaCheck(cudaMallocHost(&buffer_space, 2*buffer_size, cudaHostAllocWriteCombined)); | |
| // split allocation in two | |
| void* read_buffer = buffer_space; | |
| void* write_buffer = buffer_space + buffer_size; | |
| // prime the read buffer; | |
| char* gpu_write_ptr = (char*)dest; | |
| size_t copy_amount = std::min(buffer_size, num_bytes); | |
| freadCheck(read_buffer, 1, copy_amount, src); | |
| size_t rest_bytes = num_bytes - copy_amount; | |
| size_t write_buffer_size = copy_amount; | |
| std::swap(read_buffer, write_buffer); | |
| // now the main loop; as long as there are bytes left | |
| while(rest_bytes > 0) { | |
| // initiate next read | |
| copy_amount = std::min(buffer_size, rest_bytes); | |
| cudaCheck(cudaMemcpyAsync(gpu_write_ptr, write_buffer, write_buffer_size, cudaMemcpyHostToDevice, stream)); | |
| gpu_write_ptr += write_buffer_size; | |
| // while this is going on, read from disk | |
| freadCheck(read_buffer, 1, copy_amount, src); | |
| cudaCheck(cudaStreamSynchronize(stream)); // wait for both buffers to be ready. | |
| std::swap(read_buffer, write_buffer); | |
| rest_bytes -= copy_amount; | |
| write_buffer_size = copy_amount; | |
| } | |
| // copy the last remaining write buffer to gpu | |
| cudaCheck(cudaMemcpyAsync(gpu_write_ptr, write_buffer, write_buffer_size, cudaMemcpyHostToDevice, stream)); | |
| cudaCheck(cudaStreamSynchronize(stream)); | |
| cudaCheck(cudaFreeHost(buffer_space)); | |
| } | |