char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
8e330954a
char/aliceai-t5-moe
1#include "fit.h" 2 3#include "json.h" 4#include "log.h" 5 6#include "../src/llama-ext.h" 7 8#include <array> 9#include <cassert> 10#include <stdexcept> 11#include <cinttypes> 12#include <set> 13#include <string> 14#include <vector> 15 16// this enum is only used in llama_params_fit_impl but needs to be defined outside of it to fix a Windows compilation issue 17// enum to identify part of a layer for distributing its tensors: 18enum common_layer_fraction_t { 19LAYER_FRACTION_NONE = 0 ,// nothing 20LAYER_FRACTION_ATTN = 1 ,// attention 21LAYER_FRACTION_UP = 2 ,// attention + up 22LAYER_FRACTION_GATE = 3 ,// attention + up + gate 23LAYER_FRACTION_MOE = 4 ,// everything but sparse MoE weights 24}; 25 26class common_params_fit_exception :public std::runtime_error { 27using std::runtime_error::runtime_error ; 28}; 29 30static std::vector < llama_device_memory_data > common_get_device_memory_data_impl ( 31const char * path_model , 32const llama_model_params * mparams , 33const llama_context_params * cparams , 34 std::vector < ggml_backend_dev_t > & devs , 35uint32_t & hp_ngl , 36uint32_t & hp_n_ctx_train , 37uint32_t & hp_n_expert , 38ggml_log_level log_level ) { 39struct user_data_t { 40struct { 41ggml_log_callback callback ; 42void * user_data ; 43 }original_logger ; 44ggml_log_level min_level ;// prints below this log level go to debug log 45 }; 46user_data_t ud ; 47llama_log_get (& ud .original_logger .callback ,& ud .original_logger .user_data ); 48ud .min_level = log_level ; 49 50llama_log_set ([](ggml_log_level level ,const char * text ,void * user_data ) { 51const user_data_t * ud = (const user_data_t * )user_data ; 52const ggml_log_level level_eff = level >=ud -> min_level ?level :GGML_LOG_LEVEL_DEBUG ; 53ud -> original_logger .callback (level_eff ,text ,ud -> original_logger .user_data ); 54 },& ud ); 55 56llama_model_params mparams_copy = * mparams ; 57mparams_copy .no_alloc = true; 58mparams_copy .load_mode = LLAMA_LOAD_MODE_NONE ; 59 60llama_model * model = llama_model_load_from_file (path_model ,mparams_copy ); 61if (model == nullptr ) { 62llama_log_set (ud .original_logger .callback ,ud .original_logger .user_data ); 63throw std::runtime_error ("failed to load model" ); 64 } 65 66llama_context * ctx = llama_init_from_model (model ,* cparams ); 67if (ctx == nullptr ) { 68llama_model_free (model ); 69llama_log_set (ud .original_logger .callback ,ud .original_logger .user_data ); 70throw std::runtime_error ("failed to create llama_context from model" ); 71 } 72 73const size_t nd = llama_model_n_devices (model ); 74 std::vector < llama_device_memory_data > ret (nd + 1 ); 75 76llama_memory_breakdown memory_breakdown = llama_get_memory_breakdown (ctx ); 77 78for (const auto & [buft ,mb ] :memory_breakdown ) { 79if (ggml_backend_buft_is_host (buft )) { 80ret .back ().mb .model += mb .model ; 81ret .back ().mb .context += mb .context ; 82ret .back ().mb .compute += mb .compute ; 83continue ; 84 } 85 86ggml_backend_dev_t dev = ggml_backend_buft_get_device (buft ); 87if (!dev ) { 88continue ; 89 } 90for (size_t i = 0 ;i < nd ;i ++ ) { 91if (dev == llama_model_get_device (model ,i )) { 92ret [i ].mb .model += mb .model ; 93ret [i ].mb .context += mb .context ; 94ret [i ].mb .compute += mb .compute ; 95break ; 96 } 97 } 98 } 99 100 { 101ggml_backend_dev_t cpu_dev = ggml_backend_dev_by_type (GGML_BACKEND_DEVICE_TYPE_CPU ); 102if (cpu_dev == nullptr ) { 103throw std::runtime_error ("no CPU backend found" ); 104 } 105size_t free ; 106size_t total ; 107ggml_backend_dev_memory (cpu_dev ,& free ,& total ); 108ret .back ().free = free ; 109ret .back ().total = total ; 110 } 111for (size_t i = 0 ;i < nd ;i ++ ) { 112ggml_backend_dev_t dev = llama_model_get_device (model ,i ); 113 114size_t free ; 115size_t total ; 116ggml_backend_dev_memory (dev ,& free ,& total ); 117 118// Some non-GPU accelerator backends, such as BLAS, report 0/0 and rely on 119// the host-memory fallback. For GPU-like backends, keep 0/0 so --fit does 120// not assign anything to a device with an unknown memory budget. 121if (free == 0 && total == 0 ) { 122const enum ggml_backend_dev_type type = ggml_backend_dev_type (dev ); 123if (type == GGML_BACKEND_DEVICE_TYPE_GPU || type == GGML_BACKEND_DEVICE_TYPE_IGPU ) { 124LOG_WRN ("%s: device %s did not report memory; --fit will not use it\n" , 125__func__ ,ggml_backend_dev_name (dev )); 126 }else { 127free = ret .back ().free ; 128total = ret .back ().total ; 129 } 130 } 131ret [i ].free = free ; 132ret [i ].total = total ; 133 } 134 135devs .clear (); 136for (int i = 0 ;i < llama_model_n_devices (model );i ++ ) { 137devs .push_back (llama_model_get_device (model ,i )); 138 } 139 140hp_ngl = llama_model_n_layer (model ); 141if (mparams -> load_mtp ) { 142hp_ngl += llama_model_n_layer_nextn (model ); 143 } 144hp_n_ctx_train = llama_model_n_ctx_train (model ); 145hp_n_expert = llama_model_n_expert (model ); 146 147common_memory_breakdown_print (ctx ); 148 149llama_free (ctx ); 150llama_model_free (model ); 151llama_log_set (ud .original_logger .callback ,ud .original_logger .user_data ); 152 153return ret ; 154} 155 156common_device_memory_data_vec common_get_device_memory_data ( 157const char * path_model , 158const llama_model_params * mparams , 159const llama_context_params * cparams , 160 std::vector < ggml_backend_dev_t > & devs , 161uint32_t & hp_ngl , 162uint32_t & hp_n_ctx_train , 163uint32_t & hp_n_expert , 164ggml_log_level log_level ) { 165 std::vector < llama_device_memory_data > impl = common_get_device_memory_data_impl ( 166path_model ,mparams ,cparams ,devs ,hp_ngl ,hp_n_ctx_train ,hp_n_expert ,log_level ); 167 168common_device_memory_data_vec ret (impl .size ()); 169for (size_t i = 0 ;i < impl .size ();i ++ ) { 170ret [i ].total = impl [i ].total ; 171ret [i ].free = impl [i ].free ; 172ret [i ].model = impl [i ].mb .model ; 173ret [i ].context = impl [i ].mb .context ; 174ret [i ].compute = impl [i ].mb .compute ; 175 } 176return ret ; 177} 178 179static void common_params_fit_impl ( 180const char * path_model ,struct llama_model_params * mparams ,struct llama_context_params * cparams , 181float * tensor_split ,struct llama_model_tensor_buft_override * tensor_buft_overrides , 182size_t * margins_s ,uint32_t n_ctx_min ,const common_fit_extra_model * extra ,enum ggml_log_level log_level ) { 183if (mparams -> split_mode == LLAMA_SPLIT_MODE_TENSOR ) { 184throw common_params_fit_exception ("llama_params_fit is not implemented for SPLIT_MODE_TENSOR, abort" ); 185 } 186constexpr int64_t MiB = 1024 * 1024 ; 187typedef std::vector < llama_device_memory_data > dmds_t ; 188const llama_model_params default_mparams = llama_model_default_params (); 189 190 std::vector < ggml_backend_dev_t > devs ; 191uint32_t hp_ngl = 0 ;// hparams.n_gpu_layers 192uint32_t hp_nct = 0 ;// hparams.n_ctx_train 193uint32_t hp_nex = 0 ;// hparams.n_expert 194 195// with non-unified kv, we need to take into account n_streams 196// for example, if memory can hold more than model's trained context size, we must extend the n_ctx to hold enough n_streams 197const uint32_t n_streams = cparams -> kv_unified ?1 : std::max < uint32_t > (1 ,cparams -> n_seq_max ); 198const bool n_ctx_auto = cparams -> n_ctx == 0 ; 199 200dmds_t dmds_extra ;// memory of the extra model, laid out on the devices of the main model 201uint32_t n_ctx_extra = 0 ;// context that memory was measured at 202 203// the extra model competes for the same memory as the main model, add it to every measurement 204// its memory is measured again whenever the context it follows changes 205auto add_extra_memory = [& ](dmds_t & dmds ) { 206if (extra == nullptr ) { 207return ; 208 } 209 210if (dmds_extra .empty ()|| n_ctx_extra != cparams -> n_ctx ) { 211 std::vector < ggml_backend_dev_t > devs_extra ; 212uint32_t ngl_extra = 0 ; 213uint32_t nct_extra = 0 ; 214uint32_t nex_extra = 0 ; 215 216extra -> cparams -> n_ctx = cparams -> n_ctx ; 217 218LOG_TRC ("%s: getting device memory data for the extra model at a context size of %" PRIu32 ":\n" , 219__func__ ,cparams -> n_ctx ); 220 221dmds_t measured ; 222try { 223measured = common_get_device_memory_data_impl ( 224extra -> path_model ,extra -> mparams ,extra -> cparams ,devs_extra ,ngl_extra ,nct_extra ,nex_extra ,log_level ); 225 }catch (const std::runtime_error & e ) { 226// the extra model is optional, fit the main model alone rather than giving up 227LOG_WRN ("%s: failed to measure the memory of the extra model, fitting without it: %s\n" ,__func__ ,e .what ()); 228dmds_extra = dmds_t (devs .size ()+ 1 ); 229n_ctx_extra = cparams -> n_ctx ; 230return ; 231 } 232 233dmds_extra = dmds_t (devs .size ()+ 1 ); 234dmds_extra .back ().mb = measured .back ().mb ; 235for (size_t je = 0 ;je < devs_extra .size ();je ++ ) { 236for (size_t id = 0 ;id < devs .size ();id ++ ) { 237if (devs_extra [je ]== devs [id ]) { 238dmds_extra [id ].mb .model += measured [je ].mb .model ; 239dmds_extra [id ].mb .context += measured [je ].mb .context ; 240dmds_extra [id ].mb .compute += measured [je ].mb .compute ; 241break ; 242 } 243 } 244 } 245if (extra -> shares_model ) { 246for (llama_device_memory_data & dmd :dmds_extra ) { 247dmd .mb .model = 0 ; 248 } 249 } 250 251n_ctx_extra = cparams -> n_ctx ; 252 } 253 254for (size_t id = 0 ;id < dmds .size ();id ++ ) { 255dmds [id ].mb .model += dmds_extra [id ].mb .model ; 256dmds [id ].mb .context += dmds_extra [id ].mb .context ; 257dmds [id ].mb .compute += dmds_extra [id ].mb .compute ; 258 } 259 }; 260 261// step 1: get data for default parameters and check whether any changes are necessary in the first place 262 263LOG_TRC ("%s: getting device memory data for initial parameters:\n" ,__func__ ); 264dmds_t dmds_full = common_get_device_memory_data_impl (path_model ,mparams ,cparams ,devs ,hp_ngl ,hp_nct ,hp_nex ,log_level ); 265 266// saturate instead of overflowing, this also preserves the UINT32_MAX sentinel of n_ctx_min: 267const uint32_t n_ctx_max = (uint32_t ) std::min < uint64_t > (uint64_t (hp_nct )* n_streams ,UINT32_MAX ); 268const uint32_t n_ctx_min_total = (uint32_t ) std::min < uint64_t > (uint64_t (n_ctx_min )* n_streams ,UINT32_MAX ); 269 270// llama_context would use only hp_nct in total for n_ctx == 0, resolve the context before measuring anything else: 271if (n_ctx_auto ) { 272cparams -> n_ctx = n_ctx_max ; 273if (n_streams > 1 ) { 274LOG_TRC ("%s: context size unset and KV cache not unified -> using %" PRIu32 " for %" PRIu32 " sequences:\n" , 275__func__ ,n_ctx_max ,n_streams ); 276dmds_full = common_get_device_memory_data_impl (path_model ,mparams ,cparams ,devs ,hp_ngl ,hp_nct ,hp_nex ,log_level ); 277 } 278 } 279add_extra_memory (dmds_full ); 280 281const size_t nd = devs .size ();// number of devices 282 283 std::vector < int64_t > margins ;// this function uses int64_t rather than size_t for memory sizes to more conveniently handle deficits 284margins .reserve (nd ); 285if (nd == 0 ) { 286margins .push_back (margins_s [0 ]); 287 }else { 288for (size_t id = 0 ;id < nd ;id ++ ) { 289margins .push_back (margins_s [id ]); 290 } 291 } 292 293 std::vector < std::string > dev_names ; 294 { 295dev_names .reserve (nd ); 296size_t max_length = 0 ; 297for (const auto & dev :devs ) { 298 std::string name = ggml_backend_dev_name (dev ); 299name += " (" ; 300name += ggml_backend_dev_description (dev ); 301name += ")" ; 302dev_names .push_back (name ); 303max_length = std::max (max_length ,name .length ()); 304 } 305for (std::string & dn :dev_names ) { 306dn .insert (dn .end (),max_length - dn .length (),' ' ); 307 } 308 } 309 310int64_t sum_free = 0 ; 311int64_t sum_projected_free = 0 ; 312int64_t sum_projected_used = 0 ; 313int64_t sum_projected_model = 0 ; 314 std::vector < int64_t > projected_free_per_device ; 315projected_free_per_device .reserve (nd ); 316 317if (nd == 0 ) { 318sum_projected_used = dmds_full .back ().mb .total (); 319sum_free = dmds_full .back ().total ; 320sum_projected_free = sum_free - sum_projected_used ; 321LOG_TRC ("%s: projected to use %" PRId64 " MiB of host memory vs. %" PRId64 " MiB of total host memory\n" , 322__func__ ,sum_projected_used /MiB ,sum_free /MiB ); 323if (sum_projected_free >=margins [0 ]) { 324LOG_TRC ("%s: will leave %" PRId64 " >= %" PRId64 " MiB of system memory, no changes needed\n" , 325__func__ ,sum_projected_free /MiB ,margins [0 ]/MiB ); 326return ; 327 } 328 }else { 329if (nd > 1 ) { 330LOG_TRC ("%s: projected memory use with initial parameters [MiB]:\n" ,__func__ ); 331 } 332for (size_t id = 0 ;id < nd ;id ++ ) { 333const llama_device_memory_data & dmd = dmds_full [id ]; 334 335const int64_t projected_used = dmd .mb .total (); 336const int64_t projected_free = dmd .free - projected_used ; 337projected_free_per_device .push_back (projected_free ); 338 339sum_free += dmd .free ; 340sum_projected_used += projected_used ; 341sum_projected_free += projected_free ; 342sum_projected_model += dmd .mb .model ; 343 344if (nd > 1 ) { 345LOG_TRC ("%s: - %s: %6" PRId64 " total, %6" PRId64 " used, %6" PRId64 " free vs. target of %6" PRId64 "\n" , 346__func__ ,dev_names [id ].c_str (),dmd .total /MiB ,projected_used /MiB ,projected_free /MiB ,margins [id ]/MiB ); 347 } 348 } 349assert (sum_free >=0 && sum_projected_used >=0 ); 350LOG_TRC ("%s: projected to use %" PRId64 " MiB of device memory vs. %" PRId64 " MiB of free device memory\n" , 351__func__ ,sum_projected_used /MiB ,sum_free /MiB ); 352if (nd == 1 ) { 353if (projected_free_per_device [0 ] >=margins [0 ]) { 354LOG_TRC ("%s: will leave %" PRId64 " >= %" PRId64 " MiB of free device memory, no changes needed\n" , 355__func__ ,projected_free_per_device [0 ]/MiB ,margins [0 ]/MiB ); 356return ; 357 } 358 }else { 359bool changes_needed = false; 360for (size_t id = 0 ;id < nd ;id ++ ) { 361if (projected_free_per_device [id ]< margins [id ]) { 362changes_needed = true; 363break ; 364 } 365 } 366if (!changes_needed ) { 367LOG_TRC ("%s: targets for free memory can be met on all devices, no changes needed\n" ,__func__ ); 368return ; 369 } 370 } 371 } 372 373// step 2: try reducing memory use by reducing the context size 374 375 { 376int64_t global_surplus = sum_projected_free ; 377if (nd == 0 ) { 378global_surplus -= margins [0 ]; 379 }else { 380for (size_t id = 0 ;id < nd ;id ++ ) { 381global_surplus -= margins [id ]; 382 } 383 } 384if (global_surplus < 0 ) { 385if (nd <=1 ) { 386LOG_TRC ("%s: cannot meet free memory target of %" PRId64 " MiB, need to reduce device memory by %" PRId64 " MiB\n" , 387__func__ ,margins [0 ]/MiB ,- global_surplus /MiB ); 388 }else { 389LOG_TRC ( 390"%s: cannot meet free memory targets on all devices, need to use %" PRId64 " MiB less in total\n" , 391__func__ ,- global_surplus /MiB ); 392 } 393if (n_ctx_auto ) { 394if (n_ctx_max > n_ctx_min_total ) { 395int64_t sum_used_target = sum_free ; 396if (nd == 0 ) { 397sum_used_target -= margins [0 ]; 398 }else { 399for (size_t id = 0 ;id < nd ;id ++ ) { 400sum_used_target -= margins [id ]; 401 } 402 } 403if (nd > 1 ) { 404// for multiple devices we need to be more conservative in terms of how much context we think can fit: 405// - for dense models only whole layers can be assigned to devices 406// - for MoE models only whole tensors can be assigned to devices, which we estimate to be <= 1/3 of a layer 407// - on average we expect a waste of 0.5 layers/tensors per device 408// - use slightly more than the expected average for nd devices to be safe 409const int64_t model_per_layer = sum_projected_model / std::min (uint32_t (mparams -> n_gpu_layers ),hp_ngl ); 410sum_used_target -= (nd + 1 )* model_per_layer / (hp_nex == 0 ?2 :6 ); 411 } 412 413int64_t sum_projected_used_min_ctx = 0 ; 414cparams -> n_ctx = n_ctx_min_total ; 415dmds_t dmds_min_ctx = common_get_device_memory_data_impl (path_model ,mparams ,cparams ,devs ,hp_ngl ,hp_nct ,hp_nex ,log_level ); 416add_extra_memory (dmds_min_ctx ); 417if (nd == 0 ) { 418sum_projected_used_min_ctx = dmds_min_ctx .back ().mb .total (); 419 }else { 420for (size_t id = 0 ;id < nd ;id ++ ) { 421sum_projected_used_min_ctx += dmds_min_ctx [id ].mb .total (); 422 } 423 } 424if (sum_used_target > sum_projected_used_min_ctx ) { 425// linear interpolation between minimum and maximum context size: 426cparams -> n_ctx += (n_ctx_max - n_ctx_min_total )* (sum_used_target - sum_projected_used_min_ctx ) 427 / (sum_projected_used - sum_projected_used_min_ctx ); 428// round down context for CUDA backend, keep it divisible by the number of streams: 429const uint32_t align = 256 * n_streams ; 430cparams -> n_ctx = std::max (cparams -> n_ctx - cparams -> n_ctx %align ,n_ctx_min_total ); 431 432const int64_t bytes_per_ctx = (sum_projected_used - sum_projected_used_min_ctx ) / (n_ctx_max - n_ctx_min_total ); 433const int64_t memory_reduction = (n_ctx_max - cparams -> n_ctx )* bytes_per_ctx ; 434LOG_TRC ("%s: context size reduced from %" PRIu32 " to %" PRIu32 " -> need %" PRId64 " MiB less memory in total\n" , 435__func__ ,n_ctx_max ,cparams -> n_ctx ,memory_reduction /MiB ); 436if (nd <=1 ) { 437LOG_TRC ("%s: entire model can be fit by reducing context\n" ,__func__ ); 438return ; 439 } 440LOG_TRC ("%s: entire model should be fit across devices by reducing context\n" ,__func__ ); 441 }else { 442const int64_t memory_reduction = sum_projected_used - sum_projected_used_min_ctx ; 443LOG_TRC ("%s: context size reduced from %" PRIu32 " to %" PRIu32 " -> need %" PRId64 " MiB less memory in total\n" , 444__func__ ,n_ctx_max ,cparams -> n_ctx ,memory_reduction /MiB ); 445 } 446 }else { 447if (n_ctx_min == UINT32_MAX ) { 448LOG_TRC ("%s: user has requested full context size of %" PRIu32 " -> no change\n" ,__func__ ,n_ctx_max ); 449 }else { 450LOG_TRC ("%s: default model context size is %" PRIu32 " which is <= the min. context size of %" PRIu32 " -> no change\n" , 451__func__ ,n_ctx_max ,n_ctx_min_total ); 452 } 453 } 454 }else { 455LOG_TRC ("%s: context size set by user to %" PRIu32 " -> no change\n" ,__func__ ,cparams -> n_ctx ); 456 } 457 } 458 } 459if (nd == 0 ) { 460throw common_params_fit_exception ("was unable to fit model into system memory by reducing context, abort" ); 461 } 462 463if (mparams -> n_gpu_layers != default_mparams .n_gpu_layers ) { 464throw common_params_fit_exception ("n_gpu_layers already set by user to " + std::to_string (mparams -> n_gpu_layers )+ ", abort" ); 465 } 466if (nd > 1 ) { 467if (!tensor_split ) { 468throw common_params_fit_exception ("did not provide a buffer to write the tensor_split to, abort" ); 469 } 470if (mparams -> tensor_split ) { 471for (size_t id = 0 ;id < nd ;id ++ ) { 472if (mparams -> tensor_split [id ]!= 0.0f ) { 473throw common_params_fit_exception ("model_params::tensor_split already set by user, abort" ); 474 } 475 } 476 } 477if (mparams -> split_mode == LLAMA_SPLIT_MODE_ROW ) { 478throw common_params_fit_exception ("changing weight allocation for LLAMA_SPLIT_MODE_ROW not implemented, abort" ); 479 } 480 } 481if (!tensor_buft_overrides ) { 482throw common_params_fit_exception ("did not provide buffer to set tensor_buft_overrides, abort" ); 483 } 484if (mparams -> tensor_buft_overrides && (mparams -> tensor_buft_overrides -> pattern || mparams -> tensor_buft_overrides -> buft )) { 485throw common_params_fit_exception ("model_params::tensor_buft_overrides already set by user, abort" ); 486 } 487 488// step 3: iteratively fill the back to front with "dense" layers 489// - for a dense model simply fill full layers, giving each device a contiguous slice of the model 490// - for a MoE model, same as dense model but with all MoE tensors in system memory 491 492// utility function that returns a static C string matching the tensors for a specific layer index and layer fraction: 493auto get_overflow_pattern = [& ](const size_t il ,const common_layer_fraction_t lf )-> const char * { 494constexpr size_t n_strings = 1000 ; 495if (il >=n_strings ) { 496throw std::runtime_error ("at most " + std::to_string (n_strings )+ " model layers are supported" ); 497 } 498switch (lf ) { 499case LAYER_FRACTION_ATTN : { 500static std::array < std::string ,n_strings > patterns ; 501if (patterns [il ].empty ()) { 502patterns [il ]= "blk\\." + std::to_string (il )+ "\\.ffn_(gate|up|gate_up|down).*" ; 503 } 504return patterns [il ].c_str (); 505 } 506case LAYER_FRACTION_UP : { 507static std::array < std::string ,n_strings > patterns ; 508if (patterns [il ].empty ()) { 509patterns [il ]= "blk\\." + std::to_string (il )+ "\\.ffn_(gate|gate_up|down).*" ; 510 } 511return patterns [il ].c_str (); 512 } 513case LAYER_FRACTION_GATE : { 514static std::array < std::string ,n_strings > patterns ; 515if (patterns [il ].empty ()) { 516patterns [il ]= "blk\\." + std::to_string (il )+ "\\.ffn_down.*" ; 517 } 518return patterns [il ].c_str (); 519 } 520case LAYER_FRACTION_MOE : { 521static std::array < std::string ,n_strings > patterns ; 522if (patterns [il ].empty ()) { 523patterns [il ]= "blk\\." + std::to_string (il )+ "\\.ffn_(up|down|gate_up|gate)_(ch|)exps" ; 524 } 525return patterns [il ].c_str (); 526 } 527default : 528GGML_ABORT ("fatal error" ); 529 } 530 }; 531 532struct ngl_t { 533uint32_t n_layer = 0 ;// number of total layers 534uint32_t n_part = 0 ;// number of partial layers, <= n_layer 535 536// for the first partial layer varying parts can overflow, all further layers use LAYER_FRACTION_MOE: 537common_layer_fraction_t overflow_type = LAYER_FRACTION_MOE ; 538 539uint32_t n_full ()const { 540assert (n_layer >=n_part ); 541return n_layer - n_part ; 542 } 543 }; 544 545const size_t ntbo = llama_max_tensor_buft_overrides (); 546 547// utility function to set n_gpu_layers and tensor_split 548auto set_ngl_tensor_split_tbo = [& ]( 549const std::vector < ngl_t > & ngl_per_device , 550const std::vector < ggml_backend_buffer_type_t > & overflow_bufts , 551llama_model_params & mparams ) { 552mparams .n_gpu_layers = 0 ; 553for (size_t id = 0 ;id < nd ;id ++ ) { 554mparams .n_gpu_layers += ngl_per_device [id ].n_layer ; 555if (nd > 1 ) { 556tensor_split [id ]= ngl_per_device [id ].n_layer ; 557 } 558 } 559assert (uint32_t (mparams .n_gpu_layers ) <=hp_ngl + 1 ); 560uint32_t il0 = hp_ngl + 1 - mparams .n_gpu_layers ;// start index for tensor buft overrides 561 562mparams .tensor_split = tensor_split ; 563 564size_t itbo = 0 ; 565for (size_t id = 0 ;id < nd ;id ++ ) { 566il0 += ngl_per_device [id ].n_full (); 567for (uint32_t il = il0 ;il < il0 + ngl_per_device [id ].n_part ;il ++ ) { 568if (itbo + 1 >=ntbo ) { 569tensor_buft_overrides [itbo ].pattern = nullptr ; 570tensor_buft_overrides [itbo ].buft = nullptr ; 571itbo ++ ; 572mparams .tensor_buft_overrides = tensor_buft_overrides ; 573throw common_params_fit_exception ("llama_max_tensor_buft_overrides() == " 574+ std::to_string (ntbo )+ " is insufficient for model" ); 575 } 576tensor_buft_overrides [itbo ].pattern = get_overflow_pattern (il ,il == il0 ?ngl_per_device [id ].overflow_type :LAYER_FRACTION_MOE ); 577tensor_buft_overrides [itbo ].buft = il == il0 ?overflow_bufts [id ] :ggml_backend_cpu_buffer_type (); 578itbo ++ ; 579 } 580il0 += ngl_per_device [id ].n_part ; 581 } 582tensor_buft_overrides [itbo ].pattern = nullptr ; 583tensor_buft_overrides [itbo ].buft = nullptr ; 584itbo ++ ; 585mparams .tensor_buft_overrides = tensor_buft_overrides ; 586 }; 587 588// utility function that returns the memory use per device for given numbers of layers per device 589auto get_memory_for_layers = [& ]( 590const char * func_name , 591const std::vector < ngl_t > & ngl_per_device , 592const std::vector < ggml_backend_buffer_type_t > & overflow_bufts )-> std::vector < int64_t > { 593llama_model_params mparams_copy = * mparams ; 594set_ngl_tensor_split_tbo (ngl_per_device ,overflow_bufts ,mparams_copy ); 595 596dmds_t dmd_nl = common_get_device_memory_data_impl ( 597path_model ,& mparams_copy ,cparams ,devs ,hp_ngl ,hp_nct ,hp_nex ,log_level ); 598add_extra_memory (dmd_nl ); 599 600LOG_TRC ("%s: memory for test allocation by device:\n" ,func_name ); 601for (size_t id = 0 ;id < nd ;id ++ ) { 602const ngl_t & n = ngl_per_device [id ]; 603LOG_TRC ( 604"%s: id=%zu, n_layer=%2" PRIu32 ", n_part=%2" PRIu32 ", overflow_type=%d, mem=%6" PRId64 " MiB\n" , 605func_name ,id ,n .n_layer ,n .n_part ,int (n .overflow_type ),dmd_nl [id ].mb .total ()/MiB ); 606 } 607 608 std::vector < int64_t > ret ; 609ret .reserve (nd ); 610for (size_t id = 0 ;id < nd ;id ++ ) { 611ret .push_back (dmd_nl [id ].mb .total ()); 612 } 613return ret ; 614 }; 615 616int64_t global_surplus_cpu_moe = 0 ; 617if (hp_nex > 0 ) { 618const static std::string pattern_moe_all = "blk\\.\\d+\\.ffn_(up|down|gate_up|gate)_(ch|)exps" ;// matches all MoE tensors 619ggml_backend_buffer_type_t cpu_buft = ggml_backend_cpu_buffer_type (); 620tensor_buft_overrides [0 ]= {pattern_moe_all .c_str (),cpu_buft }; 621tensor_buft_overrides [1 ]= {nullptr ,nullptr }; 622mparams -> tensor_buft_overrides = tensor_buft_overrides ; 623 624LOG_TRC ("%s: getting device memory data with all MoE tensors moved to system memory:\n" ,__func__ ); 625dmds_t dmds_cpu_moe = common_get_device_memory_data_impl ( 626path_model ,mparams ,cparams ,devs ,hp_ngl ,hp_nct ,hp_nex ,log_level ); 627add_extra_memory (dmds_cpu_moe ); 628 629for (size_t id = 0 ;id < nd ;id ++ ) { 630global_surplus_cpu_moe += dmds_cpu_moe [id ].free ; 631global_surplus_cpu_moe -= int64_t (dmds_cpu_moe [id ].mb .total ())+ margins [id ]; 632 } 633 634if (global_surplus_cpu_moe > 0 ) { 635LOG_TRC ("%s: with only dense weights in device memory there is a total surplus of %" PRId64 " MiB\n" , 636__func__ ,global_surplus_cpu_moe /MiB ); 637 }else { 638LOG_TRC ("%s: with only dense weights in device memory there is still a total deficit of %" PRId64 " MiB\n" , 639__func__ ,- global_surplus_cpu_moe /MiB ); 640 } 641 642// reset 643tensor_buft_overrides [0 ]= {nullptr ,nullptr }; 644mparams -> tensor_buft_overrides = tensor_buft_overrides ; 645 } 646 647 std::vector < int64_t > targets ;// maximum acceptable memory use per device 648targets .reserve (nd ); 649for (size_t id = 0 ;id < nd ;id ++ ) { 650targets .push_back (dmds_full [id ].free - margins [id ]); 651LOG_TRC ("%s: id=%zu, target=%" PRId64 " MiB\n" ,__func__ ,id ,targets [id ]/MiB ); 652 } 653 654 std::vector < ggml_backend_buffer_type_t > overflow_bufts ;// which bufts the first partial layer of a device overflows to: 655overflow_bufts .reserve (nd ); 656for (size_t id = 0 ;id < nd ;id ++ ) { 657overflow_bufts .push_back (ggml_backend_cpu_buffer_type ()); 658 } 659 660 std::vector < ngl_t > ngl_per_device (nd ); 661 std::vector < int64_t > mem = get_memory_for_layers (__func__ ,ngl_per_device ,overflow_bufts ); 662 663// optimize the number of layers per device using the method of false position: 664// - ngl_per_device has 0 layers for each device, lower bound 665// - try a "high" configuration where a device is given all unassigned layers 666// - interpolate the memory use / layer between low and high linearly to get a guess where it meets our target 667// - check memory use of our guess, replace either the low or high bound 668// - once we only have a difference of a single layer, stop and return the lower bound that just barely still fits 669// - the last device has the output layer, which cannot be a partial layer 670if (hp_nex == 0 ) { 671LOG_TRC ("%s: filling dense layers back-to-front:\n" ,__func__ ); 672 }else { 673LOG_TRC ("%s: filling dense-only layers back-to-front:\n" ,__func__ ); 674 } 675for (int id = nd - 1 ;id >=0 ;id -- ) { 676uint32_t n_unassigned = hp_ngl + 1 ; 677for (size_t jd = id + 1 ;jd < nd ;++ jd ) { 678assert (n_unassigned >=ngl_per_device [jd ].n_layer ); 679n_unassigned -= ngl_per_device [jd ].n_layer ; 680 } 681 682 std::vector < ngl_t > ngl_per_device_high = ngl_per_device ; 683ngl_per_device_high [id ].n_layer = n_unassigned ; 684if (hp_nex > 0 ) { 685ngl_per_device_high [id ].n_part = size_t (id )< nd - 1 ?ngl_per_device_high [id ].n_layer :ngl_per_device_high [id ].n_layer - 1 ; 686 } 687if (ngl_per_device_high [id ].n_layer > 0 ) { 688 std::vector < int64_t > mem_high = get_memory_for_layers (__func__ ,ngl_per_device_high ,overflow_bufts ); 689if (mem_high [id ]> targets [id ]) { 690assert (ngl_per_device_high [id ].n_layer > ngl_per_device [id ].n_layer ); 691uint32_t delta = ngl_per_device_high [id ].n_layer - ngl_per_device [id ].n_layer ; 692LOG_TRC ("%s: start filling device %" PRIu32 ", delta=%" PRIu32 "\n" ,__func__ ,id ,delta ); 693while (delta > 1 ) { 694uint32_t step_size = int64_t (delta )* (targets [id ]- mem [id ]) / (mem_high [id ]- mem [id ]); 695step_size = std::max (step_size ,uint32_t (1 )); 696step_size = std::min (step_size ,delta - 1 ); 697 698 std::vector < ngl_t > ngl_per_device_test = ngl_per_device ; 699ngl_per_device_test [id ].n_layer += step_size ; 700if (hp_nex ) { 701ngl_per_device_test [id ].n_part += size_t (id )== nd - 1 && ngl_per_device_test [id ].n_part == 0 ? 702step_size - 1 :step_size ;// the first layer is the output layer which must always be full 703 } 704const std::vector < int64_t > mem_test = get_memory_for_layers (__func__ ,ngl_per_device_test ,overflow_bufts ); 705 706if (mem_test [id ] <=targets [id ]) { 707ngl_per_device = ngl_per_device_test ; 708mem = mem_test ; 709LOG_TRC ("%s: set ngl_per_device[%d].n_layer=%" PRIu32 "\n" ,__func__ ,id ,ngl_per_device [id ].n_layer ); 710 }else { 711ngl_per_device_high = ngl_per_device_test ; 712mem_high = mem_test ; 713LOG_TRC ("%s: set ngl_per_device_high[%d].n_layer=%" PRIu32 "\n" ,__func__ ,id ,ngl_per_device_high [id ].n_layer ); 714 } 715delta = ngl_per_device_high [id ].n_layer - ngl_per_device [id ].n_layer ; 716 } 717 }else { 718assert (ngl_per_device_high [id ].n_layer == n_unassigned ); 719ngl_per_device = ngl_per_device_high ; 720mem = mem_high ; 721LOG_TRC ("%s: set ngl_per_device[%d].n_layer=%" PRIu32 "\n" ,__func__ ,id ,ngl_per_device [id ].n_layer ); 722 } 723 } 724 725const int64_t projected_margin = dmds_full [id ].free - mem [id ]; 726LOG_TRC ( 727"%s: - %s: %2" PRIu32 " layers, %6" PRId64 " MiB used, %6" PRId64 " MiB free\n" , 728__func__ ,dev_names [id ].c_str (),ngl_per_device [id ].n_layer ,mem [id ]/MiB ,projected_margin /MiB ); 729 } 730if (hp_nex == 0 || global_surplus_cpu_moe <=0 ) { 731set_ngl_tensor_split_tbo (ngl_per_device ,overflow_bufts ,* mparams ); 732return ; 733 } 734 735// step 4: for a MoE model where all dense tensors fit, 736// convert the dense-only layers in the back to full layers in the front until all devices are full 737// essentially the same procedure as for the dense-only layers except front-to-back 738// also, try fitting at least part of one more layer to reduce waste for "small" GPUs with e.g. 24 GiB VRAM 739 740size_t id_dense_start = nd ; 741for (int id = nd - 1 ;id >=0 ;id -- ) { 742if (ngl_per_device [id ].n_layer > 0 ) { 743id_dense_start = id ; 744continue ; 745 } 746break ; 747 } 748assert (id_dense_start < nd ); 749 750LOG_TRC ("%s: converting dense-only layers to full layers and filling them front-to-back with overflow to next device/system memory:\n" ,__func__ ); 751for (size_t id = 0 ;id <=id_dense_start && id_dense_start < nd ;id ++ ) { 752 std::vector < ngl_t > ngl_per_device_high = ngl_per_device ; 753for (size_t jd = id_dense_start ;jd < nd ;jd ++ ) { 754const uint32_t n_layer_move = jd < nd - 1 ?ngl_per_device_high [jd ].n_layer :ngl_per_device_high [jd ].n_layer - 1 ; 755ngl_per_device_high [id ].n_layer += n_layer_move ; 756ngl_per_device_high [jd ].n_layer -= n_layer_move ; 757ngl_per_device_high [jd ].n_part = 0 ; 758 } 759size_t id_dense_start_high = nd - 1 ; 760 std::vector < int64_t > mem_high = get_memory_for_layers (__func__ ,ngl_per_device_high ,overflow_bufts ); 761 762if (mem_high [id ]> targets [id ]) { 763assert (ngl_per_device_high [id ].n_full () >=ngl_per_device [id ].n_full ()); 764uint32_t delta = ngl_per_device_high [id ].n_full ()- ngl_per_device [id ].n_full (); 765while (delta > 1 ) { 766uint32_t step_size = int64_t (delta )* (targets [id ]- mem [id ]) / (mem_high [id ]- mem [id ]); 767step_size = std::max (step_size ,uint32_t (1 )); 768step_size = std::min (step_size ,delta - 1 ); 769 770 std::vector < ngl_t > ngl_per_device_test = ngl_per_device ; 771size_t id_dense_start_test = id_dense_start ; 772uint32_t n_converted_test = 0 ; 773for (;id_dense_start_test < nd ;id_dense_start_test ++ ) { 774const uint32_t n_convert_jd = std::min (step_size - n_converted_test ,ngl_per_device_test [id_dense_start_test ].n_part ); 775ngl_per_device_test [id_dense_start_test ].n_layer -= n_convert_jd ; 776ngl_per_device_test [id_dense_start_test ].n_part -= n_convert_jd ; 777ngl_per_device_test [id ].n_layer += n_convert_jd ; 778n_converted_test += n_convert_jd ; 779 780if (ngl_per_device_test [id_dense_start_test ].n_part > 0 ) { 781break ; 782 } 783 } 784const std::vector < int64_t > mem_test = get_memory_for_layers (__func__ ,ngl_per_device_test ,overflow_bufts ); 785 786if (mem_test [id ] <=targets [id ]) { 787ngl_per_device = ngl_per_device_test ; 788mem = mem_test ; 789id_dense_start = id_dense_start_test ; 790LOG_TRC ("%s: set ngl_per_device[%zu].(n_layer, n_part)=(%" PRIu32 ", %" PRIu32 "), id_dense_start=%zu\n" , 791__func__ ,id ,ngl_per_device [id ].n_layer ,ngl_per_device [id ].n_part ,id_dense_start ); 792 }else { 793ngl_per_device_high = ngl_per_device_test ; 794mem_high = mem_test ; 795id_dense_start_high = id_dense_start_test ; 796LOG_TRC ("%s: set ngl_per_device_high[%zu].(n_layer, n_part)=(%" PRIu32 ", %" PRIu32 "), id_dense_start_high=%zu\n" , 797__func__ ,id ,ngl_per_device_high [id ].n_layer ,ngl_per_device_high [id ].n_part ,id_dense_start_high ); 798 } 799assert (ngl_per_device_high [id ].n_full () >=ngl_per_device [id ].n_full ()); 800delta = ngl_per_device_high [id ].n_full ()- ngl_per_device [id ].n_full (); 801 } 802 }else { 803ngl_per_device = ngl_per_device_high ; 804mem = mem_high ; 805id_dense_start = id_dense_start_high ; 806LOG_TRC ("%s: set ngl_per_device[%zu].(n_layer, n_part)=(%" PRIu32 ", %" PRIu32 "), id_dense_start=%zu\n" , 807__func__ ,id ,ngl_per_device [id ].n_layer ,ngl_per_device [id ].n_part ,id_dense_start ); 808 } 809 810// try to fit at least part of one more layer 811if (ngl_per_device [id_dense_start ].n_layer > (id < nd - 1 ?0 :1 )) { 812 std::vector < ngl_t > ngl_per_device_test = ngl_per_device ; 813size_t id_dense_start_test = id_dense_start ; 814ngl_per_device_test [id_dense_start_test ].n_layer -- ; 815ngl_per_device_test [id_dense_start_test ].n_part -- ; 816ngl_per_device_test [id ].n_layer ++ ; 817ngl_per_device_test [id ].n_part ++ ; 818if (ngl_per_device_test [id_dense_start_test ].n_part == 0 ) { 819id_dense_start_test ++ ; 820 } 821ngl_per_device_test [id ].overflow_type = LAYER_FRACTION_UP ; 822 std::vector < ggml_backend_buffer_type_t > overflow_bufts_test = overflow_bufts ; 823if (id < nd - 1 ) { 824overflow_bufts_test [id ]= ggml_backend_dev_buffer_type (devs [id + 1 ]); 825 } 826LOG_TRC ("%s: trying to fit one extra layer with overflow_type=LAYER_FRACTION_UP\n" ,__func__ ); 827 std::vector < int64_t > mem_test = get_memory_for_layers (__func__ ,ngl_per_device_test ,overflow_bufts_test ); 828if (mem_test [id ]< targets [id ]&& (id + 1 == nd || mem_test [id + 1 ]< targets [id + 1 ])) { 829ngl_per_device = ngl_per_device_test ; 830overflow_bufts = overflow_bufts_test ; 831mem = mem_test ; 832id_dense_start = id_dense_start_test ; 833LOG_TRC ("%s: set ngl_per_device[%zu].(n_layer, n_part, overflow_type)=(%" PRIu32 ", %" PRIu32 ", UP), id_dense_start=%zu\n" , 834__func__ ,id ,ngl_per_device [id ].n_layer ,ngl_per_device [id ].n_part ,id_dense_start ); 835 836ngl_per_device_test [id ].overflow_type = LAYER_FRACTION_GATE ; 837LOG_TRC ("%s: trying to fit one extra layer with overflow_type=LAYER_FRACTION_GATE\n" ,__func__ ); 838mem_test = get_memory_for_layers (__func__ ,ngl_per_device_test ,overflow_bufts_test ); 839if (mem_test [id ]< targets [id ]&& (id + 1 == nd || mem_test [id + 1 ]< targets [id + 1 ])) { 840ngl_per_device = ngl_per_device_test ; 841overflow_bufts = overflow_bufts_test ; 842mem = mem_test ; 843id_dense_start = id_dense_start_test ; 844LOG_TRC ("%s: set ngl_per_device[%zu].(n_layer, n_part, overflow_type)=(%" PRIu32 ", %" PRIu32 ", GATE), id_dense_start=%zu\n" , 845__func__ ,id ,ngl_per_device [id ].n_layer ,ngl_per_device [id ].n_part ,id_dense_start ); 846 } 847 }else { 848ngl_per_device_test [id ].overflow_type = LAYER_FRACTION_ATTN ; 849LOG_TRC ("%s: trying to fit one extra layer with overflow_type=LAYER_FRACTION_ATTN\n" ,__func__ ); 850mem_test = get_memory_for_layers (__func__ ,ngl_per_device_test ,overflow_bufts_test ); 851if (mem_test [id ]< targets [id ]&& (id + 1 == nd || mem_test [id + 1 ]< targets [id + 1 ])) { 852ngl_per_device = ngl_per_device_test ; 853overflow_bufts = overflow_bufts_test ; 854mem = mem_test ; 855id_dense_start = id_dense_start_test ; 856LOG_TRC ("%s: set ngl_per_device[%zu].(n_layer, n_part, overflow_type)=(%" PRIu32 ", %" PRIu32 ", ATTN), id_dense_start=%zu\n" , 857__func__ ,id ,ngl_per_device [id ].n_layer ,ngl_per_device [id ].n_part ,id_dense_start ); 858 } 859 } 860 } 861 862const int64_t projected_margin = dmds_full [id ].free - mem [id ]; 863LOG_TRC ( 864"%s: - %s: %2" PRIu32 " layers (%2" PRIu32 " overflowing), %6" PRId64 " MiB used, %6" PRId64 " MiB free\n" , 865__func__ ,dev_names [id ].c_str (),ngl_per_device [id ].n_layer ,ngl_per_device [id ].n_part ,mem [id ]/MiB ,projected_margin /MiB ); 866 } 867 868// print info for devices that were not changed during the conversion from dense only to full layers: 869for (size_t id = id_dense_start + 1 ;id < nd ;id ++ ) { 870const int64_t projected_margin = dmds_full [id ].free - mem [id ]; 871LOG_TRC ( 872"%s: - %s: %2" PRIu32 " layers (%2" PRIu32 " overflowing), %6" PRId64 " MiB used, %6" PRId64 " MiB free\n" , 873__func__ ,dev_names [id ].c_str (),ngl_per_device [id ].n_layer ,ngl_per_device [id ].n_part ,mem [id ]/MiB ,projected_margin /MiB ); 874 } 875 876set_ngl_tensor_split_tbo (ngl_per_device ,overflow_bufts ,* mparams ); 877} 878 879enum common_params_fit_status common_fit_params ( 880const char * path_model , 881llama_model_params * mparams , 882llama_context_params * cparams , 883float * tensor_split , 884llama_model_tensor_buft_override * tensor_buft_overrides , 885size_t * margins , 886uint32_t n_ctx_min , 887const common_fit_extra_model * extra , 888ggml_log_level log_level ) { 889const int64_t t0_us = llama_time_us (); 890common_params_fit_status status = COMMON_PARAMS_FIT_STATUS_SUCCESS ; 891try { 892common_params_fit_impl (path_model ,mparams ,cparams ,tensor_split ,tensor_buft_overrides ,margins ,n_ctx_min ,extra ,log_level ); 893LOG_TRC ("%s: successfully fit params to free device memory\n" ,__func__ ); 894 }catch (const common_params_fit_exception & e ) { 895LOG_WRN ("%s: failed to fit params to free device memory: %s\n" ,__func__ ,e .what ()); 896status = COMMON_PARAMS_FIT_STATUS_FAILURE ; 897 }catch (const std::runtime_error & e ) { 898LOG_ERR ("%s: encountered an error while trying to fit params to free device memory: %s\n" ,__func__ ,e .what ()); 899status = COMMON_PARAMS_FIT_STATUS_ERROR ; 900 } 901const int64_t t1_us = llama_time_us (); 902LOG_TRC ("%s: fitting params to free memory took %.2f seconds\n" ,__func__ , (t1_us - t0_us )* 1e-6 ); 903return status ; 904} 905 906void common_memory_breakdown_print (const struct llama_context * ctx ) { 907//const auto & devices = ctx->get_model().devices; 908const auto * model = llama_get_model (ctx ); 909 910 std::vector < ggml_backend_dev_t > devices ; 911for (int i = 0 ;i < llama_model_n_devices (model );i ++ ) { 912devices .push_back (llama_model_get_device (model ,i )); 913 } 914 915llama_memory_breakdown memory_breakdown = llama_get_memory_breakdown (ctx ); 916 917 std::vector < std::array < std::string ,9 >> table_data ; 918table_data .reserve (devices .size ()); 919 920// same data as the table below, for --log-jsonl consumers 921common_json rows = common_json::array (); 922const std::string template_header = "%s: | %s | %s %s %s %s %s %s %s |\n" ; 923const std::string template_gpu = "%s: | %s | %s = %s + (%s = %s + %s + %s) + %s |\n" ; 924const std::string template_other = "%s: | %s | %s %s %s = %s + %s + %s %s |\n" ; 925 926table_data .push_back ({template_header ,"memory breakdown [MiB]" ,"total" ,"free" ,"self" ,"model" ,"context" ,"compute" ,"unaccounted" }); 927 928constexpr size_t MiB = 1024 * 1024 ; 929const std::vector < std::string > desc_prefixes_strip = {"NVIDIA " ,"GeForce " ,"Tesla " ,"AMD " ,"Radeon " ,"Instinct " }; 930 931// track seen buffer types to avoid double counting: 932 std::set < ggml_backend_buffer_type_t > seen_buffer_types ; 933 934// accumulative memory breakdown for each device and for host: 935 std::vector < llama_memory_breakdown_data > mb_dev (devices .size ()); 936llama_memory_breakdown_data mb_host ; 937 938for (const auto & buft_mb :memory_breakdown ) { 939ggml_backend_buffer_type_t buft = buft_mb .first ; 940const llama_memory_breakdown_data & mb = buft_mb .second ; 941if (ggml_backend_buft_is_host (buft )) { 942mb_host .model += mb .model ; 943mb_host .context += mb .context ; 944mb_host .compute += mb .compute ; 945seen_buffer_types .insert (buft ); 946continue ; 947 } 948ggml_backend_dev_t dev = ggml_backend_buft_get_device (buft ); 949if (dev ) { 950int i_dev = -1 ; 951for (size_t i = 0 ;i < devices .size ();i ++ ) { 952if (devices [i ]== dev ) { 953i_dev = i ; 954break ; 955 } 956 } 957if (i_dev != -1 ) { 958mb_dev [i_dev ].model += mb .model ; 959mb_dev [i_dev ].context += mb .context ; 960mb_dev [i_dev ].compute += mb .compute ; 961seen_buffer_types .insert (buft ); 962continue ; 963 } 964 } 965 } 966 967// print memory breakdown for each device: 968for (size_t i = 0 ;i < devices .size ();i ++ ) { 969ggml_backend_dev_t dev = devices [i ]; 970llama_memory_breakdown_data mb = mb_dev [i ]; 971 972const std::string name = ggml_backend_dev_name (dev ); 973 std::string desc = ggml_backend_dev_description (dev ); 974for (const std::string & prefix :desc_prefixes_strip ) { 975if (desc .length () >=prefix .length ()&& desc .substr (0 ,prefix .length ())== prefix ) { 976desc = desc .substr (prefix .length ()); 977 } 978 } 979 980size_t free ,total ; 981ggml_backend_dev_memory (dev ,& free ,& total ); 982 983const size_t self = mb .model + mb .context + mb .compute ; 984const int64_t unaccounted = static_cast < int64_t > (total )- static_cast < int64_t > (free )- static_cast < int64_t > (self ); 985 986table_data .push_back ({ 987template_gpu , 988" - " + name + " (" + desc + ")" , 989 std::to_string (total /MiB ), 990 std::to_string (free /MiB ), 991 std::to_string (self /MiB ), 992 std::to_string (mb .model /MiB ), 993 std::to_string (mb .context /MiB ), 994 std::to_string (mb .compute /MiB ), 995 std::to_string (unaccounted /static_cast < int64_t > (MiB ))}); 996 997rows .push_back ({ 998 {"kind" ,"device" }, 999 {"name" ,name }, 1000 {"description" ,desc }, 1001 {"total" ,total /MiB }, 1002 {"free" ,free /MiB }, 1003 {"self" ,self /MiB }, 1004 {"model" ,mb .model /MiB }, 1005 {"context" ,mb .context /MiB }, 1006 {"compute" ,mb .compute /MiB }, 1007 {"unaccounted" ,unaccounted /static_cast < int64_t > (MiB )}, 1008 }); 1009 } 1010 1011// print memory breakdown for host: 1012 { 1013const size_t self = mb_host .model + mb_host .context + mb_host .compute ; 1014table_data .push_back ({ 1015template_other , 1016" - Host" , 1017"" ,// total 1018"" ,// free 1019 std::to_string (self /MiB ), 1020 std::to_string (mb_host .model /MiB ), 1021 std::to_string (mb_host .context /MiB ), 1022 std::to_string (mb_host .compute /MiB ), 1023"" });// unaccounted 1024 1025rows .push_back ({ 1026 {"kind" ,"host" }, 1027 {"name" ,"Host" }, 1028 {"self" ,self /MiB }, 1029 {"model" ,mb_host .model /MiB }, 1030 {"context" ,mb_host .context /MiB }, 1031 {"compute" ,mb_host .compute /MiB }, 1032 }); 1033 } 1034 1035// print memory breakdown for all remaining buffer types: 1036for (const auto & buft_mb :memory_breakdown ) { 1037ggml_backend_buffer_type_t buft = buft_mb .first ; 1038const llama_memory_breakdown_data & mb = buft_mb .second ; 1039if (seen_buffer_types .count (buft )== 1 ) { 1040continue ; 1041 } 1042const std::string name = ggml_backend_buft_name (buft ); 1043const size_t self = mb .model + mb .context + mb .compute ; 1044table_data .push_back ({ 1045template_other , 1046" - " + name , 1047"" ,// total 1048"" ,// free 1049 std::to_string (self /MiB ), 1050 std::to_string (mb .model /MiB ), 1051 std::to_string (mb .context /MiB ), 1052 std::to_string (mb .compute /MiB ), 1053"" });// unaccounted 1054 1055rows .push_back ({ 1056 {"kind" ,"buffer_type" }, 1057 {"name" ,name }, 1058 {"self" ,self /MiB }, 1059 {"model" ,mb .model /MiB }, 1060 {"context" ,mb .context /MiB }, 1061 {"compute" ,mb .compute /MiB }, 1062 }); 1063 1064seen_buffer_types .insert (buft ); 1065 } 1066 1067for (size_t j = 1 ;j < table_data [0 ].size ();j ++ ) { 1068size_t max_len = 0 ; 1069for (const auto & td :table_data ) { 1070max_len = std::max (max_len ,td [j ].length ()); 1071 } 1072for (auto & td :table_data ) { 1073td [j ].insert (j == 1 ?td [j ].length () :0 ,max_len - td [j ].length (),' ' ); 1074 } 1075 } 1076for (const auto & td :table_data ) { 1077LOG_TRC (td [0 ].c_str (), 1078__func__ ,td [1 ].c_str (),td [2 ].c_str (),td [3 ].c_str (),td [4 ].c_str (),td [5 ].c_str (), 1079td [6 ].c_str (),td [7 ].c_str (),td [8 ].c_str ()); 1080 } 1081 1082LOG_JSON ("fit_memory_breakdown" ,common_json ({ 1083 {"unit" ,"MiB" }, 1084 {"rows" ,rows }, 1085 })); 1086} 1087 1088void common_fit_print ( 1089const char * path_model , 1090llama_model_params * mparams , 1091llama_context_params * cparams ) { 1092 std::vector < ggml_backend_dev_t > devs ; 1093uint32_t hp_ngl = 0 ;// hparams.n_gpu_layers 1094uint32_t hp_nct = 0 ;// hparams.n_ctx_train 1095uint32_t hp_nex = 0 ;// hparams.n_expert 1096 1097auto dmd = common_get_device_memory_data_impl (path_model ,mparams ,cparams ,devs ,hp_ngl ,hp_nct ,hp_nex ,GGML_LOG_LEVEL_ERROR ); 1098GGML_ASSERT (dmd .size ()== devs .size ()+ 1 ); 1099 1100for (size_t id = 0 ;id < devs .size ();id ++ ) { 1101printf ("%s " ,ggml_backend_dev_name (devs [id ])); 1102printf ("%zu " ,dmd [id ].mb .model /1024 /1024 ); 1103printf ("%zu " ,dmd [id ].mb .context /1024 /1024 ); 1104printf ("%zu " ,dmd [id ].mb .compute /1024 /1024 ); 1105printf ("\n" ); 1106 } 1107 1108printf ("Host " ); 1109printf ("%zu " ,dmd .back ().mb .model /1024 /1024 ); 1110printf ("%zu " ,dmd .back ().mb .context /1024 /1024 ); 1111printf ("%zu " ,dmd .back ().mb .compute /1024 /1024 ); 1112printf ("\n" ); 1113}