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/read_write_file.h>
16
17 #include <ditto/logger.h>
18 #include <ditto/shared_variables.h>
19
20 #include <ditto/utils.h>
21
22 namespace dittosuite {
23
ReadWriteFile(const std::string & name,const Params & params,int64_t size,int64_t block_size,int64_t starting_offset,Order access_order,uint32_t seed,Reseeding reseeding,int input_fd_key)24 ReadWriteFile::ReadWriteFile(const std::string& name, const Params& params, int64_t size,
25 int64_t block_size, int64_t starting_offset, Order access_order,
26 uint32_t seed, Reseeding reseeding, int input_fd_key)
27 : Instruction(name, params),
28 size_(size),
29 block_size_(block_size),
30 starting_offset_(starting_offset),
31 access_order_(access_order),
32 gen_(seed),
33 seed_(seed),
34 reseeding_(reseeding),
35 input_fd_key_(input_fd_key),
36 update_size_(size == -1),
37 update_block_size_(block_size == -1) {
38 if (access_order == Order::kRandom && starting_offset != 0) {
39 LOGE(
40 "Starting offset is not 0, although the chosen access_order is RANDOM. Starting offset "
41 "will be "
42 "ignored");
43 }
44 }
45
CollectResults(const std::string & prefix)46 std::unique_ptr<Result> ReadWriteFile::CollectResults(const std::string& prefix) {
47 auto result = Instruction::CollectResults(prefix);
48 result->AddMeasurement("bandwidth", bandwidth_sampler_.GetSamples());
49 return result;
50 }
51
SetUp()52 void ReadWriteFile::SetUp() {
53 if (reseeding_ == Reseeding::kEachRoundOfCycles) {
54 gen_.seed(seed_);
55 }
56 }
57
SetUpSingle()58 void ReadWriteFile::SetUpSingle() {
59 int fd = std::get<int>(SharedVariables::Get(input_fd_key_));
60 int64_t file_size = GetFileSize(syscall_, fd);
61
62 if (update_size_) {
63 size_ = file_size;
64 }
65 if (update_block_size_) {
66 block_size_ = file_size;
67 }
68
69 if (block_size_ > file_size) {
70 LOGF("Supplied block_size (" + std::to_string(block_size_) +
71 ") is greater than total file size (" + std::to_string(file_size) +
72 "). File path:" + GetFilePath(syscall_, fd));
73 }
74
75 buffer_ = std::unique_ptr<char[]>(new (std::nothrow) char[block_size_]);
76 if (buffer_ == nullptr) {
77 PLOGF("Error while allocating buffer for Read/Write");
78 }
79 std::fill(buffer_.get(), buffer_.get() + block_size_, 170); // 170 = 10101010
80
81 if (reseeding_ == Reseeding::kEachCycle) {
82 gen_.seed(seed_);
83 }
84
85 units_.clear();
86
87 switch (access_order_) {
88 case Order::kSequential: {
89 int64_t offset = starting_offset_;
90 for (int64_t i = 0; i < (size_ / block_size_); i++) {
91 if (offset > file_size - block_size_) {
92 offset = 0;
93 }
94 units_.push_back({block_size_, offset});
95 offset += block_size_;
96 }
97 break;
98 }
99 case Order::kRandom: {
100 std::uniform_int_distribution<> uniform_distribution(0, file_size - block_size_);
101
102 for (int64_t i = 0; i < (size_ / block_size_); i++) {
103 units_.push_back({block_size_, uniform_distribution(gen_)});
104 }
105 break;
106 }
107 }
108
109 Instruction::SetUpSingle();
110 }
111
RunSingle()112 void ReadWriteFile::RunSingle() {}
113
WriteFile(const Params & params,int64_t size,int64_t block_size,int64_t starting_offset,Order access_order,uint32_t seed,Reseeding reseeding,bool fsync,int input_fd_key)114 WriteFile::WriteFile(const Params& params, int64_t size, int64_t block_size,
115 int64_t starting_offset, Order access_order, uint32_t seed,
116 Reseeding reseeding, bool fsync, int input_fd_key)
117 : ReadWriteFile(kName, params, size, block_size, starting_offset, access_order, seed, reseeding,
118 input_fd_key),
119 fsync_(fsync) {}
120
RunSingle()121 void WriteFile::RunSingle() {
122 int fd = std::get<int>(SharedVariables::Get(input_fd_key_));
123
124 for (const auto& unit : units_) {
125 if (syscall_.Write(fd, buffer_.get(), unit.count, unit.offset) == -1) {
126 LOGF("Error while calling write()");
127 }
128 }
129
130 if (fsync_ && syscall_.FSync(fd) != 0) {
131 LOGF("Error while calling fsync()");
132 }
133 }
134
ReadFile(const Params & params,int64_t size,int64_t block_size,int64_t starting_offset,Order access_order,uint32_t seed,Reseeding reseeding,int fadvise,int input_fd_key)135 ReadFile::ReadFile(const Params& params, int64_t size, int64_t block_size, int64_t starting_offset,
136 Order access_order, uint32_t seed, Reseeding reseeding, int fadvise,
137 int input_fd_key)
138 : ReadWriteFile(kName, params, size, block_size, starting_offset, access_order, seed, reseeding,
139 input_fd_key),
140 fadvise_(fadvise) {}
141
SetUpSingle()142 void ReadFile::SetUpSingle() {
143 int fd = std::get<int>(SharedVariables::Get(input_fd_key_));
144 int64_t file_size = GetFileSize(syscall_, fd);
145
146 if (syscall_.FAdvise(fd, 0, file_size, fadvise_) != 0) {
147 LOGF("Error while calling fadvise()");
148 }
149 ReadWriteFile::SetUpSingle();
150 }
151
RunSingle()152 void ReadFile::RunSingle() {
153 int fd = std::get<int>(SharedVariables::Get(input_fd_key_));
154
155 for (const auto& unit : units_) {
156 if (syscall_.Read(fd, buffer_.get(), unit.count, unit.offset) == -1) {
157 LOGF("Error while calling read()");
158 }
159 }
160 }
161
TearDownSingle(bool is_last)162 void ReadWriteFile::TearDownSingle(bool is_last) {
163 Instruction::TearDownSingle(is_last);
164 bandwidth_sampler_.Measure(size_, time_sampler_.GetSamples().back());
165 }
166
167 } // namespace dittosuite
168