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