xref: /aosp_15_r20/external/OpenCL-CTS/test_conformance/allocations/allocation_functions.cpp (revision 6467f958c7de8070b317fc65bcb0f6472e388d82)
1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //    http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 #include "allocation_functions.h"
17 #include "allocation_fill.h"
18 
19 
20 static cl_image_format    image_format = { CL_RGBA, CL_UNSIGNED_INT32 };
21 
allocate_buffer(cl_context context,cl_command_queue * queue,cl_device_id device_id,cl_mem * mem,size_t size_to_allocate,cl_bool blocking_write)22 int allocate_buffer(cl_context context, cl_command_queue *queue, cl_device_id device_id, cl_mem *mem, size_t size_to_allocate, cl_bool blocking_write) {
23   int error;
24   // log_info("\t\tAttempting to allocate a %gMB array and fill with %s writes.\n", (size_to_allocate/(1024.0*1024.0)), (blocking_write ? "blocking" : "non-blocking"));
25   *mem = clCreateBuffer(context, CL_MEM_READ_WRITE, size_to_allocate, NULL, &error);
26   return check_allocation_error(context, device_id, error, queue);
27 }
28 
29 
find_good_image_size(cl_device_id device_id,size_t size_to_allocate,size_t * width,size_t * height,size_t * max_size)30 int find_good_image_size(cl_device_id device_id, size_t size_to_allocate, size_t *width, size_t *height, size_t* max_size) {
31   size_t max_width, max_height, num_pixels, found_width, found_height;
32   int error;
33 
34   if (checkForImageSupport(device_id)) {
35     log_info("Can not allocate an image on this device because it does not support images.");
36     return FAILED_ABORT;
37   }
38 
39   if (size_to_allocate == 0) {
40       log_error("Trying to allocate a zero sized image.\n");
41       return FAILED_ABORT;
42   }
43 
44   error = clGetDeviceInfo( device_id, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof( max_width ), &max_width, NULL );
45   test_error_abort(error, "clGetDeviceInfo failed.");
46   error = clGetDeviceInfo( device_id, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof( max_height ), &max_height, NULL );
47   test_error_abort(error, "clGetDeviceInfo failed.");
48 
49   num_pixels = size_to_allocate / (sizeof(cl_uint)*4);
50 
51   // Use a 64-bit variable to avoid overflow in 32-bit architectures
52   long long unsigned max_pixels = (long long unsigned)max_width * max_height;
53 
54   if (num_pixels > max_pixels) {
55     if(NULL != max_size) {
56       *max_size = max_width * max_height * sizeof(cl_uint) * 4;
57     }
58     return FAILED_TOO_BIG;
59   }
60 
61   // We want a close-to-square aspect ratio.
62   // Note that this implicitly assumes that  max width >= max height
63   found_width = (int)sqrt( (double) num_pixels );
64   if( found_width > max_width ) {
65     found_width = max_width;
66   }
67   if (found_width == 0)
68     found_width = 1;
69 
70   found_height = (size_t)num_pixels/found_width;
71   if (found_height > max_height) {
72     found_height = max_height;
73   }
74   if (found_height == 0)
75     found_height = 1;
76 
77   *width = found_width;
78   *height = found_height;
79 
80   if(NULL != max_size) {
81     *max_size = found_width * found_height * sizeof(cl_uint) * 4;
82   }
83 
84   return SUCCEEDED;
85 }
86 
87 
allocate_image2d_read(cl_context context,cl_command_queue * queue,cl_device_id device_id,cl_mem * mem,size_t size_to_allocate,cl_bool blocking_write)88 int allocate_image2d_read(cl_context context, cl_command_queue *queue, cl_device_id device_id, cl_mem *mem, size_t size_to_allocate, cl_bool blocking_write) {
89   size_t width, height;
90   int error;
91 
92   error = find_good_image_size(device_id, size_to_allocate, &width, &height, NULL);
93   if (error != SUCCEEDED)
94     return error;
95 
96   log_info("\t\tAttempting to allocate a %gMB read-only image (%d x %d) and fill with %s writes.\n",
97           (size_to_allocate/(1024.0*1024.0)), (int)width, (int)height, (blocking_write ? "blocking" : "non-blocking"));
98   *mem = create_image_2d(context, CL_MEM_READ_ONLY, &image_format, width, height, 0, NULL, &error);
99 
100   return check_allocation_error(context, device_id, error, queue);
101 }
102 
103 
allocate_image2d_write(cl_context context,cl_command_queue * queue,cl_device_id device_id,cl_mem * mem,size_t size_to_allocate,cl_bool blocking_write)104 int allocate_image2d_write(cl_context context, cl_command_queue *queue, cl_device_id device_id, cl_mem *mem, size_t size_to_allocate, cl_bool blocking_write) {
105   size_t width, height;
106   int error;
107 
108   error = find_good_image_size(device_id, size_to_allocate, &width, &height, NULL);
109   if (error != SUCCEEDED)
110     return error;
111 
112   //log_info("\t\tAttempting to allocate a %gMB write-only image (%d x %d) and fill with %s writes.\n",
113            //(size_to_allocate/(1024.0*1024.0)), (int)width, (int)height, (blocking_write ? "blocking" : "non-blocking"));
114   *mem = create_image_2d(context, CL_MEM_WRITE_ONLY, &image_format, width, height, 0, NULL, &error);
115 
116   return check_allocation_error(context, device_id, error, queue);
117 }
118 
do_allocation(cl_context context,cl_command_queue * queue,cl_device_id device_id,size_t size_to_allocate,int type,cl_mem * mem)119 int do_allocation(cl_context context, cl_command_queue *queue, cl_device_id device_id, size_t size_to_allocate, int type, cl_mem *mem) {
120   if (type == BUFFER) return allocate_buffer(context, queue, device_id, mem, size_to_allocate, true);
121   if (type == IMAGE_READ) return allocate_image2d_read(context, queue, device_id, mem, size_to_allocate, true);
122   if (type == IMAGE_WRITE) return allocate_image2d_write(context, queue, device_id, mem, size_to_allocate, true);
123   if (type == BUFFER_NON_BLOCKING) return allocate_buffer(context, queue, device_id, mem, size_to_allocate, false);
124   if (type == IMAGE_READ_NON_BLOCKING) return allocate_image2d_read(context, queue, device_id, mem, size_to_allocate, false);
125   if (type == IMAGE_WRITE_NON_BLOCKING) return allocate_image2d_write(context, queue, device_id, mem, size_to_allocate, false);
126     log_error("Invalid allocation type: %d\n", type);
127   return FAILED_ABORT;
128 }
129 
130 
allocate_size(cl_context context,cl_command_queue * queue,cl_device_id device_id,int multiple_allocations,size_t size_to_allocate,int type,cl_mem mems[],int * number_of_mems,size_t * final_size,int force_fill,MTdata d)131 int allocate_size(cl_context context, cl_command_queue *queue, cl_device_id device_id, int multiple_allocations, size_t size_to_allocate,
132                   int type, cl_mem mems[], int *number_of_mems, size_t *final_size, int force_fill, MTdata d) {
133 
134     cl_ulong max_individual_allocation_size, global_mem_size;
135   int error, result;
136   size_t amount_allocated;
137   size_t reduction_amount;
138   int current_allocation;
139   size_t allocation_this_time, actual_allocation;
140 
141   // Set the number of mems used to 0 so if we fail to create even a single one we don't end up returning a garbage value
142   *number_of_mems = 0;
143 
144   error = clGetDeviceInfo(device_id, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(max_individual_allocation_size), &max_individual_allocation_size, NULL);
145   test_error_abort( error, "clGetDeviceInfo failed for CL_DEVICE_MAX_MEM_ALLOC_SIZE");
146   error = clGetDeviceInfo(device_id, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(global_mem_size), &global_mem_size, NULL);
147   test_error_abort( error, "clGetDeviceInfo failed for CL_DEVICE_GLOBAL_MEM_SIZE");
148 
149   if (global_mem_size > (cl_ulong)SIZE_MAX) {
150     global_mem_size = (cl_ulong)SIZE_MAX;
151   }
152 
153 //  log_info("Device reports CL_DEVICE_MAX_MEM_ALLOC_SIZE=%llu bytes (%gMB), CL_DEVICE_GLOBAL_MEM_SIZE=%llu bytes (%gMB).\n",
154 //           max_individual_allocation_size, toMB(max_individual_allocation_size),
155 //           global_mem_size, toMB(global_mem_size));
156 
157   if (size_to_allocate > global_mem_size) {
158     log_error("Can not allocate more than the global memory size.\n");
159     return FAILED_ABORT;
160   }
161 
162   amount_allocated = 0;
163   current_allocation = 0;
164 
165   // If allocating for images, reduce the maximum allocation size to the maximum image size.
166   // If we don't do this, then the value of CL_DEVICE_MAX_MEM_ALLOC_SIZE / 4 can be higher
167   // than the maximum image size on systems with 16GB or RAM or more. In this case, we
168   // succeed in allocating an image but its size is less than CL_DEVICE_MAX_MEM_ALLOC_SIZE / 4
169   // (min_allocation_allowed) and thus we fail the allocation below.
170   if(type == IMAGE_READ || type == IMAGE_READ_NON_BLOCKING || type == IMAGE_WRITE || type == IMAGE_WRITE_NON_BLOCKING) {
171     size_t width;
172     size_t height;
173     size_t max_size;
174     error = find_good_image_size(device_id, size_to_allocate, &width, &height, &max_size);
175     if (!(error == SUCCEEDED || error == FAILED_TOO_BIG))
176       return error;
177     if(max_size < max_individual_allocation_size)
178       max_individual_allocation_size = max_size;
179   }
180 
181   reduction_amount = (size_t)max_individual_allocation_size/16;
182 
183   if (type == BUFFER || type == BUFFER_NON_BLOCKING) log_info("\tAttempting to allocate a buffer of size %gMB.\n", toMB(size_to_allocate));
184   else if (type == IMAGE_READ || type == IMAGE_READ_NON_BLOCKING) log_info("\tAttempting to allocate a read-only image of size %gMB.\n", toMB(size_to_allocate));
185   else if (type == IMAGE_WRITE || type == IMAGE_WRITE_NON_BLOCKING) log_info("\tAttempting to allocate a write-only image of size %gMB.\n", toMB(size_to_allocate));
186 
187 //  log_info("\t\t(Reduction size is %gMB per iteration, minimum allowable individual allocation size is %gMB.)\n",
188 //           toMB(reduction_amount), toMB(min_allocation_allowed));
189 //  if (force_fill && type != IMAGE_WRITE && type != IMAGE_WRITE_NON_BLOCKING) log_info("\t\t(Allocations will be filled with random data for checksum calculation.)\n");
190 
191   // If we are only doing a single allocation, only allow 1
192   int max_to_allocate = multiple_allocations ? MAX_NUMBER_TO_ALLOCATE : 1;
193 
194   // Make sure that the maximum number of images allocated is constrained by the
195   // maximum that may be passed to a kernel
196   if (type != BUFFER && type != BUFFER_NON_BLOCKING) {
197     cl_device_info param_name = (type == IMAGE_READ || type == IMAGE_READ_NON_BLOCKING) ?
198       CL_DEVICE_MAX_READ_IMAGE_ARGS : CL_DEVICE_MAX_WRITE_IMAGE_ARGS;
199 
200     cl_uint max_image_args;
201     error = clGetDeviceInfo(device_id, param_name, sizeof(max_image_args), &max_image_args, NULL);
202     test_error( error, "clGetDeviceInfo failed for CL_DEVICE_MAX IMAGE_ARGS");
203 
204     if ((int)max_image_args < max_to_allocate) {
205       log_info("\t\tMaximum number of images per kernel limited to %d\n",(int)max_image_args);
206       max_to_allocate =  max_image_args;
207     }
208   }
209 
210 
211   // Try to allocate the requested amount.
212   while (amount_allocated != size_to_allocate && current_allocation < max_to_allocate) {
213 
214     // Determine how much more is needed
215     allocation_this_time = size_to_allocate - amount_allocated;
216 
217     // Bound by the individual allocation size
218     if (allocation_this_time > max_individual_allocation_size)
219         allocation_this_time = (size_t)max_individual_allocation_size;
220 
221     // Allocate the largest object possible
222     result = FAILED_TOO_BIG;
223     //log_info("\t\tTrying sub-allocation %d at size %gMB.\n", current_allocation, toMB(allocation_this_time));
224     while (result == FAILED_TOO_BIG && allocation_this_time != 0) {
225 
226       // Create the object
227         result = do_allocation(context, queue, device_id, allocation_this_time, type, &mems[current_allocation]);
228       if (result == SUCCEEDED) {
229         // Allocation succeeded, another memory object was added to the array
230         *number_of_mems = (current_allocation+1);
231 
232           // Verify the size is correct to within 1MB.
233         actual_allocation = get_actual_allocation_size(mems[current_allocation]);
234         if (fabs((double)allocation_this_time - (double)actual_allocation) > 1024.0*1024.0) {
235              log_error("Allocation not of expected size. Expected %gMB, got %gMB.\n", toMB(allocation_this_time), toMB( actual_allocation));
236           return FAILED_ABORT;
237         }
238 
239         // If we are filling the allocation for verification do so
240         if (force_fill) {
241           //log_info("\t\t\tWriting random values to object and calculating checksum.\n");
242           cl_bool blocking_write = true;
243           if (type == BUFFER_NON_BLOCKING || type == IMAGE_READ_NON_BLOCKING || type == IMAGE_WRITE_NON_BLOCKING) {
244             blocking_write = false;
245           }
246           result = fill_mem_with_data(context, device_id, queue, mems[current_allocation], d, blocking_write);
247         }
248       }
249 
250       // If creation failed, try to create a smaller object
251       if (result == FAILED_TOO_BIG) {
252         //log_info("\t\t\tAllocation %d failed at size %gMB. Trying smaller.\n", current_allocation, toMB(allocation_this_time));
253         if (allocation_this_time > reduction_amount)
254             allocation_this_time -= reduction_amount;
255         else if (reduction_amount > 1) {
256           reduction_amount /= 2;
257         }
258         else {
259           allocation_this_time = 0;
260         }
261 
262       }
263     }
264 
265     if (result == FAILED_ABORT) {
266       log_error("\t\tAllocation failed.\n");
267       return FAILED_ABORT;
268     }
269 
270     if (!allocation_this_time) {
271       log_info("\t\tFailed to allocate %gMB across several objects.\n", toMB(size_to_allocate));
272       return FAILED_TOO_BIG;
273     }
274 
275     // Otherwise we succeeded
276     if (result != SUCCEEDED) {
277       log_error("Test logic error.");
278       exit(-1);
279     }
280     amount_allocated += allocation_this_time;
281 
282     *final_size = amount_allocated;
283 
284     current_allocation++;
285   }
286 
287   log_info("\t\tSucceeded in allocating %gMB using %d memory objects.\n", toMB(amount_allocated), current_allocation);
288   return SUCCEEDED;
289 }
290