CoolFace
Modelpublic

Felipe97/llama-cpp-compiled

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