char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
82d6bb284
char/aliceai-t5-moe
1#pragma once 2 3#include "common.h" 4#include "log.h" 5#include "llama.h" 6#include "chat.h" 7#include "mtmd.h" 8#include "mtmd-helper.h" 9#include "subproc.h" 10 11#include "json.h" 12 13#include <atomic> 14#include <chrono> 15#include <condition_variable> 16#include <cinttypes> 17#include <cstdio> 18#include <functional> 19#include <mutex> 20#include <queue> 21#include <string> 22#include <vector> 23 24using json = common_json ; 25 26#define SLT_DBG (slot ,fmt , ...) LOG_DBG("slot %12.*s: id %2d | task %d | " fmt, 12, __func__, (slot).id, ((slot).task ? (slot).task->id : -1), __VA_ARGS__) 27#define SLT_TRC (slot ,fmt , ...) LOG_TRC("slot %12.*s: id %2d | task %d | " fmt, 12, __func__, (slot).id, ((slot).task ? (slot).task->id : -1), __VA_ARGS__) 28#define SLT_INF (slot ,fmt , ...) LOG_INF("slot %12.*s: id %2d | task %d | " fmt, 12, __func__, (slot).id, ((slot).task ? (slot).task->id : -1), __VA_ARGS__) 29#define SLT_WRN (slot ,fmt , ...) LOG_WRN("slot %12.*s: id %2d | task %d | " fmt, 12, __func__, (slot).id, ((slot).task ? (slot).task->id : -1), __VA_ARGS__) 30#define SLT_ERR (slot ,fmt , ...) LOG_ERR("slot %12.*s: id %2d | task %d | " fmt, 12, __func__, (slot).id, ((slot).task ? (slot).task->id : -1), __VA_ARGS__) 31#define SLT_CNT (slot ,fmt , ...) LOG_CNT("" fmt, __VA_ARGS__) 32 33#define SRV_DBG (fmt , ...) LOG_DBG("srv %12.*s: " fmt, 12, __func__, __VA_ARGS__) 34#define SRV_TRC (fmt , ...) LOG_TRC("srv %12.*s: " fmt, 12, __func__, __VA_ARGS__) 35#define SRV_INF (fmt , ...) LOG_INF("srv %12.*s: " fmt, 12, __func__, __VA_ARGS__) 36#define SRV_WRN (fmt , ...) LOG_WRN("srv %12.*s: " fmt, 12, __func__, __VA_ARGS__) 37#define SRV_ERR (fmt , ...) LOG_ERR("srv %12.*s: " fmt, 12, __func__, __VA_ARGS__) 38#define SRV_CNT (fmt , ...) LOG_CNT("" fmt, __VA_ARGS__) 39 40using raw_buffer = std ::vector < uint8_t > ; 41 42template < typename T > 43static T json_value (const json & body ,const std ::string & key ,const T & default_value ) { 44// Fallback null to default value 45if (body .contains (key )&& !body .at (key ).is_null ()) { 46try { 47return body .at (key ).get < T > (); 48} catch ( const common_json_error & err) { 49LOG_WRN ( "Wrong type supplied for parameter '%s', using default value: %s\n" , key. c_str (), err. what ()); 50return default_value; 51} 52} else { 53return default_value; 54} 55} 56 57// https://community.openai.com/t/openai-chat-list-of-error-codes-and-types/357791/11 58enum error_type { 59ERROR_TYPE_INVALID_REQUEST , 60ERROR_TYPE_AUTHENTICATION , 61ERROR_TYPE_SERVER , 62ERROR_TYPE_NOT_FOUND , 63ERROR_TYPE_PERMISSION , 64ERROR_TYPE_UNAVAILABLE , // custom error 65ERROR_TYPE_NOT_SUPPORTED , // custom error 66ERROR_TYPE_EXCEED_CONTEXT_SIZE , // custom error 67}; 68 69// thin wrapper around common_grammar_trigger with (de)serialization functions 70struct server_grammar_trigger { 71common_grammar_trigger value ; 72 73server_grammar_trigger() = default ; 74server_grammar_trigger ( const common_grammar_trigger & value) : value( value ) {} 75server_grammar_trigger ( const json & in) { 76value .type = ( common_grammar_trigger_type ) in.at("type").get < int > (); 77value.value = in.at("value"). get < std::string > (); 78if ( value .type == COMMON_GRAMMAR_TRIGGER_TYPE_TOKEN ) { 79value . token = ( llama_token ) in. at ("token").get < int > (); 80} 81} 82 83json to_json () const { 84json out { 85{"type", ( int ) value.type}, 86{"value", value.value}, 87}; 88if ( value .type == COMMON_GRAMMAR_TRIGGER_TYPE_TOKEN ) { 89out[ "token" ] = ( int ) value. token ; 90} 91return out; 92} 93}; 94 95json format_error_response ( const std ::string & message, const enum error_type type); 96 97// 98// random string / id 99// 100 101std :: string random_string (); 102std :: string gen_chatcmplid (); 103std :: string gen_tool_call_id (); 104 105// get a random marker; note: each time the server restarts, the marker will be different 106const char * get_media_marker (); 107 108// 109// lora utils 110// 111 112// check whether the given lora set has only aloras activated (empty => false) 113bool lora_all_alora ( const std ::vector < common_adapter_lora_info > & loras); 114 115// if the two sets of loras are different, they require a cache clear unless the 116// change is only from aloras to aloras. 117bool lora_should_clear_cache ( 118const std ::vector < common_adapter_lora_info > & current, 119const std ::vector < common_adapter_lora_info > & next); 120 121std ::map < int, float > parse_lora_request (const json & data); 122 123bool are_lora_equal ( 124const std ::vector < common_adapter_lora_info > & l1, 125const std ::vector < common_adapter_lora_info > & l2); 126 127// get the ids of all enabled loras 128std ::vector < size_t > lora_get_enabled_ids (const std::vector < common_adapter_lora_info > & loras); 129 130// 131// server_tokens 132// 133 134/** 135* server_tokens is a helper to manage the input tokens and image for the server. 136* it is made this way to simplify the logic of KV cache management. 137*/ 138struct server_tokens { 139bool has_mtmd = false; 140 141private : // disallow accessing these members directly, risking out-of-sync 142 143// map a **start** index in tokens to the image chunk 144// note: the order need to be in-sync with tokens 145std :: map < size_t , mtmd:: input_chunk_ptr > map_idx_to_media ; 146 147// list of tokens 148// if the token is LLAMA_TOKEN_NULL, it indicates that this position is occupied by media chunk 149// otherwise, it is a normal text token 150// note: a non-text chunk can occupy multiple tokens (aka memory cells) in the token list 151// note(2): for M-RoPE, an image can occupy different number of pos; do not assume 1-to-1 mapping tokens <-> pos 152llama_tokens tokens; 153 154// for ex. with input of 5 text tokens and 2 images (each image occupies 3 tokens and 2 pos): 155// [0] [1] [2] [3] [4] [img0] [img0] [img0] [img1] [img1] [img1] 156// idx 0 1 2 3 4 5 6 7 8 9 10 157// pos 0 1 2 3 4 5 5 5 7 7 7 158// map_idx_to_media will contain: {5, img0}, {8, img1} 159 160public : 161server_tokens () = default ; 162~ server_tokens () = default ; 163 164// Prevent copying 165// TODO: server_tokens should be copyable - remove this: 166server_tokens ( const server_tokens & ) = delete; 167server_tokens & operator = ( const server_tokens & ) = delete; 168 169// Allow moving (usually implicitly generated if members are movable) 170server_tokens ( server_tokens && ) = default ; 171server_tokens & operator = (server_tokens && ) = default ; 172 173// Allow accessing elements using [] operator 174llama_token operator[]( size_t index ) { return tokens [ index ]; } 175const llama_token & operator []( size_t index ) const { return tokens [ index ]; } 176 177server_tokens ( mtmd :: input_chunks & mtmd_chunks , bool has_mtmd ); 178server_tokens ( const llama_tokens & tokens , bool has_mtmd ); 179 180// for debugging 181std :: string str () const ; 182 183// the next position after n_tokens. if n_tokens < 0, return the next position after all tokens. 184llama_pos pos_next ( int64_t n_tokens = -1 ) const ; 185 186// number of tokens with position < max_pos 187size_t size_up_to_pos ( llama_pos max_pos ) const ; 188 189const mtmd :: input_chunk_ptr & find_chunk ( size_t idx ) const ; 190 191// find next media chunk after idx 192// returns a pair of pointer to the chunk (nullptr if not found) and its start index in tokens 193std :: pair < const mtmd :: input_chunk_ptr * , size_t > find_next_media_chunk ( size_t idx ) const ; 194 195void push_back ( llama_token tok ); 196 197// will create a copy of the chunk if it contains non-text data 198void push_back ( const mtmd_input_chunk * chunk ); 199 200// same as push_back, but media chunks are stored as placeholders (no image/audio data) 201// only use this if the chunk will never be encoded again (e.g. it is already in the KV cache) 202void push_back_placeholder ( const mtmd_input_chunk * chunk ); 203 204// appends server tokens, updates the media map. copies media chunks. 205void push_back ( server_tokens & tokens ); 206 207// for compatibility with context shift and prompt truncation 208void insert ( const llama_tokens & inp_tokens ); 209 210// for compatibility with speculative decoding, ctx shift 211const llama_tokens & get_tokens () const ; 212 213llama_tokens get_text_tokens () const ; 214 215std :: vector < char > serialize () const ; 216static server_tokens deserialize ( const llama_tokens & packed , bool has_mtmd ); 217 218// for compatibility with speculative decoding 219void set_token ( llama_pos pos , llama_token id ); 220 221size_t size () const { return tokens . size (); } 222 223bool empty () const { return tokens . empty (); } 224 225void clear () { 226map_idx_to_media . clear (); 227tokens . clear (); 228} 229 230void keep_first ( size_t n ); 231 232std :: string detokenize ( const llama_context * ctx , bool special ) const ; 233 234size_t get_common_prefix ( const server_tokens & b ) const ; 235 236// split the tokens into message spans, skipping over media chunks 237common_chat_msg_spans find_message_spans ( const common_chat_msg_delimiters & delims ) const ; 238 239// check text token IDs and the mapping between media chunks and token ranges 240bool validate ( const struct llama_context * ctx ) const ; 241 242server_tokens clone () const ; 243}; 244 245 246// 247// tokenizer and input processing utils 248// 249 250bool json_is_array_of_numbers ( const json & data ); 251 252// is array having BOTH numbers & strings? 253bool json_is_array_of_mixed_numbers_strings ( const json & data ); 254 255// does array have any individual integers/tokens? 256bool json_is_array_and_contains_numbers ( const json & data ); 257 258// get value by path(key1 / key2) 259json json_get_nested_values ( const std :: vector < std :: string > & paths , const json & js ); 260 261/** 262* this handles 2 cases: 263* - only string, example: "string" 264* - mixed string and tokens, example: [12, 34, "string", 56, 78] 265*/ 266llama_tokens tokenize_mixed ( const llama_vocab * vocab , const json & json_prompt , bool add_special , bool parse_special ); 267 268// return the last index of character that can form a valid string 269// if the last character is potentially cut in half, return the index before the cut 270// if validate_utf8(text) == text.size(), then the whole text is valid utf8 271size_t validate_utf8 ( const std :: string & text ); 272 273// process mtmd prompt, return the server_tokens containing both text tokens and media chunks 274// if is_placeholder is true, the media chunk will be treated as placeholder for counting tokens; the output tokens are not usable for actual inference (e.g. for submitting a task to server_queue) 275server_tokens process_mtmd_prompt ( 276mtmd_context * mctx , 277const std :: string & prompt , 278const std :: vector < raw_buffer > & files , 279const mtmd_helper_init_opt & init_opt , 280bool is_placeholder = false); 281 282/** 283* break the input "prompt" object into multiple prompt if needed, then tokenize them 284* this supports these cases: 285* - "prompt": "string" 286* - "prompt": [12, 34, 56] 287* - "prompt": [12, 34, "string", 56, 78] 288* - "prompt": { "prompt_string": "string", "multimodal_data": [ "base64" ] } 289* and multiple prompts (multi-tasks): 290* - "prompt": ["string1", "string2"] 291* - "prompt": ["string1", [12, 34, 56]] 292* - "prompt": [[12, 34, 56], [78, 90, 12]] 293* - "prompt": [[12, 34, "string", 56, 78], [12, 34, 56], { "prompt_string": "string", "multimodal_data": [ "base64" ]}] 294*/ 295std :: vector < server_tokens > tokenize_input_prompts ( 296const llama_vocab * vocab , 297mtmd_context * mctx , 298const json & json_prompt , 299bool add_special , 300bool parse_special , 301const mtmd_helper_init_opt & init_opt ); 302 303// 304// OAI utils 305// 306 307// global server parameters for chat formatting / parsing 308struct server_chat_params { 309bool use_jinja; 310bool prefill_assistant; 311common_reasoning_format reasoning_format; 312std ::map < std:: string , std:: string > chat_template_kwargs ; // mapping key --> json value 313common_chat_templates_ptr tmpls; 314bool allow_image; 315bool allow_audio; 316bool allow_video; 317bool enable_thinking = true; 318int reasoning_budget = -1 ; 319std ::string reasoning_budget_message; 320std ::string media_path; 321bool force_pure_content = false; 322} ; 323 324// used by /completions endpoint 325json oaicompat_completion_params_parse ( const json & body); 326 327// used by /chat/completions endpoint 328json oaicompat_chat_params_parse ( 329json & body, /* openai api json semantics */ 330const server_chat_params & opt, 331std ::vector < raw_buffer > & out_files); 332 333// TODO: move it to server-task.cpp 334json format_embeddings_response_oaicompat ( 335const json & request, 336const std ::string & model_name, 337const json & embeddings, 338bool use_base64 = false); 339 340// TODO: move it to server-task.cpp 341json format_response_rerank ( 342const json & request, 343const std ::string & model_name, 344const json & ranks, 345bool is_tei_format, 346std ::vector < std::string > & texts, 347int top_n); 348 349// 350// stats and metrics 351// 352 353// shared between server_slot and server_task_result_* 354struct server_slot_stats { 355uint64_t n_prompt_cached = 0 ; 356uint64_t n_prompt_processed = 0 ; 357uint64_t n_gen = 0 ; 358 359// speculative decoding stats 360// note: the per-position breakdown lives in server_slot, it is not needed in a task result 361uint64_t n_draft_tokens = 0 ; 362uint64_t n_draft_accepted = 0 ; 363uint64_t n_draft_verif_steps = 0 ; 364 365// these are absolute timestamps (in us) 366// note: must be signed - they are subtracted before the later ones are set 367int64_t t_start = 0 ; 368int64_t t_prompt_last = 0 ; 369int64_t t_gen_last = 0 ; 370 371// can only move one direction: start -> prompt -> gen 372void update_prompt_start () { 373GGML_ASSERT ( t_start == 0 ); 374t_start = ggml_time_us (); 375} 376void set_prompt_last ( int64_t t_us) { 377GGML_ASSERT ( t_start > 0 ); 378t_prompt_last = t_us; 379} 380void update_prompt_last () { 381set_prompt_last ( ggml_time_us ()); 382} 383void update_gen_last () { 384GGML_ASSERT (t_prompt_last > 0 ); 385t_gen_last = ggml_time_us (); 386} 387 388// these are time durations 389int64_t t_elapsed_us () const { 390return ggml_time_us () - t_start; 391} 392double t_prompt_ms () const { 393if (t_prompt_last == 0 ) { 394return 0.0 ; // the prompt is not processed yet 395} 396return (t_prompt_last - t_start) / 1000.0 ; 397} 398int64_t t_gen_us () const { 399if (t_gen_last == 0 ) { 400return 0 ; // the generation is not started yet 401} 402// clamp to 1 us, the first token can land in the same us as t_prompt_last 403return std::max < int64_t > ( 1 , t_gen_last - t_prompt_last); 404} 405double t_gen_ms () const { 406return t_gen_us () / 1000.0 ; 407} 408 409// number of decode steps spent on generation 410// the first token is free, it comes from the logits of the last prompt batch 411uint64_t n_gen_steps () const { 412return n_gen > 0 ? n_gen - 1 : 0 ; 413} 414 415// other derived metrics 416// note: all of them return 0.0 if the divisor is not known yet 417double t_prompt_per_token_ms () const { 418return n_prompt_processed > 0 ? t_prompt_ms () / n_prompt_processed : 0.0 ; 419} 420double t_gen_per_token_ms () const { 421return n_gen_steps () > 0 ? t_gen_ms () / n_gen_steps () : 0.0 ; 422} 423double n_prompt_tps () const { 424const double t_ms = t_prompt_ms (); 425return t_ms > 0.0 ? 1e3 / t_ms * n_prompt_processed : 0.0 ; 426} 427double n_gen_tps () const { 428const double t_ms = t_gen_ms (); 429return t_ms > 0.0 ? 1e3 / t_ms * n_gen_steps () : 0.0 ; 430} 431 432// false if the slot never started, i.e. the task result carries no stats 433bool is_set () const { 434return t_start > 0 ; 435} 436 437json to_json () const ; 438}; 439 440// shared between server_context_impl and server_task_result_* 441// unlike server_slot_stats, server_metrics is server-global and cumulative, not tied to a slot 442struct server_metrics { 443int64_t t_start = 0 ; 444 445struct bucket { 446uint64_t count = 0 ; // number of tokens 447uint64_t steps = 0 ; // number of decode steps, 448// this excludes first generated token (logits from prompt batch) 449uint64_t time = 0 ; // in microseconds 450 451// the rate uses the decode steps, so that "free" tokens do not inflate it 452double n_per_second () const { 453return time > 0 ? ( double ) steps / ( double ) time * 1e6 : 0.0 ; 454} 455 456void add ( uint64_t n, uint64_t n_steps, uint64_t t_us) { 457count += n ; 458steps += n_steps ; 459time += t_us ; 460} 461}; 462 463// these are reset by reset_bucket(), only the rate is read from them 464bucket prompt_bucket; 465bucket predict_bucket; 466 467// metrics below are cumulative since the server started 468bucket prompt; // only processed tokens, cached ones are counted separately below 469bucket predict; 470 471// tokens reused from the cache need no decode, so they only have a count 472uint64_t n_prompt_cached = 0 ; 473 474uint64_t n_tokens_max = 0 ; 475 476uint64_t n_decode = 0 ; 477uint64_t n_busy_slots = 0 ; 478 479uint64_t n_draft_tokens = 0 ; // Total draft tokens generated 480uint64_t n_draft_accepted = 0 ; // Draft tokens actually accepted 481uint64_t n_draft_verif_steps = 0 ; // Total draft token verification steps by the target model 482std ::vector < uint64_t > n_accepted_per_pos; // Accepted tokens per draft position 483 484void init () { 485t_start = ggml_time_us (); 486} 487 488void reset_bucket () { 489prompt_bucket = {}; 490predict_bucket = {}; 491} 492 493void add_prompt ( uint64_t n_tokens, uint64_t t_us) { 494prompt . add (n_tokens, n_tokens, t_us); 495prompt_bucket. add (n_tokens, n_tokens, t_us); 496} 497 498void add_prompt_cached ( uint64_t n_tokens) { 499n_prompt_cached += n_tokens; 500} 501}; 502 503// 504// other utils 505// 506 507std ::vector < llama_token_data > get_token_probabilities (llama_context * ctx, int idx, size_t n_top); 508 509std :: string safe_json_to_str ( const json & data); 510 511std :: string tokens_to_str ( llama_context * ctx, const llama_tokens & tokens); 512std :: string tokens_to_str ( const llama_vocab * vocab, const llama_tokens & tokens); 513 514// format incomplete utf-8 multibyte character for output 515std :: string tokens_to_output_formatted_string ( const llama_context * ctx, const llama_token token); 516 517// format server-sent event (SSE), return the formatted string to send 518// note: if data is a json array, it will be sent as multiple events, one per item 519std :: string format_oai_sse ( const json & data); 520 521std :: string format_oai_resp_sse ( const json & data); 522 523// format Anthropic-style SSE with event types 524std :: string format_anthropic_sse ( const json & data); 525 526bool is_valid_utf8 ( const std ::string & str); 527 528// 529// formatting output responses 530// TODO: move these to server-task.cpp 531// 532 533llama_tokens format_prompt_infill ( 534const llama_vocab * vocab, 535const json & input_prefix, 536const json & input_suffix, 537const json & input_extra, 538const int n_batch, 539const int n_predict, 540const int n_ctx, 541const bool spm_infill, 542const llama_tokens & tokens_prompt); 543 544// format rerank task: [BOS]query[EOS][SEP]doc[EOS]. 545server_tokens format_prompt_rerank ( 546const struct llama_model * model, 547const struct llama_vocab * vocab, 548mtmd_context * mctx, 549const std ::string & query, 550const std ::string & doc, 551const mtmd_helper_init_opt & init_opt); 552 553// simple implementation of a pipe 554// used for streaming data between threads 555template < typename T > 556struct server_pipe { 557std :: mutex mutex; 558std :: condition_variable cv; 559std ::queue < T > queue; 560std ::atomic < bool > writer_closed{false}; 561std ::atomic < bool > reader_closed{false}; 562 563// 0 = unbounded (default) 564// > 0, write() drops the oldest item once the queue is full 565size_t max_size = 0 ; 566 567void close_write () { 568writer_closed. store (true, std::memory_order_relaxed); 569cv. notify_all (); 570} 571 572void close_read () { 573reader_closed. store (true, std::memory_order_relaxed); 574cv. notify_all (); 575} 576 577// close_on_stop = true: should_stop means the reader is gone for good, so the writer is told the pipe is broken. 578// close_on_stop = false: should_stop is a per-read deadline and further reads still come, so the pipe stays usable. 579bool read ( T & output, const std ::function < bool () > & should_stop, bool close_on_stop = true) { 580std ::unique_lock < std::mutex > lk (mutex); 581constexpr auto poll_interval = std::chrono:: milliseconds ( 500 ); 582while (true) { 583if (!queue. empty ()) { 584output = std:: move (queue. front ()); 585queue. pop (); 586return true; 587} 588if (writer_closed. load ()) { 589return false; // clean EOF 590} 591if (should_stop && should_stop ()) { // a null should_stop means "never stop" 592if (close_on_stop) { 593close_read (); // signal broken pipe to writer 594} 595return false; // cancelled / deadline reached 596} 597cv. wait_for (lk, poll_interval); 598} 599} 600 601bool write ( T && data) { 602std ::lock_guard < std::mutex > lk (mutex); 603if (reader_closed. load ()) { 604return false; // broken pipe 605} 606if (max_size > 0 ) { 607while (queue. size () >= max_size) { 608queue. pop (); // drop oldest to stay bounded 609} 610} 611queue. push (std:: move (data)); 612cv. notify_one (); 613return true; 614} 615}; 616 617// wrapper around common_subproc to manage a child server process 618// mainly used by router mode 619struct server_subproc { 620common_subproc sproc ; 621std :: atomic < bool > stopped {false}; // set by the monitor once the process exited and was reaped 622 623bool is_alive () { return sproc. alive (); } 624void terminate () { sproc. terminate (); } 625int join () { return sproc. join (); } 626 627// true if the child's combined stdout/stderr pipe is available (call after create()) 628bool has_output (); 629 630// non-blocking read 631// returns the number of bytes read, 0 when nothing is available, -1 when the pipe is closed or broken 632int read_output ( char * buf, size_t len); 633 634// wait until one of a set of children has output, wake() is called, or a timeout passes 635struct waiter { 636waiter( ); 637~ waiter (); 638 639// thread-safe; on Windows this is a no-op, wait() returns within 50 ms anyway 640void wake (); 641 642// timeout_ms < 0 waits until data or wake(); ready[i] is set for each child with data (or a broken pipe) 643void wait ( const std:: vector < server_subproc *> & procs , std :: vector < bool > & ready , int64_t timeout_ms ); 644 645private: 646intptr_t wake_fd [ 2 ] = { -1 , - 1 }; // POSIX self-pipe 647}; 648 649private : 650intptr_t out_handle = -1 ; // fd on POSIX, HANDLE on Windows; taken lazily from sproc 651};