"Fossies" - the Fresh Open Source Software Archive 
Member "bonnie++-2.00a/zcav_io.cpp" (23 Nov 2012, 6073 Bytes) of package /linux/privat/bonnie++-2.00a.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "zcav_io.cpp" see the
Fossies "Dox" file reference documentation.
1 #include "zcav_io.h"
2
3 #include <unistd.h>
4 #include <sys/resource.h>
5 #include <sys/time.h>
6 #include <time.h>
7 #include <stdlib.h>
8 #include <string.h>
9
10 ZcavRead::~ZcavRead()
11 {
12 delete m_name;
13 }
14
15 int ZcavRead::Open(bool *finished, int block_size, const char *file
16 , const char *log, int chunk_size, int do_write)
17 {
18 m_name = strdup(file);
19 m_finished = finished;
20 m_block_size = block_size;
21 m_chunk_size = chunk_size;
22 m_do_write = do_write;
23 m_buf = calloc(chunk_size * MEG, 1);
24
25 if(strcmp(file, "-"))
26 {
27 if(m_do_write)
28 m_fd = file_open(file, O_WRONLY);
29 else
30 m_fd = file_open(file, O_RDONLY);
31 if(m_fd == -1)
32 {
33 fprintf(stderr, "Can't open %s\n", file);
34 return 1;
35 }
36 }
37 else
38 {
39 m_fd = 0;
40 }
41 if(strcmp(log, "-"))
42 {
43 m_logFile = true;
44 m_log = fopen(log, "w");
45 if(m_log == NULL)
46 {
47 fprintf(stderr, "Can't open %s\n", log);
48 close(m_fd);
49 return 1;
50 }
51 }
52 else
53 {
54 m_logFile = false;
55 m_log = stdout;
56 }
57 return 0;
58 }
59
60 void ZcavRead::Close()
61 {
62 if(m_logFile)
63 fclose(m_log);
64 if(m_fd != 0)
65 ::close(m_fd);
66 }
67
68 int ZcavRead::writeStatus(int fd, char c)
69 {
70 if(write(fd, &c, 1) != 1)
71 {
72 fprintf(stderr, "Write channel broken\n");
73 return 1;
74 }
75 return 0;
76 }
77
78 int ZcavRead::Read(int max_loops, int max_size, int writeCom, int skip_rate, int start_offset)
79 {
80 bool exiting = false;
81 if(max_loops == 1)
82 fprintf(m_log, "#block offset (GiB), MiB/s, time\n");
83 for(int loops = 0; !exiting && loops < max_loops; loops++)
84 {
85 int i = 0;
86 #ifdef _LARGEFILE64_SOURCE
87 if(start_offset)
88 {
89 OFF_TYPE real_offset = OFF_TYPE(start_offset) * OFF_TYPE(m_block_size) * OFF_TYPE(1<<20);
90 if(file_lseek(m_fd, real_offset, SEEK_CUR) == OFF_TYPE(-1))
91 {
92 fprintf(stderr, "Can't lseek().\n");
93 writeStatus(writeCom, eSEEK);
94 return 1;
95 }
96 i = start_offset;
97 }
98 else
99 #endif
100 if(lseek(m_fd, 0, SEEK_SET))
101 {
102 fprintf(stderr, "Can't lseek().\n");
103 writeStatus(writeCom, eSEEK);
104 return 1;
105 }
106
107 // i is block index
108 double total_read_time = 0.0;
109 bool nextLoop = false;
110 for( ; !nextLoop && (!max_size || i < max_size)
111 && (loops == 0 || (m_times[i] && m_times[i][0] != -1.0))
112 && (!max_size || i < max_size); i++)
113 {
114 double read_time = access_data(i ? skip_rate - 1 : 0);
115 if(read_time < 0.0)
116 {
117 if(i == 0)
118 {
119 fprintf(stderr, "Data file/device \"%s\" too small.\n", m_name);
120 writeStatus(writeCom, eSIZE);
121 return 1;
122 }
123 nextLoop = true;
124 break;
125 }
126 total_read_time += read_time;
127 if(max_loops == 1)
128 {
129 printavg(i * skip_rate, read_time, m_block_size);
130 }
131 else
132 {
133 if(loops == 0)
134 {
135 m_times.push_back(new double[max_loops]);
136 m_count.push_back(0);
137 }
138 m_times[i][loops] = read_time;
139 m_count[i]++;
140 }
141 } // end loop for reading blocks
142
143 time_t now = time(NULL);
144 struct tm *cur_time = localtime(&now);
145 fprintf(stderr, "# Finished loop %d, on device %s at %d:%02d:%02d\n"
146 , loops + 1, m_name, cur_time->tm_hour, cur_time->tm_min
147 , cur_time->tm_sec);
148 fprintf(m_log, "# Read %d megs in %d seconds, %d megabytes per second.\n"
149 , i * m_block_size, int(total_read_time)
150 , int(double(i * m_block_size) / total_read_time));
151
152 if(exiting)
153 return 1;
154 } // end loop for multiple disk reads
155 if(max_loops > 1)
156 {
157 fprintf(m_log, "#loops: %d\n", max_loops);
158 fprintf(m_log, "#block offset (GiB), MiB/s, time\n");
159 for(int i = 0; m_times[i]; i++)
160 printavg(i * skip_rate, average(m_times[i], m_count[i]), m_block_size);
161 }
162 writeStatus(writeCom, eEND);
163 return 0;
164 }
165
166 void ZcavRead::printavg(int position, double avg, int block_size)
167 {
168 if(avg < 1.0)
169 fprintf(m_log, "#%.2f ++++ %.3f\n", float(position) * float(block_size) / 1024.0, avg);
170 else
171 fprintf(m_log, "%.2f %.2f %.3f\n", float(position) * float(block_size) / 1024.0, double(block_size) / avg, avg);
172 }
173
174 int compar(const void *a, const void *b)
175 {
176 double *c = (double *)(a);
177 double *d = (double *)(b);
178 if(*c < *d) return -1;
179 if(*c > *d) return 1;
180 return 0;
181 }
182
183 // Returns the mean of the values in the array. If the array contains
184 // more than 2 items then discard the highest and lowest thirds of the
185 // results before calculating the mean.
186 double average(double *array, int count)
187 {
188 qsort(array, count, sizeof(double), compar);
189 int skip = count / 3;
190 int arr_items = count - (skip * 2);
191 double total = 0.0;
192 for(int i = skip; i < (count - skip); i++)
193 {
194 total += double(array[i]);
195 }
196 return total / double(arr_items);
197 }
198
199 // just like read() or write() but will not return a partial result and the
200 // size is expressed in MEG.
201 ssize_t ZcavRead::access_all(int count)
202 {
203 ssize_t total = 0;
204 count *= MEG;
205 while(total != static_cast<ssize_t>(count) )
206 {
207 ssize_t rc;
208 // for both read and write just pass the base address of the buffer
209 // as we don't care for the data, if we ever do checksums we have to
210 // change this
211 if(m_do_write)
212 rc = write(m_fd, m_buf, count - total);
213 else
214 rc = read(m_fd, m_buf, count - total);
215 if(rc == -1 || rc == 0)
216 return -1;
217 total += rc;
218 }
219 if(m_do_write && fsync(m_fd))
220 return -1;
221 return total / MEG;
222 }
223
224 // Read/write a block of data
225 double ZcavRead::access_data(int skip)
226 {
227 #ifdef _LARGEFILE64_SOURCE
228 if(skip)
229 {
230 OFF_TYPE real_offset = OFF_TYPE(skip) * OFF_TYPE(m_block_size) * OFF_TYPE(1<<20);
231 if(file_lseek(m_fd, real_offset, SEEK_CUR) == OFF_TYPE(-1))
232 return -1.0;
233 }
234 #endif
235
236 m_dur.start();
237 for(int i = 0; i < m_block_size; i+= m_chunk_size)
238 {
239 int access_size = m_chunk_size;
240 if(i + m_chunk_size > m_block_size)
241 access_size = m_block_size - i;
242 int rc = access_all(access_size);
243 if(rc != access_size)
244 return -1.0;
245 }
246 return m_dur.stop();
247 }
248