Skip to content

Commit

Permalink
System layer implementation. (#154)
Browse files Browse the repository at this point in the history
* System layer implementation.

* Update README.md

* Update loader/linux/icd_linux.c

Co-authored-by: Nagy-Egri Máté Ferenc <[email protected]>

* Update loader/windows/icd_windows.c

Co-authored-by: Nagy-Egri Máté Ferenc <[email protected]>

* Update loader/windows/icd_windows.c

Co-authored-by: Nagy-Egri Máté Ferenc <[email protected]>

* Rename OCL_LAYERS to OPENCL_LAYER_PATH.

* Add comment explaining use of strcoll.

* Update windows revision.

Co-authored-by: Nagy-Egri Máté Ferenc <[email protected]>
  • Loading branch information
Kerilk and MathiasMagnus authored Sep 13, 2022
1 parent 2e35ae7 commit 7305673
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 93 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,5 +147,6 @@ The following debug environment variables are available for use with the OpenCL
|:---------------------------------:|---------------------|----------------------|
| OCL_ICD_FILENAMES | Specifies a list of additional ICDs to load. The ICDs will be enumerated first, before any ICDs discovered via default mechanisms. | `export OCL_ICD_FILENAMES=libVendorA.so:libVendorB.so`<br/><br/>`set OCL_ICD_FILENAMES=vendor_a.dll;vendor_b.dll` |
| OCL_ICD_VENDORS | On Linux and Android, specifies a directory to scan for ICDs to enumerate in place of the default `/etc/OpenCL/vendors'. | `export OCL_ICD_VENDORS=/my/local/icd/search/path` |
| OPENCL_LAYERS | Specifies a list of layers to load. | `export OPENCL_LAYERS=libLayerA.so:libLayerB.so`<br/><br/>`set OPENCL_LAYERS=libLayerA.dll;libLayerB.dll` |
| OCL_ICD_ENABLE_TRACE | Enable the trace mechanism | `export OCL_ICD_ENABLE_TRACE=True`<br/><br/>`set OCL_ICD_ENABLE_TRACE=True`<br/>`true, T, 1 can also be used here.` |
| OPENCL_LAYERS | Specifies a list of layers to load. | `export OPENCL_LAYERS=libLayerA.so:libLayerB.so`<br/><br/>`set OPENCL_LAYERS=libLayerA.dll;libLayerB.dll` |
| OPENCL_LAYER_PATH | On Linux and Android, specifies a directory to scan for layers to enumerate in place of the default `/etc/OpenCL/layers'. | `export OPENCL_LAYER_PATH=/my/local/layers/search/path` |
| OCL_ICD_ENABLE_TRACE | Enable the trace mechanism | `export OCL_ICD_ENABLE_TRACE=True`<br/><br/>`set OCL_ICD_ENABLE_TRACE=True`<br/>`true, T, 1 can also be used here.` |
6 changes: 4 additions & 2 deletions loader/icd_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
#define PATH_SEPARATOR ':'
#define DIRECTORY_SYMBOL '/'
#ifdef __ANDROID__
#define ICD_VENDOR_PATH "/system/vendor/Khronos/OpenCL/vendors";
#define ICD_VENDOR_PATH "/system/vendor/Khronos/OpenCL/vendors"
#define LAYER_PATH "/system/vendor/Khronos/OpenCL/layers"
#else
#define ICD_VENDOR_PATH "/etc/OpenCL/vendors";
#define ICD_VENDOR_PATH "/etc/OpenCL/vendors"
#define LAYER_PATH "/etc/OpenCL/layers"
#endif // ANDROID

#elif defined(_WIN32)
Expand Down
247 changes: 159 additions & 88 deletions loader/linux/icd_linux.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <sys/stat.h>
#include <dirent.h>
#include <pthread.h>
#include <limits.h>

static pthread_once_t initialized = PTHREAD_ONCE_INIT;

Expand All @@ -36,112 +37,169 @@ static pthread_once_t initialized = PTHREAD_ONCE_INIT;
*
*/

// go through the list of vendors in the two configuration files
void khrIcdOsVendorsEnumerate(void)
typedef void khrIcdFileAdd(const char *);

static inline void khrIcdOsDirEntryValidateAndAdd(const char *d_name, const char *path,
const char *extension, khrIcdFileAdd addFunc)
{
struct stat statBuff;
char* fileName = NULL;

// make sure the file name ends in `extension` (eg. .icd, or .lay)
if (strlen(extension) > strlen(d_name))
{
return;
}
if (strcmp(d_name + strlen(d_name) - strlen(extension), extension))
{
return;
}

// allocate space for the full path of the vendor library name
fileName = malloc(strlen(d_name) + strlen(path) + 2);
if (!fileName)
{
KHR_ICD_TRACE("Failed allocate space for ICD file path\n");
return;
}
sprintf(fileName, "%s/%s", path, d_name);

if (stat(fileName, &statBuff))
{
KHR_ICD_TRACE("Failed stat for: %s, continuing\n", fileName);
free(fileName);
return;
}

if (S_ISREG(statBuff.st_mode) || S_ISLNK(statBuff.st_mode))
{
FILE *fin = NULL;
char* buffer = NULL;
long bufferSize = 0;

// open the file and read its contents
fin = fopen(fileName, "r");
if (!fin)
{
free(fileName);
return;
}
fseek(fin, 0, SEEK_END);
bufferSize = ftell(fin);

buffer = malloc(bufferSize+1);
if (!buffer)
{
free(fileName);
fclose(fin);
return;
}
memset(buffer, 0, bufferSize+1);
fseek(fin, 0, SEEK_SET);
if (bufferSize != (long)fread(buffer, 1, bufferSize, fin))
{
free(fileName);
free(buffer);
fclose(fin);
return;
}
// ignore a newline at the end of the file
if (buffer[bufferSize-1] == '\n') buffer[bufferSize-1] = '\0';

// load the string read from the file
addFunc(buffer);

free(fileName);
free(buffer);
fclose(fin);
}
else
{
KHR_ICD_TRACE("File %s is not a regular file nor symbolic link, continuing\n", fileName);
free(fileName);
}
}

struct dirElem
{
char *d_name;
unsigned char d_type;
};

static int compareDirElem(const void *a, const void *b)
{
// sort files the same way libc alpahnumerically sorts directory entries.
return strcoll(((struct dirElem *)a)->d_name, ((struct dirElem *)b)->d_name);
}

static inline void khrIcdOsDirEnumerate(char *path, char *env, const char *extension,
khrIcdFileAdd addFunc, int bSort)
{
DIR *dir = NULL;
struct dirent *dirEntry = NULL;
const char* vendorPath = ICD_VENDOR_PATH;
char* envPath = NULL;

khrIcdInitializeTrace();
khrIcdVendorsEnumerateEnv();

envPath = khrIcd_secure_getenv("OCL_ICD_VENDORS");
envPath = khrIcd_secure_getenv(env);
if (NULL != envPath)
{
vendorPath = envPath;
path = envPath;
}

dir = opendir(vendorPath);
if (NULL == dir)
dir = opendir(path);
if (NULL == dir)
{
KHR_ICD_TRACE("Failed to open path %s, continuing\n", vendorPath);
KHR_ICD_TRACE("Failed to open path %s, continuing\n", path);
}
else
{
// attempt to load all files in the directory
for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir))
{
struct stat statBuff;
const char* extension = ".icd";
char* fileName = NULL;

// make sure the file name ends in .icd
if (strlen(extension) > strlen(dirEntry->d_name))
{
continue;
}
if (strcmp(dirEntry->d_name + strlen(dirEntry->d_name) - strlen(extension), extension))
{
continue;
}
struct dirent *dirEntry = NULL;

// allocate space for the full path of the vendor library name
fileName = malloc(strlen(dirEntry->d_name) + strlen(vendorPath) + 2);
if (!fileName)
{
KHR_ICD_TRACE("Failed allocate space for ICD file path\n");
continue;
}
sprintf(fileName, "%s/%s", vendorPath, dirEntry->d_name);
// attempt to load all files in the directory
if (bSort) {
// store the entries name and type in a buffer for sorting
size_t sz = 0;
size_t elemCount = 0;
size_t elemAlloc = 0;
struct dirElem *dirElems = NULL;
struct dirElem *newDirElems = NULL;
const size_t startupAlloc = 8;

if (stat(fileName, &statBuff))
{
KHR_ICD_TRACE("Failed stat for: %s, continuing\n", fileName);
free(fileName);
continue;
}
// start with a small buffer
dirElems = (struct dirElem *)malloc(startupAlloc*sizeof(struct dirElem));
if (NULL != dirElems) {
elemAlloc = startupAlloc;
for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir) ) {
char *nameCopy = NULL;

if (S_ISREG(statBuff.st_mode) || S_ISLNK(statBuff.st_mode))
{
FILE *fin = NULL;
char* buffer = NULL;
long bufferSize = 0;

// open the file and read its contents
fin = fopen(fileName, "r");
if (!fin)
{
free(fileName);
continue;
}
fseek(fin, 0, SEEK_END);
bufferSize = ftell(fin);

buffer = malloc(bufferSize+1);
if (!buffer)
{
free(fileName);
fclose(fin);
continue;
if (elemCount + 1 > elemAlloc) {
// double buffer size if necessary and possible
if (elemAlloc >= UINT_MAX/2)
break;
newDirElems = (struct dirElem *)realloc(dirElems, elemAlloc*2*sizeof(struct dirElem));
if (NULL == newDirElems)
break;
dirElems = newDirElems;
elemAlloc *= 2;
}
sz = strlen(dirEntry->d_name) + 1;
nameCopy = (char *)malloc(sz);
if (NULL == nameCopy)
break;
memcpy(nameCopy, dirEntry->d_name, sz);
dirElems[elemCount].d_name = nameCopy;
dirElems[elemCount].d_type = dirEntry->d_type;
elemCount++;
}
memset(buffer, 0, bufferSize+1);
fseek(fin, 0, SEEK_SET);
if (bufferSize != (long)fread(buffer, 1, bufferSize, fin))
{
free(fileName);
free(buffer);
fclose(fin);
continue;
qsort(dirElems, elemCount, sizeof(struct dirElem), compareDirElem);
for (struct dirElem *elem = dirElems; elem < dirElems + elemCount; ++elem) {
khrIcdOsDirEntryValidateAndAdd(elem->d_name, path, extension, addFunc);
free(elem->d_name);
}
// ignore a newline at the end of the file
if (buffer[bufferSize-1] == '\n') buffer[bufferSize-1] = '\0';

// load the string read from the file
khrIcdVendorAdd(buffer);

free(fileName);
free(buffer);
fclose(fin);
free(dirElems);
}
else
{
KHR_ICD_TRACE("File %s is not a regular file nor symbolic link, continuing\n", fileName);
free(fileName);
continue;
}
}
} else
// use system provided ordering
for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir) )
khrIcdOsDirEntryValidateAndAdd(dirEntry->d_name, path, extension, addFunc);

closedir(dir);
}
Expand All @@ -150,7 +208,20 @@ void khrIcdOsVendorsEnumerate(void)
{
khrIcd_free_getenv(envPath);
}
}

// go through the list of vendors in the two configuration files
void khrIcdOsVendorsEnumerate(void)
{
khrIcdInitializeTrace();
khrIcdVendorsEnumerateEnv();

khrIcdOsDirEnumerate(ICD_VENDOR_PATH, "OCL_ICD_VENDORS", ".icd", khrIcdVendorAdd, 0);

#if defined(CL_ENABLE_LAYERS)
// system layers should be closer to the driver
khrIcdOsDirEnumerate(LAYER_PATH, "OPENCL_LAYER_PATH", ".lay", khrIcdLayerAdd, 1);

khrIcdLayersEnumerateEnv();
#endif // defined(CL_ENABLE_LAYERS)
}
Expand Down
2 changes: 1 addition & 1 deletion loader/windows/OpenCL.rc
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

#define OPENCL_ICD_LOADER_VERSION_MAJOR 3
#define OPENCL_ICD_LOADER_VERSION_MINOR 0
#define OPENCL_ICD_LOADER_VERSION_REV 3
#define OPENCL_ICD_LOADER_VERSION_REV 4

#ifdef RC_INVOKED

Expand Down
Loading

0 comments on commit 7305673

Please sign in to comment.