]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | ||
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> | |
10 | #include <iostream> | |
11 | #include <set> | |
12 | #include <sstream> | |
13 | #include <stdlib.h> | |
14 | #include <fstream> | |
15 | ||
16 | #include "common/Formatter.h" | |
17 | ||
18 | #include "bencher.h" | |
19 | #include "rados_backend.h" | |
20 | #include "detailed_stat_collector.h" | |
21 | #include "distribution.h" | |
22 | ||
23 | namespace po = boost::program_options; | |
24 | using namespace std; | |
25 | ||
26 | int main(int argc, char **argv) | |
27 | { | |
28 | po::options_description desc("Allowed options"); | |
29 | desc.add_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), | |
36 | "set object size") | |
37 | ("io-size", po::value<unsigned>()->default_value(4<<10), | |
38 | "set io size") | |
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>(), | |
46 | "seed") | |
47 | ("ceph-client-id", po::value<string>()->default_value("admin"), | |
48 | "set ceph client id") | |
49 | ("pool-name", po::value<string>()->default_value("data"), | |
50 | "set pool") | |
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), | |
60 | "align offset by") | |
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") | |
65 | ; | |
66 | ||
67 | po::variables_map vm; | |
68 | po::store(po::parse_command_line(argc, argv, desc), vm); | |
69 | po::notify(vm); | |
70 | ||
71 | if (vm.count("help")) { | |
72 | cout << desc << std::endl; | |
73 | return 1; | |
74 | } | |
75 | ||
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; | |
79 | return 1; | |
80 | } | |
81 | ||
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; | |
85 | return 1; | |
86 | } | |
87 | ||
88 | string prefix; | |
89 | if (vm["use-prefix"].as<string>().size()) { | |
90 | prefix = vm["use-prefix"].as<string>(); | |
91 | } else { | |
92 | char hostname_cstr[100]; | |
93 | gethostname(hostname_cstr, 100); | |
94 | stringstream hostpid; | |
95 | hostpid << hostname_cstr << getpid() << "-"; | |
96 | prefix = hostpid.str(); | |
97 | } | |
98 | ||
99 | set<string> objects; | |
100 | for (unsigned i = 0; i < vm["num-objects"].as<unsigned>(); | |
101 | ++i) { | |
102 | stringstream name; | |
103 | name << prefix << "-object_" << i; | |
104 | objects.insert(name.str()); | |
105 | } | |
106 | ||
107 | rngen_t rng; | |
108 | if (vm.count("seed")) | |
109 | rng = rngen_t(vm["seed"].as<unsigned>()); | |
110 | ||
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)); | |
114 | ||
115 | librados::Rados rados; | |
116 | librados::IoCtx ioctx; | |
117 | int r = rados.init(vm["ceph-client-id"].as<string>().c_str()); | |
118 | if (r < 0) { | |
119 | cerr << "error in init r=" << r << std::endl; | |
120 | return -r; | |
121 | } | |
122 | r = rados.conf_read_file(NULL); | |
123 | if (r < 0) { | |
124 | cerr << "error in conf_read_file r=" << r << std::endl; | |
125 | return -r; | |
126 | } | |
127 | r = rados.conf_parse_env(NULL); | |
128 | if (r < 0) { | |
129 | cerr << "error in conf_parse_env r=" << r << std::endl; | |
130 | return -r; | |
131 | } | |
132 | r = rados.connect(); | |
133 | if (r < 0) { | |
134 | cerr << "error in connect r=" << r << std::endl; | |
135 | return -r; | |
136 | } | |
137 | r = rados.ioctx_create(vm["pool-name"].as<string>().c_str(), ioctx); | |
138 | if (r < 0) { | |
139 | cerr << "error in ioctx_create r=" << r << std::endl; | |
140 | return -r; | |
141 | } | |
142 | ||
143 | ostream *detailed_ops = 0; | |
144 | ofstream myfile; | |
145 | if (vm["disable-detailed-ops"].as<bool>()) { | |
146 | detailed_ops = 0; | |
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; | |
150 | } else { | |
151 | detailed_ops = &cerr; | |
152 | } | |
153 | ||
154 | Distribution< | |
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( | |
159 | objects, | |
160 | vm["object-size"].as<unsigned>(), | |
161 | vm["io-size"].as<unsigned>(), | |
162 | new WeightedDist<Bencher::OpType>(rng, ops) | |
163 | ); | |
164 | } else { | |
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), | |
168 | new Align( | |
169 | new UniformRandom( | |
170 | rng, | |
171 | 0, | |
172 | vm["object-size"].as<unsigned>() - vm["io-size"].as<unsigned>()), | |
173 | vm["offset-align"].as<unsigned>() | |
174 | ), | |
175 | new Uniform(vm["io-size"].as<unsigned>()), | |
176 | new WeightedDist<Bencher::OpType>(rng, ops) | |
177 | ); | |
178 | } | |
179 | ||
180 | Bencher bencher( | |
181 | gen, | |
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>()); | |
187 | ||
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; | |
191 | } else { | |
192 | cout << "Not initing objects..." << std::endl; | |
193 | } | |
194 | ||
195 | if (!vm["init-only"].as<bool>()) { | |
196 | bencher.run_bench(); | |
197 | } else { | |
198 | cout << "init-only" << std::endl; | |
199 | } | |
200 | ||
201 | rados.shutdown(); | |
202 | if (vm["op-dump-file"].as<string>().size()) { | |
203 | myfile.close(); | |
204 | } | |
205 | return 0; | |
206 | } |