1 #ifndef GPU_OBJECT_LIFETIME_H
2 #define GPU_OBJECT_LIFETIME_H
3 
4 #include <array>
5 #include <stdio.h>
6 #include <string.h>
7 
8 namespace Halide {
9 namespace Internal {
10 
11 class GpuObjectLifetimeTracker {
12     struct ObjectType {
13         const char *const created;
14         const char *const destroyed;
15         bool const is_global;
16         int total_created;
17         int live_count;
18 
19         ObjectType(const char *created, const char *destroyed, bool is_global = false)
createdObjectType20             : created(created), destroyed(destroyed),
21               is_global(is_global), total_created(0), live_count(0) {
22         }
23     };
24 
25     std::array<ObjectType, 13> object_types = {{
26         // OpenCL objects
27         {"clCreateContext", "clReleaseContext", true},
28         {"clCreateCommandQueue", "clReleaseCommandQueue", true},
29         // This handles both "clCreateProgramWithSource" and
30         // "clCreateProgramWithBinary".
31         {"clCreateProgram", "clReleaseProgram"},
32         {"clCreateBuffer", "clReleaseMemObject"},
33         {"clCreateKernel", "clReleaseKernel"},
34 
35         // CUDA objects
36         {"cuCtxCreate", "cuCtxDestroy", true},
37         {"cuModuleLoad", "cuModuleUnload"},
38         {"cuMemAlloc", "cuMemFree"},
39 
40         // Metal objects
41         {"Allocating: MTLCreateSystemDefaultDevice", "Releasing: MTLCreateSystemDefaultDevice", true},
42         {"Allocating: new_command_queue", "Releasing: new_command_queue"},
43         {"Allocating: new_library_with_source", "Releasing: new_library_with_source"},
44 
45         // Hexagon objects
46         {"halide_remote_load_library", "halide_remote_release_library"},
47         {"ion_alloc", "ion_free"},
48     }};
49 
50 public:
51     // Parse a line of output from gpu_debug and update object counts.
record_gpu_debug(const char * str)52     void record_gpu_debug(const char *str) {
53         for (auto &o : object_types) {
54             if (strstr(str, o.created)) {
55                 o.total_created++;
56                 o.live_count++;
57             } else if (strstr(str, o.destroyed)) {
58                 o.live_count--;
59             }
60         }
61     }
62 
63     // Check that there are no live objects remaining, and we created at least one object.
validate_gpu_object_lifetime(bool allow_globals,bool allow_none,int max_globals)64     int validate_gpu_object_lifetime(bool allow_globals, bool allow_none, int max_globals) {
65         int total = 0;
66         for (auto &o : object_types) {
67             if (o.live_count != 0 &&
68                 !(allow_globals && o.is_global)) {
69                 printf("Error! %d objects created by %s still live\n",
70                        o.live_count, o.created);
71                 return -1;
72             }
73             if (o.is_global && o.total_created > max_globals) {
74                 printf("Error! %d global objects created by %s, max is %d\n",
75                        o.total_created, o.created, max_globals);
76                 return -1;
77             }
78 
79             total += o.total_created;
80         }
81         if (!allow_none && total == 0) {
82             printf("Error! No objects created. Ensure gpu_debug is set, ");
83             printf("and record_gpu_debug is called from halide_print.\n");
84             return -1;
85         }
86         return 0;
87     }
88 };
89 
90 }  // namespace Internal
91 }  // namespace Halide
92 
93 #endif
94