1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
3 #include <boost/lexical_cast.hpp>
4 #include <boost/program_options/option.hpp>
5 #include <boost/program_options/options_description.hpp>
6 #include <boost/program_options/variables_map.hpp>
7 #include <boost/program_options/cmdline.hpp>
8 #include <boost/program_options/parsers.hpp>
15 #include "common/Formatter.h"
18 #include "rbd_backend.h"
19 #include "detailed_stat_collector.h"
20 #include "distribution.h"
22 namespace po = boost::program_options;
25 int main(int argc, char **argv)
27 po::options_description desc("Allowed options");
29 ("help", "produce help message")
30 ("num-concurrent-ops", po::value<unsigned>()->default_value(10),
31 "set number of concurrent ops")
32 ("num-images", po::value<unsigned>()->default_value(2),
33 "set number of rbd images to use")
34 ("image-size", po::value<unsigned>()->default_value(4096),
35 "set image size in megabytes")
36 ("order", po::value<unsigned>()->default_value(22),
37 "set log_2(object size)")
38 ("io-size", po::value<unsigned>()->default_value(4<<10),
40 ("write-ratio", po::value<double>()->default_value(0.25),
41 "set ratio of read to write")
42 ("duration", po::value<unsigned>()->default_value(0),
43 "set max duration, 0 for unlimited")
44 ("max-ops", po::value<unsigned>()->default_value(0),
45 "set max ops, 0 for unlimited")
46 ("seed", po::value<unsigned>(),
48 ("ceph-client-id", po::value<string>()->default_value("admin"),
50 ("pool-name", po::value<string>()->default_value("data"),
52 ("op-dump-file", po::value<string>()->default_value(""),
53 "set file for dumping op details, omit for stderr")
54 ("offset-align", po::value<unsigned>()->default_value(4096),
56 ("sequential", po::value<bool>()->default_value(false),
57 "use sequential access pattern")
58 ("disable-detailed-ops", po::value<bool>()->default_value(false),
59 "don't dump per op stats")
63 po::store(po::parse_command_line(argc, argv, desc), vm);
66 if (vm.count("help")) {
67 cout << desc << std::endl;
72 char hostname_cstr[100];
73 gethostname(hostname_cstr, 100);
75 hostpid << hostname_cstr << getpid() << "-";
76 prefix = hostpid.str();
78 set<string> image_names;
79 for (unsigned i = 0; i < vm["num-images"].as<unsigned>();
82 name << prefix << "-image_" << i;
83 image_names.insert(name.str());
88 rng = rngen_t(vm["seed"].as<unsigned>());
90 set<pair<double, Bencher::OpType> > ops;
91 ops.insert(make_pair(vm["write-ratio"].as<double>(), Bencher::WRITE));
92 ops.insert(make_pair(1-vm["write-ratio"].as<double>(), Bencher::READ));
94 librados::Rados rados;
95 librados::IoCtx ioctx;
96 int r = rados.init(vm["ceph-client-id"].as<string>().c_str());
98 cerr << "error in init r=" << r << std::endl;
101 r = rados.conf_read_file(NULL);
103 cerr << "error in conf_read_file r=" << r << std::endl;
106 r = rados.conf_parse_env(NULL);
108 cerr << "error in conf_parse_env r=" << r << std::endl;
113 cerr << "error in connect r=" << r << std::endl;
116 r = rados.ioctx_create(vm["pool-name"].as<string>().c_str(), ioctx);
118 cerr << "error in ioctx_create r=" << r << std::endl;
122 ostream *detailed_ops = 0;
124 if (vm["disable-detailed-ops"].as<bool>()) {
126 } else if (vm["op-dump-file"].as<string>().size()) {
127 myfile.open(vm["op-dump-file"].as<string>().c_str());
128 detailed_ops = &myfile;
130 detailed_ops = &cerr;
135 map<string, ceph::shared_ptr<librbd::Image> > images;
136 int order = vm["order"].as<unsigned>();
137 uint64_t image_size = ((uint64_t)vm["image-size"].as<unsigned>()) << 20;
138 for (set<string>::const_iterator i = image_names.begin();
139 i != image_names.end(); ++i) {
140 r = rbd.create(ioctx, i->c_str(), image_size, &order);
142 cerr << "error creating image " << *i << " r=" << r << std::endl;
145 ceph::shared_ptr<librbd::Image> image(new librbd::Image());
146 r = rbd.open(ioctx, *image, i->c_str());
148 cerr << "error opening image " << *i << " r=" << r << std::endl;
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(
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, image_names),
172 image_size - 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 RBDBackend(&images),
184 vm["num-concurrent-ops"].as<unsigned>(),
185 vm["duration"].as<unsigned>(),
186 vm["max-ops"].as<unsigned>());
191 for (set<string>::const_iterator i = image_names.begin();
192 i != image_names.end(); ++i) {
193 rbd.remove(ioctx, i->c_str());
196 if (vm["op-dump-file"].as<string>().size()) {