Skip to content

Commit 7305673

Browse files
System layer implementation. (#154)
* System layer implementation. * Update README.md * Update loader/linux/icd_linux.c Co-authored-by: Nagy-Egri Máté Ferenc <beiktatas+github@outlook.hu> * Update loader/windows/icd_windows.c Co-authored-by: Nagy-Egri Máté Ferenc <beiktatas+github@outlook.hu> * Update loader/windows/icd_windows.c Co-authored-by: Nagy-Egri Máté Ferenc <beiktatas+github@outlook.hu> * Rename OCL_LAYERS to OPENCL_LAYER_PATH. * Add comment explaining use of strcoll. * Update windows revision. Co-authored-by: Nagy-Egri Máté Ferenc <beiktatas+github@outlook.hu>
1 parent 2e35ae7 commit 7305673

5 files changed

Lines changed: 314 additions & 93 deletions

File tree

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,5 +147,6 @@ The following debug environment variables are available for use with the OpenCL
147147
|:---------------------------------:|---------------------|----------------------|
148148
| 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` |
149149
| 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` |
150-
| 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` |
151-
| 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.` |
150+
| 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` |
151+
| 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` |
152+
| 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.` |

loader/icd_platform.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
#define PATH_SEPARATOR ':'
2525
#define DIRECTORY_SYMBOL '/'
2626
#ifdef __ANDROID__
27-
#define ICD_VENDOR_PATH "/system/vendor/Khronos/OpenCL/vendors";
27+
#define ICD_VENDOR_PATH "/system/vendor/Khronos/OpenCL/vendors"
28+
#define LAYER_PATH "/system/vendor/Khronos/OpenCL/layers"
2829
#else
29-
#define ICD_VENDOR_PATH "/etc/OpenCL/vendors";
30+
#define ICD_VENDOR_PATH "/etc/OpenCL/vendors"
31+
#define LAYER_PATH "/etc/OpenCL/layers"
3032
#endif // ANDROID
3133

3234
#elif defined(_WIN32)

loader/linux/icd_linux.c

Lines changed: 159 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <sys/stat.h>
2828
#include <dirent.h>
2929
#include <pthread.h>
30+
#include <limits.h>
3031

3132
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
3233

@@ -36,112 +37,169 @@ static pthread_once_t initialized = PTHREAD_ONCE_INIT;
3637
*
3738
*/
3839

39-
// go through the list of vendors in the two configuration files
40-
void khrIcdOsVendorsEnumerate(void)
40+
typedef void khrIcdFileAdd(const char *);
41+
42+
static inline void khrIcdOsDirEntryValidateAndAdd(const char *d_name, const char *path,
43+
const char *extension, khrIcdFileAdd addFunc)
44+
{
45+
struct stat statBuff;
46+
char* fileName = NULL;
47+
48+
// make sure the file name ends in `extension` (eg. .icd, or .lay)
49+
if (strlen(extension) > strlen(d_name))
50+
{
51+
return;
52+
}
53+
if (strcmp(d_name + strlen(d_name) - strlen(extension), extension))
54+
{
55+
return;
56+
}
57+
58+
// allocate space for the full path of the vendor library name
59+
fileName = malloc(strlen(d_name) + strlen(path) + 2);
60+
if (!fileName)
61+
{
62+
KHR_ICD_TRACE("Failed allocate space for ICD file path\n");
63+
return;
64+
}
65+
sprintf(fileName, "%s/%s", path, d_name);
66+
67+
if (stat(fileName, &statBuff))
68+
{
69+
KHR_ICD_TRACE("Failed stat for: %s, continuing\n", fileName);
70+
free(fileName);
71+
return;
72+
}
73+
74+
if (S_ISREG(statBuff.st_mode) || S_ISLNK(statBuff.st_mode))
75+
{
76+
FILE *fin = NULL;
77+
char* buffer = NULL;
78+
long bufferSize = 0;
79+
80+
// open the file and read its contents
81+
fin = fopen(fileName, "r");
82+
if (!fin)
83+
{
84+
free(fileName);
85+
return;
86+
}
87+
fseek(fin, 0, SEEK_END);
88+
bufferSize = ftell(fin);
89+
90+
buffer = malloc(bufferSize+1);
91+
if (!buffer)
92+
{
93+
free(fileName);
94+
fclose(fin);
95+
return;
96+
}
97+
memset(buffer, 0, bufferSize+1);
98+
fseek(fin, 0, SEEK_SET);
99+
if (bufferSize != (long)fread(buffer, 1, bufferSize, fin))
100+
{
101+
free(fileName);
102+
free(buffer);
103+
fclose(fin);
104+
return;
105+
}
106+
// ignore a newline at the end of the file
107+
if (buffer[bufferSize-1] == '\n') buffer[bufferSize-1] = '\0';
108+
109+
// load the string read from the file
110+
addFunc(buffer);
111+
112+
free(fileName);
113+
free(buffer);
114+
fclose(fin);
115+
}
116+
else
117+
{
118+
KHR_ICD_TRACE("File %s is not a regular file nor symbolic link, continuing\n", fileName);
119+
free(fileName);
120+
}
121+
}
122+
123+
struct dirElem
124+
{
125+
char *d_name;
126+
unsigned char d_type;
127+
};
128+
129+
static int compareDirElem(const void *a, const void *b)
130+
{
131+
// sort files the same way libc alpahnumerically sorts directory entries.
132+
return strcoll(((struct dirElem *)a)->d_name, ((struct dirElem *)b)->d_name);
133+
}
134+
135+
static inline void khrIcdOsDirEnumerate(char *path, char *env, const char *extension,
136+
khrIcdFileAdd addFunc, int bSort)
41137
{
42138
DIR *dir = NULL;
43-
struct dirent *dirEntry = NULL;
44-
const char* vendorPath = ICD_VENDOR_PATH;
45139
char* envPath = NULL;
46140

47-
khrIcdInitializeTrace();
48-
khrIcdVendorsEnumerateEnv();
49-
50-
envPath = khrIcd_secure_getenv("OCL_ICD_VENDORS");
141+
envPath = khrIcd_secure_getenv(env);
51142
if (NULL != envPath)
52143
{
53-
vendorPath = envPath;
144+
path = envPath;
54145
}
55146

56-
dir = opendir(vendorPath);
57-
if (NULL == dir)
147+
dir = opendir(path);
148+
if (NULL == dir)
58149
{
59-
KHR_ICD_TRACE("Failed to open path %s, continuing\n", vendorPath);
150+
KHR_ICD_TRACE("Failed to open path %s, continuing\n", path);
60151
}
61152
else
62153
{
63-
// attempt to load all files in the directory
64-
for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir))
65-
{
66-
struct stat statBuff;
67-
const char* extension = ".icd";
68-
char* fileName = NULL;
69-
70-
// make sure the file name ends in .icd
71-
if (strlen(extension) > strlen(dirEntry->d_name))
72-
{
73-
continue;
74-
}
75-
if (strcmp(dirEntry->d_name + strlen(dirEntry->d_name) - strlen(extension), extension))
76-
{
77-
continue;
78-
}
154+
struct dirent *dirEntry = NULL;
79155

80-
// allocate space for the full path of the vendor library name
81-
fileName = malloc(strlen(dirEntry->d_name) + strlen(vendorPath) + 2);
82-
if (!fileName)
83-
{
84-
KHR_ICD_TRACE("Failed allocate space for ICD file path\n");
85-
continue;
86-
}
87-
sprintf(fileName, "%s/%s", vendorPath, dirEntry->d_name);
156+
// attempt to load all files in the directory
157+
if (bSort) {
158+
// store the entries name and type in a buffer for sorting
159+
size_t sz = 0;
160+
size_t elemCount = 0;
161+
size_t elemAlloc = 0;
162+
struct dirElem *dirElems = NULL;
163+
struct dirElem *newDirElems = NULL;
164+
const size_t startupAlloc = 8;
88165

89-
if (stat(fileName, &statBuff))
90-
{
91-
KHR_ICD_TRACE("Failed stat for: %s, continuing\n", fileName);
92-
free(fileName);
93-
continue;
94-
}
166+
// start with a small buffer
167+
dirElems = (struct dirElem *)malloc(startupAlloc*sizeof(struct dirElem));
168+
if (NULL != dirElems) {
169+
elemAlloc = startupAlloc;
170+
for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir) ) {
171+
char *nameCopy = NULL;
95172

96-
if (S_ISREG(statBuff.st_mode) || S_ISLNK(statBuff.st_mode))
97-
{
98-
FILE *fin = NULL;
99-
char* buffer = NULL;
100-
long bufferSize = 0;
101-
102-
// open the file and read its contents
103-
fin = fopen(fileName, "r");
104-
if (!fin)
105-
{
106-
free(fileName);
107-
continue;
108-
}
109-
fseek(fin, 0, SEEK_END);
110-
bufferSize = ftell(fin);
111-
112-
buffer = malloc(bufferSize+1);
113-
if (!buffer)
114-
{
115-
free(fileName);
116-
fclose(fin);
117-
continue;
173+
if (elemCount + 1 > elemAlloc) {
174+
// double buffer size if necessary and possible
175+
if (elemAlloc >= UINT_MAX/2)
176+
break;
177+
newDirElems = (struct dirElem *)realloc(dirElems, elemAlloc*2*sizeof(struct dirElem));
178+
if (NULL == newDirElems)
179+
break;
180+
dirElems = newDirElems;
181+
elemAlloc *= 2;
182+
}
183+
sz = strlen(dirEntry->d_name) + 1;
184+
nameCopy = (char *)malloc(sz);
185+
if (NULL == nameCopy)
186+
break;
187+
memcpy(nameCopy, dirEntry->d_name, sz);
188+
dirElems[elemCount].d_name = nameCopy;
189+
dirElems[elemCount].d_type = dirEntry->d_type;
190+
elemCount++;
118191
}
119-
memset(buffer, 0, bufferSize+1);
120-
fseek(fin, 0, SEEK_SET);
121-
if (bufferSize != (long)fread(buffer, 1, bufferSize, fin))
122-
{
123-
free(fileName);
124-
free(buffer);
125-
fclose(fin);
126-
continue;
192+
qsort(dirElems, elemCount, sizeof(struct dirElem), compareDirElem);
193+
for (struct dirElem *elem = dirElems; elem < dirElems + elemCount; ++elem) {
194+
khrIcdOsDirEntryValidateAndAdd(elem->d_name, path, extension, addFunc);
195+
free(elem->d_name);
127196
}
128-
// ignore a newline at the end of the file
129-
if (buffer[bufferSize-1] == '\n') buffer[bufferSize-1] = '\0';
130-
131-
// load the string read from the file
132-
khrIcdVendorAdd(buffer);
133-
134-
free(fileName);
135-
free(buffer);
136-
fclose(fin);
197+
free(dirElems);
137198
}
138-
else
139-
{
140-
KHR_ICD_TRACE("File %s is not a regular file nor symbolic link, continuing\n", fileName);
141-
free(fileName);
142-
continue;
143-
}
144-
}
199+
} else
200+
// use system provided ordering
201+
for (dirEntry = readdir(dir); dirEntry; dirEntry = readdir(dir) )
202+
khrIcdOsDirEntryValidateAndAdd(dirEntry->d_name, path, extension, addFunc);
145203

146204
closedir(dir);
147205
}
@@ -150,7 +208,20 @@ void khrIcdOsVendorsEnumerate(void)
150208
{
151209
khrIcd_free_getenv(envPath);
152210
}
211+
}
212+
213+
// go through the list of vendors in the two configuration files
214+
void khrIcdOsVendorsEnumerate(void)
215+
{
216+
khrIcdInitializeTrace();
217+
khrIcdVendorsEnumerateEnv();
218+
219+
khrIcdOsDirEnumerate(ICD_VENDOR_PATH, "OCL_ICD_VENDORS", ".icd", khrIcdVendorAdd, 0);
220+
153221
#if defined(CL_ENABLE_LAYERS)
222+
// system layers should be closer to the driver
223+
khrIcdOsDirEnumerate(LAYER_PATH, "OPENCL_LAYER_PATH", ".lay", khrIcdLayerAdd, 1);
224+
154225
khrIcdLayersEnumerateEnv();
155226
#endif // defined(CL_ENABLE_LAYERS)
156227
}

loader/windows/OpenCL.rc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
#define OPENCL_ICD_LOADER_VERSION_MAJOR 3
2222
#define OPENCL_ICD_LOADER_VERSION_MINOR 0
23-
#define OPENCL_ICD_LOADER_VERSION_REV 3
23+
#define OPENCL_ICD_LOADER_VERSION_REV 4
2424

2525
#ifdef RC_INVOKED
2626

0 commit comments

Comments
 (0)