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