HSF / prmon

Standalone monitor for process resource consumption

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

spdlog vs boost.log for prmon logging

quantum-shift opened this issue · comments

It was decided to test spdlog and boost.log for integration with prmon. spdlog turned out to be a clear winner in all tests.

The speeds of spdlog and boost.log were compared. Three kinds of tests were conducted varying the number and types of sinks being logged into:
a) Only a console sink
b) Only a file sink
c) Both console and file sinks.

1e6 messages were logged to the sinks and the execution times were recorded. Each test was repeated 5 times.

Here are the results:

ONLY CONSOLE SINK ONLY FILE SINK BOTH CONSOLE AND FILE SINKS
Time (in s) Average Median Time (in s) Average Median Time (in s) Average Median
4.431 0.125 4.403
4.364 0.111 4.459
SPDLOG 4.35 4.3892 4.35 0.136 0.121 0.119 4.531 4.4984 4.522
4.459 0.114 4.522
4.342 0.119 4.577
7.429 2.812 9.921
7.271 2.878 10.235
BOOSTLOG 7.28 7.2894 7.28 2.949 2.8996 2.914 9.83 9.8566 9.83
7.298 2.914 9.579
7.169 2.945 9.718

Some other differences:
a) It was much harder to install and configure boost.log than spdlog.
b) The number of header files to include for spdlog was much less than that for boost.log to accomplish the same behaviour.
c) The amount of code required to initialise sinks and logger to produce similar output for

  • boost.log
BOOST_LOG_ATTRIBUTE_KEYWORD(scope_attr, "Scope", boost::log::attributes::named_scope::value_type)
BOOST_LOG_ATTRIBUTE_KEYWORD(severity_attr, "Severity", boost::log::trivial::severity_level)

void custom_formatter(logging::record_view const& rec, logging::formatting_ostream& strm)
{
    strm << logging::extract< boost::posix_time::ptime >("TimeStamp", rec);
    strm << " [" << rec[scope_attr] << "] ";
    strm << "[" << rec[severity_attr] << "] ";
    strm << rec[expr::smessage];
}

void init_fsink()
{
    //Initialise the file sink
    typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_sink;
    boost::shared_ptr< text_sink > sink = boost::make_shared< text_sink >();
    sink->locked_backend()->add_stream(boost::make_shared< std::ofstream >("sample.log"));
    sink->set_formatter(&custom_formatter);
    logging::core::get()->add_sink(sink);
}


void init_sink()
{
    //Initialise the console sink
    typedef sinks::synchronous_sink< sinks::text_ostream_backend > text_sink;
    boost::shared_ptr< text_sink > sink = boost::make_shared< text_sink >();
    boost::shared_ptr< std::ostream > stream(&std::clog, boost::null_deleter());
    sink->locked_backend()->add_stream(stream);
    sink->set_formatter(&custom_formatter);
    logging::core::get()->add_sink(sink);
}

BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::severity_logger<boost::log::trivial::severity_level>)


int main() {
    boost::log::core::get()->add_global_attribute("Scope", boost::log::attributes::named_scope());
    boost::log::add_common_attributes();
    BOOST_LOG_NAMED_SCOPE("benchmark");
    init_fsink();
    init_sink();
    src::severity_logger<boost::log::trivial::severity_level>& lg = my_logger::get();
    ...
}
  • spdlog
int main(){
    auto sink = std::make_shared<spdlog::sinks::stdout_color_sink_st>();
    auto fsink = std::make_shared<spdlog::sinks::basic_file_sink_mt> ("sample.log", true);
    spdlog::sinks_init_list sink_list = {sink, fsink};
    auto logger = std::make_shared<spdlog::logger>("benchmark", sink_list.begin(), sink_list.end());
    logger->set_level(spdlog::level::warn);
    ...
}

Taking all these into account, we decided to proceed with spdlog for the integration.

Thanks very much for this study @quantum-shift - it's a nice result to get such an unambiguous answer.

I have a few questions, mostly for completeness

  • What versions of spdlog and boost::log were tried?
  • Which compiler and build flags were used?
  • What was the hardware and OS that you tested on?
  • It looks like you did 5 tests and took stats from that, so a good idea just to state that explicitly
  • What versions of spdlog and boost::log were tried?

spdlog version - 1.8.5
boost.log version - 1.76.0

  • Which compiler and build flags were used?

There were no flags specific to spdlog.
For boost.log, the Boost_USE_STATIC_LIBS flag was set as we had decided to use static libraries.

  • What was the hardware and OS that you tested on?

CPU - Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz
RAM - 16 GB
OS - Ubuntu 20.04.2

I have updated the first comment to clarify that each test was performed 5 times.

Thanks @quantum-shift ! One thing I would say is that we should test with at least the -O2 flag set. Some libraries are coded in such a way that unoptimised they might run quite slowly, but with optimisations on they would run a lot faster. That should be quite easy to do.

After that I think we are done with this issue.

Yes, @graeme-a-stewart. Both spdlog and boost.log were built with O3 flag set (the default for prmon).

I would like to bring your attention to another logging library candidate that has some potential (and claims to be faster than many competitors): https://github.com/odygrd/quill

Hi @pikacic - cool, thanks for bringing that up. prmon doesn't log much so probably we will start with spdlog for now (as it's in fact ready to go). However, the implementation abstracts from the underlying library so we could swap in the future (or later in the GSoC project!).

Would you test again with latest version?

a) It was much harder to install and configure boost.log than spdlog.

Now with vcpkg, it's easy to install and configure boost.log.