1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
5 * Copyright (C) 2016 Red Hat Inc.
7 * Author: J. Eric Ivancich <ivancich@redhat.com>
9 * This is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License version
11 * 2.1, as published by the Free Software Foundation. See file
16 #include "test_dmclock.h"
24 namespace dmc
= crimson::dmclock
;
25 namespace test
= crimson::test_dmc
;
26 namespace sim
= crimson::qos_simulation
;
28 using namespace std::placeholders
;
33 void server_data(std::ostream
& out
,
35 test::MySim::ServerFilter server_disp_filter
,
36 int head_w
, int data_w
, int data_prec
);
38 void client_data(std::ostream
& out
,
40 test::MySim::ClientFilter client_disp_filter
,
41 int head_w
, int data_w
, int data_prec
);
46 int main(int argc
, char* argv
[]) {
47 std::vector
<const char*> args
;
48 for (int i
= 1; i
< argc
; ++i
) {
49 args
.push_back(argv
[i
]);
52 std::string conf_file_list
;
53 sim::ceph_argparse_early_args(args
, &conf_file_list
);
55 sim::sim_config_t g_conf
;
56 std::vector
<sim::cli_group_t
> &cli_group
= g_conf
.cli_group
;
57 std::vector
<sim::srv_group_t
> &srv_group
= g_conf
.srv_group
;
59 if (!conf_file_list
.empty()) {
61 ret
= sim::parse_config_file(conf_file_list
, g_conf
);
67 // default simulation parameter
68 g_conf
.client_groups
= 2;
71 srv_group
.push_back(st
);
73 sim::cli_group_t
ct1(99, 0);
74 cli_group
.push_back(ct1
);
76 sim::cli_group_t
ct2(1, 10);
77 cli_group
.push_back(ct2
);
80 const unsigned server_groups
= g_conf
.server_groups
;
81 const unsigned client_groups
= g_conf
.client_groups
;
82 const bool server_random_selection
= g_conf
.server_random_selection
;
83 const bool server_soft_limit
= g_conf
.server_soft_limit
;
84 const double anticipation_timeout
= g_conf
.anticipation_timeout
;
85 unsigned server_total_count
= 0;
86 unsigned client_total_count
= 0;
88 for (unsigned i
= 0; i
< client_groups
; ++i
) {
89 client_total_count
+= cli_group
[i
].client_count
;
92 for (unsigned i
= 0; i
< server_groups
; ++i
) {
93 server_total_count
+= srv_group
[i
].server_count
;
96 std::vector
<test::dmc::ClientInfo
> client_info
;
97 for (unsigned i
= 0; i
< client_groups
; ++i
) {
98 client_info
.push_back(test::dmc::ClientInfo
99 { cli_group
[i
].client_reservation
,
100 cli_group
[i
].client_weight
,
101 cli_group
[i
].client_limit
} );
104 auto ret_client_group_f
= [&](const ClientId
& c
) -> unsigned {
105 unsigned group_max
= 0;
107 for (; i
< client_groups
; ++i
) {
108 group_max
+= cli_group
[i
].client_count
;
116 auto ret_server_group_f
= [&](const ServerId
& s
) -> unsigned {
117 unsigned group_max
= 0;
119 for (; i
< server_groups
; ++i
) {
120 group_max
+= srv_group
[i
].server_count
;
129 [=](const ClientId
& c
) -> const test::dmc::ClientInfo
* {
130 return &client_info
[ret_client_group_f(c
)];
133 auto client_disp_filter
= [=] (const ClientId
& i
) -> bool {
134 return i
< 3 || i
>= (client_total_count
- 3);
137 auto server_disp_filter
= [=] (const ServerId
& i
) -> bool {
138 return i
< 3 || i
>= (server_total_count
- 3);
142 test::MySim
*simulation
;
145 // lambda to post a request to the identified server; called by client
146 test::SubmitFunc server_post_f
=
149 &ret_client_group_f
](const ServerId
& server
,
150 sim::TestRequest
&& request
,
151 const ClientId
& client_id
,
152 const test::dmc::ReqParams
& req_params
) {
153 test::DmcServer
& s
= simulation
->get_server(server
);
154 sim::Cost request_cost
= cli_group
[ret_client_group_f(client_id
)].client_req_cost
;
155 s
.post(std::move(request
), client_id
, req_params
, request_cost
);
158 std::vector
<std::vector
<sim::CliInst
>> cli_inst
;
159 for (unsigned i
= 0; i
< client_groups
; ++i
) {
160 if (cli_group
[i
].client_wait
== std::chrono::seconds(0)) {
163 (uint32_t)cli_group
[i
].client_total_ops
,
164 (double)cli_group
[i
].client_iops_goal
,
165 (uint16_t)cli_group
[i
].client_outstanding_ops
} } );
168 { { sim::wait_op
, cli_group
[i
].client_wait
},
170 (uint32_t)cli_group
[i
].client_total_ops
,
171 (double)cli_group
[i
].client_iops_goal
,
172 (uint16_t)cli_group
[i
].client_outstanding_ops
} } );
176 simulation
= new test::MySim();
178 test::DmcServer::ClientRespFunc client_response_f
=
179 [&simulation
](ClientId client_id
,
180 const sim::TestResponse
& resp
,
181 const ServerId
& server_id
,
182 const dmc::PhaseType
& phase
,
183 const sim::Cost request_cost
) {
184 simulation
->get_client(client_id
).receive_response(resp
,
190 test::CreateQueueF create_queue_f
=
191 [&](test::DmcQueue::CanHandleRequestFunc can_f
,
192 test::DmcQueue::HandleRequestFunc handle_f
) -> test::DmcQueue
* {
193 return new test::DmcQueue(client_info_f
,
196 server_soft_limit
? dmc::AtLimit::Allow
: dmc::AtLimit::Wait
,
197 anticipation_timeout
);
201 auto create_server_f
= [&](ServerId id
) -> test::DmcServer
* {
202 unsigned i
= ret_server_group_f(id
);
203 return new test::DmcServer(id
,
204 srv_group
[i
].server_iops
,
205 srv_group
[i
].server_threads
,
207 test::dmc_server_accumulate_f
,
211 auto create_client_f
= [&](ClientId id
) -> test::DmcClient
* {
212 unsigned i
= ret_client_group_f(id
);
213 test::MySim::ClientBasedServerSelectFunc server_select_f
;
214 unsigned client_server_select_range
= cli_group
[i
].client_server_select_range
;
215 if (!server_random_selection
) {
216 server_select_f
= simulation
->make_server_select_alt_range(client_server_select_range
);
218 server_select_f
= simulation
->make_server_select_ran_range(client_server_select_range
);
220 return new test::DmcClient(id
,
222 std::bind(server_select_f
, _1
, id
),
223 test::dmc_client_accumulate_f
,
228 std::cout
<< "[global]" << std::endl
<< g_conf
<< std::endl
;
229 for (unsigned i
= 0; i
< client_groups
; ++i
) {
230 std::cout
<< std::endl
<< "[client." << i
<< "]" << std::endl
;
231 std::cout
<< cli_group
[i
] << std::endl
;
233 for (unsigned i
= 0; i
< server_groups
; ++i
) {
234 std::cout
<< std::endl
<< "[server." << i
<< "]" << std::endl
;
235 std::cout
<< srv_group
[i
] << std::endl
;
237 std::cout
<< std::endl
;
240 simulation
->add_servers(server_total_count
, create_server_f
);
241 simulation
->add_clients(client_total_count
, create_client_f
);
244 simulation
->display_stats(std::cout
,
245 &test::server_data
, &test::client_data
,
246 server_disp_filter
, client_disp_filter
);
252 void test::client_data(std::ostream
& out
,
254 test::MySim::ClientFilter client_disp_filter
,
255 int head_w
, int data_w
, int data_prec
) {
256 // report how many ops were done by reservation and proportion for
260 out
<< std::setw(head_w
) << "res_ops:";
261 for (unsigned i
= 0; i
< sim
->get_client_count(); ++i
) {
262 const auto& client
= sim
->get_client(i
);
263 auto r
= client
.get_accumulator().reservation_count
;
265 if (!client_disp_filter(i
)) continue;
266 out
<< " " << std::setw(data_w
) << r
;
268 out
<< " " << std::setw(data_w
) << std::setprecision(data_prec
) <<
269 std::fixed
<< total_r
<< std::endl
;
272 out
<< std::setw(head_w
) << "prop_ops:";
273 for (unsigned i
= 0; i
< sim
->get_client_count(); ++i
) {
274 const auto& client
= sim
->get_client(i
);
275 auto p
= client
.get_accumulator().proportion_count
;
277 if (!client_disp_filter(i
)) continue;
278 out
<< " " << std::setw(data_w
) << p
;
280 out
<< " " << std::setw(data_w
) << std::setprecision(data_prec
) <<
281 std::fixed
<< total_p
<< std::endl
;
285 void test::server_data(std::ostream
& out
,
287 test::MySim::ServerFilter server_disp_filter
,
288 int head_w
, int data_w
, int data_prec
) {
289 out
<< std::setw(head_w
) << "res_ops:";
291 for (unsigned i
= 0; i
< sim
->get_server_count(); ++i
) {
292 const auto& server
= sim
->get_server(i
);
293 auto rc
= server
.get_accumulator().reservation_count
;
295 if (!server_disp_filter(i
)) continue;
296 out
<< " " << std::setw(data_w
) << rc
;
298 out
<< " " << std::setw(data_w
) << std::setprecision(data_prec
) <<
299 std::fixed
<< total_r
<< std::endl
;
301 out
<< std::setw(head_w
) << "prop_ops:";
303 for (unsigned i
= 0; i
< sim
->get_server_count(); ++i
) {
304 const auto& server
= sim
->get_server(i
);
305 auto pc
= server
.get_accumulator().proportion_count
;
307 if (!server_disp_filter(i
)) continue;
308 out
<< " " << std::setw(data_w
) << pc
;
310 out
<< " " << std::setw(data_w
) << std::setprecision(data_prec
) <<
311 std::fixed
<< total_p
<< std::endl
;
313 const auto& q
= sim
->get_server(0).get_priority_queue();
315 " k-way heap: " << q
.get_heap_branching_factor() << std::endl
319 crimson::ProfileCombiner
<std::chrono::nanoseconds
> art_combiner
;
320 crimson::ProfileCombiner
<std::chrono::nanoseconds
> rct_combiner
;
321 for (unsigned i
= 0; i
< sim
->get_server_count(); ++i
) {
322 const auto& q
= sim
->get_server(i
).get_priority_queue();
323 const auto& art
= q
.add_request_timer
;
324 art_combiner
.combine(art
);
325 const auto& rct
= q
.request_complete_timer
;
326 rct_combiner
.combine(rct
);
328 out
<< "Server add_request_timer: count:" << art_combiner
.get_count() <<
329 ", mean:" << art_combiner
.get_mean() <<
330 ", std_dev:" << art_combiner
.get_std_dev() <<
331 ", low:" << art_combiner
.get_low() <<
332 ", high:" << art_combiner
.get_high() << std::endl
;
333 out
<< "Server request_complete_timer: count:" << rct_combiner
.get_count() <<
334 ", mean:" << rct_combiner
.get_mean() <<
335 ", std_dev:" << rct_combiner
.get_std_dev() <<
336 ", low:" << rct_combiner
.get_low() <<
337 ", high:" << rct_combiner
.get_high() << std::endl
;
338 out
<< "Server combined mean: " <<
339 (art_combiner
.get_mean() + rct_combiner
.get_mean()) <<