1#include "arg.h"
  2#include "common.h"
  3#include "log.h"
  4#include "llama.h"
  5
  6#include <cmath>
  7#include <cstdio>
  8#include <cstring>
  9#include <string>
 10#include <thread>
 11#include <vector>
 12
 13static void print_usage(int /*argc*/, char ** argv) {
 14    printf("\nexample usage:\n");
 15    printf("\n    %s -m model.gguf [-ngl n_gpu_layers]\n", argv[0]);
 16    printf("\n");
 17}
 18
 19int main(int argc, char ** argv) {
 20    common_params params;
 21
 22    if (!common_params_parse(argc, argv, params, LLAMA_EXAMPLE_COMMON, print_usage)) {
 23        return 1;
 24    }
 25
 26    common_init();
 27
 28    // init LLM
 29
 30    llama_backend_init();
 31    llama_numa_init(params.numa);
 32
 33    // initialize the model
 34
 35    llama_model_params model_params = common_model_params_to_llama(params);
 36
 37    llama_model * model = llama_model_load_from_file(params.model.path.c_str(), model_params);
 38
 39    if (model == NULL) {
 40        LOG_ERR("%s: error: unable to load model\n" , __func__);
 41        return 1;
 42    }
 43
 44    const llama_vocab * vocab = llama_model_get_vocab(model);
 45
 46    // we need just a dummy token to evaluate
 47    std::vector<llama_token> prompt_tokens(1, llama_vocab_bos(vocab));
 48
 49    llama_context_params ctx_params = llama_context_default_params();
 50    ctx_params.n_ctx   = 512;
 51    ctx_params.n_batch = 512;
 52    ctx_params.no_perf = false;
 53
 54    llama_context * ctx = llama_init_from_model(model, ctx_params);
 55    if (ctx == NULL) {
 56        fprintf(stderr , "%s: error: failed to create the llama_context\n" , __func__);
 57        return 1;
 58    }
 59
 60    llama_batch batch = llama_batch_get_one(prompt_tokens.data(), prompt_tokens.size());
 61
 62    const int n_iters = 3;
 63
 64    // warm-up
 65    llama_decode(ctx, batch);
 66    llama_memory_clear(llama_get_memory(ctx), true);
 67    llama_synchronize(ctx);
 68
 69    for (int64_t t_pause_ms = 0; t_pause_ms <= 4000; t_pause_ms += 800) {
 70        double t_sum_us  = 0.0;
 71        double t_sum2_us = 0.0;
 72
 73        for (int i = 0; i < n_iters; i++) {
 74            // this pause is important - it simulates "idle GPU"
 75            std::this_thread::sleep_for(std::chrono::milliseconds(t_pause_ms));
 76
 77            const int64_t t_start_us = llama_time_us();
 78
 79            // this should take constant time
 80            llama_decode(ctx, batch);
 81            llama_synchronize(ctx);
 82
 83            const int64_t t_end_us = llama_time_us();
 84
 85            const double t_cur_us = t_end_us - t_start_us;
 86
 87#if 1
 88            // print individual decode times
 89            printf("  - decode time: %8.2f ms\n", t_cur_us / 1000);
 90#endif
 91
 92            t_sum_us  += t_cur_us;
 93            t_sum2_us += t_cur_us * t_cur_us;
 94
 95            llama_memory_clear(llama_get_memory(ctx), true);
 96            llama_synchronize(ctx); // just in case
 97        }
 98
 99        const double t_avg_us = t_sum_us / n_iters;
100        const double t_dev_us = sqrt((t_sum2_us / (n_iters - 1)) - (t_avg_us * t_avg_us * n_iters) / (n_iters - 1));
101
102        printf("iters: %4d, pause: %5d ms, avg decode time: %8.2f +/- %4.2f ms\n", n_iters, (int) t_pause_ms, t_avg_us / 1000, t_dev_us / 1000);
103        fflush(stdout);
104    }
105
106    llama_free(ctx);
107    llama_model_free(model);
108
109    return 0;
110}