OverviewFilesCommitsIssuesDocsReleasesPeers

opencog-atomese-simd / opencog / opencl / scaffolding / scaffolding.cc

173 lines · cc ref:
/**
 * OpenCL scaffolding.
 *
 * This provides minimalistic scaffolding to allow OpenCL experiments
 * to take place.
 *
 * Copyright (c) 2025 Linas Vepstas
 */

#include "scaffolding.h"

#include <iostream>
#include <fstream>

/* ================================================================ */

/// Print rudimentary report of available OpenCL hardware.
void report_hardware(void)
{
	std::vector<cl::Platform> platforms;
	cl::Platform::get(&platforms);
	printf("OpenCL Hardware report\n");
	printf("Should match what the `clinfo` tool reports.\n");
	printf("Found %ld platforms:\n", platforms.size());

	for (const auto& plat : platforms)
	{
		std::string pname = plat.getInfo<CL_PLATFORM_NAME>();
		std::string pvend = plat.getInfo<CL_PLATFORM_VENDOR>();
		std::string pvers = plat.getInfo<CL_PLATFORM_VERSION>();
		printf("Platform: %s\n", pname.c_str());
		printf("\tVendor: %s\n", pvend.c_str());
		printf("\tVersion: %s\n", pvers.c_str());

		std::vector<cl::Device> devices;
		plat.getDevices(CL_DEVICE_TYPE_ALL, &devices);
		// plat.getDevices(CL_DEVICE_TYPE_GPU, &devices);

		printf("\tThis platform has %ld GPU devices:\n", devices.size());

		for (const auto& dev: devices)
		{
			std::string dname = dev.getInfo<CL_DEVICE_NAME>();
			std::string dvers = dev.getInfo<CL_DEVICE_VERSION>();
			printf("\t\tDevice: %s\n", dname.c_str());
			printf("\t\tVersion: %s\n", dvers.c_str());

			unsigned int wdim = dev.getInfo<CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS>();
			printf("\t\tWork item dimensions: %d\n", wdim);
			size_t maxsz = dev.getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>();
			printf("\t\tMax work group size: %ld\n", maxsz);
			auto dimensions = dev.getInfo<CL_DEVICE_MAX_WORK_ITEM_SIZES>();
			printf("\t\tMax dimensions: %ld", dimensions[0]);
			for (unsigned int i=1; i<wdim; i++)
				printf(" x %ld", dimensions[i]);
			printf("\n");
			unsigned int svmcaps = dev.getInfo<CL_DEVICE_SVM_CAPABILITIES>();
			printf("\t\tSVM Caps bitflag: %x\n", svmcaps);

			printf("\n");
		}
		printf("\n");
	}
	printf("\n");
}

/* ================================================================ */

/// Return the first device that has platsubstr and devsubstr as
/// substrings in the platform and device name.
cl::Device find_device(const char* platsubstr, const char* devsubstr)
{
	std::vector<cl::Platform> platforms;
	cl::Platform::get(&platforms);

	for (const auto& plat : platforms)
	{
		std::string pname = plat.getInfo<CL_PLATFORM_NAME>();
		if (pname.find(platsubstr) == std::string::npos)
			continue;

		std::vector<cl::Device> devices;
		// plat.getDevices(CL_DEVICE_TYPE_ALL, &devices);
		plat.getDevices(CL_DEVICE_TYPE_GPU, &devices);

		for (const cl::Device& dev: devices)
		{
			std::string dname = dev.getInfo<CL_DEVICE_NAME>();
			if (dname.find(devsubstr) == std::string::npos)
				continue;

			// Return first matching device.
			return dev;
		}
	}

	static const cl::Device nulldev;
	return nulldev;
}

/* ================================================================ */

/// Read source text file and build program.
/// Set return context and program as return results.
void build_kernel(cl::Context& context, const char* srcfile,
                  cl::Program& prog)
{
	// Copy in source code. Must be a better way!?
	fprintf(stderr, "Reading sourcefile %s\n", srcfile);
	std::ifstream srcfm(srcfile);
	// std::stringstream buffer;
	// buffer << srcfm.rdbuf();
	std::string src(std::istreambuf_iterator<char>(srcfm),
		(std::istreambuf_iterator<char>()));

	if (0 == src.size())
	{
		fprintf(stderr, "Error: Could not find file %s\n", srcfile);
		exit(1);
	}

	cl::Program::Sources sources;
	sources.push_back(src);

	cl::Program program(context, sources);

	// Compile
	fprintf(stderr, "Compiling sourcefile %s\n", srcfile);
	try
	{
		// Specifying flags causes exception.
		// program.build("-cl-std=CL1.2");
		program.build("");
	}
	catch (const cl::Error& e)
	{
		printf("Compile failed! %s\n", e.what());
#if 0
		printf("Log >>%s<<\n",
			program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(ocldev).c_str());
#endif
		exit(1);
	}

	prog = program;
}

/* ================================================================ */

/// Read SPV binary file and wrap it into a program.
/// Set return context and program as return results.
void load_kernel(cl::Context &context, const char* spvfile,
                 cl::Program& prog)
{
	// Copy in SPV file. Must be a better way!?
	fprintf(stderr, "Reading SPV file %s\n", spvfile);
	std::ifstream spvfm(spvfile);
	std::vector<char> spv(std::istreambuf_iterator<char>(spvfm),
		(std::istreambuf_iterator<char>()));

	if (0 == spv.size())
	{
		fprintf(stderr, "Error: Could not find file %s\n", spvfile);
		exit(1);
	}

	cl::Program program(context, spv);

	prog = program;
}

/* ======================= The End ================================ */