144 lines
4.5 KiB
C++
144 lines
4.5 KiB
C++
|
//// to compile: c++ bench.cpp -o bench -Wall -Wshadow -Wextra -pedantic -std=c++11 -pthread -I../include -O3 -fPIC -Ofast -m64 -march=native
|
||
|
|
||
|
// Alternative: c++ bench.cpp -o bench -Wall -Wshadow -Wextra -pedantic -std=c++11 -pthread -I../include -O3 -march=native
|
||
|
|
||
|
|
||
|
// the test code itself is Public domain @ref: Unlicense.org
|
||
|
// made by KjellKod, 2015, first published for testing of g3log at github.com/kjellkod/g3log
|
||
|
// Feel free to share, modify etc with no obligations but also with no guarantees from my part either
|
||
|
// enjoy - Kjell Hedstrom (aka KjellKod)
|
||
|
//
|
||
|
//
|
||
|
// spdlog follows however another license. See the bottow of this file
|
||
|
//
|
||
|
|
||
|
#include <thread>
|
||
|
#include <vector>
|
||
|
#include <atomic>
|
||
|
#include <iostream>
|
||
|
#include <chrono>
|
||
|
#include <algorithm>
|
||
|
#include <iomanip>
|
||
|
#include <iostream>
|
||
|
#include <sstream>
|
||
|
#include <fstream>
|
||
|
#include <cstdio>
|
||
|
#include <map>
|
||
|
#include <numeric>
|
||
|
#include <functional>
|
||
|
#include <thread>
|
||
|
#include "utils.h"
|
||
|
#include <g3log/g3log.hpp>
|
||
|
#include <g3log/logworker.hpp>
|
||
|
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
const uint64_t g_iterations = 1000000;
|
||
|
|
||
|
|
||
|
std::atomic<size_t> g_counter = {0};
|
||
|
|
||
|
|
||
|
void MeasurePeakDuringLogWrites(const size_t id, std::vector<uint64_t>& result)
|
||
|
{
|
||
|
|
||
|
while (true)
|
||
|
{
|
||
|
const size_t value_now = ++g_counter;
|
||
|
if (value_now > g_iterations)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto start_time = std::chrono::high_resolution_clock::now();
|
||
|
LOGF(INFO, "Some text to log for thread: %ld", id);
|
||
|
auto stop_time = std::chrono::high_resolution_clock::now();
|
||
|
uint64_t time_us = std::chrono::duration_cast<std::chrono::microseconds>(stop_time - start_time).count();
|
||
|
result.push_back(time_us);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void PrintResults(const std::map<size_t, std::vector<uint64_t>>& threads_result, size_t total_us)
|
||
|
{
|
||
|
|
||
|
std::vector<uint64_t> all_measurements;
|
||
|
all_measurements.reserve(g_iterations);
|
||
|
for (auto& t_result : threads_result)
|
||
|
{
|
||
|
all_measurements.insert(all_measurements.end(), t_result.second.begin(), t_result.second.end());
|
||
|
}
|
||
|
|
||
|
// calc worst latenct
|
||
|
auto worst = *std::max_element(all_measurements.begin(), all_measurements.end());
|
||
|
|
||
|
// calc avg
|
||
|
auto total = accumulate(begin(all_measurements), end(all_measurements), 0, std::plus<uint64_t>());
|
||
|
auto avg = double(total)/all_measurements.size();
|
||
|
|
||
|
std::cout << "[g3log] worst: " << std::setw(10) << std::right << worst << "\tAvg: " << avg << "\tTotal: " << utils::format(total_us) << " us" << std::endl;
|
||
|
|
||
|
}
|
||
|
}// anonymous
|
||
|
|
||
|
|
||
|
// The purpose of this test is NOT to see how fast
|
||
|
// each thread can possibly write. It is to see what
|
||
|
// the worst latency is for writing a log entry
|
||
|
//
|
||
|
// In the test 1 million log entries will be written
|
||
|
// an atomic counter is used to give each thread what
|
||
|
// it is to write next. The overhead of atomic
|
||
|
// synchronization between the threads are not counted in the worst case latency
|
||
|
int main(int argc, char** argv)
|
||
|
{
|
||
|
size_t number_of_threads {0};
|
||
|
if (argc == 2)
|
||
|
{
|
||
|
number_of_threads = atoi(argv[1]);
|
||
|
}
|
||
|
if (argc != 2 || number_of_threads == 0)
|
||
|
{
|
||
|
std::cerr << "USAGE is: " << argv[0] << " number_threads" << std::endl;
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
|
||
|
std::vector<std::thread> threads(number_of_threads);
|
||
|
std::map<size_t, std::vector<uint64_t>> threads_result;
|
||
|
|
||
|
for (size_t idx = 0; idx < number_of_threads; ++idx)
|
||
|
{
|
||
|
// reserve to 1 million for all the result
|
||
|
// it's a test so let's not care about the wasted space
|
||
|
threads_result[idx].reserve(g_iterations);
|
||
|
}
|
||
|
|
||
|
const std::string g_path = "./" ;
|
||
|
const std::string g_prefix_log_name = "g3log-performance-";
|
||
|
const std::string g_measurement_dump = g_path + g_prefix_log_name + "_RESULT.txt";
|
||
|
|
||
|
auto worker = g3::LogWorker::createLogWorker();
|
||
|
auto handle= worker->addDefaultLogger(argv[0], "g3log.txt");
|
||
|
g3::initializeLogging(worker.get());
|
||
|
|
||
|
auto start_time_application_total = std::chrono::high_resolution_clock::now();
|
||
|
for (uint64_t idx = 0; idx < number_of_threads; ++idx)
|
||
|
{
|
||
|
threads[idx] = std::thread(MeasurePeakDuringLogWrites, idx, std::ref(threads_result[idx]));
|
||
|
}
|
||
|
for (size_t idx = 0; idx < number_of_threads; ++idx)
|
||
|
{
|
||
|
threads[idx].join();
|
||
|
}
|
||
|
auto stop_time_application_total = std::chrono::high_resolution_clock::now();
|
||
|
|
||
|
uint64_t total_time_in_us = std::chrono::duration_cast<std::chrono::microseconds>(stop_time_application_total - start_time_application_total).count();
|
||
|
PrintResults(threads_result, total_time_in_us);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|