src/gpu_types.cc (100 lines of code) (raw):
#include "gpu_types.h"
#include <stdio.h>
#include <sys/time.h>
#define CUDA_CHECK( fn ) do { \
CUresult status = (fn); \
if ( CUDA_SUCCESS != status ) { \
const char* errstr; \
cuGetErrorString(status, &errstr); \
printf("CUDA Driver Failure (line %d of file %s):\n\t%s returned 0x%x (%s)\n", __LINE__, __FILE__, #fn, status, errstr); \
} \
} while (0)
int GetCountSMs()
{
CUdevice device; int count;
cuCtxGetDevice(&device);
cuDeviceGetAttribute(&count, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, device);
return count;
}
int GetCountSMsVersion(int* major, int* minor)
{
CUdevice device; int count;
cuCtxGetDevice(&device);
cuDeviceGetAttribute(&count, CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT, device);
if (major != NULL)
cuDeviceGetAttribute(major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, device);
if (minor != NULL)
cuDeviceGetAttribute(minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, device);
return count;
}
// Returns current wall time in micros.
static double NowMicros() {
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<unsigned long long>(tv.tv_sec) * 1000000 + tv.tv_usec;
}
Benchmark::Benchmark(CUstream stream, const char* name, float mem_size, float num_flops, int repeat, bool isgpu)
{
stream_ = stream;
name_ = name;
mem_size_ = mem_size;
num_flops_ = num_flops * 2.0f;
repeat_ = (float)repeat;
isgpu_ = isgpu;
if (isgpu)
{
CUDA_CHECK( cuEventCreate(&hStart_, CU_EVENT_BLOCKING_SYNC) );
CUDA_CHECK( cuEventCreate(&hStop_, CU_EVENT_BLOCKING_SYNC) );
CUDA_CHECK( cuEventRecord(hStart_, stream_) );
}
else
us_start_ = NowMicros();
}
Benchmark::~Benchmark()
{
float ms = 1.0f;
if (isgpu_)
{
CUDA_CHECK( cuEventRecord(hStop_, stream_) );
CUDA_CHECK( cuEventSynchronize(hStop_) );
CUDA_CHECK( cuEventElapsedTime(&ms, hStart_, hStop_) );
CUDA_CHECK( cuEventDestroy(hStart_) );
CUDA_CHECK( cuEventDestroy(hStop_) );
}
else
ms = (float)(NowMicros() - us_start_) / 1000.0f;
ms /= repeat_;
if (mem_size_ != 0.0f)
{
float gbps = mem_size_ / (ms * 1024.0f*1024.0f);
printf("ms:%8.4f GBps:%4.0f name: %s\n", ms, gbps, name_);
}
else
{
float gflops = num_flops_ / (ms * 1000000.0f);
printf("%s fma: %12.0f ms:%8.4f gflops %5.0f\n", name_, num_flops_, ms, gflops);
//printf("ms:%8.4f Gflops:%5.0f name: %s\n", ms, gflops, name_);
}
}
typedef unsigned long long uint64;
// http://www.hackersdelight.org/hdcodetxt/magicgu.py.txt
void magicu64(uint d, uint &magic, uint &shift)
{
// common cases
if (d == 1) { magic = 1; shift = 0; }
else if (d == 2) { magic = 1; shift = 1; }
else if (d == 4) { magic = 1; shift = 2; }
else if (d == 8) { magic = 1; shift = 3; }
else
{
// 3 is a special case that only ends up in the high bits if the nmax is 0xffffffff
// we can't use 0xffffffff for all cases as some return a 33 bit magic number
uint nbits = d == 3 ? (2*32)+1 : (2*31)+1;
uint64 nmax = d == 3 ? 0xffffffff : 0x7fffffff;
uint64 d64 = d;
uint64 nc = ((nmax + 1ull) / d64) * d64 - 1ull;
for (uint p = 0; p < nbits; p++)
{
if ((1ull << p) > nc * (d64 - 1ull - ((1ull << p) - 1ull) % d64))
{
magic = (uint)(((1ull << p) + d64 - 1ull - ((1ull << p) - 1ull) % d64) / d64);
shift = magic == 1 ? p : p - 32;
//printf("div:%u magic:%u shift:%u\n", d, magic, shift);
return;
}
}
}
}
// def _magic32u(nmax, d):
// nc = ((nmax + 1) / d) * d - 1
// nbits = len(bin(nmax)) - 2
// for p in range(0, 2 * nbits + 1):
// if 2 ** p > nc * (d - 1 - (2 ** p - 1) % d):
// m = (2 ** p + d - 1 - (2 ** p - 1) % d) // d
// return (m, p)
// raise ValueError("Can't find magic number for division")
//
// _magic32u(0xffffffff, 3)