@@ -65,6 +65,9 @@ struct Config {
6565
6666 std::int64_t table_size = 1000 * 1000L ;
6767 std::int64_t query_size = 1000 ;
68+
69+ bool use_only_clients = false ;
70+ bool use_only_stubs = false ;
6871};
6972
7073std::ostream& operator <<(std::ostream& os, Config const & config);
@@ -201,6 +204,8 @@ std::ostream& operator<<(std::ostream& os, Config const& config) {
201204 << " s"
202205 << " \n # Table Size: " << config.table_size
203206 << " \n # Query Size: " << config.query_size
207+ << " \n # Use Only Stubs: " << config.use_only_stubs
208+ << " \n # Use Only Clients: " << config.use_only_clients
204209 << " \n # Compiler: " << cs::internal::CompilerId () << " -"
205210 << cs::internal::CompilerVersion ()
206211 << " \n # Build Flags: " << cs::internal::BuildFlags () << " \n " ;
@@ -336,8 +341,8 @@ class ExperimentImpl {
336341 explicit ExperimentImpl (google::cloud::internal::DefaultPRNG const & generator)
337342 : generator_(generator) {}
338343
339- Status FillTable (Config const & config , cs::Database const & database,
340- std::string const & table_name) {
344+ Status CreateTable (Config const &, cs::Database const & database,
345+ std::string const & table_name) {
341346 std::string statement = " CREATE TABLE " + table_name;
342347 statement += " (Key INT64 NOT NULL,\n " ;
343348 for (int i = 0 ; i != 10 ; ++i) {
@@ -359,6 +364,13 @@ class ExperimentImpl {
359364 std::cerr << " Error creating table: " << db.status () << " \n " ;
360365 return std::move (db).status ();
361366 }
367+ return {};
368+ }
369+
370+ Status FillTable (Config const & config, cs::Database const & database,
371+ std::string const & table_name) {
372+ auto status = CreateTable (config, database, table_name);
373+ if (!status.ok ()) return status;
362374
363375 // We need to populate some data or all the requests to read will fail.
364376 cs::Client client (cs::MakeConnection (database));
@@ -401,6 +413,36 @@ class ExperimentImpl {
401413 cs::MakeKeyBoundClosed (cs::Value (end)));
402414 }
403415
416+ bool UseStub (Config const & config) {
417+ if (config.use_only_clients ) {
418+ return false ;
419+ }
420+ if (config.use_only_stubs ) {
421+ return true ;
422+ }
423+ std::lock_guard<std::mutex> lk (mu_);
424+ return std::uniform_int_distribution<int >(0 , 1 )(generator_) == 1 ;
425+ }
426+
427+ int ThreadCount (Config const & config) {
428+ std::lock_guard<std::mutex> lk (mu_);
429+ return std::uniform_int_distribution<int >(
430+ config.minimum_threads , config.maximum_threads )(generator_);
431+ }
432+
433+ int ClientCount (Config const & config, int thread_count) {
434+ // TODO(#1000) - avoid deadlocks with more than 100 threads per client
435+ auto const min_clients =
436+ (std::max<int >)(thread_count / 100 + 1 , config.minimum_clients );
437+ auto const max_clients = config.maximum_clients ;
438+ if (min_clients <= max_clients) {
439+ return min_clients;
440+ }
441+ std::lock_guard<std::mutex> lk (mu_);
442+ return std::uniform_int_distribution<int >(min_clients,
443+ max_clients - 1 )(generator_);
444+ }
445+
404446 // / Get a snapshot of the random bit generator
405447 google::cloud::internal::DefaultPRNG Generator () const {
406448 std::lock_guard<std::mutex> lk (mu_);
@@ -532,30 +574,13 @@ class ReadExperiment : public Experiment {
532574 }
533575 std::cout << " DONE\n " ;
534576
535- std::uniform_int_distribution<int > use_stubs_gen (0 , 1 );
536- std::uniform_int_distribution<int > thread_count_gen (config.minimum_threads ,
537- config.maximum_threads );
538-
539- // Get a snapshot of the generator, to be used in this thread only.
540- auto generator = impl_.Generator ();
541-
542577 // Capture some overall getrusage() statistics as comments.
543578 SimpleTimer overall;
544579 overall.Start ();
545580 for (int i = 0 ; i != config.samples ; ++i) {
546- auto const use_stubs = use_stubs_gen (generator) == 1 ;
547- auto const thread_count = thread_count_gen (generator);
548- // TODO(#1000) - avoid deadlocks with more than 100 threads per client
549- auto const min_clients = (std::max<std::size_t >)(thread_count / 100 + 1 ,
550- config.minimum_clients );
551- auto const max_clients = clients.size ();
552- auto const client_count = [min_clients, max_clients, &generator] {
553- if (min_clients <= max_clients) {
554- return min_clients;
555- }
556- return std::uniform_int_distribution<std::size_t >(
557- min_clients, max_clients - 1 )(generator);
558- }();
581+ auto const use_stubs = impl_.UseStub (config);
582+ auto const thread_count = impl_.ThreadCount (config);
583+ auto const client_count = impl_.ClientCount (config, thread_count);
559584 if (use_stubs) {
560585 std::vector<std::shared_ptr<cs::internal::SpannerStub>> iteration_stubs (
561586 stubs.begin (), stubs.begin () + client_count);
@@ -773,28 +798,13 @@ class UpdateExperiment : public Experiment {
773798 }
774799 std::cout << " DONE\n " ;
775800
776- std::uniform_int_distribution<int > use_stubs_gen (0 , 1 );
777- std::uniform_int_distribution<int > thread_count_gen (config.minimum_threads ,
778- config.maximum_threads );
779-
780- auto generator = impl_.Generator ();
781801 // Capture some overall getrusage() statistics as comments.
782802 SimpleTimer overall;
783803 overall.Start ();
784804 for (int i = 0 ; i != config.samples ; ++i) {
785- auto const use_stubs = use_stubs_gen (generator) == 1 ;
786- auto const thread_count = thread_count_gen (generator);
787- // TODO(#1000) - avoid deadlocks with more than 100 threads per client
788- auto const min_clients = (std::max<std::size_t >)(thread_count / 100 + 1 ,
789- config.minimum_clients );
790- auto const max_clients = clients.size ();
791- auto const client_count = [min_clients, max_clients, &generator] {
792- if (min_clients <= max_clients) {
793- return min_clients;
794- }
795- return std::uniform_int_distribution<std::size_t >(
796- min_clients, max_clients - 1 )(generator);
797- }();
805+ auto const use_stubs = impl_.UseStub (config);
806+ auto const thread_count = impl_.ThreadCount (config);
807+ auto const client_count = impl_.ClientCount (config, thread_count);
798808 if (use_stubs) {
799809 std::vector<std::shared_ptr<cs::internal::SpannerStub>> iteration_stubs (
800810 stubs.begin (), stubs.begin () + client_count);
@@ -1023,34 +1033,61 @@ class RunAllExperiment : public Experiment {
10231033
10241034 Status Run (Config const & cfg, cs::Database const & database) override {
10251035 // Smoke test all the experiments by running a very small version of each.
1036+
1037+ std::vector<std::future<google::cloud::Status>> tasks;
10261038 for (auto & kv : AvailableExperiments ()) {
10271039 // Do not recurse, skip this experiment.
10281040 if (kv.first == " run-all" ) continue ;
10291041 Config config = cfg;
10301042 config.experiment = kv.first ;
1031- config.samples = 2 ;
1043+ config.samples = 1 ;
10321044 config.iteration_duration = std::chrono::seconds (1 );
10331045 config.minimum_threads = 1 ;
10341046 config.maximum_threads = 1 ;
10351047 config.minimum_clients = 1 ;
10361048 config.maximum_clients = 1 ;
10371049 config.table_size = 10 ;
10381050 config.query_size = 1 ;
1039- std::cout << " # Smoke test for experiment: " << kv.first << " \n " ;
1040- std::cout << config << " \n " << std::flush;
1051+
10411052 auto experiment = kv.second (generator_);
1042- auto status = experiment->SetUp (config, database);
1043- if (!status.ok ()) {
1044- std::cout << " # ERROR in SetUp: " << status << " \n " ;
1045- continue ;
1053+
1054+ tasks.push_back (std::async (
1055+ std::launch::async,
1056+ [](Config config, cs::Database const & database, std::mutex& mu,
1057+ std::unique_ptr<Experiment> experiment) {
1058+ {
1059+ std::lock_guard<std::mutex> lk (mu);
1060+ std::cout << " # Smoke test for experiment\n " ;
1061+ std::cout << config << " \n " << std::flush;
1062+ }
1063+ auto status = experiment->SetUp (config, database);
1064+ if (!status.ok ()) {
1065+ std::lock_guard<std::mutex> lk (mu);
1066+ std::cout << " # ERROR in SetUp: " << status << " \n " ;
1067+ return status;
1068+ }
1069+ config.use_only_clients = true ;
1070+ experiment->Run (config, database);
1071+ config.use_only_stubs = true ;
1072+ experiment->Run (config, database);
1073+ experiment->TearDown (config, database);
1074+ return google::cloud::Status ();
1075+ },
1076+ config, database, std::ref (mu_), std::move (experiment)));
1077+ }
1078+
1079+ Status status;
1080+ for (auto & task : tasks) {
1081+ auto s = task.get ();
1082+ if (!s.ok ()) {
1083+ status = std::move (s);
10461084 }
1047- experiment->Run (config, database);
1048- experiment->TearDown (config, database);
10491085 }
1050- return {} ;
1086+ return status ;
10511087 }
10521088
10531089 private:
1090+ std::mutex mu_;
10541091 google::cloud::internal::DefaultPRNG generator_;
10551092};
10561093
@@ -1144,6 +1181,10 @@ google::cloud::StatusOr<Config> ParseArgs(std::vector<std::string> args) {
11441181 [](Config& c, std::string const & v) { c.table_size = std::stol (v); }},
11451182 {" --query-size=" ,
11461183 [](Config& c, std::string const & v) { c.query_size = std::stol (v); }},
1184+ {" --use-only-stubs" ,
1185+ [](Config& c, std::string const &) { c.use_only_stubs = true ; }},
1186+ {" --use-only-clients" ,
1187+ [](Config& c, std::string const &) { c.use_only_clients = true ; }},
11471188 };
11481189
11491190 auto invalid_argument = [](std::string msg) {
@@ -1224,6 +1265,13 @@ google::cloud::StatusOr<Config> ParseArgs(std::vector<std::string> args) {
12241265 << " than the query size (" << config.query_size << " )" ;
12251266 return invalid_argument (os.str ());
12261267 }
1268+
1269+ if (config.use_only_stubs && config.use_only_clients ) {
1270+ std::ostringstream os;
1271+ os << " Only one of --use-only-stubs or --use-only-clients can be set" ;
1272+ return invalid_argument (os.str ());
1273+ }
1274+
12271275 return config;
12281276}
12291277
0 commit comments