async_bench.cpp 5.47 KB
Newer Older
gabime's avatar
gabime committed
1 2 3 4 5 6 7 8
//
// Copyright(c) 2015 Gabi Melman.
// Distributed under the MIT License (http://opensource.org/licenses/MIT)
//

//
// bench.cpp : spdlog benchmarks
//
gabime's avatar
gabime committed
9
#include "spdlog/spdlog.h"
gabime's avatar
gabime committed
10 11 12
#include "spdlog/async.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
gabime's avatar
gabime committed
13

gabime's avatar
gabime committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
#include "utils.h"
#include <atomic>
#include <iostream>
#include <memory>
#include <string>
#include <thread>

using namespace std;
using namespace std::chrono;
using namespace spdlog;
using namespace spdlog::sinks;
using namespace utils;

void bench_mt(int howmany, std::shared_ptr<spdlog::logger> log, int thread_count);

gabime's avatar
gabime committed
29
#ifdef _MSC_VER
gabime's avatar
gabime committed
30 31 32
#pragma warning(push)
#pragma warning(disable : 4996) // disable fopen warning under msvc
#endif                          // _MSC_VER
gabime's avatar
gabime committed
33

gabime's avatar
gabime committed
34 35 36 37 38 39 40 41 42 43
int count_lines(const char *filename)
{
    int counter = 0;
    auto *infile = fopen(filename, "r");
    int ch;
    while (EOF != (ch = getc(infile)))
    {
        if ('\n' == ch)
            counter++;
    }
gabime's avatar
gabime committed
44
    fclose(infile);
gabime's avatar
gabime committed
45 46 47

    return counter;
}
48 49 50

void verify_file(const char *filename, int expected_count)
{
gabime's avatar
gabime committed
51
    spdlog::info("Verifying {} to contain {:n} line..", filename, expected_count);
52 53 54 55 56 57 58 59 60
    auto count = count_lines(filename);
    if (count != expected_count)
    {
        spdlog::error("Test failed. {} has {:n} lines instead of {:n}", filename, count, expected_count);
        exit(1);
    }
    spdlog::info("Line count OK ({:n})\n", count);
}

gabime's avatar
gabime committed
61
#ifdef _MSC_VER
gabime's avatar
gabime committed
62
#pragma warning(pop)
gabime's avatar
gabime committed
63 64
#endif

gabime's avatar
gabime committed
65 66 67 68
int main(int argc, char *argv[])
{

    int howmany = 1000000;
69
    int queue_size = std::min(howmany + 2, 8192);
gabime's avatar
gabime committed
70 71 72 73 74
    int threads = 10;
    int iters = 3;

    try
    {
75
        spdlog::set_pattern("[%^%l%$] %v");
gabime's avatar
gabime committed
76 77
        if (argc == 1)
        {
78
            spdlog::info("Usage: {} <message_count> <threads> <q_size> <iterations>", argv[0]);
gabime's avatar
gabime committed
79 80 81 82 83 84 85 86
            return 0;
        }

        if (argc > 1)
            howmany = atoi(argv[1]);
        if (argc > 2)
            threads = atoi(argv[2]);
        if (argc > 3)
87
        {
gabime's avatar
gabime committed
88
            queue_size = atoi(argv[3]);
gabime's avatar
gabime committed
89
            if (queue_size > 500000)
90 91 92 93 94
            {
                spdlog::error("Max queue size allowed: 500,000");
                exit(1);
            }
        }
gabime's avatar
gabime committed
95 96 97 98

        if (argc > 4)
            iters = atoi(argv[4]);

99
        auto slot_size = sizeof(spdlog::details::async_msg);
100
        spdlog::info("-------------------------------------------------");
101 102 103
        spdlog::info("Messages     : {:n}", howmany);
        spdlog::info("Threads      : {:n}", threads);
        spdlog::info("Queue        : {:n} slots", queue_size);
gabime's avatar
gabime committed
104
        spdlog::info("Queue memory : {:n} x {} = {:n} KB ", queue_size, slot_size, (queue_size * slot_size) / 1024);
105
        spdlog::info("Total iters  : {:n}", iters);
106
        spdlog::info("-------------------------------------------------");
gabime's avatar
gabime committed
107 108

        const char *filename = "logs/basic_async.log";
109 110 111 112
        spdlog::info("");
        spdlog::info("*********************************");
        spdlog::info("Queue Overflow Policy: block");
        spdlog::info("*********************************");
gabime's avatar
gabime committed
113 114 115 116 117 118
        for (int i = 0; i < iters; i++)
        {
            auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
            auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
            auto logger = std::make_shared<async_logger>("async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::block);
            bench_mt(howmany, std::move(logger), threads);
gabime's avatar
gabime committed
119
            // verify_file(filename, howmany);
120
        }
gabime's avatar
gabime committed
121

122 123 124 125 126
        spdlog::info("");
        spdlog::info("*********************************");
        spdlog::info("Queue Overflow Policy: overrun");
        spdlog::info("*********************************");
        // do same test but discard oldest if queue is full instead of blocking
gabime's avatar
gabime committed
127
        filename = "logs/basic_async-overrun.log";
128 129 130 131
        for (int i = 0; i < iters; i++)
        {
            auto tp = std::make_shared<details::thread_pool>(queue_size, 1);
            auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
gabime's avatar
gabime committed
132 133
            auto logger =
                std::make_shared<async_logger>("async_logger", std::move(file_sink), std::move(tp), async_overflow_policy::overrun_oldest);
134
            bench_mt(howmany, std::move(logger), threads);
gabime's avatar
gabime committed
135
        }
gabime's avatar
gabime committed
136
        spdlog::shutdown();
gabime's avatar
gabime committed
137 138 139 140 141 142 143 144 145 146
    }
    catch (std::exception &ex)
    {
        std::cerr << "Error: " << ex.what() << std::endl;
        perror("Last error");
        return 1;
    }
    return 0;
}

gabime's avatar
gabime committed
147 148 149 150 151 152 153 154 155
void thread_fun(std::shared_ptr<spdlog::logger> logger, int howmany)
{
    for (int i = 0; i < howmany; i++)
    {
        logger->info("Hello logger: msg number {}", i);
    }
}

void bench_mt(int howmany, std::shared_ptr<spdlog::logger> logger, int thread_count)
gabime's avatar
gabime committed
156 157 158 159
{
    using std::chrono::high_resolution_clock;
    vector<thread> threads;
    auto start = high_resolution_clock::now();
gabime's avatar
gabime committed
160 161 162

    int msgs_per_thread = howmany / thread_count;
    int msgs_per_thread_mod = howmany % thread_count;
gabime's avatar
gabime committed
163 164
    for (int t = 0; t < thread_count; ++t)
    {
gabime's avatar
gabime committed
165 166 167 168
        if (t == 0 && msgs_per_thread_mod)
            threads.push_back(std::thread(thread_fun, logger, msgs_per_thread + msgs_per_thread_mod));
        else
            threads.push_back(std::thread(thread_fun, logger, msgs_per_thread));
gabime's avatar
gabime committed
169 170 171 172 173 174 175 176 177
    }

    for (auto &t : threads)
    {
        t.join();
    };

    auto delta = high_resolution_clock::now() - start;
    auto delta_d = duration_cast<duration<double>>(delta).count();
178
    spdlog::info("Elapsed: {} secs\t {:n}/sec", delta_d, int(howmany / delta_d));
gabime's avatar
gabime committed
179
}