opencv/modules/ocl/src/cl_programcache.cpp

312 lines
9.9 KiB
C++
Raw Normal View History

/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2010-2012, Institute Of Software Chinese Academy Of Science, all rights reserved.
// Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
// Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// @Authors
// Guoping Long, longguoping@gmail.com
// Niko Li, newlife20080214@gmail.com
// Yao Wang, bitwangyaoyao@gmail.com
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other oclMaterials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "precomp.hpp"
#include <iomanip>
#include <fstream>
#include "binarycaching.hpp"
#undef __CL_ENABLE_EXCEPTIONS
#include <CL/cl.hpp>
namespace cv { namespace ocl {
/*
* The binary caching system to eliminate redundant program source compilation.
* Strictly, this is not a cache because we do not implement evictions right now.
* We shall add such features to trade-off memory consumption and performance when necessary.
*/
std::auto_ptr<ProgramCache> _programCache;
ProgramCache* ProgramCache::getProgramCache()
{
if (NULL == _programCache.get())
_programCache.reset(new ProgramCache());
return _programCache.get();
}
ProgramCache::ProgramCache()
{
codeCache.clear();
cacheSize = 0;
}
ProgramCache::~ProgramCache()
{
releaseProgram();
}
cl_program ProgramCache::progLookup(string srcsign)
{
map<string, cl_program>::iterator iter;
iter = codeCache.find(srcsign);
if(iter != codeCache.end())
return iter->second;
else
return NULL;
}
void ProgramCache::addProgram(string srcsign , cl_program program)
{
if(!progLookup(srcsign))
{
codeCache.insert(map<string, cl_program>::value_type(srcsign, program));
}
}
void ProgramCache::releaseProgram()
{
map<string, cl_program>::iterator iter;
for(iter = codeCache.begin(); iter != codeCache.end(); iter++)
{
openCLSafeCall(clReleaseProgram(iter->second));
}
codeCache.clear();
cacheSize = 0;
}
static int enable_disk_cache =
#ifdef _DEBUG
false;
#else
true;
#endif
static int update_disk_cache = false;
static String binpath = "";
void setBinaryDiskCache(int mode, String path)
{
if(mode == CACHE_NONE)
{
update_disk_cache = 0;
enable_disk_cache = 0;
return;
}
update_disk_cache |= (mode & CACHE_UPDATE) == CACHE_UPDATE;
enable_disk_cache |=
#ifdef _DEBUG
(mode & CACHE_DEBUG) == CACHE_DEBUG;
#else
(mode & CACHE_RELEASE) == CACHE_RELEASE;
#endif
if(enable_disk_cache && !path.empty())
{
binpath = path;
}
}
void setBinpath(const char *path)
{
binpath = path;
}
int savetofile(const Context*, cl_program &program, const char *fileName)
{
size_t binarySize;
openCLSafeCall(clGetProgramInfo(program,
CL_PROGRAM_BINARY_SIZES,
sizeof(size_t),
&binarySize, NULL));
char* binary = (char*)malloc(binarySize);
if(binary == NULL)
{
CV_Error(CV_StsNoMem, "Failed to allocate host memory.");
}
openCLSafeCall(clGetProgramInfo(program,
CL_PROGRAM_BINARIES,
sizeof(char *),
&binary,
NULL));
FILE *fp = fopen(fileName, "wb+");
if(fp != NULL)
{
fwrite(binary, binarySize, 1, fp);
free(binary);
fclose(fp);
}
return 1;
}
cl_program ProgramCache::getProgram(const Context *ctx, const char **source, string kernelName,
const char *build_options)
{
cl_program program;
cl_int status = 0;
stringstream src_sign;
string srcsign;
string filename;
if (NULL != build_options)
{
src_sign << (int64)(*source) << getClContext(ctx) << "_" << build_options;
}
else
{
src_sign << (int64)(*source) << getClContext(ctx);
}
srcsign = src_sign.str();
program = NULL;
program = ProgramCache::getProgramCache()->progLookup(srcsign);
if (!program)
{
//config build programs
std::string all_build_options;
if (!ctx->getDeviceInfo().compilationExtraOptions.empty())
all_build_options += ctx->getDeviceInfo().compilationExtraOptions;
if (build_options != NULL)
{
all_build_options += " ";
all_build_options += build_options;
}
filename = binpath + kernelName + "_" + ctx->getDeviceInfo().deviceName + all_build_options + ".clb";
FILE *fp = enable_disk_cache ? fopen(filename.c_str(), "rb") : NULL;
if(fp == NULL || update_disk_cache)
{
if(fp != NULL)
fclose(fp);
program = clCreateProgramWithSource(
getClContext(ctx), 1, source, NULL, &status);
openCLVerifyCall(status);
cl_device_id device = getClDeviceID(ctx);
status = clBuildProgram(program, 1, &device, all_build_options.c_str(), NULL, NULL);
if(status == CL_SUCCESS && enable_disk_cache)
savetofile(ctx, program, filename.c_str());
}
else
{
fseek(fp, 0, SEEK_END);
size_t binarySize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *binary = new char[binarySize];
CV_Assert(1 == fread(binary, binarySize, 1, fp));
fclose(fp);
cl_int status = 0;
cl_device_id device = getClDeviceID(ctx);
program = clCreateProgramWithBinary(getClContext(ctx),
1,
&device,
(const size_t *)&binarySize,
(const unsigned char **)&binary,
NULL,
&status);
openCLVerifyCall(status);
status = clBuildProgram(program, 1, &device, all_build_options.c_str(), NULL, NULL);
delete[] binary;
}
if(status != CL_SUCCESS)
{
if(status == CL_BUILD_PROGRAM_FAILURE)
{
cl_int logStatus;
char *buildLog = NULL;
size_t buildLogSize = 0;
logStatus = clGetProgramBuildInfo(program,
getClDeviceID(ctx), CL_PROGRAM_BUILD_LOG, buildLogSize,
buildLog, &buildLogSize);
if(logStatus != CL_SUCCESS)
std::cout << "Failed to build the program and get the build info." << endl;
buildLog = new char[buildLogSize];
CV_DbgAssert(!!buildLog);
memset(buildLog, 0, buildLogSize);
openCLSafeCall(clGetProgramBuildInfo(program, getClDeviceID(ctx),
CL_PROGRAM_BUILD_LOG, buildLogSize, buildLog, NULL));
std::cout << "\n\t\t\tBUILD LOG\n";
std::cout << buildLog << endl;
delete [] buildLog;
}
openCLVerifyCall(status);
}
//Cache the binary for future use if build_options is null
if( (this->cacheSize += 1) < MAX_PROG_CACHE_SIZE)
this->addProgram(srcsign, program);
else
cout << "Warning: code cache has been full.\n";
}
return program;
}
//// Converts the contents of a file into a string
//static int convertToString(const char *filename, std::string& s)
//{
// size_t size;
// char* str;
//
// std::fstream f(filename, (std::fstream::in | std::fstream::binary));
// if(f.is_open())
// {
// size_t fileSize;
// f.seekg(0, std::fstream::end);
// size = fileSize = (size_t)f.tellg();
// f.seekg(0, std::fstream::beg);
//
// str = new char[size+1];
// if(!str)
// {
// f.close();
// return -1;
// }
//
// f.read(str, fileSize);
// f.close();
// str[size] = '\0';
//
// s = str;
// delete[] str;
// return 0;
// }
// printf("Error: Failed to open file %s\n", filename);
// return -1;
//}
} // namespace ocl
} // namespace cv