char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
0190529ec
char/aliceai-t5-moe
1#include "ggml-et-cpu-compare.h" 2 3#include "ggml-cpu/ggml-cpu-impl.h" 4#include "ggml-cpu/ops.h" 5 6#include <algorithm> 7#include <cmath> 8#include <cstdlib> 9#include <cstring> 10 11bool ggml_et_cpu_compare_init_pre (ggml_et_cpu_compare_ctx * ctx ,const ggml_tensor * node ,ggml_op op ) { 12if (!ctx || !node ) { 13GGML_LOG_ERROR ("ET: Invalid parameters for CPU compare init\n" ); 14return false; 15 } 16 17// Clear context 18memset (ctx ,0 ,sizeof (* ctx )); 19 20// Calculate actual buffer sizes - use backend buffer size for accurate copy 21auto get_tensor_buffer_size = [](const ggml_tensor * tensor )-> size_t { 22if (!tensor ) { 23return 0 ; 24 } 25 26if (tensor -> buffer ) { 27// Get actual backend buffer size 28size_t buffer_size = ggml_backend_buffer_get_size (tensor -> buffer ); 29 30// Use the full buffer size to avoid any truncation issues 31return buffer_size ; 32 }else { 33// Fallback to logical size if no buffer 34return ggml_nbytes (tensor ); 35 } 36 }; 37 38ctx -> src0_size = get_tensor_buffer_size (node -> src [0 ]); 39ctx -> src1_size = get_tensor_buffer_size (node -> src [1 ]); 40ctx -> src2_size = get_tensor_buffer_size (node -> src [2 ]); 41ctx -> dst_size = get_tensor_buffer_size (node ); 42 43// Allocate CPU buffers for all tensors 44if (ctx -> src0_size > 0 ) { 45ctx -> cpu_src0_data = malloc (ctx -> src0_size ); 46if (!ctx -> cpu_src0_data ) { 47GGML_LOG_ERROR ("ET: Failed to allocate CPU src0 buffer\n" ); 48 gotocleanup ; 49 } 50 } 51 52if (ctx -> src1_size > 0 ) { 53ctx -> cpu_src1_data = malloc (ctx -> src1_size ); 54if (!ctx -> cpu_src1_data ) { 55GGML_LOG_ERROR ("ET: Failed to allocate CPU src1 buffer\n" ); 56 gotocleanup ; 57 } 58 } 59 60if (ctx -> src2_size > 0 ) { 61ctx -> cpu_src2_data = malloc (ctx -> src2_size ); 62if (!ctx -> cpu_src2_data ) { 63GGML_LOG_ERROR ("ET: Failed to allocate CPU src2 buffer\n" ); 64 gotocleanup ; 65 } 66 } 67 68ctx -> cpu_dst_data = malloc (ctx -> dst_size ); 69if (!ctx -> cpu_dst_data ) { 70GGML_LOG_ERROR ("ET: Failed to allocate CPU dst buffer\n" ); 71 gotocleanup ; 72 } 73 74ctx -> et_dst_data = malloc (ctx -> dst_size ); 75if (!ctx -> et_dst_data ) { 76GGML_LOG_ERROR ("ET: Failed to allocate ET dst buffer\n" ); 77 gotocleanup ; 78 } 79 80// Copy data from ET device buffers to CPU host buffers 81if (ctx -> src0_size > 0 ) { 82// Copy logical tensor size - ggml_backend_tensor_get handles stride layout internally 83size_t logical_size = ggml_nbytes (node -> src [0 ]); 84ggml_backend_tensor_get (node -> src [0 ],ctx -> cpu_src0_data ,0 ,logical_size ); 85 } 86if (ctx -> src1_size > 0 ) { 87size_t logical_size = ggml_nbytes (node -> src [1 ]); 88ggml_backend_tensor_get (node -> src [1 ],ctx -> cpu_src1_data ,0 ,logical_size ); 89 } 90if (ctx -> src2_size > 0 ) { 91size_t logical_size = ggml_nbytes (node -> src [2 ]); 92ggml_backend_tensor_get (node -> src [2 ],ctx -> cpu_src2_data ,0 ,logical_size ); 93 } 94 95// Copy destination data from device (for operations like SET_ROWS that modify existing data) 96// Most ops create new tensors so this is unused, but SET_ROWS requires existing dst data 97 { 98size_t logical_size = ggml_nbytes (node ); 99ggml_backend_tensor_get (node ,ctx -> cpu_dst_data ,0 ,logical_size ); 100 } 101 102// Create CPU backend for reference computation 103GGML_LOG_DEBUG ("ET: Creating CPU backend for reference computation\n" ); 104ctx -> cpu_backend = ggml_backend_cpu_init (); 105if (!ctx -> cpu_backend ) { 106GGML_LOG_ERROR ("ET: Failed to create CPU backend\n" ); 107 gotocleanup ; 108 } 109 110// Create GGML context for CPU tensors 111GGML_LOG_DEBUG ("ET: Creating GGML context for CPU computation\n" ); 112ggml_init_params ctx_params ; 113ctx_params .mem_size = ggml_tensor_overhead ()* 4 + ggml_graph_overhead ();// up to 4 tensors + graph 114ctx_params .mem_buffer = nullptr ; 115ctx_params .no_alloc = true;// We'll manage data ourselves 116ctx -> ggml_ctx = ggml_init (ctx_params ); 117if (!ctx -> ggml_ctx ) { 118GGML_LOG_ERROR ("ET: Failed to create GGML context\n" ); 119 gotocleanup ; 120 } 121 122// Create CPU tensors with proper context 123if (node -> src [0 ]) { 124ctx -> cpu_src0 = ggml_new_tensor (ctx -> ggml_ctx ,node -> src [0 ]-> type ,GGML_MAX_DIMS ,node -> src [0 ]-> ne ); 125if (!ctx -> cpu_src0 ) { 126GGML_LOG_ERROR ("ET: Failed to create CPU src0 tensor\n" ); 127 gotocleanup ; 128 } 129ctx -> cpu_src0 -> data = ctx -> cpu_src0_data ; 130// Copy stride array (nb) for correct memory layout 131memcpy (ctx -> cpu_src0 -> nb ,node -> src [0 ]-> nb ,sizeof (node -> src [0 ]-> nb )); 132// Copy op_params if present 133memcpy (ctx -> cpu_src0 -> op_params ,node -> src [0 ]-> op_params ,sizeof (node -> src [0 ]-> op_params )); 134 } 135 136if (node -> src [1 ]) { 137ctx -> cpu_src1 = ggml_new_tensor (ctx -> ggml_ctx ,node -> src [1 ]-> type ,GGML_MAX_DIMS ,node -> src [1 ]-> ne ); 138if (!ctx -> cpu_src1 ) { 139GGML_LOG_ERROR ("ET: Failed to create CPU src1 tensor\n" ); 140 gotocleanup ; 141 } 142ctx -> cpu_src1 -> data = ctx -> cpu_src1_data ; 143// Copy stride array (nb) for correct memory layout 144memcpy (ctx -> cpu_src1 -> nb ,node -> src [1 ]-> nb ,sizeof (node -> src [1 ]-> nb )); 145// Copy op_params if present 146memcpy (ctx -> cpu_src1 -> op_params ,node -> src [1 ]-> op_params ,sizeof (node -> src [1 ]-> op_params )); 147 } 148 149if (node -> src [2 ]) { 150ctx -> cpu_src2 = ggml_new_tensor (ctx -> ggml_ctx ,node -> src [2 ]-> type ,GGML_MAX_DIMS ,node -> src [2 ]-> ne ); 151if (!ctx -> cpu_src2 ) { 152GGML_LOG_ERROR ("ET: Failed to create CPU src2 tensor\n" ); 153 gotocleanup ; 154 } 155ctx -> cpu_src2 -> data = ctx -> cpu_src2_data ; 156// Copy stride array (nb) for correct memory layout 157memcpy (ctx -> cpu_src2 -> nb ,node -> src [2 ]-> nb ,sizeof (node -> src [2 ]-> nb )); 158// Copy op_params if present 159memcpy (ctx -> cpu_src2 -> op_params ,node -> src [2 ]-> op_params ,sizeof (node -> src [2 ]-> op_params )); 160 } 161 162return true; 163 164cleanup : 165ggml_et_cpu_compare_free (ctx ); 166return false; 167} 168 169bool ggml_et_cpu_compare_compute_and_check (ggml_et_cpu_compare_ctx * ctx , 170const ggml_tensor * node , 171const ggml_et_cpu_compare_config * config ) { 172if (!ctx || !ctx -> cpu_backend || !ctx -> ggml_ctx || !node || !config ) { 173GGML_LOG_ERROR ("ET: Invalid parameters for CPU compute and check\n" ); 174return false; 175 } 176 177// Create operation-specific CPU destination tensor based on the node's operation 178ggml_op op = node -> op ; 179switch (op ) { 180case GGML_OP_MUL : 181ctx -> cpu_dst = ggml_mul (ctx -> ggml_ctx ,ctx -> cpu_src0 ,ctx -> cpu_src1 ); 182break ; 183case GGML_OP_ADD : 184ctx -> cpu_dst = ggml_add (ctx -> ggml_ctx ,ctx -> cpu_src0 ,ctx -> cpu_src1 ); 185break ; 186case GGML_OP_MUL_MAT : 187ctx -> cpu_dst = ggml_mul_mat (ctx -> ggml_ctx ,ctx -> cpu_src0 ,ctx -> cpu_src1 ); 188break ; 189case GGML_OP_MUL_MAT_ID : 190// MUL_MAT_ID: Mixture of Experts matrix multiplication 191// src0 (as): expert weight matrices [K, M, n_expert] 192// src1 (b): activations [K, n_expert_used, batch] 193// src2 (ids): expert selection indices [n_expert_used, batch] 194ctx -> cpu_dst = ggml_mul_mat_id (ctx -> ggml_ctx ,ctx -> cpu_src0 ,ctx -> cpu_src1 ,ctx -> cpu_src2 ); 195break ; 196case GGML_OP_ROPE : 197 { 198const int32_t * op_params = (const int32_t * )node -> op_params ; 199const int32_t n_dims = op_params [1 ]; 200const int32_t mode = op_params [2 ]; 201const int32_t n_ctx_orig = op_params [4 ]; 202const float freq_base = * ((const float * ) (op_params + 5 )); 203const float freq_scale = * ((const float * ) (op_params + 6 )); 204const float ext_factor = * ((const float * ) (op_params + 7 )); 205const float attn_factor = * ((const float * ) (op_params + 8 )); 206const float beta_fast = * ((const float * ) (op_params + 9 )); 207const float beta_slow = * ((const float * ) (op_params + 10 )); 208 209if (mode & GGML_ROPE_TYPE_MROPE ) { 210int sections [GGML_MROPE_SECTIONS ]; 211memcpy (sections ,op_params + 11 ,sizeof (sections )); 212ctx -> cpu_dst = ggml_rope_multi (ctx -> ggml_ctx ,ctx -> cpu_src0 ,ctx -> cpu_src1 ,ctx -> cpu_src2 , 213n_dims ,sections ,mode ,n_ctx_orig ,freq_base ,freq_scale , 214ext_factor ,attn_factor ,beta_fast ,beta_slow ); 215 }else { 216ctx -> cpu_dst = ggml_rope_ext (ctx -> ggml_ctx ,ctx -> cpu_src0 ,ctx -> cpu_src1 ,ctx -> cpu_src2 , 217n_dims ,mode ,n_ctx_orig ,freq_base ,freq_scale ,ext_factor , 218attn_factor ,beta_fast ,beta_slow ); 219 } 220 } 221break ; 222case GGML_OP_RMS_NORM : 223// Extract epsilon parameter from op_params (stored as float) 224 { 225float eps ; 226memcpy (& eps ,node -> op_params ,sizeof (float )); 227ctx -> cpu_dst = ggml_rms_norm (ctx -> ggml_ctx ,ctx -> cpu_src0 ,eps ); 228 } 229break ; 230case GGML_OP_SQR : 231ctx -> cpu_dst = ggml_sqr (ctx -> ggml_ctx ,ctx -> cpu_src0 ); 232break ; 233case GGML_OP_UNARY : 234 { 235ggml_unary_op uop = (ggml_unary_op )ggml_get_op_params_i32 (node ,0 ); 236ctx -> cpu_dst = ggml_unary (ctx -> ggml_ctx ,ctx -> cpu_src0 ,uop ); 237 } 238break ; 239case GGML_OP_SUM_ROWS : 240ctx -> cpu_dst = ggml_sum_rows (ctx -> ggml_ctx ,ctx -> cpu_src0 ); 241break ; 242case GGML_OP_MEAN : 243ctx -> cpu_dst = ggml_mean (ctx -> ggml_ctx ,ctx -> cpu_src0 ); 244break ; 245case GGML_OP_CLAMP : 246 { 247float clamp_min ,clamp_max ; 248memcpy (& clamp_min , (const float * )node -> op_params + 0 ,sizeof (float )); 249memcpy (& clamp_max , (const float * )node -> op_params + 1 ,sizeof (float )); 250ctx -> cpu_dst = ggml_clamp (ctx -> ggml_ctx ,ctx -> cpu_src0 ,clamp_min ,clamp_max ); 251 } 252break ; 253case GGML_OP_GLU : 254// Extract GLU parameters from op_params (split mode only) 255 { 256int32_t glu_op_type = ggml_get_op_params_i32 (node ,0 );// GLU variant 257ggml_glu_op glu_op = (ggml_glu_op )glu_op_type ; 258 259// Only support split tensor mode 260if (!ctx -> cpu_src1 ) { 261GGML_LOG_ERROR ("ET: GLU CPU comparison requires split tensor mode\n" ); 262return false; 263 } 264if (glu_op == GGML_GLU_OP_SWIGLU_CLAMP ) { 265const float limit = ggml_get_op_params_f32 (node ,3 ); 266ctx -> cpu_dst = ggml_swiglu_clamp (ctx -> ggml_ctx ,ctx -> cpu_src0 ,ctx -> cpu_src1 ,limit ); 267 }else { 268ctx -> cpu_dst = ggml_glu_split (ctx -> ggml_ctx ,ctx -> cpu_src0 ,ctx -> cpu_src1 ,glu_op ); 269 } 270 } 271break ; 272case GGML_OP_SOFT_MAX : 273 { 274// Extract scale and max_bias from op_params 275float scale = 1.0f ; 276float max_bias = 0.0f ; 277memcpy (& scale , (const float * )node -> op_params + 0 ,sizeof (float )); 278memcpy (& max_bias , (const float * )node -> op_params + 1 ,sizeof (float )); 279 280if (ctx -> cpu_src1 || scale != 1.0f || max_bias != 0.0f ) { 281// Use extended softmax when mask or non-default parameters are present 282ctx -> cpu_dst = ggml_soft_max_ext (ctx -> ggml_ctx ,ctx -> cpu_src0 ,ctx -> cpu_src1 ,scale ,max_bias ); 283 }else { 284// Use simple softmax when no mask and default parameters 285ctx -> cpu_dst = ggml_soft_max (ctx -> ggml_ctx ,ctx -> cpu_src0 ); 286 } 287 288// Add sinks if present 289if (ctx -> cpu_src2 ) { 290ggml_soft_max_add_sinks (ctx -> cpu_dst ,ctx -> cpu_src2 ); 291 } 292 } 293break ; 294case GGML_OP_GET_ROWS : 295ctx -> cpu_dst = ggml_get_rows (ctx -> ggml_ctx ,ctx -> cpu_src0 ,ctx -> cpu_src1 ); 296break ; 297case GGML_OP_CONT : 298ctx -> cpu_dst = ggml_cont (ctx -> ggml_ctx ,ctx -> cpu_src0 ); 299break ; 300case GGML_OP_SET_ROWS : 301 { 302// SET_ROWS operation scatters src0 rows to dst[src1] positions 303// Create destination tensor (this is the "view" that SET_ROWS returns) 304ggml_tensor * cpu_dst_base = ggml_new_tensor (ctx -> ggml_ctx ,node -> type ,GGML_MAX_DIMS ,node -> ne ); 305if (!cpu_dst_base ) { 306GGML_LOG_ERROR ("ET: Failed to create CPU destination base tensor for SET_ROWS\n" ); 307return false; 308 } 309cpu_dst_base -> data = ctx -> cpu_dst_data ; 310memcpy (cpu_dst_base -> nb ,node -> nb ,sizeof (node -> nb )); 311 312// Note: cpu_dst_data already contains the pre-existing destination data from device 313// SET_ROWS will update specific rows, leaving others unchanged 314 315// Perform SET_ROWS operation: returns a view that scatters src0 rows to dst[src1] positions 316ctx -> cpu_dst = ggml_set_rows (ctx -> ggml_ctx ,cpu_dst_base ,ctx -> cpu_src0 ,ctx -> cpu_src1 ); 317 } 318break ; 319default : 320GGML_LOG_ERROR ("ET: Unsupported operation %s for CPU comparison\n" ,ggml_op_name (op )); 321return false; 322 } 323 324if (!ctx -> cpu_dst ) { 325GGML_LOG_ERROR ("ET: Failed to create CPU destination tensor for operation %s\n" ,ggml_op_name (op )); 326return false; 327 } 328 329ctx -> cpu_dst -> data = ctx -> cpu_dst_data ; 330// Copy stride array (nb) for correct memory layout - except for CONT which should keep contiguous strides 331if (op != GGML_OP_CONT ) { 332memcpy (ctx -> cpu_dst -> nb ,node -> nb ,sizeof (node -> nb )); 333 } 334// For CONT operations, keep the contiguous strides created by ggml_cont() 335 336// Create minimal computation graph 337ctx -> cpu_graph = ggml_new_graph_custom (ctx -> ggml_ctx ,1 , false); 338if (!ctx -> cpu_graph ) { 339GGML_LOG_ERROR ("ET: Failed to create CPU computation graph\n" ); 340return false; 341 } 342ctx -> cpu_graph -> nodes [0 ]= ctx -> cpu_dst ; 343ctx -> cpu_graph -> n_nodes = 1 ; 344 345// Log input data for debugging if enabled 346if (config && config -> log_differences ) { 347if (ctx -> cpu_src0_data && ctx -> src0_size >=4 ) { 348GGML_LOG_DEBUG ("ET: CPU src0 first few bytes: %02x %02x %02x %02x\n" , ((uint8_t * )ctx -> cpu_src0_data )[0 ], 349 ((uint8_t * )ctx -> cpu_src0_data )[1 ], ((uint8_t * )ctx -> cpu_src0_data )[2 ], 350 ((uint8_t * )ctx -> cpu_src0_data )[3 ]); 351 } 352if (ctx -> cpu_src1_data && ctx -> src1_size >=16 ) { 353GGML_LOG_DEBUG ("ET: CPU src1 first few floats: %.6f %.6f %.6f %.6f\n" , ((float * )ctx -> cpu_src1_data )[0 ], 354 ((float * )ctx -> cpu_src1_data )[1 ], ((float * )ctx -> cpu_src1_data )[2 ], 355 ((float * )ctx -> cpu_src1_data )[3 ]); 356 } 357 } 358 359// Compute using CPU backend 360ggml_status cpu_result = ggml_backend_graph_compute (ctx -> cpu_backend ,ctx -> cpu_graph ); 361 362if (cpu_result != GGML_STATUS_SUCCESS ) { 363GGML_LOG_ERROR ("ET: CPU reference computation failed with status %d\n" ,cpu_result ); 364return false; 365 } 366 367// Log output data for debugging if enabled 368if (config && config -> log_differences && ctx -> dst_size >=16 ) { 369GGML_LOG_DEBUG ("ET: CPU dst first few floats after computation: %.6f %.6f %.6f %.6f\n" , 370 ((float * )ctx -> cpu_dst_data )[0 ], ((float * )ctx -> cpu_dst_data )[1 ], 371 ((float * )ctx -> cpu_dst_data )[2 ], ((float * )ctx -> cpu_dst_data )[3 ]); 372 } 373 374// Now copy ET device destination to host for comparison 375size_t dst_logical_size = ggml_nbytes (node ); 376ggml_backend_tensor_get (node ,ctx -> et_dst_data ,0 ,dst_logical_size ); 377 378if (config -> log_differences ) { 379size_t num_elements = ggml_nelements (node ); 380size_t max_log = std::min (num_elements ,config -> max_log_elements ); 381 382// Check if this is an elementwise operation that can show src inputs 383bool is_elementwise = (op == GGML_OP_MUL || op == GGML_OP_ADD || op == GGML_OP_GLU ); 384float * cpu_src0_float = is_elementwise ? (float * )ctx -> cpu_src0_data :nullptr ; 385float * cpu_src1_float = is_elementwise ? (float * )ctx -> cpu_src1_data :nullptr ; 386 387// Helper to get float value from tensor data (handles f16 and f32) 388auto get_float = [](const void * data ,size_t idx ,ggml_type type )-> float { 389if (type == GGML_TYPE_F16 ) { 390const ggml_fp16_t * fp16_data = (const ggml_fp16_t * )data ; 391return ggml_fp16_to_fp32 (fp16_data [idx ]); 392 } 393 394const float * float_data = (const float * )data ; 395return float_data [idx ]; 396 }; 397 398// Compare all elements but log only the first max_log_elements 399bool matches = true; 400size_t total_mismatches = 0 ; 401 402// First pass: check all elements for mismatches 403for (size_t i = 0 ;i < num_elements ;i ++ ) { 404float cpu_val = get_float (ctx -> cpu_dst_data ,i ,node -> type ); 405float et_val = get_float (ctx -> et_dst_data ,i ,node -> type ); 406float diff = fabsf (cpu_val - et_val ); 407float rel_diff = diff / (fabsf (cpu_val )+ 1e-8f ); 408 409if (rel_diff > config -> tolerance ) { 410matches = false; 411total_mismatches ++ ; 412 } 413 } 414 415// Second pass: log detailed info for first max_log elements only 416for (size_t i = 0 ;i < max_log ;i ++ ) { 417float cpu_val = get_float (ctx -> cpu_dst_data ,i ,node -> type ); 418float et_val = get_float (ctx -> et_dst_data ,i ,node -> type ); 419float diff = fabsf (cpu_val - et_val ); 420 421if (is_elementwise && cpu_src0_float && cpu_src1_float ) { 422GGML_LOG_DEBUG ("ET: [%zu] src0=%.6f, src1=%.6f -> CPU=%.6f, ET=%.6f, diff=%.6f\n" ,i ,cpu_src0_float [i ], 423cpu_src1_float [i ],cpu_val ,et_val ,diff ); 424 }else if (is_elementwise && cpu_src0_float ) { 425GGML_LOG_DEBUG ("ET: [%zu] src0=%.6f -> CPU=%.6f, ET=%.6f, diff=%.6f\n" ,i ,cpu_src0_float [i ],cpu_val , 426et_val ,diff ); 427 }else { 428GGML_LOG_DEBUG ("ET: [%zu] CPU=%.6f, ET=%.6f, diff=%.6f\n" ,i ,cpu_val ,et_val ,diff ); 429 } 430 } 431 432// Check some elements from the middle and end for full coverage 433if (num_elements > max_log ) { 434size_t mid = num_elements /2 ; 435size_t end = num_elements - 1 ; 436float cpu_mid = get_float (ctx -> cpu_dst_data ,mid ,node -> type ); 437float et_mid = get_float (ctx -> et_dst_data ,mid ,node -> type ); 438float cpu_end = get_float (ctx -> cpu_dst_data ,end ,node -> type ); 439float et_end = get_float (ctx -> et_dst_data ,end ,node -> type ); 440 441GGML_LOG_DEBUG ("ET: Middle element [%zu]: CPU=%.6f, ET=%.6f\n" ,mid ,cpu_mid ,et_mid ); 442GGML_LOG_DEBUG ("ET: Last element [%zu]: CPU=%.6f, ET=%.6f\n" ,end ,cpu_end ,et_end ); 443 } 444 445GGML_LOG_DEBUG ("ET: Results %s (%zu/%zu elements match within tolerance %.6f)\n" ,matches ?"MATCH" :"DIFFER" , 446num_elements - total_mismatches ,num_elements ,config -> tolerance ); 447 } 448 449// Copy CPU result to device if flag is set 450if (config -> use_cpu_result ) { 451GGML_LOG_DEBUG ("ET: Overwriting ET device result with CPU result for correct inference\n" ); 452size_t dst_logical_size = ggml_nbytes (node ); 453ggml_backend_tensor_set (const_cast < ggml_tensor *> (node ),ctx -> cpu_dst_data ,0 ,dst_logical_size ); 454GGML_LOG_DEBUG ("ET: CPU result copied to ET device buffer\n" ); 455 } 456 457return true; 458} 459 460void ggml_et_cpu_compare_free (ggml_et_cpu_compare_ctx * ctx ) { 461if (!ctx ) { 462return ; 463 } 464 465if (ctx -> cpu_src0_data ) { 466free (ctx -> cpu_src0_data ); 467ctx -> cpu_src0_data = nullptr ; 468 } 469if (ctx -> cpu_src1_data ) { 470free (ctx -> cpu_src1_data ); 471ctx -> cpu_src1_data = nullptr ; 472 } 473if (ctx -> cpu_src2_data ) { 474free (ctx -> cpu_src2_data ); 475ctx -> cpu_src2_data = nullptr ; 476 } 477if (ctx -> cpu_dst_data ) { 478free (ctx -> cpu_dst_data ); 479ctx -> cpu_dst_data = nullptr ; 480 } 481if (ctx -> et_dst_data ) { 482free (ctx -> et_dst_data ); 483ctx -> et_dst_data = nullptr ; 484 } 485 486if (ctx -> ggml_ctx ) { 487ggml_free (ctx -> ggml_ctx ); 488ctx -> ggml_ctx = nullptr ; 489 } 490 491if (ctx -> cpu_backend ) { 492ggml_backend_free (ctx -> cpu_backend ); 493ctx -> cpu_backend = nullptr ; 494 } 495 496// Clear pointers 497ctx -> cpu_src0 = nullptr ; 498ctx -> cpu_src1 = nullptr ; 499ctx -> cpu_src2 = nullptr ; 500ctx -> cpu_dst = nullptr ; 501ctx -> cpu_graph = nullptr ; 502}