github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/benchmark/benchmark_instances.cpp (about)

     1  // Copyright (C) 2018 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or
     6  // modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // (at your option) any later version.
    10  //
    11  // the go-nebulas library is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with the go-nebulas library.  If not, see
    18  // <http://www.gnu.org/licenses/>.
    19  //
    20  #include "benchmark/benchmark_instances.h"
    21  #include <boost/asio/ip/host_name.hpp>
    22  #include <boost/date_time/posix_time/posix_time.hpp>
    23  #include <boost/program_options.hpp>
    24  #include <boost/property_tree/json_parser.hpp>
    25  #include <boost/property_tree/ptree.hpp>
    26  #include <chrono>
    27  #include <iostream>
    28  
    29  #include <sys/sysinfo.h>
    30  #include <sys/types.h>
    31  
    32  namespace po = boost::program_options;
    33  
    34  namespace neb {
    35  benchmark_instances::~benchmark_instances() {}
    36  
    37  void benchmark_instances::init_benchmark_instances(int argc, char *argv[]) {
    38    po::options_description desc("Do benchmark");
    39    desc.add_options()("help", "show help message")(
    40        "list", "show all benchmarks")("output", po::value<std::string>(),
    41                                       "output file of benchmark result")(
    42        "eval-count", po::value<int>(), "benchmark eval count [default: 10]")(
    43        "fixture", po::value<std::string>(), "enabled benchmark fixure, can be a "
    44                                             "fixture name shown in \"list\" "
    45                                             "option [default: all]");
    46  
    47    po::variables_map vm;
    48    po::store(po::parse_command_line(argc, argv, desc), vm);
    49    po::notify(vm);
    50    if (vm.count("help")) {
    51      std::cout << desc << std::endl;
    52      exit(1);
    53    }
    54    if (vm.count("list")) {
    55      show_all_benchmarks();
    56      exit(1);
    57    }
    58  
    59    std::string fixture_name = "all";
    60    if (vm.count("fixture")) {
    61      fixture_name = vm["fixture"].as<std::string>();
    62    }
    63    parse_all_enabled_fixtures(fixture_name);
    64  
    65    if (!vm.count("output")) {
    66      std::cout << "You must specify \"output\"!" << std::endl;
    67      exit(1);
    68    }
    69    m_output_fp = vm["output"].as<std::string>();
    70  
    71    m_eval_count = 10;
    72    if (vm.count("eval-count")) {
    73      m_eval_count = vm["eval-count"].as<int>();
    74    }
    75  }
    76  
    77  void benchmark_instances::parse_all_enabled_fixtures(
    78      const std::string &fixture_name) {
    79    std::for_each(m_all_instances.begin(), m_all_instances.end(),
    80                  [&](const benchmark_instance_base_ptr &p) {
    81                    if (p->get_fixture_name() == fixture_name ||
    82                        fixture_name == std::string("all")) {
    83                      m_enabled_fixtures.insert(p->get_fixture_name());
    84                    }
    85                  });
    86  }
    87  
    88  void benchmark_instances::show_all_benchmarks() {
    89    std::map<std::string, std::vector<std::string>> all;
    90    for (auto it = m_all_instances.begin(); it != m_all_instances.end(); ++it) {
    91      std::string fixture = (*it)->get_fixture_name();
    92      std::string name = (*it)->get_instance_name();
    93  
    94      if (all.find(fixture) == all.end()) {
    95        all.insert(std::make_pair(fixture, std::vector<std::string>()));
    96      }
    97      all[fixture].push_back(name);
    98    }
    99  
   100    for (decltype(all)::iterator it = all.begin(); it != all.end(); ++it) {
   101      std::cout << "|" << it->first << std::endl;
   102      for (size_t i = 0; i < it->second.size(); ++i) {
   103        std::cout << "|----" << it->second[i] << std::endl;
   104      }
   105    }
   106  }
   107  
   108  int benchmark_instances::run_all_benchmarks() {
   109    boost::property_tree::ptree property_tree;
   110  
   111    std::chrono::time_point<std::chrono::system_clock> start, end;
   112    auto prefix_str = [](const std::string &fixture, const std::string &name) {
   113      return fixture + std::string(".") + name;
   114    };
   115  
   116    property_tree.put("unit", "microseconds");
   117    property_tree.put("time-zone", "UTC");
   118    property_tree.put("time",
   119                      boost::posix_time::to_iso_string(
   120                          boost::posix_time::second_clock::universal_time()));
   121    property_tree.put("host", boost::asio::ip::host_name());
   122  
   123    struct sysinfo mem_start, mem_end;
   124    auto f_mem = [](boost::property_tree::ptree &pt,
   125                    const struct sysinfo &mem_start,
   126                    const struct sysinfo &mem_end) {
   127      auto mem_unit = mem_start.mem_unit;
   128      pt.put("totalram", (mem_end.totalram - mem_start.totalram) * mem_unit);
   129      pt.put("freeram", (mem_end.freeram - mem_start.freeram) * mem_unit);
   130      pt.put("sharedram", (mem_end.sharedram - mem_start.sharedram) * mem_unit);
   131      pt.put("bufferram", (mem_end.bufferram - mem_start.bufferram) * mem_unit);
   132      pt.put("totalswap", (mem_end.totalswap - mem_start.totalswap) * mem_unit);
   133      pt.put("freeswap", (mem_end.freeswap - mem_start.freeswap) * mem_unit);
   134      pt.put("totalhigh", (mem_end.totalhigh - mem_start.totalhigh) * mem_unit);
   135      pt.put("freeshigh", (mem_end.freehigh - mem_start.freehigh) * mem_unit);
   136    };
   137  
   138    struct proc_stat_t {
   139      uint64_t user;
   140      uint64_t nice;
   141      uint64_t system;
   142      uint64_t idle;
   143      uint64_t iowait;
   144      uint64_t irq;
   145      uint64_t softrq;
   146    };
   147    struct proc_stat_t cpu_start, cpu_end;
   148    auto procstat = [](struct proc_stat_t &cpu_info) {
   149      std::ifstream file("/proc/stat");
   150      std::string ignore;
   151      file >> ignore >> cpu_info.user >> cpu_info.nice >> cpu_info.system >>
   152          cpu_info.idle >> cpu_info.iowait >> cpu_info.irq >> cpu_info.softrq;
   153    };
   154  
   155    auto f_cpu = [](boost::property_tree::ptree &pt,
   156                    const struct proc_stat_t &cpu_start,
   157                    const struct proc_stat_t &cpu_end) {
   158      auto delta_idle = cpu_end.idle - cpu_start.idle;
   159      auto delta_iowait = cpu_end.iowait - cpu_start.iowait;
   160      auto delta_total =
   161          cpu_end.user + cpu_end.nice + cpu_end.system + cpu_end.idle +
   162          cpu_end.iowait + cpu_end.irq + cpu_end.softrq -
   163          (cpu_start.user + cpu_start.nice + cpu_start.system + cpu_start.idle +
   164           cpu_start.iowait + cpu_start.irq + cpu_start.softrq);
   165      decltype(delta_idle) usage = 0;
   166      if (delta_total > 0) {
   167        usage = 1 - (delta_idle + delta_iowait) / delta_total;
   168      }
   169      pt.put("cpu_usage", usage);
   170    };
   171  
   172    for (auto it = m_all_instances.begin(); it != m_all_instances.end(); ++it) {
   173      std::string fixture = (*it)->get_fixture_name();
   174      std::string name = (*it)->get_instance_name();
   175      if (m_enabled_fixtures.find(fixture) == m_enabled_fixtures.end())
   176        continue;
   177  
   178      boost::property_tree::ptree results;
   179      for (size_t i = 0; i < m_eval_count; ++i) {
   180        procstat(cpu_start);
   181        sysinfo(&mem_start);
   182        start = std::chrono::system_clock::now();
   183        (*it)->run();
   184        end = std::chrono::system_clock::now();
   185        sysinfo(&mem_end);
   186        procstat(cpu_end);
   187        auto elapsed_seconds =
   188            std::chrono::duration_cast<std::chrono::nanoseconds>(end - start)
   189                .count();
   190        boost::property_tree::ptree time_result;
   191        time_result.put("nano_seconds", elapsed_seconds);
   192        f_cpu(time_result, cpu_start, cpu_end);
   193        f_mem(time_result, mem_start, mem_end);
   194        results.push_back(std::make_pair("", time_result));
   195      }
   196      property_tree.add_child(prefix_str(fixture, name), results);
   197    }
   198  
   199    boost::property_tree::write_json(m_output_fp, property_tree);
   200    return 0;
   201  }
   202  
   203  size_t
   204  benchmark_instances::register_benchmark(const benchmark_instance_base_ptr &b) {
   205    m_all_instances.push_back(b);
   206    return m_all_instances.size();
   207  }
   208  } // end namespace neb