1 #include "HalideRuntime.h"
2 #include "hexagon_dma_pool.h"
3 #include "mini_hexagon_dma.h"
4 #include "printer.h"
5 #include "scoped_mutex_lock.h"
6
7 namespace Halide {
8 namespace Runtime {
9 namespace Internal {
10 namespace Hexagon {
11
12 typedef struct hexagon_local_cache {
13 void *l2memory;
14 bool used;
15 size_t bytes;
16 struct hexagon_local_cache *next;
17 } hexagon_cache_pool_t;
18
19 typedef hexagon_cache_pool_t *pcache_pool;
20
21 WEAK pcache_pool hexagon_cache_pool = NULL;
22 WEAK halide_mutex hexagon_cache_mutex;
23
24 } // namespace Hexagon
25 } // namespace Internal
26 } // namespace Runtime
27 } // namespace Halide
28
29 using namespace Halide::Runtime::Internal::Hexagon;
30
31 namespace {
32
free_unused_buffers(void * user_context)33 inline void *free_unused_buffers(void *user_context) {
34 // Walk the list and deallocate unused blocks.
35 ScopedMutexLock lock(&hexagon_cache_mutex);
36 pcache_pool temp2 = hexagon_cache_pool;
37 pcache_pool prev_node = hexagon_cache_pool;
38 while (temp2 != NULL) {
39 if (temp2->used == false) {
40 int err = HAP_cache_unlock(temp2->l2memory);
41 if (err != 0) {
42 error(user_context) << "Hexagon: HAP_cache_unlock failure on unused free\n";
43 return NULL;
44 }
45 // Set previous node details.
46 prev_node->next = (temp2->next)->next;
47 prev_node = temp2->next;
48 // Set Head.
49 if (temp2 == hexagon_cache_pool) {
50 hexagon_cache_pool = temp2->next;
51 }
52 // Free node and reassign the variable.
53 free(temp2);
54 temp2 = prev_node;
55 }
56 prev_node = temp2;
57 temp2 = temp2->next;
58 }
59 return (void *)prev_node;
60 }
61
62 // Retry logic if enabled will walk the list and deallocate unused blocks to make room for a larger block size
63 // Once all unused blocks are deallocated it will try to allocate a larger block
hexagon_cache_pool_get(void * user_context,size_t size,bool retry)64 inline void *hexagon_cache_pool_get(void *user_context, size_t size, bool retry) {
65
66 pcache_pool prev = NULL;
67 pcache_pool temp = hexagon_cache_pool;
68 // Walk the list to find free buffer
69 {
70 ScopedMutexLock lock(&hexagon_cache_mutex);
71 while (temp != NULL) {
72 if ((temp->used == false) &&
73 (size == temp->bytes)) {
74 temp->used = true;
75 return (void *)temp->l2memory;
76 }
77 prev = temp;
78 temp = temp->next;
79 }
80 }
81
82 // If we are still here that means temp was null.
83 temp = (pcache_pool)malloc(sizeof(hexagon_cache_pool_t));
84 if (temp == NULL) {
85 error(user_context) << "Hexagon: Out of memory (Cache Pool Allocation Failed)\n";
86 return NULL;
87 }
88 uint8_t *mem = (uint8_t *)HAP_cache_lock(sizeof(char) * size, NULL);
89 if ((mem == NULL) && retry) {
90 pcache_pool prev_node = (pcache_pool)free_unused_buffers(user_context);
91 // Retry one more time after deallocating unused nodes.
92 mem = (uint8_t *)HAP_cache_lock(sizeof(char) * size, NULL);
93 prev = prev_node;
94 if (mem == NULL) {
95 free(temp);
96 error(user_context) << "Hexagon: Out of memory (HAP_cache_lock retry failed)\n";
97 return NULL;
98 }
99 } else if (mem == NULL) {
100 free(temp);
101 error(user_context) << "Hexagon: Out of memory (HAP_cache_lock failed)\n";
102 return NULL;
103 }
104 temp->l2memory = (void *)mem;
105 temp->bytes = size;
106 temp->used = true;
107 temp->next = NULL;
108
109 {
110 ScopedMutexLock lock_obj(&hexagon_cache_mutex);
111 if (prev != NULL) {
112 prev->next = temp;
113 } else if (hexagon_cache_pool == NULL) {
114 hexagon_cache_pool = temp;
115 }
116 }
117 return (void *)temp->l2memory;
118 }
119
hexagon_cache_pool_put(void * user_context,void * cache_mem)120 inline void hexagon_cache_pool_put(void *user_context, void *cache_mem) {
121 ScopedMutexLock lock(&hexagon_cache_mutex);
122 halide_assert(user_context, cache_mem);
123 pcache_pool temp = hexagon_cache_pool;
124 while (temp != NULL) {
125 if (temp->l2memory == cache_mem) {
126 temp->used = false;
127 return;
128 }
129 temp = temp->next;
130 }
131 }
132
hexagon_cache_pool_free(void * user_context)133 inline int hexagon_cache_pool_free(void *user_context) {
134 ScopedMutexLock lock(&hexagon_cache_mutex);
135 pcache_pool temp = hexagon_cache_pool;
136 pcache_pool prev = hexagon_cache_pool;
137 int err = QURT_EOK;
138 while (temp != NULL) {
139 if (temp->l2memory != NULL) {
140 err = HAP_cache_unlock(temp->l2memory);
141 if (err != QURT_EOK) {
142 error(user_context) << "Hexagon: HAP_cache_unlock failed on pool free\n";
143 return err;
144 }
145 }
146 prev = temp->next;
147 free(temp);
148 temp = prev;
149 }
150 hexagon_cache_pool = NULL;
151 return QURT_EOK;
152 }
153
154 } // namespace
155
156 extern "C" {
157
halide_locked_cache_malloc(void * user_context,size_t size)158 WEAK void *halide_locked_cache_malloc(void *user_context, size_t size) {
159 // TODO Currently option to retry allocation is disabled, we will have to decide if can be
160 // set by user or pipeline.
161 bool retry = false;
162 debug(user_context) << "halide_locked_cache_malloc\n";
163 return hexagon_cache_pool_get(user_context, size, retry);
164 }
165
halide_locked_cache_free(void * user_context,void * ptr)166 WEAK void halide_locked_cache_free(void *user_context, void *ptr) {
167 debug(user_context) << "halide_locked_cache_free\n";
168 hexagon_cache_pool_put(user_context, ptr);
169 }
170
halide_hexagon_allocate_l2_pool(void * user_context)171 WEAK int halide_hexagon_allocate_l2_pool(void *user_context) {
172 // TODO not sure what is required to be done here ?
173 debug(user_context) << "halide_hexagon_allocate_l2_pool\n";
174 return halide_error_code_success;
175 }
176
halide_hexagon_free_l2_pool(void * user_context)177 WEAK int halide_hexagon_free_l2_pool(void *user_context) {
178 debug(user_context) << "halide_hexagon_free_l2_pool\n";
179 return hexagon_cache_pool_free(user_context);
180 }
181 }
182