1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
3 #include <boost/scoped_ptr.hpp>
4 #include <boost/lexical_cast.hpp>
5 #include <boost/program_options/option.hpp>
6 #include <boost/program_options/options_description.hpp>
7 #include <boost/program_options/variables_map.hpp>
8 #include <boost/program_options/cmdline.hpp>
9 #include <boost/program_options/parsers.hpp>
16 #include "common/Formatter.h"
19 #include "rados_backend.h"
20 #include "detailed_stat_collector.h"
21 #include "distribution.h"
23 namespace po = boost::program_options;
26 int main(int argc, char **argv)
28 po::options_description desc("Allowed options");
30 ("help", "produce help message")
31 ("num-concurrent-ops", po::value<unsigned>()->default_value(10),
32 "set number of concurrent ops")
33 ("num-objects", po::value<unsigned>()->default_value(500),
34 "set number of objects to use")
35 ("object-size", po::value<unsigned>()->default_value(4<<20),
37 ("io-size", po::value<unsigned>()->default_value(4<<10),
39 ("write-ratio", po::value<double>()->default_value(0.75),
40 "set ratio of read to write")
41 ("duration", po::value<unsigned>()->default_value(0),
42 "set max duration, 0 for unlimited")
43 ("max-ops", po::value<unsigned>()->default_value(0),
44 "set max ops, 0 for unlimited")
45 ("seed", po::value<unsigned>(),
47 ("ceph-client-id", po::value<string>()->default_value("admin"),
49 ("pool-name", po::value<string>()->default_value("data"),
51 ("op-dump-file", po::value<string>()->default_value(""),
52 "set file for dumping op details, omit for stderr")
53 ("init-only", po::value<bool>()->default_value(false),
54 "populate object set")
55 ("do-not-init", po::value<bool>()->default_value(false),
56 "use existing object set")
57 ("use-prefix", po::value<string>()->default_value(""),
58 "use previously populated prefix")
59 ("offset-align", po::value<unsigned>()->default_value(4096),
61 ("sequential", po::value<bool>()->default_value(false),
62 "use sequential access pattern")
63 ("disable-detailed-ops", po::value<bool>()->default_value(false),
64 "don't dump per op stats")
68 po::store(po::parse_command_line(argc, argv, desc), vm);
71 if (vm.count("help")) {
72 cout << desc << std::endl;
76 if (vm["do-not-init"].as<bool>() && !vm["use-prefix"].as<string>().size()) {
77 cout << "Must supply prefix if do-not-init is specified" << std::endl;
78 cout << desc << std::endl;
82 if (vm["init-only"].as<bool>() && !vm["use-prefix"].as<string>().size()) {
83 cout << "Must supply prefix for init-only" << std::endl;
84 cout << desc << std::endl;
89 if (vm["use-prefix"].as<string>().size()) {
90 prefix = vm["use-prefix"].as<string>();
92 char hostname_cstr[100];
93 gethostname(hostname_cstr, 100);
95 hostpid << hostname_cstr << getpid() << "-";
96 prefix = hostpid.str();
100 for (unsigned i = 0; i < vm["num-objects"].as<unsigned>();
103 name << prefix << "-object_" << i;
104 objects.insert(name.str());
108 if (vm.count("seed"))
109 rng = rngen_t(vm["seed"].as<unsigned>());
111 set<pair<double, Bencher::OpType> > ops;
112 ops.insert(make_pair(vm["write-ratio"].as<double>(), Bencher::WRITE));
113 ops.insert(make_pair(1-vm["write-ratio"].as<double>(), Bencher::READ));
115 librados::Rados rados;
116 librados::IoCtx ioctx;
117 int r = rados.init(vm["ceph-client-id"].as<string>().c_str());
119 cerr << "error in init r=" << r << std::endl;
122 r = rados.conf_read_file(NULL);
124 cerr << "error in conf_read_file r=" << r << std::endl;
127 r = rados.conf_parse_env(NULL);
129 cerr << "error in conf_parse_env r=" << r << std::endl;
134 cerr << "error in connect r=" << r << std::endl;
137 r = rados.ioctx_create(vm["pool-name"].as<string>().c_str(), ioctx);
139 cerr << "error in ioctx_create r=" << r << std::endl;
143 ostream *detailed_ops = 0;
145 if (vm["disable-detailed-ops"].as<bool>()) {
147 } else if (vm["op-dump-file"].as<string>().size()) {
148 myfile.open(vm["op-dump-file"].as<string>().c_str());
149 detailed_ops = &myfile;
151 detailed_ops = &cerr;
155 boost::tuple<string, uint64_t, uint64_t, Bencher::OpType> > *gen = 0;
156 if (vm["sequential"].as<bool>()) {
157 std::cout << "Using Sequential generator" << std::endl;
158 gen = new SequentialLoad(
160 vm["object-size"].as<unsigned>(),
161 vm["io-size"].as<unsigned>(),
162 new WeightedDist<Bencher::OpType>(rng, ops)
165 std::cout << "Using random generator" << std::endl;
166 gen = new FourTupleDist<string, uint64_t, uint64_t, Bencher::OpType>(
167 new RandomDist<string>(rng, objects),
172 vm["object-size"].as<unsigned>() - vm["io-size"].as<unsigned>()),
173 vm["offset-align"].as<unsigned>()
175 new Uniform(vm["io-size"].as<unsigned>()),
176 new WeightedDist<Bencher::OpType>(rng, ops)
182 new DetailedStatCollector(1, new JSONFormatter, detailed_ops, &cout),
183 new RadosBackend(&ioctx),
184 vm["num-concurrent-ops"].as<unsigned>(),
185 vm["duration"].as<unsigned>(),
186 vm["max-ops"].as<unsigned>());
188 if (!vm["do-not-init"].as<bool>()) {
189 bencher.init(objects, vm["object-size"].as<unsigned>(), &std::cout);
190 cout << "Created objects..." << std::endl;
192 cout << "Not initing objects..." << std::endl;
195 if (!vm["init-only"].as<bool>()) {
198 cout << "init-only" << std::endl;
202 if (vm["op-dump-file"].as<string>().size()) {