char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
8e330954a
char/aliceai-t5-moe
1#include "common.h" 2#include "log.h" 3#include "json.h" 4 5#include <chrono> 6#include <condition_variable> 7#include <cstdarg> 8#include <cstdio> 9#include <cstdlib> 10#include <cstring> 11#include <mutex> 12#include <sstream> 13#include <thread> 14#include <vector> 15#include <algorithm> 16 17#if defined(_WIN32 ) 18# define WIN32_LEAN_AND_MEAN 19# ifndef NOMINMAX 20# define NOMINMAX 21# endif 22# include <io.h> 23# include <windows.h> 24# define isatty _isatty 25# define fileno _fileno 26#else 27# include <unistd.h> 28#endif // defined(_WIN32) 29 30int common_log_verbosity_thold = LOG_DEFAULT_LLAMA ; 31 32int common_log_get_verbosity_thold (void ) { 33return common_log_verbosity_thold ; 34} 35 36void common_log_set_verbosity_thold (int verbosity ) { 37common_log_verbosity_thold = verbosity ; 38} 39 40static bool common_log_jsonl = false; 41 42bool common_log_get_jsonl (void ) { 43return common_log_jsonl ; 44} 45 46void common_log_set_jsonl (bool jsonl ) { 47common_log_jsonl = jsonl ; 48} 49 50static int64_t t_us () { 51return std::chrono::duration_cast < std::chrono::microseconds > (std::chrono::system_clock::now ().time_since_epoch ()).count (); 52} 53 54// colors 55enum common_log_col :int { 56COMMON_LOG_COL_DEFAULT = 0 , 57COMMON_LOG_COL_BOLD , 58COMMON_LOG_COL_RED , 59COMMON_LOG_COL_GREEN , 60COMMON_LOG_COL_YELLOW , 61COMMON_LOG_COL_BLUE , 62COMMON_LOG_COL_MAGENTA , 63COMMON_LOG_COL_CYAN , 64COMMON_LOG_COL_WHITE , 65}; 66 67// disable colors by default 68static const char * g_col []= { 69"" , 70"" , 71"" , 72"" , 73"" , 74"" , 75"" , 76"" , 77"" , 78}; 79 80static const char * level_str (enum ggml_log_level level ) { 81switch (level ) { 82case GGML_LOG_LEVEL_DEBUG :return "debug" ; 83case GGML_LOG_LEVEL_INFO :return "info" ; 84case GGML_LOG_LEVEL_WARN :return "warn" ; 85case GGML_LOG_LEVEL_ERROR :return "error" ; 86case GGML_LOG_LEVEL_CONT :return "cont" ; 87default :return "none" ; 88 } 89} 90 91struct common_log_entry { 92enum ggml_log_level level {GGML_LOG_LEVEL_INFO }; 93 94 std::vector < char > msg ; 95 96int64_t timestamp {0 }; 97bool is_end { false };// signals the worker thread to stop 98bool prefix { false }; 99bool jsonl { false }; 100bool is_json { false };// msg already holds a serialized JSON object 101 102common_log_entry (size_t size = 256 ) :msg (size ) { } 103 104void FILE * file = nullptr )const { 105FILE * fcur = file ; 106if (!fcur ) { 107// stderr displays DBG messages only when their verbosity level is not higher than the threshold 108// these messages will still be logged to a file 109if (level == GGML_LOG_LEVEL_DEBUG && common_log_verbosity_thold < LOG_DEFAULT_DEBUG ) { 110return ; 111 } 112 113fcur = stdout ; 114 115if (level != GGML_LOG_LEVEL_NONE && !jsonl ) { 116fcur = stderr ; 117 } 118 } 119 120if (jsonl ) { 121if (is_json ) { 122fprintf (fcur ,"%s\n" ,msg .data ()); 123fflush (fcur ); 124return ; 125 } 126 127common_json obj = { 128 {"type" ,"log" }, 129 {"time" ,timestamp }, 130 {"level" ,level_str (level )}, 131 {"msg" ,msg .data ()}, 132 }; 133fprintf (fcur ,"%s\n" ,obj .dump_safe ().c_str ()); 134fflush (fcur ); 135return ; 136 } 137 138if (level != GGML_LOG_LEVEL_NONE && level != GGML_LOG_LEVEL_CONT && prefix ) { 139if (timestamp ) { 140// [M.s.ms.us] 141fprintf (fcur ,"%s%d.%02d.%03d.%03d%s " , 142g_col [COMMON_LOG_COL_BLUE ], 143 (int ) (timestamp /1000000 /60 ), 144 (int ) (timestamp /1000000 %60 ), 145 (int ) (timestamp /1000 %1000 ), 146 (int ) (timestamp %1000 ), 147g_col [COMMON_LOG_COL_DEFAULT ]); 148 } 149 150switch (level ) { 151case GGML_LOG_LEVEL_INFO :fprintf (fcur ,"%sI %s" ,g_col [COMMON_LOG_COL_GREEN ],g_col [COMMON_LOG_COL_DEFAULT ]);break ; 152case GGML_LOG_LEVEL_WARN :fprintf (fcur ,"%sW %s" ,g_col [COMMON_LOG_COL_MAGENTA ],"" );break ; 153case GGML_LOG_LEVEL_ERROR :fprintf (fcur ,"%sE %s" ,g_col [COMMON_LOG_COL_RED ],"" );break ; 154case GGML_LOG_LEVEL_DEBUG :fprintf (fcur ,"%sD %s" ,g_col [COMMON_LOG_COL_YELLOW ],"" );break ; 155default : 156break ; 157 } 158 } 159 160fprintf (fcur ,"%s" ,msg .data ()); 161 162if (level == GGML_LOG_LEVEL_WARN || level == GGML_LOG_LEVEL_ERROR || level == GGML_LOG_LEVEL_DEBUG ) { 163fprintf (fcur ,"%s" ,g_col [COMMON_LOG_COL_DEFAULT ]); 164 } 165 166fflush (fcur ); 167 } 168}; 169 170struct common_log { 171// default capacity 172common_log (size_t capacity = 512 ) { 173file = nullptr ; 174prefix = false; 175timestamps = false; 176running = false; 177t_start = t_us (); 178 179queue .resize (capacity ,common_log_entry (256 )); 180head = 0 ; 181tail = 0 ; 182 183resume (); 184 } 185 186 ~common_log () { 187pause (); 188if (file ) { 189fclose (file ); 190 } 191 } 192 193private : 194 std::mutex mtx ; 195 std::thread thrd ; 196 std::condition_variable cv_new ;// new entry 197 std::condition_variable cv_full ;// wait on full 198 199FILE * file ; 200 201bool prefix ; 202bool timestamps ; 203bool running ; 204 205int64_t t_start ; 206 207// queue of entries 208 std::vector < common_log_entry > queue ; 209size_t head ; 210size_t tail ; 211 212bool print_entry (const common_log_entry & e )const { 213if (e .is_end )return true; 214 215e .if (file ) { 217e .file ); 218 } 219return false; 220 } 221 222bool flush_queue (size_t start_head ,size_t end_tail ,size_t & out_head )const { 223bool stop = false; 224size_t h = start_head ; 225while (h != end_tail && !stop ) { 226stop = print_entry (queue [h ]); 227h = (h + 1 ) %queue .size (); 228 } 229out_head = h ; 230return stop ; 231 } 232 233public : 234bool is_full ()const { 235return ((tail + 1 ) %queue .size ())== head ; 236 } 237 238bool is_empty ()const { 239return head == tail ; 240 } 241 242void add (enum ggml_log_level level ,const char * fmt ,va_list args ) { 243 std::unique_lock < std::mutex > lock (mtx ); 244 245// block if the queue is full 246cv_full .wait (lock , [this ]() {return !running || !is_full (); }); 247 248if (!running ) { 249// discard messages while the worker thread is paused 250return ; 251 } 252 253auto & entry = queue [tail ]; 254 255 { 256// cannot use args twice, so make a copy in case we need to expand the buffer 257va_list args_copy ; 258va_copy (args_copy ,args ); 259 260#if 1 261const size_t n = vsnprintf (entry .msg .data (),entry .msg .size (),fmt ,args ); 262if (n >=entry .msg .size ()) { 263entry .msg .resize (n + 1 ); 264vsnprintf (entry .msg .data (),entry .msg .size (),fmt ,args_copy ); 265 } 266#else 267// hack for bolding arguments 268 269 std::stringstream ss ; 270for (int i = 0 ;fmt [i ]!= 0 ;i ++ ) { 271if (fmt [i ]== '%' ) { 272ss <<LOG_COL_BOLD ; 273while (fmt [i ]!= ' ' && fmt [i ]!= ')' && fmt [i ]!= ']' && fmt [i ]!= 0 )ss <<fmt [i ++ ]; 274ss <<LOG_COL_DEFAULT ; 275if (fmt [i ]== 0 )break ; 276 } 277ss <<fmt [i ]; 278 } 279const size_t n = vsnprintf (entry .msg .data (),entry .msg .size (),ss .str ().c_str (),args ); 280if (n >=entry .msg .size ()) { 281entry .msg .resize (n + 1 ); 282vsnprintf (entry .msg .data (),entry .msg .size (),ss .str ().c_str (),args_copy ); 283 } 284#endif 285va_end (args_copy ); 286 } 287 288entry .is_end = false; 289entry .level = level ; 290entry .prefix = prefix ; 291entry .jsonl = common_log_jsonl ; 292entry .is_json = false; 293entry .timestamp = 0 ; 294if (timestamps ) { 295entry .timestamp = t_us ()- t_start ; 296 } 297 298tail = (tail + 1 ) %queue .size (); 299cv_new .notify_one (); 300 } 301 302void add_json (const char * type ,const common_json & obj ) { 303const common_json full = { 304 {"type" ,type }, 305 {"data" ,obj }, 306 }; 307 308const std::string text = full .dump_safe (); 309 310 std::unique_lock < std::mutex > lock (mtx ); 311 312// block if the queue is full 313cv_full .wait (lock , [this ]() {return !running || !is_full (); }); 314 315if (!running ) { 316// discard messages while the worker thread is paused 317return ; 318 } 319 320auto & entry = queue [tail ]; 321 322if (entry .msg .size ()< text .size ()+ 1 ) { 323entry .msg .resize (text .size ()+ 1 ); 324 } 325memcpy (entry .msg .data (),text .c_str (),text .size ()+ 1 ); 326 327entry .is_end = false; 328entry .level = GGML_LOG_LEVEL_NONE ; 329entry .prefix = false; 330entry .jsonl = true; 331entry .is_json = true; 332entry .timestamp = 0 ; 333 334tail = (tail + 1 ) %queue .size (); 335cv_new .notify_one (); 336 } 337 338void resume () { 339 std::lock_guard < std::mutex > lock (mtx ); 340 341if (running ) { 342return ; 343 } 344 345running = true; 346 347thrd = std::thread ([this ]() { 348while (true) { 349 std::unique_lock < std::mutex > lock (mtx ); 350cv_new .wait (lock , [this ]() {return !is_empty (); }); 351 352size_t cached_head = head ; 353size_t cached_tail = tail ; 354 355lock .unlock ();// drop the lock during flush 356 357size_t next_head ; 358bool stop = flush_queue (cached_head ,cached_tail ,next_head ); 359 360lock .lock (); 361head = next_head ; 362cv_full .notify_all (); 363 364if (stop ) { 365break ; 366 } 367 } 368 }); 369 } 370 371void pause () { 372 { 373 std::lock_guard < std::mutex > lock (mtx ); 374 375if (!running ) { 376return ; 377 } 378 379running = false; 380 381// push an entry to signal the worker thread to stop 382auto & entry = queue [tail ]; 383entry .is_end = true; 384tail = (tail + 1 ) %queue .size (); 385 386// wakeup everyone 387cv_new .notify_one (); 388cv_full .notify_all (); 389 } 390 391thrd .join (); 392 } 393 394void set_file (const char * path ) { 395pause (); 396 397if (file ) { 398fclose (file ); 399 } 400 401if (path ) { 402file = fopen (path ,"w" ); 403 }else { 404file = nullptr ; 405 } 406 407resume (); 408 } 409 410void set_colors (bool colors ) { 411pause (); 412 413if (colors ) { 414g_col [COMMON_LOG_COL_DEFAULT ]= LOG_COL_DEFAULT ; 415g_col [COMMON_LOG_COL_BOLD ]= LOG_COL_BOLD ; 416g_col [COMMON_LOG_COL_RED ]= LOG_COL_RED ; 417g_col [COMMON_LOG_COL_GREEN ]= LOG_COL_GREEN ; 418g_col [COMMON_LOG_COL_YELLOW ]= LOG_COL_YELLOW ; 419g_col [COMMON_LOG_COL_BLUE ]= LOG_COL_BLUE ; 420g_col [COMMON_LOG_COL_MAGENTA ]= LOG_COL_MAGENTA ; 421g_col [COMMON_LOG_COL_CYAN ]= LOG_COL_CYAN ; 422g_col [COMMON_LOG_COL_WHITE ]= LOG_COL_WHITE ; 423 }else { 424for (size_t i = 0 ;i < std::size (g_col );i ++ ) { 425g_col [i ]= "" ; 426 } 427 } 428 429resume (); 430 } 431 432void set_prefix (bool prefix ) { 433 std::lock_guard < std::mutex > lock (mtx ); 434 435this -> prefix = prefix ; 436 } 437 438void set_timestamps (bool timestamps ) { 439 std::lock_guard < std::mutex > lock (mtx ); 440 441this -> timestamps = timestamps ; 442 } 443}; 444 445// 446// public API 447// 448 449struct common_log * common_log_init () { 450return new common_log ; 451} 452 453struct common_log * common_log_main () { 454// We intentionally leak (i.e. do not delete) the logger singleton because 455// common_log destructor called at DLL teardown phase will cause hanging on Windows. 456// OS will release resources anyway so it should not be a significant issue, 457// though this design may cause logs to be lost if not flushed before the program exits. 458// Refer to https://github.com/ggml-org/llama.cpp/issues/22142 for details. 459static struct common_log * log ; 460static std::once_flag init_flag ; 461 std::call_once (init_flag , [& ]() { 462log = new common_log ; 463// Set default to auto-detect colors 464log -> set_colors (tty_can_use_colors ()); 465 }); 466 467return log ; 468} 469 470void common_log_pause (struct common_log * log ) { 471log -> pause (); 472} 473 474void common_log_resume (struct common_log * log ) { 475log -> resume (); 476} 477 478void common_log_free (struct common_log * log ) { 479delete log ; 480} 481 482void common_log_add (struct common_log * log ,enum ggml_log_level level ,const char * fmt , ...) { 483va_list args ; 484va_start (args ,fmt ); 485log -> add (level ,fmt ,args ); 486va_end (args ); 487} 488 489void common_log_add_json (struct common_log * log ,const char * type ,const common_json & obj ) { 490if (!common_log_jsonl ) { 491return ; 492 } 493 494log -> add_json (type ,obj ); 495} 496 497void common_log_set_file (struct common_log * log ,const char * file ) { 498log -> set_file (file ); 499} 500 501void common_log_set_colors (struct common_log * log ,log_colors colors ) { 502if (colors == LOG_COLORS_AUTO ) { 503log -> set_colors (tty_can_use_colors ()); 504return ; 505 } 506 507if (colors == LOG_COLORS_DISABLED ) { 508log -> set_colors (false); 509return ; 510 } 511 512GGML_ASSERT (colors == LOG_COLORS_ENABLED ); 513log -> set_colors (true); 514} 515 516void common_log_set_prefix (struct common_log * log ,bool prefix ) { 517log -> set_prefix (prefix ); 518} 519 520void common_log_set_timestamps (struct common_log * log ,bool timestamps ) { 521log -> set_timestamps (timestamps ); 522} 523 524void common_log_flush (struct common_log * log ) { 525log -> pause (); 526log -> resume (); 527} 528 529int common_log_get_verbosity (enum ggml_log_level level ) { 530switch (level ) { 531case GGML_LOG_LEVEL_DEBUG :return LOG_LEVEL_DEBUG ; 532case GGML_LOG_LEVEL_INFO :return LOG_LEVEL_TRACE ; 533case GGML_LOG_LEVEL_WARN :return LOG_LEVEL_WARN ; 534case GGML_LOG_LEVEL_ERROR :return LOG_LEVEL_ERROR ; 535case GGML_LOG_LEVEL_CONT :return LOG_LEVEL_TRACE ; 536case GGML_LOG_LEVEL_NONE : 537default : 538return LOG_LEVEL_OUTPUT ; 539 } 540} 541 542void common_log_default_callback (enum ggml_log_level level ,const char * text ,void * /*user_data*/ ) { 543auto verbosity = common_log_get_verbosity (level ); 544if (verbosity <=common_log_verbosity_thold ) { 545common_log_add (common_log_main (),level ,"%s" ,text ); 546 } 547}