char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
eafe15a5e
char/aliceai-t5-moe
1#include "htp-tensor.h" 2 3#include <qurt.h> 4#include <qurt_memory.h> 5#include <HAP_farf.h> 6 7#include "hex-common.h" 8#include "hex-utils.h" 9#include "hex-fastdiv.h" 10#include "hex-profile.h" 11#include "htp-ctx.h" 12#include "work-queue.h" 13 14struct l2flush_range { 15uint32_t start ;// line-aligned start address 16uint32_t end ;// line-aligned end address 17uint32_t block_first ;// global block index of this range's first block 18uint32_t n_blocks ;// number of HEX_L2_BLOCK_SIZE chunks (last may be partial) 19}; 20 21struct l2flush_multi_task { 22struct htp_thread_trace * trace ; 23struct l2flush_range ranges [HTP_MAX_DIRTY_RANGES ]; 24uint32_t n_ranges ; 25uint32_t total_blocks ; 26uint32_t blocks_per_thread ; 27}; 28 29static void flush_all_dcache (struct htp_context * ctx ) { 30struct htp_thread_trace * tr = & ctx -> trace [0 ]; 31htp_trace_event_start (tr ,HTP_TRACE_EVT_L2FLUSH ,0 ); 32qurt_mem_cache_clean ((qurt_addr_t )0 ,0 ,QURT_MEM_CACHE_FLUSH_INVALIDATE_ALL ,QURT_MEM_DCACHE ); 33hex_l2fetch_block (ctx ,ctx -> footprint ); 34htp_trace_event_stop (tr ,HTP_TRACE_EVT_L2FLUSH ,0 ); 35memset (ctx -> dirty_ranges ,0 ,sizeof (ctx -> dirty_ranges )); 36} 37 38static void l2flush_multi_worker (unsigned int n ,unsigned int i ,void * data ) { 39struct l2flush_multi_task * task = (struct l2flush_multi_task * )data ; 40 (void )n ; 41 42const uint32_t gb_first = i * task -> blocks_per_thread ; 43uint32_t gb_last = gb_first + task -> blocks_per_thread ; 44if (gb_last > task -> total_blocks ) { 45gb_last = task -> total_blocks ; 46 } 47if (gb_first >=gb_last ) { 48return ; 49 } 50 51struct htp_thread_trace * tr = & task -> trace [i ]; 52htp_trace_event_start (tr ,HTP_TRACE_EVT_L2FLUSH ,gb_first ); 53 54for (uint32_t r = 0 ;r < task -> n_ranges ;r ++ ) { 55const struct l2flush_range * rg = & task -> ranges [r ]; 56const uint32_t rb_first = rg -> block_first ; 57const uint32_t rb_last = rg -> block_first + rg -> n_blocks ; 58 59const uint32_t lo = gb_first > rb_first ?gb_first :rb_first ; 60const uint32_t hi = gb_last < rb_last ?gb_last :rb_last ; 61if (lo >=hi ) { 62continue ; 63 } 64 65const uint32_t s = rg -> start + (lo - rb_first )* HEX_L2_BLOCK_SIZE ; 66uint32_t e = rg -> start + (hi - rb_first )* HEX_L2_BLOCK_SIZE ; 67if (e > rg -> end ) { 68e = rg -> end ; 69 } 70hex_l2flush ((void * ) (uintptr_t )s ,e - s ); 71 } 72 73htp_trace_event_stop (tr ,HTP_TRACE_EVT_L2FLUSH ,gb_first ); 74} 75 76static void merge_dirty_ranges (struct htp_context * ctx ) { 77for (uint32_t i = 0 ;i < HTP_MAX_DIRTY_RANGES ;i ++ ) { 78struct htp_dirty_range * r = & ctx -> dirty_ranges [i ]; 79if (!r -> start )continue ; 80 81for (uint32_t j = 0 ;j < HTP_MAX_DIRTY_RANGES ;) { 82struct htp_dirty_range * s = & ctx -> dirty_ranges [j ]; 83if (i == j || !s -> start || r -> end < s -> start || s -> end < r -> start ) { 84j ++ ; 85continue ; 86 } 87 88r -> start = MIN (r -> start ,s -> start ); 89r -> end = MAX (r -> end ,s -> end ); 90s -> start = 0 ; 91s -> end = 0 ; 92j = 0 ; 93 } 94 } 95} 96 97void htp_tensor_dirty_all (struct htp_context * ctx ,const struct htp_tensor * const * tensors ,uint32_t n ) { 98const struct htp_tensor * pending [HTP_OP_MAX_OUTPUTS ]; 99uint32_t n_pending = 0 ; 100 101for (uint32_t i = 0 ;i < n ;i ++ ) { 102const struct htp_tensor * t = tensors [i ]; 103if (!t || (t -> flags & (HTP_TENSOR_WEIGHT |HTP_TENSOR_FENCE ))) { 104continue ; 105 } 106 107uint32_t t_start = t -> data ; 108uint32_t t_end = t_start + t -> size ; 109 110bool merged = false; 111for (uint32_t j = 0 ;j < HTP_MAX_DIRTY_RANGES ;j ++ ) { 112struct htp_dirty_range * r = & ctx -> dirty_ranges [j ]; 113if (!r -> start )continue ; 114 115if (r -> start <=t_end && t_start <=r -> end ) { 116uint32_t new_start = (t_start < r -> start ) ?t_start :r -> start ; 117uint32_t new_end = (t_end > r -> end ) ?t_end :r -> end ; 118r -> start = new_start ; 119r -> end = new_end ; 120merged = true; 121 } 122 } 123 124if (!merged ) { 125pending [n_pending ++ ]= t ; 126 } 127 } 128 129merge_dirty_ranges (ctx ); 130 131if (n_pending == 0 ) { 132return ; 133 } 134 135uint32_t empty_indices [HTP_MAX_DIRTY_RANGES ]; 136uint32_t active_indices [HTP_MAX_DIRTY_RANGES ]; 137uint32_t n_active = 0 ; 138uint32_t n_empty = 0 ; 139for (uint32_t j = 0 ;j < HTP_MAX_DIRTY_RANGES ;j ++ ) { 140if (ctx -> dirty_ranges [j ].start ) { 141active_indices [n_active ++ ]= j ; 142 }else { 143empty_indices [n_empty ++ ]= j ; 144 } 145 } 146 147if (n_pending <=n_empty ) { 148for (uint32_t i = 0 ;i < n_pending ;i ++ ) { 149uint32_t idx = empty_indices [i ]; 150struct htp_dirty_range * r = & ctx -> dirty_ranges [idx ]; 151r -> start = pending [i ]-> data ; 152r -> end = pending [i ]-> data + pending [i ]-> size ; 153 } 154merge_dirty_ranges (ctx ); 155return ; 156 } 157 158uint32_t n_evict = n_pending - n_empty ; 159uint32_t total_evict_size = 0 ; 160for (uint32_t i = 0 ;i < n_evict ;i ++ ) { 161uint32_t idx = active_indices [i ]; 162struct htp_dirty_range * r = & ctx -> dirty_ranges [idx ]; 163total_evict_size += r -> end - r -> start ; 164 } 165 166if (total_evict_size > HEX_L2_FLUSH_ALL_THRESHOLD ) { 167flush_all_dcache (ctx ); 168for (uint32_t i = 0 ;i < n_pending ;i ++ ) { 169struct htp_dirty_range * r = & ctx -> dirty_ranges [i ]; 170r -> start = pending [i ]-> data ; 171r -> end = pending [i ]-> data + pending [i ]-> size ; 172 } 173merge_dirty_ranges (ctx ); 174return ; 175 } 176 177if (total_evict_size > HEX_L2_FLUSH_WQ_THRESHOLD && ctx -> n_threads > 1 && n_evict <=HTP_MAX_DIRTY_RANGES ) { 178struct l2flush_multi_task task ; 179task .trace = ctx -> trace ; 180task .n_ranges = n_evict ; 181 182uint32_t block_acc = 0 ; 183for (uint32_t i = 0 ;i < n_evict ;i ++ ) { 184uint32_t idx = active_indices [i ]; 185struct htp_dirty_range * r = & ctx -> dirty_ranges [idx ]; 186 187struct l2flush_range * rg = & task .ranges [i ]; 188rg -> start = hex_align_down ((size_t )r -> start ,HEX_L2_LINE_SIZE ); 189rg -> end = hex_align_up ((size_t )r -> end ,HEX_L2_LINE_SIZE ); 190rg -> block_first = block_acc ; 191rg -> n_blocks = (rg -> end - rg -> start + HEX_L2_BLOCK_SIZE - 1 ) /HEX_L2_BLOCK_SIZE ; 192block_acc += rg -> n_blocks ; 193 } 194 195task .total_blocks = block_acc ; 196task .blocks_per_thread = fastdiv (block_acc + ctx -> n_threads - 1 ,& ctx -> n_threads_div ); 197 198work_queue_run (ctx -> work_queue ,l2flush_multi_worker ,& task ,ctx -> n_threads ); 199 }else { 200struct htp_thread_trace * tr = & ctx -> trace [0 ]; 201htp_trace_event_start (tr ,HTP_TRACE_EVT_L2FLUSH ,0 ); 202for (uint32_t i = 0 ;i < n_evict ;i ++ ) { 203uint32_t idx = active_indices [i ]; 204struct htp_dirty_range * r = & ctx -> dirty_ranges [idx ]; 205uint32_t size = r -> end - r -> start ; 206hex_l2flush ((void * ) (uintptr_t )r -> start ,size ); 207 } 208htp_trace_event_stop (tr ,HTP_TRACE_EVT_L2FLUSH ,0 ); 209 } 210 211for (uint32_t i = 0 ;i < n_evict ;i ++ ) { 212uint32_t idx = active_indices [i ]; 213struct htp_dirty_range * r = & ctx -> dirty_ranges [idx ]; 214r -> start = pending [i ]-> data ; 215r -> end = pending [i ]-> data + pending [i ]-> size ; 216 } 217 218for (uint32_t i = 0 ;i < n_empty ;i ++ ) { 219uint32_t idx = empty_indices [i ]; 220struct htp_dirty_range * r = & ctx -> dirty_ranges [idx ]; 221r -> start = pending [n_evict + i ]-> data ; 222r -> end = pending [n_evict + i ]-> data + pending [n_evict + i ]-> size ; 223 } 224 225merge_dirty_ranges (ctx ); 226} 227 228static void make_tensor_clean (struct htp_context * ctx ,const struct htp_tensor * t ) { 229uint32_t t_start = t -> data ; 230uint32_t t_end = t_start + t -> size ; 231 232for (uint32_t i = 0 ;i < HTP_MAX_DIRTY_RANGES ;i ++ ) { 233struct htp_dirty_range * r = & ctx -> dirty_ranges [i ]; 234if (!r -> start )continue ; 235 236if (r -> start < t_end && t_start < r -> end ) { 237if (t_start <=r -> start && r -> end <=t_end ) { 238r -> start = 0 ; 239 }else if (t_start <=r -> start ) { 240r -> start = t_end ; 241 }else if (r -> end <=t_end ) { 242r -> end = t_start ; 243 } 244 } 245 } 246} 247 248static inline bool is_tensor_dirty (struct htp_context * ctx ,const struct htp_tensor * t ) { 249uint32_t t_start = t -> data ; 250uint32_t t_end = t_start + t -> size ; 251 252for (uint32_t i = 0 ;i < HTP_MAX_DIRTY_RANGES ;i ++ ) { 253struct htp_dirty_range * r = & ctx -> dirty_ranges [i ]; 254if (!r -> start )continue ; 255 256if (r -> start < t_end && t_start < r -> end ) { 257return true; 258 } 259 } 260return false; 261} 262 263static void flush_dirty_ranges (struct htp_context * ctx ,const struct htp_dirty_range * ranges ,uint32_t n_ranges ,uint64_t total_dirty ) { 264if (total_dirty >=HEX_L2_FLUSH_WQ_THRESHOLD && ctx -> n_threads > 1 ) { 265struct l2flush_multi_task task ; 266task .trace = ctx -> trace ; 267task .n_ranges = n_ranges ; 268 269uint32_t block_acc = 0 ; 270for (uint32_t i = 0 ;i < n_ranges ;i ++ ) { 271const struct htp_dirty_range * r = & ranges [i ]; 272struct l2flush_range * rg = & task .ranges [i ]; 273rg -> start = hex_align_down ((size_t )r -> start ,HEX_L2_LINE_SIZE ); 274rg -> end = hex_align_up ((size_t )r -> end ,HEX_L2_LINE_SIZE ); 275rg -> block_first = block_acc ; 276rg -> n_blocks = (rg -> end - rg -> start + HEX_L2_BLOCK_SIZE - 1 ) /HEX_L2_BLOCK_SIZE ; 277block_acc += rg -> n_blocks ; 278 } 279 280task .total_blocks = block_acc ; 281task .blocks_per_thread = fastdiv (block_acc + ctx -> n_threads - 1 ,& ctx -> n_threads_div ); 282 283work_queue_run (ctx -> work_queue ,l2flush_multi_worker ,& task ,ctx -> n_threads ); 284 }else { 285struct htp_thread_trace * tr = & ctx -> trace [0 ]; 286htp_trace_event_start (tr ,HTP_TRACE_EVT_L2FLUSH ,0 ); 287for (uint32_t i = 0 ;i < n_ranges ;i ++ ) { 288const struct htp_dirty_range * r = & ranges [i ]; 289hex_l2flush ((void * ) (uintptr_t )r -> start ,r -> end - r -> start ); 290 } 291htp_trace_event_stop (tr ,HTP_TRACE_EVT_L2FLUSH ,0 ); 292 } 293} 294 295void htp_flush_dirty_ranges (struct htp_context * ctx ) { 296struct htp_dirty_range ranges [HTP_MAX_DIRTY_RANGES ]; 297uint32_t n_ranges = 0 ; 298uint64_t total_dirty = 0 ; 299 300for (uint32_t i = 0 ;i < HTP_MAX_DIRTY_RANGES ;i ++ ) { 301const struct htp_dirty_range * r = & ctx -> dirty_ranges [i ]; 302if (!r -> start ) { 303continue ; 304 } 305ranges [n_ranges ++ ]= * r ; 306total_dirty += r -> end - r -> start ; 307 } 308 309if (total_dirty == 0 ) { 310return ; 311 } 312 313if (total_dirty > HEX_L2_FLUSH_ALL_THRESHOLD ) { 314flush_all_dcache (ctx ); 315return ; 316 } 317 318flush_dirty_ranges (ctx ,ranges ,n_ranges ,total_dirty ); 319memset (ctx -> dirty_ranges ,0 ,sizeof (ctx -> dirty_ranges )); 320} 321 322void htp_tensor_flush_all (struct htp_context * ctx ,const struct htp_tensor * const * tensors ,uint32_t n ) { 323const struct htp_tensor * dirty_tensors [HTP_OP_MAX_INPUTS ]; 324struct htp_dirty_range ranges [HTP_OP_MAX_INPUTS ]; 325uint32_t n_dirty = 0 ; 326uint64_t total_dirty = 0 ; 327 328for (uint32_t i = 0 ;i < n ;i ++ ) { 329const struct htp_tensor * t = tensors [i ]; 330if (t && is_tensor_dirty (ctx ,t )) { 331dirty_tensors [n_dirty ++ ]= t ; 332ranges [n_dirty - 1 ].start = t -> data ; 333ranges [n_dirty - 1 ].end = t -> data + t -> size ; 334total_dirty += t -> size ; 335 } 336 } 337 338if (total_dirty == 0 ) { 339return ; 340 } 341 342if (total_dirty > HEX_L2_FLUSH_ALL_THRESHOLD ) { 343flush_all_dcache (ctx ); 344return ; 345 } 346 347flush_dirty_ranges (ctx ,ranges ,n_dirty ,total_dirty ); 348for (uint32_t i = 0 ;i < n_dirty ;i ++ ) { 349make_tensor_clean (ctx ,dirty_tensors [i ]); 350 } 351}