• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_factory.h>
16 
17 #include <fcntl.h>
18 #include <sys/types.h>
19 
20 #include <random>
21 
22 #include <ditto/close_file.h>
23 #include <ditto/delete_file.h>
24 #include <ditto/instruction_set.h>
25 #include <ditto/invalidate_cache.h>
26 #include <ditto/logger.h>
27 #include <ditto/multithreading.h>
28 #include <ditto/open_file.h>
29 #include <ditto/read_directory.h>
30 #include <ditto/read_write_file.h>
31 #include <ditto/resize_file.h>
32 #include <ditto/shared_variables.h>
33 #include <ditto/syscall.h>
34 
35 namespace dittosuite {
36 typedef dittosuiteproto::Instruction::InstructionOneofCase InstructionType;
37 
CreateFromProtoInstructionSet(const std::list<int> & thread_ids,const int repeat,const dittosuiteproto::InstructionSet & proto_instruction_set)38 std::unique_ptr<InstructionSet> InstructionFactory::CreateFromProtoInstructionSet(
39     const std::list<int>& thread_ids, const int repeat,
40     const dittosuiteproto::InstructionSet& proto_instruction_set) {
41   std::vector<std::unique_ptr<Instruction>> instructions;
42   for (const auto& instruction : proto_instruction_set.instructions()) {
43     instructions.push_back(
44         std::move(InstructionFactory::CreateFromProtoInstruction(thread_ids, instruction)));
45   }
46 
47   if (proto_instruction_set.has_iterate_options()) {
48     const auto& options = proto_instruction_set.iterate_options();
49 
50     int list_key = SharedVariables::GetKey(thread_ids, options.list_name());
51     int item_key = SharedVariables::GetKey(thread_ids, options.item_name());
52     auto access_order = ConvertOrder(options.access_order());
53     auto reseeding = ConvertReseeding(options.reseeding());
54 
55     uint32_t seed = options.seed();
56     if (!options.has_seed()) {
57       seed = time(nullptr);
58     }
59 
60     return std::make_unique<InstructionSet>(Syscall::GetSyscall(), repeat, std::move(instructions),
61                                             list_key, item_key, access_order, reseeding, seed);
62   } else {
63     return std::make_unique<InstructionSet>(Syscall::GetSyscall(), repeat, std::move(instructions));
64   }
65 }
66 
CreateFromProtoInstruction(const std::list<int> & thread_ids,const dittosuiteproto::Instruction & proto_instruction)67 std::unique_ptr<Instruction> InstructionFactory::CreateFromProtoInstruction(
68     const std::list<int>& thread_ids, const dittosuiteproto::Instruction& proto_instruction) {
69   int repeat = proto_instruction.repeat();
70 
71   switch (proto_instruction.instruction_oneof_case()) {
72     case InstructionType::kInstructionSet: {
73       return InstructionFactory::CreateFromProtoInstructionSet(thread_ids, repeat,
74                                                                proto_instruction.instruction_set());
75     }
76     case InstructionType::kOpenFile: {
77       const auto& options = proto_instruction.open_file();
78 
79       int fd_key = -1;
80       if (options.has_output_fd()) {
81         fd_key = SharedVariables::GetKey(thread_ids, options.output_fd());
82       }
83 
84       dittosuite::OpenFile::AccessMode access_mode;
85       {
86         switch (options.access_mode()) {
87           case dittosuiteproto::AccessMode::READ_ONLY:
88             access_mode = OpenFile::AccessMode::kReadOnly;
89             break;
90           case dittosuiteproto::AccessMode::WRITE_ONLY:
91             access_mode = OpenFile::AccessMode::kWriteOnly;
92             break;
93           case dittosuiteproto::AccessMode::READ_WRITE:
94             access_mode = OpenFile::AccessMode::kReadWrite;
95             break;
96           default:
97             LOGF("Invalid instruction OpenFile access mode: it should be at least read or write");
98             break;
99         }
100       }
101 
102       if (options.has_input()) {
103         int input_key = SharedVariables::GetKey(thread_ids, options.input());
104         return std::make_unique<OpenFile>(Syscall::GetSyscall(), repeat, input_key,
105                                           options.create(), options.direct_io(), fd_key,
106                                           access_mode);
107       } else if (options.has_path_name()) {
108         return std::make_unique<OpenFile>(Syscall::GetSyscall(), repeat, options.path_name(),
109                                           options.create(), options.direct_io(), fd_key,
110                                           access_mode);
111       } else {
112         return std::make_unique<OpenFile>(Syscall::GetSyscall(), repeat, options.create(),
113                                           options.direct_io(), fd_key, access_mode);
114       }
115     }
116     case InstructionType::kDeleteFile: {
117       const auto& options = proto_instruction.delete_file();
118 
119       if (options.has_input()) {
120         int input_key = SharedVariables::GetKey(thread_ids, options.input());
121         return std::make_unique<DeleteFile>(Syscall::GetSyscall(), repeat, input_key);
122       } else {
123         return std::make_unique<DeleteFile>(Syscall::GetSyscall(), repeat, options.path_name());
124       }
125     }
126     case InstructionType::kCloseFile: {
127       const auto& options = proto_instruction.close_file();
128 
129       int fd_key = SharedVariables::GetKey(thread_ids, options.input_fd());
130 
131       return std::make_unique<CloseFile>(Syscall::GetSyscall(), repeat, fd_key);
132     }
133     case InstructionType::kResizeFile: {
134       const auto& options = proto_instruction.resize_file();
135 
136       int fd_key = SharedVariables::GetKey(thread_ids, options.input_fd());
137 
138       return std::make_unique<ResizeFile>(Syscall::GetSyscall(), repeat, options.size(), fd_key);
139     }
140     case InstructionType::kWriteFile: {
141       const auto& options = proto_instruction.write_file();
142 
143       auto access_order = ConvertOrder(options.access_order());
144 
145       uint32_t seed = options.seed();
146       if (!options.has_seed()) {
147         seed = time(nullptr);
148       }
149 
150       auto reseeding = ConvertReseeding(options.reseeding());
151       int fd_key = SharedVariables::GetKey(thread_ids, options.input_fd());
152 
153       return std::make_unique<WriteFile>(Syscall::GetSyscall(), repeat, options.size(),
154                                          options.block_size(), options.starting_offset(),
155                                          access_order, seed, reseeding, options.fsync(), fd_key);
156     }
157     case InstructionType::kReadFile: {
158       const auto& options = proto_instruction.read_file();
159 
160       auto access_order = ConvertOrder(options.access_order());
161 
162       uint32_t seed = options.seed();
163       if (!options.has_seed()) {
164         seed = time(nullptr);
165       }
166 
167       auto fadvise = ConvertReadFAdvise(access_order, options.fadvise());
168       auto reseeding = ConvertReseeding(options.reseeding());
169       int fd_key = SharedVariables::GetKey(thread_ids, options.input_fd());
170 
171       return std::make_unique<ReadFile>(Syscall::GetSyscall(), repeat, options.size(),
172                                         options.block_size(), options.starting_offset(),
173                                         access_order, seed, reseeding, fadvise, fd_key);
174     }
175     case InstructionType::kReadDirectory: {
176       const auto& options = proto_instruction.read_directory();
177 
178       int output_key = SharedVariables::GetKey(thread_ids, options.output());
179 
180       return std::make_unique<ReadDirectory>(Syscall::GetSyscall(), repeat,
181                                              options.directory_name(), output_key);
182     }
183     case InstructionType::kResizeFileRandom: {
184       const auto& options = proto_instruction.resize_file_random();
185 
186       uint32_t seed = options.seed();
187       if (!options.has_seed()) {
188         seed = time(nullptr);
189       }
190 
191       auto reseeding = ConvertReseeding(options.reseeding());
192       int fd_key = SharedVariables::GetKey(thread_ids, options.input_fd());
193 
194       return std::make_unique<ResizeFileRandom>(Syscall::GetSyscall(), repeat, options.min(),
195                                                 options.max(), seed, reseeding, fd_key);
196     }
197     case InstructionType::kMultithreading: {
198       const auto& options = proto_instruction.multithreading();
199 
200       std::vector<std::unique_ptr<Instruction>> instructions;
201       for (const auto& thread : options.threads()) {
202         for (int i = 0; i < thread.spawn(); i++) {
203           auto thread_ids_copy = thread_ids;
204           thread_ids_copy.push_back(InstructionFactory::GenerateThreadId());
205           instructions.push_back(std::move(InstructionFactory::CreateFromProtoInstruction(
206               thread_ids_copy, thread.instruction())));
207         }
208       }
209 
210       return std::make_unique<Multithreading>(Syscall::GetSyscall(), repeat,
211                                               std::move(instructions));
212     }
213     case InstructionType::kInvalidateCache: {
214       return std::make_unique<InvalidateCache>(Syscall::GetSyscall(), repeat);
215     }
216     case InstructionType::INSTRUCTION_ONEOF_NOT_SET: {
217       LOGF("Instruction was not set in .ditto file");
218     }
219     default: {
220       LOGF("Invalid instruction was set in .ditto file");
221     }
222   }
223 }
224 
GenerateThreadId()225 int InstructionFactory::GenerateThreadId() {
226   return current_thread_id_++;
227 }
228 
229 int InstructionFactory::current_thread_id_ = 0;
230 
ConvertReseeding(const dittosuiteproto::Reseeding proto_reseeding)231 Reseeding InstructionFactory::ConvertReseeding(const dittosuiteproto::Reseeding proto_reseeding) {
232   switch (proto_reseeding) {
233     case dittosuiteproto::Reseeding::ONCE: {
234       return Reseeding::kOnce;
235     }
236     case dittosuiteproto::Reseeding::EACH_ROUND_OF_CYCLES: {
237       return Reseeding::kEachRoundOfCycles;
238     }
239     case dittosuiteproto::Reseeding::EACH_CYCLE: {
240       return Reseeding::kEachCycle;
241     }
242     default: {
243       LOGF("Invalid Reseeding was provided");
244     }
245   }
246 }
247 
ConvertOrder(const dittosuiteproto::Order proto_order)248 Order InstructionFactory::ConvertOrder(const dittosuiteproto::Order proto_order) {
249   switch (proto_order) {
250     case dittosuiteproto::Order::SEQUENTIAL: {
251       return Order::kSequential;
252     }
253     case dittosuiteproto::Order::RANDOM: {
254       return Order::kRandom;
255     }
256     default: {
257       LOGF("Invalid Order was provided");
258     }
259   }
260 }
261 
ConvertReadFAdvise(const Order access_order,const dittosuiteproto::ReadFile_ReadFAdvise proto_fadvise)262 int InstructionFactory::ConvertReadFAdvise(
263     const Order access_order, const dittosuiteproto::ReadFile_ReadFAdvise proto_fadvise) {
264   switch (proto_fadvise) {
265     case dittosuiteproto::ReadFile_ReadFAdvise_AUTOMATIC: {
266       switch (access_order) {
267         case Order::kSequential: {
268           return POSIX_FADV_SEQUENTIAL;
269         }
270         case Order::kRandom: {
271           return POSIX_FADV_RANDOM;
272         }
273       }
274     }
275     case dittosuiteproto::ReadFile_ReadFAdvise_NORMAL: {
276       return POSIX_FADV_NORMAL;
277     }
278     case dittosuiteproto::ReadFile_ReadFAdvise_SEQUENTIAL: {
279       return POSIX_FADV_SEQUENTIAL;
280     }
281     case dittosuiteproto::ReadFile_ReadFAdvise_RANDOM: {
282       return POSIX_FADV_RANDOM;
283     }
284     default: {
285       LOGF("Invalid ReadFAdvise was provided");
286     }
287   }
288 }
289 
290 }  // namespace dittosuite
291