xref: /aosp_15_r20/external/OpenCL-CTS/test_conformance/allocations/main.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 "testBase.h"
17 
18 #include "allocation_functions.h"
19 #include "allocation_fill.h"
20 #include "allocation_execute.h"
21 #include "harness/testHarness.h"
22 #include "harness/parseParameters.h"
23 #include <time.h>
24 
25 typedef long long unsigned llu;
26 
27 int g_repetition_count = 1;
28 int g_reduction_percentage = 100;
29 int g_write_allocations = 1;
30 int g_multiple_allocations = 0;
31 int g_execute_kernel = 1;
32 
33 static size_t g_max_size;
34 static RandomSeed g_seed( gRandomSeed );
35 
36 cl_long g_max_individual_allocation_size;
37 cl_long g_global_mem_size;
38 
39 cl_uint checksum;
40 
41 static void printUsage( const char *execName );
42 
init_cl(cl_device_id device)43 test_status init_cl( cl_device_id device ) {
44     int error;
45 
46     error = clGetDeviceInfo( device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(g_max_individual_allocation_size), &g_max_individual_allocation_size, NULL );
47     if ( error ) {
48         print_error( error, "clGetDeviceInfo failed for CL_DEVICE_MAX_MEM_ALLOC_SIZE");
49         return TEST_FAIL;
50     }
51     error = clGetDeviceInfo( device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(g_global_mem_size), &g_global_mem_size, NULL );
52     if ( error ) {
53         print_error( error, "clGetDeviceInfo failed for CL_DEVICE_GLOBAL_MEM_SIZE");
54         return TEST_FAIL;
55     }
56 
57     log_info("Device reports CL_DEVICE_MAX_MEM_ALLOC_SIZE=%llu bytes (%gMB), CL_DEVICE_GLOBAL_MEM_SIZE=%llu bytes (%gMB).\n",
58              llu( g_max_individual_allocation_size ), toMB( g_max_individual_allocation_size ),
59              llu( g_global_mem_size ), toMB( g_global_mem_size ) );
60 
61     if( g_global_mem_size > (cl_ulong)SIZE_MAX )
62     {
63         g_global_mem_size = (cl_ulong)SIZE_MAX;
64     }
65 
66     if( g_max_individual_allocation_size > g_global_mem_size )
67     {
68         log_error( "FAILURE:  CL_DEVICE_MAX_MEM_ALLOC_SIZE (%llu) is greater than the CL_DEVICE_GLOBAL_MEM_SIZE (%llu)\n",
69                    llu( g_max_individual_allocation_size ), llu( g_global_mem_size ) );
70         return TEST_FAIL;
71     }
72 
73     // We may need to back off the global_mem_size on unified memory devices to leave room for application and operating system code
74     // and associated data in the working set, so we dont start pathologically paging.
75     // Check to see if we are a unified memory device
76     cl_bool hasUnifiedMemory = CL_FALSE;
77     if( ( error = clGetDeviceInfo( device, CL_DEVICE_HOST_UNIFIED_MEMORY, sizeof( hasUnifiedMemory ), &hasUnifiedMemory, NULL ) ) )
78     {
79         print_error( error, "clGetDeviceInfo failed for CL_DEVICE_HOST_UNIFIED_MEMORY");
80         return TEST_FAIL;
81     }
82     // we share unified memory so back off to 1/2 the global memory size.
83     if( CL_TRUE == hasUnifiedMemory )
84     {
85         g_global_mem_size -= g_global_mem_size /2;
86         log_info( "Device shares memory with the host, so backing off the maximum combined allocation size to be %gMB to avoid rampant paging.\n",
87                   toMB( g_global_mem_size ) );
88     }
89     else
90     {
91         // Lets just use 60% of total available memory as framework/driver may not allow using all of it
92         // e.g. vram on GPU is used by window server and even for this test, we need some space for context,
93         // queue, kernel code on GPU.
94         g_global_mem_size *= 0.60;
95     }
96 
97     if( gReSeed )
98     {
99         g_seed = RandomSeed( gRandomSeed );
100     }
101 
102     return TEST_PASS;
103 }
104 
doTest(cl_device_id device,cl_context context,cl_command_queue queue,AllocType alloc_type)105 int doTest( cl_device_id device, cl_context context, cl_command_queue queue, AllocType alloc_type )
106 {
107     int error;
108     int failure_counts = 0;
109     size_t final_size;
110     size_t current_test_size;
111     cl_mem mems[MAX_NUMBER_TO_ALLOCATE];
112     int number_of_mems_used;
113     cl_ulong max_individual_allocation_size = g_max_individual_allocation_size;
114     cl_ulong global_mem_size = g_global_mem_size ;
115     const bool allocate_image =
116         (alloc_type != BUFFER) && (alloc_type != BUFFER_NON_BLOCKING);
117 
118     static const char* alloc_description[] = {
119         "buffer(s)",
120         "read-only image(s)",
121         "write-only image(s)",
122         "buffer(s)",
123         "read-only image(s)",
124         "write-only image(s)",
125     };
126 
127     // Skip image tests if we don't support images on the device
128     if (allocate_image && checkForImageSupport(device))
129     {
130         log_info( "Can not test image allocation because device does not support images.\n" );
131         return 0;
132     }
133 
134     // This section was added in order to fix a bug in the test
135     // If CL_DEVICE_MAX_MEM_ALLOC_SIZE is much grater than CL_DEVICE_IMAGE2D_MAX_WIDTH * CL_DEVICE_IMAGE2D_MAX_HEIGHT
136     // The test will fail in image allocations as the size requested for the allocation will be much grater than the maximum size allowed for image
137     if (allocate_image)
138     {
139         size_t max_width, max_height;
140 
141         error = clGetDeviceInfo( device, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof( max_width ), &max_width, NULL );
142         test_error_abort( error, "clGetDeviceInfo failed for CL_DEVICE_IMAGE2D_MAX_WIDTH" );
143 
144         error = clGetDeviceInfo( device, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof( max_height ), &max_height, NULL );
145         test_error_abort( error, "clGetDeviceInfo failed for CL_DEVICE_IMAGE2D_MAX_HEIGHT" );
146 
147         cl_ulong max_image2d_size = (cl_ulong)max_height * max_width * 4 * sizeof(cl_uint);
148 
149         if( max_individual_allocation_size > max_image2d_size )
150         {
151             max_individual_allocation_size = max_image2d_size;
152         }
153     }
154 
155     // Pick the baseline size based on whether we are doing a single large or multiple allocations
156     g_max_size = g_multiple_allocations ? (size_t)global_mem_size : (size_t)max_individual_allocation_size;
157 
158     // Adjust based on the percentage
159     if( g_reduction_percentage != 100 )
160     {
161         log_info( "NOTE: reducing max allocations to %d%%.\n", g_reduction_percentage );
162         g_max_size = (size_t)( (double)g_max_size * (double)g_reduction_percentage / 100.0 );
163     }
164 
165     // Round to nearest MB.
166     g_max_size &= (size_t)(0xFFFFFFFFFF00000ULL);
167 
168     log_info( "** Target allocation size (rounded to nearest MB) is: %llu bytes (%gMB).\n", llu( g_max_size ), toMB( g_max_size ) );
169     log_info( "** Allocating %s to size %gMB.\n", alloc_description[alloc_type], toMB( g_max_size ) );
170 
171     for( int count = 0; count < g_repetition_count; count++ )
172     {
173         current_test_size = g_max_size;
174         error = FAILED_TOO_BIG;
175         log_info( "  => Allocation %d\n", count + 1 );
176 
177         while( ( error == FAILED_TOO_BIG ) && ( current_test_size > g_max_size / 8 ) )
178         {
179             // Reset our checksum for each allocation
180             checksum = 0;
181 
182             // Do the allocation
183             error = allocate_size( context, &queue, device, g_multiple_allocations, current_test_size, alloc_type,
184                                    mems, &number_of_mems_used, &final_size, g_write_allocations, g_seed );
185 
186             // If we succeeded and we're supposed to execute a kernel, do so.
187             if( error == SUCCEEDED && g_execute_kernel )
188             {
189                 log_info( "\tExecuting kernel with memory objects.\n" );
190                 error = execute_kernel( context, &queue, device, alloc_type, mems, number_of_mems_used,
191                                         g_write_allocations );
192             }
193 
194             // If we failed to allocate more than 1/8th of the requested amount return a failure.
195             if( final_size < (size_t)g_max_size / 8 )
196             {
197                 log_error( "===> Allocation %d failed to allocate more than 1/8th of the requested size.\n", count + 1 );
198                 failure_counts++;
199             }
200 
201             // Clean up.
202             for( int i = 0; i < number_of_mems_used; i++ )
203             {
204                 clReleaseMemObject( mems[i] );
205             }
206 
207             if( error == FAILED_ABORT )
208             {
209                 log_error( "  => Allocation %d failed.\n", count + 1 );
210                 failure_counts++;
211             }
212 
213             if( error == FAILED_TOO_BIG )
214             {
215                 current_test_size -= g_max_size / 16;
216                 log_info( "\tFailed at this size; trying a smaller size of %gMB.\n", toMB( current_test_size ) );
217             }
218         }
219 
220         if( error == SUCCEEDED && current_test_size == g_max_size )
221         {
222             log_info("\tPASS: Allocation succeeded.\n");
223         }
224         else if( error == SUCCEEDED && current_test_size > g_max_size / 8 )
225         {
226             log_info("\tPASS: Allocation succeeded at reduced size.\n");
227         }
228         else
229         {
230             log_error("\tFAIL: Allocation failed.\n");
231             failure_counts++;
232         }
233     }
234 
235     return failure_counts;
236 }
237 
test_buffer(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)238 int test_buffer(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
239 {
240     return doTest( device, context, queue, BUFFER );
241 }
test_image2d_read(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)242 int test_image2d_read(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
243 {
244     return doTest( device, context, queue, IMAGE_READ );
245 }
test_image2d_write(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)246 int test_image2d_write(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
247 {
248     return doTest( device, context, queue, IMAGE_WRITE );
249 }
test_buffer_non_blocking(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)250 int test_buffer_non_blocking(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
251 {
252     return doTest( device, context, queue, BUFFER_NON_BLOCKING );
253 }
test_image2d_read_non_blocking(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)254 int test_image2d_read_non_blocking(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
255 {
256     return doTest( device, context, queue, IMAGE_READ_NON_BLOCKING );
257 }
test_image2d_write_non_blocking(cl_device_id device,cl_context context,cl_command_queue queue,int num_elements)258 int test_image2d_write_non_blocking(cl_device_id device, cl_context context, cl_command_queue queue, int num_elements)
259 {
260     return doTest( device, context, queue, IMAGE_WRITE_NON_BLOCKING );
261 }
262 
263 test_definition test_list[] = {
264     ADD_TEST( buffer ),
265     ADD_TEST( image2d_read ),
266     ADD_TEST( image2d_write ),
267     ADD_TEST( buffer_non_blocking ),
268     ADD_TEST( image2d_read_non_blocking ),
269     ADD_TEST( image2d_write_non_blocking ),
270 };
271 
272 const int test_num = ARRAY_SIZE( test_list );
273 
main(int argc,const char * argv[])274 int main(int argc, const char *argv[])
275 {
276     char *endPtr;
277     int r;
278 
279     argc = parseCustomParam(argc, argv);
280     if (argc == -1)
281     {
282         return 1;
283     }
284 
285     const char ** argList = (const char **)calloc( argc, sizeof( char*) );
286 
287     if( NULL == argList )
288     {
289         log_error( "Failed to allocate memory for argList array.\n" );
290         return 1;
291     }
292 
293     argList[0] = argv[0];
294     size_t argCount = 1;
295 
296     // Parse arguments
297     for( int i = 1; i < argc; i++ )
298     {
299         if( strcmp( argv[i], "multiple" ) == 0 )
300             g_multiple_allocations = 1;
301         else if( strcmp( argv[i], "single" ) == 0 )
302             g_multiple_allocations = 0;
303 
304         else if( ( r = (int)strtol( argv[i], &endPtr, 10 ) ) && ( endPtr != argv[i] ) && ( *endPtr == 0 ) )
305         {
306             // By spec, that means the entire string was an integer, so take it as a repetition count
307             g_repetition_count = r;
308         }
309 
310         else if( strchr( argv[i], '%' ) != NULL )
311         {
312             // Reduction percentage (let strtol ignore the percentage)
313             g_reduction_percentage = (int)strtol( argv[i], NULL, 10 );
314         }
315 
316         else if( strcmp( argv[i], "do_not_force_fill" ) == 0 )
317         {
318             g_write_allocations = 0;
319         }
320 
321         else if( strcmp( argv[i], "do_not_execute" ) == 0 )
322         {
323             g_execute_kernel = 0;
324         }
325 
326         else if ( strcmp( argv[i], "--help" ) == 0 || strcmp( argv[i], "-h" ) == 0 )
327         {
328             printUsage( argv[0] );
329             free(argList);
330             return -1;
331         }
332 
333         else
334         {
335             argList[argCount] = argv[i];
336             argCount++;
337         }
338     }
339 
340     int ret = runTestHarnessWithCheck( argCount, argList, test_num, test_list, false, 0, init_cl );
341 
342     free(argList);
343     return ret;
344 }
345 
printUsage(const char * execName)346 void printUsage( const char *execName )
347 {
348     const char *p = strrchr( execName, '/' );
349     if( p != NULL )
350         execName = p + 1;
351 
352     log_info( "Usage: %s [options] [test_names]\n", execName );
353     log_info( "Options:\n" );
354     log_info( "\trandomize - Uses random seed\n" );
355     log_info( "\tsingle - Tests using a single allocation as large as possible\n" );
356     log_info( "\tmultiple - Tests using as many allocations as possible\n" );
357     log_info( "\n" );
358     log_info( "\tnumReps - Optional integer specifying the number of repetitions to run and average the result (defaults to 1)\n" );
359     log_info( "\treduction%% - Optional integer, followed by a %% sign, that acts as a multiplier for the target amount of memory.\n" );
360     log_info( "\t             Example: target amount of 512MB and a reduction of 75%% will result in a target of 384MB.\n" );
361     log_info( "\n" );
362     log_info( "\tdo_not_force_fill - Disable explicitly write data to all memory objects after creating them.\n" );
363     log_info( "\t                    Without this, the kernel execution can not verify its checksum.\n" );
364     log_info( "\tdo_not_execute - Disable executing a kernel that accesses all of the memory objects.\n" );
365     log_info( "\n" );
366     log_info( "Test names (Allocation Types):\n" );
367     for( int i = 0; i < test_num; i++ )
368     {
369         log_info( "\t%s\n", test_list[i].name );
370     }
371 }
372