1 // Copyright (C) 2021 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include <ditto/instruction_set.h>
16 
17 #include <variant>
18 
19 #include <ditto/logger.h>
20 #include <ditto/shared_variables.h>
21 
22 namespace dittosuite {
23 
24 template <class... Ts>
25 struct overloaded : Ts... {
26   using Ts::operator()...;
27 };
28 template <class... Ts>
29 overloaded(Ts...) -> overloaded<Ts...>;
30 
InstructionSet(const Params & params,std::vector<std::unique_ptr<Instruction>> instructions,int list_key,int item_key,Order access_order,Reseeding reseeding,uint32_t seed)31 InstructionSet::InstructionSet(const Params& params,
32                                std::vector<std::unique_ptr<Instruction>> instructions, int list_key,
33                                int item_key, Order access_order, Reseeding reseeding, uint32_t seed)
34     : Instruction(kName, params),
35       instructions_(std::move(instructions)),
36       list_key_(list_key),
37       item_key_(item_key),
38       access_order_(access_order),
39       reseeding_(reseeding),
40       seed_(seed),
41       gen_(seed) {}
42 
InstructionSet(const Params & params,std::vector<std::unique_ptr<Instruction>> instructions)43 InstructionSet::InstructionSet(const Params& params,
44                                std::vector<std::unique_ptr<Instruction>> instructions)
45     : Instruction(kName, params),
46       instructions_(std::move(instructions)),
47       list_key_(-1),
48       item_key_(-1) {}
49 
SetUp()50 void InstructionSet::SetUp() {
51   if (reseeding_ == Reseeding::kEachRoundOfCycles) {
52     gen_.seed(seed_);
53   }
54   Instruction::SetUp();
55 }
56 
SetUpSingle()57 void InstructionSet::SetUpSingle() {
58   if (reseeding_ == Reseeding::kEachCycle) {
59     gen_.seed(seed_);
60   }
61   Instruction::SetUpSingle();
62 }
63 
RunSingle()64 void InstructionSet::RunSingle() {
65   if (list_key_ != -1 && item_key_ != -1) {
66     std::visit(overloaded{[&](const std::vector<std::string>& list) {
67                             std::uniform_int_distribution<> uniform_distribution(0,
68                                                                                  list.size() - 1);
69                             for (std::size_t i = 0; i < list.size(); ++i) {
70                               switch (access_order_) {
71                                 case Order::kSequential: {
72                                   SharedVariables::Set(item_key_, list[i]);
73                                   break;
74                                 }
75                                 case Order::kRandom: {
76                                   SharedVariables::Set(item_key_, list[uniform_distribution(gen_)]);
77                                   break;
78                                 }
79                               }
80                               RunInstructions();
81                             }
82                           },
83                           [](int) {
84                             LOGE("Input for InstructionSet is not iterable.");
85                             exit(EXIT_FAILURE);
86                           },
87                           [](const std::string&) {
88                             LOGE("Input for InstructionSet is not iterable.");
89                             exit(EXIT_FAILURE);
90                           }},
91                SharedVariables::Get(list_key_));
92   } else {
93     RunInstructions();
94   }
95 }
96 
RunInstructions()97 void InstructionSet::RunInstructions() {
98   for (const auto& instruction : instructions_) {
99     instruction->SetUp();
100     instruction->Run();
101     instruction->TearDown();
102   }
103 }
104 
105 // The duration for an instruction set is a sum of its child instruction durations.
CollectResults(const std::string & prefix)106 std::unique_ptr<Result> InstructionSet::CollectResults(const std::string& prefix) {
107   auto result = std::make_unique<Result>(prefix + name_, repeat_);
108   std::vector<double> duration;
109   for (const auto& instruction : instructions_) {
110     auto sub_result = instruction->CollectResults("");
111     auto samples = sub_result->GetSamples("duration");
112     auto repeat = sub_result->GetRepeat();
113 
114     if (duration.empty()) {
115       duration.resize(samples.size() / repeat);
116     }
117 
118     for (std::size_t i = 0; i < samples.size() / repeat; ++i) {
119       for (int j = 0; j < repeat; ++j) {
120         duration[i] += samples[i * repeat + j];
121       }
122     }
123 
124     result->AddSubResult(std::move(sub_result));
125   }
126   result->AddMeasurement("duration", duration);
127   return result;
128 }
129 
130 }  // namespace dittosuite
131