1*f40fafd4SAndroid Build Coastguard Worker /*
2*f40fafd4SAndroid Build Coastguard Worker * Copyright (C) 2020 The Android Open Source Project
3*f40fafd4SAndroid Build Coastguard Worker *
4*f40fafd4SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*f40fafd4SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*f40fafd4SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*f40fafd4SAndroid Build Coastguard Worker *
8*f40fafd4SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*f40fafd4SAndroid Build Coastguard Worker *
10*f40fafd4SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*f40fafd4SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*f40fafd4SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f40fafd4SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*f40fafd4SAndroid Build Coastguard Worker * limitations under the License.
15*f40fafd4SAndroid Build Coastguard Worker */
16*f40fafd4SAndroid Build Coastguard Worker #include <chrono>
17*f40fafd4SAndroid Build Coastguard Worker #include <functional>
18*f40fafd4SAndroid Build Coastguard Worker #include <iostream>
19*f40fafd4SAndroid Build Coastguard Worker #include <ratio>
20*f40fafd4SAndroid Build Coastguard Worker #include <sstream>
21*f40fafd4SAndroid Build Coastguard Worker #include <string>
22*f40fafd4SAndroid Build Coastguard Worker #include <unordered_map>
23*f40fafd4SAndroid Build Coastguard Worker #include <vector>
24*f40fafd4SAndroid Build Coastguard Worker
25*f40fafd4SAndroid Build Coastguard Worker #include <dirent.h>
26*f40fafd4SAndroid Build Coastguard Worker #include <fcntl.h>
27*f40fafd4SAndroid Build Coastguard Worker #include <stdlib.h>
28*f40fafd4SAndroid Build Coastguard Worker #include <sys/stat.h>
29*f40fafd4SAndroid Build Coastguard Worker #include <sys/types.h>
30*f40fafd4SAndroid Build Coastguard Worker #include <unistd.h>
31*f40fafd4SAndroid Build Coastguard Worker
32*f40fafd4SAndroid Build Coastguard Worker static constexpr char VERSION[] = "0";
33*f40fafd4SAndroid Build Coastguard Worker
34*f40fafd4SAndroid Build Coastguard Worker // Self-contained class for collecting and reporting benchmark metrics
35*f40fafd4SAndroid Build Coastguard Worker // (currently only execution time).
36*f40fafd4SAndroid Build Coastguard Worker class Collector {
37*f40fafd4SAndroid Build Coastguard Worker using time_point = std::chrono::time_point<std::chrono::steady_clock>;
38*f40fafd4SAndroid Build Coastguard Worker using time_unit = std::chrono::duration<double, std::milli>;
39*f40fafd4SAndroid Build Coastguard Worker
40*f40fafd4SAndroid Build Coastguard Worker struct Metric {
41*f40fafd4SAndroid Build Coastguard Worker std::string workload;
42*f40fafd4SAndroid Build Coastguard Worker time_unit exec_time;
MetricCollector::Metric43*f40fafd4SAndroid Build Coastguard Worker Metric(const std::string& workload, const time_unit& exec_time)
44*f40fafd4SAndroid Build Coastguard Worker : workload(workload), exec_time(exec_time) {}
45*f40fafd4SAndroid Build Coastguard Worker };
46*f40fafd4SAndroid Build Coastguard Worker
47*f40fafd4SAndroid Build Coastguard Worker static constexpr char TIME_UNIT[] = "ms";
48*f40fafd4SAndroid Build Coastguard Worker static constexpr char VERSION[] = "0";
49*f40fafd4SAndroid Build Coastguard Worker std::vector<Metric> metrics;
50*f40fafd4SAndroid Build Coastguard Worker time_point reset_time;
51*f40fafd4SAndroid Build Coastguard Worker
52*f40fafd4SAndroid Build Coastguard Worker public:
Collector()53*f40fafd4SAndroid Build Coastguard Worker Collector() { reset(); }
54*f40fafd4SAndroid Build Coastguard Worker
reset()55*f40fafd4SAndroid Build Coastguard Worker void reset() { reset_time = std::chrono::steady_clock::now(); }
56*f40fafd4SAndroid Build Coastguard Worker
collect_metric(const std::string & workload)57*f40fafd4SAndroid Build Coastguard Worker void collect_metric(const std::string& workload) {
58*f40fafd4SAndroid Build Coastguard Worker auto elapsed = std::chrono::steady_clock::now() - reset_time;
59*f40fafd4SAndroid Build Coastguard Worker metrics.emplace_back(workload, std::chrono::duration_cast<time_unit>(elapsed));
60*f40fafd4SAndroid Build Coastguard Worker }
61*f40fafd4SAndroid Build Coastguard Worker
report_metrics()62*f40fafd4SAndroid Build Coastguard Worker void report_metrics() {
63*f40fafd4SAndroid Build Coastguard Worker for (const Metric& metric : metrics)
64*f40fafd4SAndroid Build Coastguard Worker std::cout << VERSION << ";" << metric.workload << ";" << metric.exec_time.count() << ";"
65*f40fafd4SAndroid Build Coastguard Worker << TIME_UNIT << std::endl;
66*f40fafd4SAndroid Build Coastguard Worker }
67*f40fafd4SAndroid Build Coastguard Worker };
68*f40fafd4SAndroid Build Coastguard Worker
69*f40fafd4SAndroid Build Coastguard Worker struct Command {
70*f40fafd4SAndroid Build Coastguard Worker static constexpr char CREATE[] = "create";
71*f40fafd4SAndroid Build Coastguard Worker static constexpr char DELETE[] = "delete";
72*f40fafd4SAndroid Build Coastguard Worker static constexpr char MOVE[] = "move";
73*f40fafd4SAndroid Build Coastguard Worker static constexpr char HARDLINK[] = "hardlink";
74*f40fafd4SAndroid Build Coastguard Worker static constexpr char SYMLINK[] = "symlink";
75*f40fafd4SAndroid Build Coastguard Worker static constexpr char READDIR[] = "readdir";
76*f40fafd4SAndroid Build Coastguard Worker std::string workload;
77*f40fafd4SAndroid Build Coastguard Worker std::string from_dir;
78*f40fafd4SAndroid Build Coastguard Worker std::string from_basename;
79*f40fafd4SAndroid Build Coastguard Worker std::string to_dir;
80*f40fafd4SAndroid Build Coastguard Worker std::string to_basename;
81*f40fafd4SAndroid Build Coastguard Worker bool drop_state;
82*f40fafd4SAndroid Build Coastguard Worker int n_file;
83*f40fafd4SAndroid Build Coastguard Worker
CommandCommand84*f40fafd4SAndroid Build Coastguard Worker Command() { reset(); }
85*f40fafd4SAndroid Build Coastguard Worker
to_stringCommand86*f40fafd4SAndroid Build Coastguard Worker std::string to_string() const {
87*f40fafd4SAndroid Build Coastguard Worker std::stringstream string_repr;
88*f40fafd4SAndroid Build Coastguard Worker string_repr << "Command {\n";
89*f40fafd4SAndroid Build Coastguard Worker string_repr << "\t.workload = " << workload << ",\n";
90*f40fafd4SAndroid Build Coastguard Worker string_repr << "\t.from_dir = " << from_dir << ",\n";
91*f40fafd4SAndroid Build Coastguard Worker string_repr << "\t.from_basename = " << from_basename << ",\n";
92*f40fafd4SAndroid Build Coastguard Worker string_repr << "\t.to_dir = " << to_dir << ",\n";
93*f40fafd4SAndroid Build Coastguard Worker string_repr << "\t.to_basename = " << to_basename << ",\n";
94*f40fafd4SAndroid Build Coastguard Worker string_repr << "\t.drop_state = " << drop_state << ",\n";
95*f40fafd4SAndroid Build Coastguard Worker string_repr << "\t.n_file = " << n_file << "\n";
96*f40fafd4SAndroid Build Coastguard Worker string_repr << "}\n";
97*f40fafd4SAndroid Build Coastguard Worker return string_repr.str();
98*f40fafd4SAndroid Build Coastguard Worker }
99*f40fafd4SAndroid Build Coastguard Worker
resetCommand100*f40fafd4SAndroid Build Coastguard Worker void reset() {
101*f40fafd4SAndroid Build Coastguard Worker workload = "";
102*f40fafd4SAndroid Build Coastguard Worker from_dir = to_dir = "./";
103*f40fafd4SAndroid Build Coastguard Worker from_basename = "from_file";
104*f40fafd4SAndroid Build Coastguard Worker to_basename = "to_file";
105*f40fafd4SAndroid Build Coastguard Worker drop_state = true;
106*f40fafd4SAndroid Build Coastguard Worker n_file = 0;
107*f40fafd4SAndroid Build Coastguard Worker }
108*f40fafd4SAndroid Build Coastguard Worker };
109*f40fafd4SAndroid Build Coastguard Worker
print_version()110*f40fafd4SAndroid Build Coastguard Worker void print_version() {
111*f40fafd4SAndroid Build Coastguard Worker std::cout << VERSION << std::endl;
112*f40fafd4SAndroid Build Coastguard Worker }
113*f40fafd4SAndroid Build Coastguard Worker
print_commands(const std::vector<Command> & commands)114*f40fafd4SAndroid Build Coastguard Worker void print_commands(const std::vector<Command>& commands) {
115*f40fafd4SAndroid Build Coastguard Worker for (const Command& command : commands) std::cout << command.to_string();
116*f40fafd4SAndroid Build Coastguard Worker }
117*f40fafd4SAndroid Build Coastguard Worker
usage(std::ostream & ostr,const std::string & program_name)118*f40fafd4SAndroid Build Coastguard Worker void usage(std::ostream& ostr, const std::string& program_name) {
119*f40fafd4SAndroid Build Coastguard Worker Command command;
120*f40fafd4SAndroid Build Coastguard Worker
121*f40fafd4SAndroid Build Coastguard Worker ostr << "Usage: " << program_name << " [global_options] {[workload_options] -w WORKLOAD_T}\n";
122*f40fafd4SAndroid Build Coastguard Worker ostr << "WORKLOAD_T = {" << Command::CREATE << ", " << Command::DELETE << ", " << Command::MOVE
123*f40fafd4SAndroid Build Coastguard Worker << ", " << Command::HARDLINK << ", " << Command::SYMLINK << "}\n";
124*f40fafd4SAndroid Build Coastguard Worker ostr << "Global options\n";
125*f40fafd4SAndroid Build Coastguard Worker ostr << "\t-v: Print version.\n";
126*f40fafd4SAndroid Build Coastguard Worker ostr << "\t-p: Print parsed workloads and exit.\n";
127*f40fafd4SAndroid Build Coastguard Worker ostr << "Workload options\n";
128*f40fafd4SAndroid Build Coastguard Worker ostr << "\t-d DIR\t\t: Work directory for " << Command::CREATE << "/" << Command::DELETE
129*f40fafd4SAndroid Build Coastguard Worker << " (default '" << command.from_dir << "').\n";
130*f40fafd4SAndroid Build Coastguard Worker ostr << "\t-f FROM-DIR\t: Source directory for " << Command::MOVE << "/" << Command::SYMLINK
131*f40fafd4SAndroid Build Coastguard Worker << "/" << Command::HARDLINK << " (default '" << command.from_dir << "').\n";
132*f40fafd4SAndroid Build Coastguard Worker ostr << "\t-t TO-DIR\t: Destination directory for " << Command::MOVE << "/" << Command::SYMLINK
133*f40fafd4SAndroid Build Coastguard Worker << "/" << Command::HARDLINK << " (default '" << command.to_dir << "').\n";
134*f40fafd4SAndroid Build Coastguard Worker ostr << "\t-n N_FILES\t: Number of files to create/delete etc. (default " << command.n_file
135*f40fafd4SAndroid Build Coastguard Worker << ").\n";
136*f40fafd4SAndroid Build Coastguard Worker ostr << "\t-s\t\t: Do not drop state (caches) before running the workload (default "
137*f40fafd4SAndroid Build Coastguard Worker << !command.drop_state << ").\n";
138*f40fafd4SAndroid Build Coastguard Worker ostr << "NOTE: -w WORKLOAD_T defines a new command and must come after its workload_options."
139*f40fafd4SAndroid Build Coastguard Worker << std::endl;
140*f40fafd4SAndroid Build Coastguard Worker }
141*f40fafd4SAndroid Build Coastguard Worker
drop_state()142*f40fafd4SAndroid Build Coastguard Worker void drop_state() {
143*f40fafd4SAndroid Build Coastguard Worker // Drop inode/dentry/page caches.
144*f40fafd4SAndroid Build Coastguard Worker std::system("sync; echo 3 > /proc/sys/vm/drop_caches");
145*f40fafd4SAndroid Build Coastguard Worker }
146*f40fafd4SAndroid Build Coastguard Worker
147*f40fafd4SAndroid Build Coastguard Worker static constexpr int OPEN_DIR_FLAGS = O_RDONLY | O_DIRECTORY | O_PATH | O_CLOEXEC;
148*f40fafd4SAndroid Build Coastguard Worker
delete_files(const std::string & dir,int n_file,const std::string & basename)149*f40fafd4SAndroid Build Coastguard Worker bool delete_files(const std::string& dir, int n_file, const std::string& basename) {
150*f40fafd4SAndroid Build Coastguard Worker int dir_fd = open(dir.c_str(), OPEN_DIR_FLAGS);
151*f40fafd4SAndroid Build Coastguard Worker if (dir_fd == -1) {
152*f40fafd4SAndroid Build Coastguard Worker int error = errno;
153*f40fafd4SAndroid Build Coastguard Worker std::cerr << "Failed to open work directory '" << dir << "', error '" << strerror(error)
154*f40fafd4SAndroid Build Coastguard Worker << "'." << std::endl;
155*f40fafd4SAndroid Build Coastguard Worker return false;
156*f40fafd4SAndroid Build Coastguard Worker }
157*f40fafd4SAndroid Build Coastguard Worker
158*f40fafd4SAndroid Build Coastguard Worker bool ret = true;
159*f40fafd4SAndroid Build Coastguard Worker for (int i = 0; i < n_file; i++) {
160*f40fafd4SAndroid Build Coastguard Worker std::string filename = basename + std::to_string(i);
161*f40fafd4SAndroid Build Coastguard Worker ret = ret && (unlinkat(dir_fd, filename.c_str(), 0) == 0);
162*f40fafd4SAndroid Build Coastguard Worker }
163*f40fafd4SAndroid Build Coastguard Worker
164*f40fafd4SAndroid Build Coastguard Worker if (!ret) std::cerr << "Failed to delete at least one of the files" << std::endl;
165*f40fafd4SAndroid Build Coastguard Worker close(dir_fd);
166*f40fafd4SAndroid Build Coastguard Worker return ret;
167*f40fafd4SAndroid Build Coastguard Worker }
168*f40fafd4SAndroid Build Coastguard Worker
create_files(const std::string & dir,int n_file,const std::string & basename)169*f40fafd4SAndroid Build Coastguard Worker bool create_files(const std::string& dir, int n_file, const std::string& basename) {
170*f40fafd4SAndroid Build Coastguard Worker int dir_fd = open(dir.c_str(), OPEN_DIR_FLAGS);
171*f40fafd4SAndroid Build Coastguard Worker if (dir_fd == -1) {
172*f40fafd4SAndroid Build Coastguard Worker int error = errno;
173*f40fafd4SAndroid Build Coastguard Worker std::cerr << "Failed to open work directory '" << dir << "', error '" << strerror(error)
174*f40fafd4SAndroid Build Coastguard Worker << "'." << std::endl;
175*f40fafd4SAndroid Build Coastguard Worker return false;
176*f40fafd4SAndroid Build Coastguard Worker }
177*f40fafd4SAndroid Build Coastguard Worker
178*f40fafd4SAndroid Build Coastguard Worker bool ret = true;
179*f40fafd4SAndroid Build Coastguard Worker for (int i = 0; i < n_file; i++) {
180*f40fafd4SAndroid Build Coastguard Worker std::string filename = basename + std::to_string(i);
181*f40fafd4SAndroid Build Coastguard Worker int fd = openat(dir_fd, filename.c_str(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0777);
182*f40fafd4SAndroid Build Coastguard Worker ret = ret && fd != -1;
183*f40fafd4SAndroid Build Coastguard Worker close(fd);
184*f40fafd4SAndroid Build Coastguard Worker }
185*f40fafd4SAndroid Build Coastguard Worker
186*f40fafd4SAndroid Build Coastguard Worker close(dir_fd);
187*f40fafd4SAndroid Build Coastguard Worker if (!ret) {
188*f40fafd4SAndroid Build Coastguard Worker std::cerr << "Failed to open at least one of the files" << std::endl;
189*f40fafd4SAndroid Build Coastguard Worker delete_files(dir, n_file, basename);
190*f40fafd4SAndroid Build Coastguard Worker }
191*f40fafd4SAndroid Build Coastguard Worker return ret;
192*f40fafd4SAndroid Build Coastguard Worker }
193*f40fafd4SAndroid Build Coastguard Worker
move_files(const std::string & from_dir,const std::string & to_dir,int n_file,const std::string & from_basename,const std::string & to_basename)194*f40fafd4SAndroid Build Coastguard Worker bool move_files(const std::string& from_dir, const std::string& to_dir, int n_file,
195*f40fafd4SAndroid Build Coastguard Worker const std::string& from_basename, const std::string& to_basename) {
196*f40fafd4SAndroid Build Coastguard Worker int from_dir_fd = open(from_dir.c_str(), OPEN_DIR_FLAGS);
197*f40fafd4SAndroid Build Coastguard Worker if (from_dir_fd == -1) {
198*f40fafd4SAndroid Build Coastguard Worker int error = errno;
199*f40fafd4SAndroid Build Coastguard Worker std::cerr << "Failed to open source directory '" << from_dir << "', error '"
200*f40fafd4SAndroid Build Coastguard Worker << strerror(error) << "'." << std::endl;
201*f40fafd4SAndroid Build Coastguard Worker return false;
202*f40fafd4SAndroid Build Coastguard Worker }
203*f40fafd4SAndroid Build Coastguard Worker int to_dir_fd = open(to_dir.c_str(), OPEN_DIR_FLAGS);
204*f40fafd4SAndroid Build Coastguard Worker if (to_dir_fd == -1) {
205*f40fafd4SAndroid Build Coastguard Worker int error = errno;
206*f40fafd4SAndroid Build Coastguard Worker std::cerr << "Failed to open destination directory '" << to_dir << "', error '"
207*f40fafd4SAndroid Build Coastguard Worker << strerror(error) << "'." << std::endl;
208*f40fafd4SAndroid Build Coastguard Worker close(from_dir_fd);
209*f40fafd4SAndroid Build Coastguard Worker return false;
210*f40fafd4SAndroid Build Coastguard Worker }
211*f40fafd4SAndroid Build Coastguard Worker
212*f40fafd4SAndroid Build Coastguard Worker bool ret = true;
213*f40fafd4SAndroid Build Coastguard Worker for (int i = 0; i < n_file; i++) {
214*f40fafd4SAndroid Build Coastguard Worker std::string from_filename = from_basename + std::to_string(i);
215*f40fafd4SAndroid Build Coastguard Worker std::string to_filename = to_basename + std::to_string(i);
216*f40fafd4SAndroid Build Coastguard Worker ret = ret &&
217*f40fafd4SAndroid Build Coastguard Worker (renameat(from_dir_fd, from_filename.c_str(), to_dir_fd, to_filename.c_str()) == 0);
218*f40fafd4SAndroid Build Coastguard Worker }
219*f40fafd4SAndroid Build Coastguard Worker
220*f40fafd4SAndroid Build Coastguard Worker if (!ret) std::cerr << "Failed to move at least one of the files" << std::endl;
221*f40fafd4SAndroid Build Coastguard Worker close(from_dir_fd);
222*f40fafd4SAndroid Build Coastguard Worker close(from_dir_fd);
223*f40fafd4SAndroid Build Coastguard Worker return ret;
224*f40fafd4SAndroid Build Coastguard Worker }
225*f40fafd4SAndroid Build Coastguard Worker
hardlink_files(const std::string & from_dir,const std::string & to_dir,int n_file,const std::string & from_basename,const std::string & to_basename)226*f40fafd4SAndroid Build Coastguard Worker bool hardlink_files(const std::string& from_dir, const std::string& to_dir, int n_file,
227*f40fafd4SAndroid Build Coastguard Worker const std::string& from_basename, const std::string& to_basename) {
228*f40fafd4SAndroid Build Coastguard Worker int from_dir_fd = open(from_dir.c_str(), OPEN_DIR_FLAGS);
229*f40fafd4SAndroid Build Coastguard Worker if (from_dir_fd == -1) {
230*f40fafd4SAndroid Build Coastguard Worker int error = errno;
231*f40fafd4SAndroid Build Coastguard Worker std::cerr << "Failed to open source directory '" << from_dir << "', error '"
232*f40fafd4SAndroid Build Coastguard Worker << strerror(error) << "'." << std::endl;
233*f40fafd4SAndroid Build Coastguard Worker return false;
234*f40fafd4SAndroid Build Coastguard Worker }
235*f40fafd4SAndroid Build Coastguard Worker int to_dir_fd = open(to_dir.c_str(), OPEN_DIR_FLAGS);
236*f40fafd4SAndroid Build Coastguard Worker if (to_dir_fd == -1) {
237*f40fafd4SAndroid Build Coastguard Worker int error = errno;
238*f40fafd4SAndroid Build Coastguard Worker std::cerr << "Failed to open destination directory '" << to_dir << "', error '"
239*f40fafd4SAndroid Build Coastguard Worker << strerror(error) << "'." << std::endl;
240*f40fafd4SAndroid Build Coastguard Worker close(from_dir_fd);
241*f40fafd4SAndroid Build Coastguard Worker return false;
242*f40fafd4SAndroid Build Coastguard Worker }
243*f40fafd4SAndroid Build Coastguard Worker
244*f40fafd4SAndroid Build Coastguard Worker bool ret = true;
245*f40fafd4SAndroid Build Coastguard Worker for (int i = 0; i < n_file; i++) {
246*f40fafd4SAndroid Build Coastguard Worker std::string from_filename = from_basename + std::to_string(i);
247*f40fafd4SAndroid Build Coastguard Worker std::string to_filename = to_basename + std::to_string(i);
248*f40fafd4SAndroid Build Coastguard Worker ret = ret &&
249*f40fafd4SAndroid Build Coastguard Worker (linkat(from_dir_fd, from_filename.c_str(), to_dir_fd, to_filename.c_str(), 0) == 0);
250*f40fafd4SAndroid Build Coastguard Worker }
251*f40fafd4SAndroid Build Coastguard Worker
252*f40fafd4SAndroid Build Coastguard Worker if (!ret) std::cerr << "Failed to hardlink at least one of the files" << std::endl;
253*f40fafd4SAndroid Build Coastguard Worker close(from_dir_fd);
254*f40fafd4SAndroid Build Coastguard Worker close(to_dir_fd);
255*f40fafd4SAndroid Build Coastguard Worker return ret;
256*f40fafd4SAndroid Build Coastguard Worker }
257*f40fafd4SAndroid Build Coastguard Worker
symlink_files(std::string from_dir,const std::string & to_dir,int n_file,const std::string & from_basename,const std::string & to_basename)258*f40fafd4SAndroid Build Coastguard Worker bool symlink_files(std::string from_dir, const std::string& to_dir, int n_file,
259*f40fafd4SAndroid Build Coastguard Worker const std::string& from_basename, const std::string& to_basename) {
260*f40fafd4SAndroid Build Coastguard Worker if (from_dir.back() != '/') from_dir.push_back('/');
261*f40fafd4SAndroid Build Coastguard Worker int to_dir_fd = open(to_dir.c_str(), OPEN_DIR_FLAGS);
262*f40fafd4SAndroid Build Coastguard Worker if (to_dir_fd == -1) {
263*f40fafd4SAndroid Build Coastguard Worker int error = errno;
264*f40fafd4SAndroid Build Coastguard Worker std::cerr << "Failed to open destination directory '" << to_dir << "', error '"
265*f40fafd4SAndroid Build Coastguard Worker << strerror(error) << "'." << std::endl;
266*f40fafd4SAndroid Build Coastguard Worker return false;
267*f40fafd4SAndroid Build Coastguard Worker }
268*f40fafd4SAndroid Build Coastguard Worker
269*f40fafd4SAndroid Build Coastguard Worker bool ret = true;
270*f40fafd4SAndroid Build Coastguard Worker for (int i = 0; i < n_file; i++) {
271*f40fafd4SAndroid Build Coastguard Worker std::string from_filepath = from_dir + from_basename + std::to_string(i);
272*f40fafd4SAndroid Build Coastguard Worker std::string to_filename = to_basename + std::to_string(i);
273*f40fafd4SAndroid Build Coastguard Worker ret = ret && (symlinkat(from_filepath.c_str(), to_dir_fd, to_filename.c_str()) == 0);
274*f40fafd4SAndroid Build Coastguard Worker }
275*f40fafd4SAndroid Build Coastguard Worker
276*f40fafd4SAndroid Build Coastguard Worker if (!ret) std::cerr << "Failed to symlink at least one of the files" << std::endl;
277*f40fafd4SAndroid Build Coastguard Worker close(to_dir_fd);
278*f40fafd4SAndroid Build Coastguard Worker return ret;
279*f40fafd4SAndroid Build Coastguard Worker }
280*f40fafd4SAndroid Build Coastguard Worker
exhaustive_readdir(const std::string & from_dir)281*f40fafd4SAndroid Build Coastguard Worker bool exhaustive_readdir(const std::string& from_dir) {
282*f40fafd4SAndroid Build Coastguard Worker DIR* dir = opendir(from_dir.c_str());
283*f40fafd4SAndroid Build Coastguard Worker if (dir == nullptr) {
284*f40fafd4SAndroid Build Coastguard Worker int error = errno;
285*f40fafd4SAndroid Build Coastguard Worker std::cerr << "Failed to open working directory '" << from_dir << "', error '"
286*f40fafd4SAndroid Build Coastguard Worker << strerror(error) << "'." << std::endl;
287*f40fafd4SAndroid Build Coastguard Worker return false;
288*f40fafd4SAndroid Build Coastguard Worker }
289*f40fafd4SAndroid Build Coastguard Worker
290*f40fafd4SAndroid Build Coastguard Worker errno = 0;
291*f40fafd4SAndroid Build Coastguard Worker while (readdir(dir) != nullptr)
292*f40fafd4SAndroid Build Coastguard Worker ;
293*f40fafd4SAndroid Build Coastguard Worker // In case of failure readdir returns nullptr and sets errno accordingly (to
294*f40fafd4SAndroid Build Coastguard Worker // something != 0).
295*f40fafd4SAndroid Build Coastguard Worker // In case of success readdir != nullptr and errno is not changed.
296*f40fafd4SAndroid Build Coastguard Worker // Source: man 3 readdir.
297*f40fafd4SAndroid Build Coastguard Worker bool ret = errno == 0;
298*f40fafd4SAndroid Build Coastguard Worker closedir(dir);
299*f40fafd4SAndroid Build Coastguard Worker return ret;
300*f40fafd4SAndroid Build Coastguard Worker }
301*f40fafd4SAndroid Build Coastguard Worker
create_workload(Collector * collector,const Command & command)302*f40fafd4SAndroid Build Coastguard Worker void create_workload(Collector* collector, const Command& command) {
303*f40fafd4SAndroid Build Coastguard Worker if (command.drop_state) drop_state();
304*f40fafd4SAndroid Build Coastguard Worker collector->reset();
305*f40fafd4SAndroid Build Coastguard Worker if (create_files(command.from_dir, command.n_file, command.from_basename))
306*f40fafd4SAndroid Build Coastguard Worker collector->collect_metric(command.workload);
307*f40fafd4SAndroid Build Coastguard Worker
308*f40fafd4SAndroid Build Coastguard Worker delete_files(command.from_dir, command.n_file, command.from_basename);
309*f40fafd4SAndroid Build Coastguard Worker }
310*f40fafd4SAndroid Build Coastguard Worker
delete_workload(Collector * collector,const Command & command)311*f40fafd4SAndroid Build Coastguard Worker void delete_workload(Collector* collector, const Command& command) {
312*f40fafd4SAndroid Build Coastguard Worker if (!create_files(command.from_dir, command.n_file, command.from_basename)) return;
313*f40fafd4SAndroid Build Coastguard Worker
314*f40fafd4SAndroid Build Coastguard Worker if (command.drop_state) drop_state();
315*f40fafd4SAndroid Build Coastguard Worker collector->reset();
316*f40fafd4SAndroid Build Coastguard Worker if (delete_files(command.from_dir, command.n_file, command.from_basename))
317*f40fafd4SAndroid Build Coastguard Worker collector->collect_metric(command.workload);
318*f40fafd4SAndroid Build Coastguard Worker }
319*f40fafd4SAndroid Build Coastguard Worker
move_workload(Collector * collector,const Command & command)320*f40fafd4SAndroid Build Coastguard Worker void move_workload(Collector* collector, const Command& command) {
321*f40fafd4SAndroid Build Coastguard Worker if (!create_files(command.from_dir, command.n_file, command.from_basename)) return;
322*f40fafd4SAndroid Build Coastguard Worker
323*f40fafd4SAndroid Build Coastguard Worker if (command.drop_state) drop_state();
324*f40fafd4SAndroid Build Coastguard Worker collector->reset();
325*f40fafd4SAndroid Build Coastguard Worker if (move_files(command.from_dir, command.to_dir, command.n_file, command.from_basename,
326*f40fafd4SAndroid Build Coastguard Worker command.to_basename))
327*f40fafd4SAndroid Build Coastguard Worker collector->collect_metric(command.workload);
328*f40fafd4SAndroid Build Coastguard Worker
329*f40fafd4SAndroid Build Coastguard Worker delete_files(command.to_dir, command.n_file, command.to_basename);
330*f40fafd4SAndroid Build Coastguard Worker }
331*f40fafd4SAndroid Build Coastguard Worker
hardlink_workload(Collector * collector,const Command & command)332*f40fafd4SAndroid Build Coastguard Worker void hardlink_workload(Collector* collector, const Command& command) {
333*f40fafd4SAndroid Build Coastguard Worker if (!create_files(command.from_dir, command.n_file, command.from_basename)) return;
334*f40fafd4SAndroid Build Coastguard Worker
335*f40fafd4SAndroid Build Coastguard Worker if (command.drop_state) drop_state();
336*f40fafd4SAndroid Build Coastguard Worker collector->reset();
337*f40fafd4SAndroid Build Coastguard Worker if (hardlink_files(command.from_dir, command.to_dir, command.n_file, command.from_basename,
338*f40fafd4SAndroid Build Coastguard Worker command.to_basename))
339*f40fafd4SAndroid Build Coastguard Worker collector->collect_metric(command.workload);
340*f40fafd4SAndroid Build Coastguard Worker
341*f40fafd4SAndroid Build Coastguard Worker delete_files(command.from_dir, command.n_file, command.from_basename);
342*f40fafd4SAndroid Build Coastguard Worker delete_files(command.to_dir, command.n_file, command.to_basename);
343*f40fafd4SAndroid Build Coastguard Worker }
344*f40fafd4SAndroid Build Coastguard Worker
symlink_workload(Collector * collector,const Command & command)345*f40fafd4SAndroid Build Coastguard Worker void symlink_workload(Collector* collector, const Command& command) {
346*f40fafd4SAndroid Build Coastguard Worker if (!create_files(command.from_dir, command.n_file, command.from_basename)) return;
347*f40fafd4SAndroid Build Coastguard Worker
348*f40fafd4SAndroid Build Coastguard Worker if (command.drop_state) drop_state();
349*f40fafd4SAndroid Build Coastguard Worker collector->reset();
350*f40fafd4SAndroid Build Coastguard Worker if (symlink_files(command.from_dir, command.to_dir, command.n_file, command.from_basename,
351*f40fafd4SAndroid Build Coastguard Worker command.to_basename))
352*f40fafd4SAndroid Build Coastguard Worker collector->collect_metric(command.workload);
353*f40fafd4SAndroid Build Coastguard Worker
354*f40fafd4SAndroid Build Coastguard Worker delete_files(command.to_dir, command.n_file, command.to_basename);
355*f40fafd4SAndroid Build Coastguard Worker delete_files(command.from_dir, command.n_file, command.from_basename);
356*f40fafd4SAndroid Build Coastguard Worker }
357*f40fafd4SAndroid Build Coastguard Worker
readdir_workload(Collector * collector,const Command & command)358*f40fafd4SAndroid Build Coastguard Worker void readdir_workload(Collector* collector, const Command& command) {
359*f40fafd4SAndroid Build Coastguard Worker if (!create_files(command.from_dir, command.n_file, command.from_basename)) return;
360*f40fafd4SAndroid Build Coastguard Worker
361*f40fafd4SAndroid Build Coastguard Worker if (command.drop_state) drop_state();
362*f40fafd4SAndroid Build Coastguard Worker collector->reset();
363*f40fafd4SAndroid Build Coastguard Worker if (exhaustive_readdir(command.from_dir)) collector->collect_metric(command.workload);
364*f40fafd4SAndroid Build Coastguard Worker
365*f40fafd4SAndroid Build Coastguard Worker delete_files(command.from_dir, command.n_file, command.from_basename);
366*f40fafd4SAndroid Build Coastguard Worker }
367*f40fafd4SAndroid Build Coastguard Worker
368*f40fafd4SAndroid Build Coastguard Worker using workload_executor_t = std::function<void(Collector*, const Command&)>;
369*f40fafd4SAndroid Build Coastguard Worker
370*f40fafd4SAndroid Build Coastguard Worker std::unordered_map<std::string, workload_executor_t> executors = {
371*f40fafd4SAndroid Build Coastguard Worker {Command::CREATE, create_workload}, {Command::DELETE, delete_workload},
372*f40fafd4SAndroid Build Coastguard Worker {Command::MOVE, move_workload}, {Command::HARDLINK, hardlink_workload},
373*f40fafd4SAndroid Build Coastguard Worker {Command::SYMLINK, symlink_workload}, {Command::READDIR, readdir_workload}};
374*f40fafd4SAndroid Build Coastguard Worker
main(int argc,char ** argv)375*f40fafd4SAndroid Build Coastguard Worker int main(int argc, char** argv) {
376*f40fafd4SAndroid Build Coastguard Worker std::vector<Command> commands;
377*f40fafd4SAndroid Build Coastguard Worker Command command;
378*f40fafd4SAndroid Build Coastguard Worker int opt;
379*f40fafd4SAndroid Build Coastguard Worker
380*f40fafd4SAndroid Build Coastguard Worker while ((opt = getopt(argc, argv, "hvpsw:d:f:t:n:")) != -1) {
381*f40fafd4SAndroid Build Coastguard Worker switch (opt) {
382*f40fafd4SAndroid Build Coastguard Worker case 'h':
383*f40fafd4SAndroid Build Coastguard Worker usage(std::cout, argv[0]);
384*f40fafd4SAndroid Build Coastguard Worker return EXIT_SUCCESS;
385*f40fafd4SAndroid Build Coastguard Worker case 'v':
386*f40fafd4SAndroid Build Coastguard Worker print_version();
387*f40fafd4SAndroid Build Coastguard Worker return EXIT_SUCCESS;
388*f40fafd4SAndroid Build Coastguard Worker case 'p':
389*f40fafd4SAndroid Build Coastguard Worker print_commands(commands);
390*f40fafd4SAndroid Build Coastguard Worker return EXIT_SUCCESS;
391*f40fafd4SAndroid Build Coastguard Worker case 's':
392*f40fafd4SAndroid Build Coastguard Worker command.drop_state = false;
393*f40fafd4SAndroid Build Coastguard Worker break;
394*f40fafd4SAndroid Build Coastguard Worker case 'w':
395*f40fafd4SAndroid Build Coastguard Worker command.workload = optarg;
396*f40fafd4SAndroid Build Coastguard Worker commands.push_back(command);
397*f40fafd4SAndroid Build Coastguard Worker command.reset();
398*f40fafd4SAndroid Build Coastguard Worker break;
399*f40fafd4SAndroid Build Coastguard Worker case 'd':
400*f40fafd4SAndroid Build Coastguard Worker case 'f':
401*f40fafd4SAndroid Build Coastguard Worker command.from_dir = optarg;
402*f40fafd4SAndroid Build Coastguard Worker break;
403*f40fafd4SAndroid Build Coastguard Worker case 't':
404*f40fafd4SAndroid Build Coastguard Worker command.to_dir = optarg;
405*f40fafd4SAndroid Build Coastguard Worker break;
406*f40fafd4SAndroid Build Coastguard Worker case 'n':
407*f40fafd4SAndroid Build Coastguard Worker command.n_file = std::stoi(optarg);
408*f40fafd4SAndroid Build Coastguard Worker break;
409*f40fafd4SAndroid Build Coastguard Worker default:
410*f40fafd4SAndroid Build Coastguard Worker usage(std::cerr, argv[0]);
411*f40fafd4SAndroid Build Coastguard Worker return EXIT_FAILURE;
412*f40fafd4SAndroid Build Coastguard Worker }
413*f40fafd4SAndroid Build Coastguard Worker }
414*f40fafd4SAndroid Build Coastguard Worker
415*f40fafd4SAndroid Build Coastguard Worker Collector collector;
416*f40fafd4SAndroid Build Coastguard Worker for (const Command& command : commands) {
417*f40fafd4SAndroid Build Coastguard Worker auto executor = executors.find(command.workload);
418*f40fafd4SAndroid Build Coastguard Worker if (executor == executors.end()) continue;
419*f40fafd4SAndroid Build Coastguard Worker executor->second(&collector, command);
420*f40fafd4SAndroid Build Coastguard Worker }
421*f40fafd4SAndroid Build Coastguard Worker collector.report_metrics();
422*f40fafd4SAndroid Build Coastguard Worker
423*f40fafd4SAndroid Build Coastguard Worker return EXIT_SUCCESS;
424*f40fafd4SAndroid Build Coastguard Worker }
425