Statistics
| Branch: | Revision:

root / synthbench / bonnie++ / .svn / text-base / zcav.cpp.svn-base @ 0:839f52ef7657

History | View | Annotate | Download (8.2 kB)

1

    
2
using namespace std;
3

    
4
#include <unistd.h>
5
#include <sys/time.h>
6
#include <sys/resource.h>
7
#include <time.h>
8
#include <sys/types.h>
9
#include <sys/stat.h>
10
#include <fcntl.h>
11
#include <cstdlib>
12
#include <cstring>
13
#include "bonnie.h"
14
#ifdef HAVE_VECTOR
15
#include <vector>
16
#else
17
#include <vector.h>
18
#endif
19

    
20
// Read the specified number of megabytes of data from the fd and return the
21
// amount of time elapsed in seconds.
22
double access_data(int fd, int size, void *buf, int chunk_size, int do_write);
23

    
24
// Returns the mean of the values in the array.  If the array contains
25
// more than 2 items then discard the highest and lowest thirds of the
26
// results before calculating the mean.
27
double average(double *array, int count);
28
void printavg(int position, double avg, int block_size);
29

    
30
const int MEG = 1024*1024;
31
const int DEFAULT_CHUNK_SIZE = 1;
32
typedef double *PDOUBLE;
33

    
34
void usage()
35
{
36
  printf("Usage: zcav [-b block-size] [-c count] [-n number of megs to read]\n"
37
         "            [-u uid-to-use:gid-to-use] [-g gid-to-use]\n"
38
         "            [-f] file-name\n"
39
         "File name of \"-\" means standard input\n"
40
         "Count is the number of times to read the data (default 1).\n"
41
         "Version: " BON_VERSION "\n");
42
  exit(1);
43
}
44

    
45
int main(int argc, char *argv[])
46
{
47
  vector<double *> times;
48
  vector<int> count;
49
  int block_size = 256;
50

    
51
  int max_loops = 1, pass_size = 0, chunk_size = DEFAULT_CHUNK_SIZE;
52
  int do_write = 0;
53
  char *file_name = NULL;
54

    
55
  char *userName = NULL, *groupName = NULL;
56
  int c;
57
  while(-1 != (c = getopt(argc, argv, "-c:b:f:g:n:u:w")) )
58
  {
59
    switch(char(c))
60
    {
61
      case 'b':
62
      {
63
        int rc = sscanf(optarg, "%d:%d", &block_size, &chunk_size);
64
        if(rc == 1)
65
          chunk_size = DEFAULT_CHUNK_SIZE;
66
        else if(rc != 2)
67
          usage();
68
      }
69
      break;
70
      case 'c':
71
        max_loops = atoi(optarg);
72
      break;
73
      case 'g':
74
        if(groupName)
75
          usage();
76
        groupName = optarg;
77
      break;
78
      case 'u':
79
      {
80
        if(userName)
81
          usage();
82
        userName = strdup(optarg);
83
        int i;
84
        for(i = 0; userName[i] && userName[i] != ':'; i++)
85
        {}
86
        if(userName[i] == ':')
87
        {
88
          if(groupName)
89
            usage();
90
          userName[i] = '\0';
91
          groupName = &userName[i + 1];
92
        }
93
      }
94
      break;
95
      case 'n':
96
        pass_size = atoi(optarg);
97
      break;
98
      case 'w':
99
        do_write = 1;
100
      break;
101
      case 'f':
102
      case char(1):
103
        file_name = optarg;
104
      break;
105
      default:
106
        usage();
107
    }
108
  }
109

    
110
  pass_size = pass_size / block_size;
111

    
112
  if(userName || groupName)
113
  {
114
    if(bon_setugid(userName, groupName, false))
115
      return 1;
116
    if(userName)
117
      free(userName);
118
  }
119

    
120
  if(max_loops < 1 || block_size < 1 || chunk_size < 1
121
    || chunk_size > block_size)
122
    usage();
123
  if(!file_name)
124
    usage();
125
  printf("#loops: %d, version: %s\n", max_loops, BON_VERSION);
126

    
127
  int i;
128
  void *buf = calloc(chunk_size * MEG, 1);
129
  int fd;
130
  if(strcmp(file_name, "-"))
131
  {
132
    if(do_write)
133
      fd = open(file_name, O_WRONLY);
134
    else
135
      fd = open(file_name, O_RDONLY);
136
    if(fd == -1)
137
    {
138
      printf("Can't open %s\n", file_name);
139
      return 1;
140
    }
141
  }
142
  else
143
  {
144
    fd = 0;
145
  }
146
  if(max_loops > 1)
147
  {
148
    struct stat stat_out, stat_err;
149
    if(fstat(1, &stat_out) || fstat(2, &stat_err))
150
    {
151
      printf("Can't stat stdout/stderr.\n");
152
      return 1;
153
    }
154
    for(int loops = 0; loops < max_loops; loops++)
155
    {
156
      if(lseek(fd, 0, SEEK_SET))
157
      {
158
        printf("Can't llseek().\n");
159
        return 1;
160
      }
161
      double total_read_time = 0.0;
162
      for(i = 0; (loops == 0 || times[0][i] != -1.0) && (!pass_size || i < pass_size); i++)
163
      {
164
        double read_time = access_data(fd, block_size, buf, chunk_size, do_write);
165
        total_read_time += read_time;
166
        if(loops == 0)
167
        {
168
          times.push_back(new double[max_loops]);
169
          count.push_back(0);
170
        }
171
        times[i][loops] = read_time;
172
        if(read_time < 0.0)
173
        {
174
          if(i == 0)
175
          {
176
            fprintf(stderr, "Data file/device too small.\n");
177
            return 1;
178
          }
179
          times[i][0] = -1.0;
180
          break;
181
        }
182
        count[i]++;
183
      }
184
      time_t now = time(NULL);
185
      struct tm *cur_time = localtime(&now);
186
      fprintf(stderr, "# Finished loop %d, %d:%02d:%02d\n", loops + 1
187
            , cur_time->tm_hour, cur_time->tm_min, cur_time->tm_sec);
188
      printf("# Read %d gigs in %d seconds, %d megabytes per second.\n"
189
           , i * block_size / 1024, int(total_read_time)
190
           , int(double(i * block_size) / total_read_time));
191
      if(stat_out.st_dev != stat_err.st_dev || stat_out.st_ino != stat_err.st_ino)
192
      {
193
        fprintf(stderr, "Read %d gigs in %d seconds, %d megabytes per second.\n"
194
             , i * block_size / 1024, int(total_read_time)
195
             , int(double(i * block_size) / total_read_time));
196
      }
197
    }
198
    printf("#\n#block offset (GiB), MiB/s, time\n");
199
    for(i = 0; count[i]; i++)
200
    {
201
      printavg(i, average(times[i], count[i]), block_size);
202
    }
203
  }
204
  else
205
  {
206
    printf("#block offset (GiB), MiB/s, time\n");
207
    double total_read_time = 0.0;
208
    for(i = 0; !pass_size || i < pass_size; i++)
209
    {
210
      double read_time = access_data(fd, block_size, buf, chunk_size, do_write);
211
      if(read_time < 0.0)
212
        break;
213
      printavg(i, read_time, block_size);
214
      total_read_time += read_time;
215
    }
216
    if(i == 0)
217
    {
218
      fprintf(stderr, "File/device too small.\n");
219
      return 1;
220
    }
221
    printf("# Read %d gigs in %d seconds, %d megabytes per second.\n"
222
         , i * block_size / 1024, int(total_read_time)
223
         , int(double(i * block_size) / total_read_time));
224
  }
225
  return 0;
226
}
227

    
228
void printavg(int position, double avg, int block_size)
229
{
230
  if(avg < MinTime)
231
    printf("#%.2f ++++ %.3f \n", float(position) * float(block_size) / 1024.0, avg);
232
  else
233
    printf("%.2f %.2f %.3f\n", float(position) * float(block_size) / 1024.0, float(double(block_size) / avg), avg);
234
}
235

    
236
int compar(const void *a, const void *b)
237
{
238
  double *c = (double *)(a);
239
  double *d = (double *)(b);
240
  if(*c < *d) return -1;
241
  if(*c > *d) return 1;
242
  return 0;
243
}
244

    
245
// Returns the mean of the values in the array.  If the array contains
246
// more than 2 items then discard the highest and lowest thirds of the
247
// results before calculating the mean.
248
double average(double *array, int count)
249
{
250
  qsort(array, count, sizeof(double), compar);
251
  int skip = count / 3;
252
  int arr_items = count - (skip * 2);
253
  double total = 0.0;
254
  for(int i = skip; i < (count - skip); i++)
255
  {
256
    total += array[i];
257
  }
258
  return total / arr_items;
259
}
260

    
261
// just like read() or write() but will not return a partial result and the
262
// size is expressed in MEG.
263
ssize_t access_all(int fd, void *buf, size_t chunk_size, int do_write)
264
{
265
  ssize_t total = 0;
266
  chunk_size *= MEG;
267
  while(total != static_cast<ssize_t>(chunk_size) )
268
  {
269
    ssize_t rc;
270
    // for both read and write just pass the base address of the buffer
271
    // as we don't care for the data, if we ever do checksums we have to
272
    // change this
273
    if(do_write)
274
      rc = write(fd, buf, chunk_size - total);
275
    else
276
      rc = read(fd, buf, chunk_size - total);
277
    if(rc == -1 || rc == 0)
278
      return -1;
279
    total += rc;
280
  }
281
  if(do_write && fsync(fd))
282
    return -1;
283
  return total / MEG;
284
}
285

    
286
// Read the specified number of megabytes of data from the fd and return the
287
// amount of time elapsed in seconds.  If do_write == 1 then write data.
288
double access_data(int fd, int size, void *buf, int chunk_size, int do_write)
289
{
290
  struct timeval tp;
291
 
292
  if (gettimeofday(&tp, static_cast<struct timezone *>(NULL)) == -1)
293
  {
294
    printf("Can't get time.\n");
295
    return -1.0;
296
  }
297
  double start = double(tp.tv_sec) +
298
    (double(tp.tv_usec) / 1000000.0);
299

    
300
  for(int i = 0; i < size; i += chunk_size)
301
  {
302
    int access_size = chunk_size;
303
    if(i + chunk_size > size)
304
      access_size = size - i;
305
    int rc = access_all(fd, buf, access_size, do_write);
306
    if(rc != access_size)
307
      return -1.0;
308
  }
309
  if (gettimeofday(&tp, static_cast<struct timezone *>(NULL)) == -1)
310
  {
311
    printf("Can't get time.\n");
312
    return -1.0;
313
  }
314
  return (double(tp.tv_sec) + (double(tp.tv_usec) / 1000000.0))
315
        - start;
316
}
317