RSS

(root)/alps/fwbench : /fwbench.c (revision 19)

To get this branch, use:
bzr branch /webbzr/alps/fwbench
Line Revision Contents
1 2
#define _BSD_SOURCE
2 1
#include <stdio.h>
3
#include <stdlib.h>
4
#include <string.h>
5
#include <errno.h>
6
#include <fcntl.h>
7
#include <glib.h>
8
#include <math.h>
9
#include <unistd.h>
10
#include <sys/stat.h>
11
#include <sys/time.h>
12 3
#include <getopt.h>
13
#include <stdarg.h>
14 1
15
#include <fastwriter.h>
16 2
17
#ifdef USE_UFO_GENERATOR
18
# include <ufo/ufo-graph.h>
19
#endif /* USE_UFO_GENERATOR */
20 1
21
#include "config.h"
22
23 2
//#define USE_FIFO
24 14
#define WRITE_RANDOM "/dev/frandom"
25 1
#define WRITE_INTERVAL 1
26
#define WRITE_SUMMARY 5
27 2
#define DELTA_TOLERANCE 5
28 1
29 2
#ifdef USE_UFO_GENERATOR
30
# ifndef USE_FIFO
31
#  define USE_FIFO
32
# endif /* !USE_FIFO */
33
#endif /* USE_UFO_GENERATOR */
34 1
35
const char *fifo_name = ".fifo";
36
37
struct setup_s {
38 14
    size_t uc;
39 1
    size_t width;
40
    size_t height;
41
    size_t bpp;
42
    size_t fps;
43 2
44 3
    size_t fpf;
45 1
    size_t iters;
46 3
    double tolerance;
47
    const char *output;
48
    const char *fs;
49
    
50
    int verbose;
51 1
52
    volatile int run_started;
53 2
54
    struct timeval tv_started;
55
    struct timeval tv_last_written;
56
57
    int broken_frame;
58
    unsigned long frames, lost;
59
    unsigned long last_frames, last_lost;
60
61
    size_t frame_size;
62
    size_t num_read;
63
    size_t buf_max;
64
    
65
    size_t writeouts;
66
    
67
    fastwriter_t *fw;
68 3
    char *current_output;
69 1
};
70
71
typedef struct setup_s setup_t;
72
73 2
74 3
75
typedef enum {
76
    OPT_OUTPUT = 'o',
77
    OPT_BUFFER = 'b',
78
    OPT_SIZE = 's',
79
    OPT_TIME = 't',
80
    OPT_RATE = 'r',
81
    OPT_FRAMES = 'n',
82
    OPT_GEOMETRY = 'g',
83
    OPT_FPF = 'f',
84
    OPT_MISSING = 'm',
85
    OPT_QUIET = 'q',
86 14
    OPT_UC = 'u',
87 3
    OPT_HELP = 'h'
88
} options_t;
89
90
91
void Usage(int argc,  char* const argv[], const char *format, ...) {
92
    if (format) {
93
	va_list ap;
94
    
95
	va_start(ap, format);
96
	printf("Error %i: ", errno);
97
	vprintf(format, ap);
98
	printf("\n");
99
	va_end(ap);
100
    
101
        printf("\n");
102
    }
103
104
    printf(
105
"Usage:\n"
106
" %s [options]\n"
107
"   -o <file|device>	- Output to file/device [/dev/null]\n"
108
"			use %%zu to replace with frame number\n"
109
"   -f <number>		- Number of frames per file [all]\n"
110
"   -b size		- Buffer Size (MB)\n"
111
"   -r rate		- Write rate (MB/s)\n"
112
"   -s size		- Total size of data to write (GB)\n"
113
"   -t run_time		- Run time (s)\n"
114
"   -n frames		- Number of frames to write\n"
115
"   -g <width>x<height>	- Geometry [1024]\n"
116
"   -g <pixels>		- Number of megapixels [0.7]\n"
117 14
"   -m <percent>		- Tolerable missing frames  [100%%]\n"
118
"   -u <size>		- Use uncompressable data, repeating block (MB)\n"
119 3
"   -q			- Quiete\n"
120
"   -h			- Help\n"
121
"\n\n",
122
argv[0]);
123
124
    exit(0);
125
}
126
127
128 2
#ifdef USE_UFO_GENERATOR
129
static void handle_error(GError *error) {
130 1
    if (error != NULL) {
131
        g_print("%s\n", error->message); 
132
        g_error_free(error);
133
        exit(EXIT_FAILURE);
134
    }
135
}
136 2
#endif /* USE_UFO_GENERATOR */
137
138 3
static void set_verbosity(setup_t *setup, int level) {
139
    setup->verbose = level;
140
}
141
142
static void set_current_output(setup_t *setup, size_t frame) {
143
    sprintf(setup->current_output, setup->output, frame);
144
}
145
146
static void set_output(setup_t *setup, const char *name) {
147
    setup->output = name;
148
    setup->fs = name;
149
    setup->current_output = malloc(strlen(setup->output) + 32);
150
    g_assert(setup->current_output);
151
    set_current_output(setup, 0);
152
}
153 2
154
static void set_dim(setup_t *setup, size_t width, size_t height) {
155 1
    setup->bpp = sizeof(float);
156 2
    setup->width = width;
157
    setup->height = height;
158
159
    setup->frame_size = setup->width * setup->height * setup->bpp;
160
}
161
162 3
static void set_pixels(setup_t *setup, size_t pixels) {
163
    int width = sqrt(4 * pixels / 3);
164
    set_dim(setup, width, width * 3 / 4);
165
}
166
167 2
static void set_speed(setup_t *setup, size_t speed) {
168 1
    setup->fps = 1 + speed / setup->width / setup->height / setup->bpp;
169
}
170
171 3
static void set_iters(setup_t *setup, size_t iters) {
172
    setup->iters = iters;
173
}
174
175
static void set_time(setup_t *setup, size_t run_time) {
176
    setup->iters = run_time * setup->fps;
177
}
178
179 2
static void set_size(setup_t *setup, size_t size) {
180 4
    setup->iters = size / setup->frame_size + ((size % setup->frame_size)?1:0);
181 3
}
182
183
static void set_frames_per_file(setup_t *setup, size_t fpf) {
184
    setup->fpf = fpf;
185
}
186
187
static void set_fail_tolerance(setup_t *setup, double fail_rate) {
188
    setup->tolerance = fail_rate;
189
}
190
191 14
static void request_uncompressable_data(setup_t *setup, size_t uc) {
192
    setup->uc = uc;
193
}
194 1
195 2
static int callback(setup_t *s, size_t result, void *buffer);
196
197 1
static void *run(setup_t *setup) {
198 2
#ifdef USE_UFO_GENERATOR
199 1
    GError *error = NULL;
200
    UfoGraph *graph = NULL;
201
    /* If you want to use system-wide installed filters: 
202
     * graph = ufo_graph_new(); */
203
204
    graph = g_object_new(UFO_TYPE_GRAPH,
205 2
# ifdef METABALLS_PATH
206 1
            "paths", METABALLS_PATH,
207 2
# endif /* METABALLS_PATH */
208 1
            NULL);
209
210
//    printf("%lu %lu %lu %lu\n", setup->width, setup->height, setup->iters, setup->width * setup->height * setup->iters * sizeof(float));
211
    UfoFilter *metaballs = ufo_graph_get_filter(graph, "metaballs", &error);
212
    handle_error(error);
213
    g_object_set(G_OBJECT(metaballs),
214
            "width", setup->width,
215
            "height", setup->height,
216
            "num-balls", 1,
217
            "num-iterations", setup->iters,
218
            "frames-per-second", setup->fps,
219
            NULL);
220
221
    UfoFilter *writer = ufo_graph_get_filter(graph, "pipeoutput", &error);
222
    handle_error(error);
223
    g_object_set(G_OBJECT(writer),
224
            "pipe-name", fifo_name,
225
            NULL);
226
227
    ufo_filter_connect_to(metaballs, writer, &error);
228
    handle_error(error);
229
230
    setup->run_started = 1;
231 2
232 1
    ufo_graph_run(graph, &error);
233
    handle_error(error);
234 3
235
    g_thread_exit(NULL);
236 2
#else /* USE_UFO_GENERATOR */
237
    size_t i;
238
    struct timeval tv;
239
    size_t size = setup->width * setup->height * setup->bpp;
240 14
    size_t pos = 0, mult = setup->uc / size;
241
    char *buffer = malloc((mult + 1) * size);
242 2
    double interval = 1000000. / setup->fps, nextus;
243
    ssize_t tmp;
244
    size_t nexts;
245
246 14
    g_assert(buffer);
247
    
248
    if (!mult) mult = 1;
249
250
# ifdef WRITE_RANDOM
251
    if (setup->uc) {
252
	printf("Generating %zu MB of randomness...\n", mult * size / 1024 / 1024);
253
	int rfd = open(WRITE_RANDOM, O_RDONLY);
254
	g_assert(rfd >= 0);
255
	read(rfd, buffer, mult * size);
256
	close(rfd);
257
    }
258
# endif /* WRITE_RANDOM */
259
260 2
    setup->run_started = 1;
261
262 14
# ifdef USE_FIFO
263 2
    int fd = open(fifo_name, O_WRONLY);
264
    g_assert(fd >= 0);
265 14
# endif /* USE_FIFO */
266
267 2
    gettimeofday(&tv, NULL); 
268
    nexts = tv.tv_sec;
269
    nextus = tv.tv_usec + interval;
270
    for (i = 0; i < setup->iters; i++) {
271 14
# ifdef USE_FIFO
272
	ssize_t res = write(fd, buffer + pos * size, size);
273 2
	g_assert(res == size);
274 14
# else /* USE_FIFO */
275
	callback(setup, size, buffer + pos * size);
276
# endif /* USE_FIFO */
277 2
278 14
	if ((++pos) == mult) pos = 0;
279
	
280 2
	tmp = ((size_t)round(nextus)) / 1000000;
281
	nexts += tmp;
282
	nextus -= tmp * 1000000;
283
284
	gettimeofday(&tv, NULL);
285
	tmp = (nexts - tv.tv_sec)*1000000 + (nextus - tv.tv_usec);
286
	if (tmp > 10) usleep(tmp);
287
	
288
	nextus += interval;
289
    }
290
291 14
# ifdef USE_FIFO
292 2
    close(fd);
293 14
# endif /* USE_FIFO */
294 2
295 14
    free(buffer);
296 2
#endif /* USE_UFO_GENERATOR */
297 1
298
    return NULL;
299
}
300
301 2
static int callback(setup_t *s, size_t result, void *buffer) {
302
    int err;
303
    struct timeval tv;
304
305
    fastwriter_t *fw = s->fw;
306
    fastwriter_stats_t stats;
307
308
    size_t duration, last_duration, expected;
309
    long delta;
310
311 3
    gettimeofday(&tv, NULL);
312 2
313
    if (!s->broken_frame) {
314
	err = fastwriter_push(fw, result, buffer);
315
    	if (err) {
316
    	    if (err == EWOULDBLOCK) {
317 3
    		if (!s->tolerance) {
318
    		    if (s->verbose >= 0) printf("Lost frame...\n");
319
    		    exit(1);
320
    		}
321
    		
322 2
		if (s->num_read) fastwriter_cancel(fw);
323
		s->broken_frame = 1;
324
    	    } else {
325
	    	if (err) printf("FastWriter returned error %i\n", err);
326
		g_assert(!err);
327
	    }
328
	}
329
    }
330
331
    s->num_read += result; 
332
333
    if (s->num_read < s->frame_size) return 0;
334
335
    s->num_read = 0;
336
337
    if (s->broken_frame) {
338
	s->lost++;
339
	s->broken_frame = 0;
340
    } else {
341
	err = fastwriter_commit(fw);
342
	s->frames++;
343 3
344
	if ((s->fpf)&&((s->frames%s->fpf) == 0)) {
345
	    fastwriter_close(s->fw);
346
	    set_current_output(s, s->frames);
347
	    err = fastwriter_open(s->fw, s->current_output,  FASTWRITER_FLAGS_OVERWRITE);
348
	    if (err) {
349
		printf("FastWriter returned error %i\n", err);
350
		g_assert(!err);
351
	    }
352
353
	// reopen
354
    }
355
356
    }
357
    
358 2
    if (!s->tv_started.tv_sec) {
359
    	memcpy(&s->tv_started, &tv, sizeof(struct timeval));
360
    	if (s->tv_started.tv_usec >= (1000000 / s->fps)) 
361
    	    s->tv_started.tv_usec -= (1000000 / s->fps);
362
    	else {
363
    	    s->tv_started.tv_sec--;
364
    	    s->tv_started.tv_usec += 1000000 - (1000000 / s->fps);
365
    	}
366
    	memcpy(&s->tv_last_written, &s->tv_started, sizeof(struct timeval));
367
    }
368
369
    fastwriter_get_stats(fw, &stats);
370
    if (stats.buffer_used > s->buf_max) s->buf_max = stats.buffer_used;
371
372
    if ((tv.tv_sec - s->tv_last_written.tv_sec) >= WRITE_INTERVAL) {
373 3
	if ((s->tolerance > 0)&&(s->tolerance < 100)) {
374
	    double lost = (100. * s->lost / (s->lost + s->frames));
375
	    double last_lost = (100. * (s->lost - s->last_lost) / (s->lost + s->frames - s->last_lost - s->last_frames));
376
	    if ((lost > s->tolerance)||(last_lost > s->tolerance)) {
377
		if (s->verbose >= 0)
378
		    printf("Lost %.2lf%% (%lu) frames, total: %.2lf%% (%lu)\n", last_lost, s->lost - s->last_lost, lost, s->lost);
379
		exit(1);
380
	    }
381
	}
382
	
383
	if (s->verbose >= 0) {
384
	    last_duration = (tv.tv_sec - s->tv_last_written.tv_sec) * 1000000 + (tv.tv_usec - s->tv_last_written.tv_usec);
385
	    printf("Lost  %6.2lf%% (% 8lu of % 8lu), %9.3lf GB at %8.3lf MB/s, buf:%6.2lf%%\n", 100.*(s->lost - s->last_lost) / (s->lost + s->frames - s->last_lost - s->last_frames), s->lost - s->last_lost, s->lost + s->frames - (s->last_lost + s->last_frames), 1. * s->frame_size * (s->frames - s->last_frames) / 1024 / 1024 / 1024, 1000000. * s->frame_size * (s->frames - s->last_frames) / last_duration / 1024 / 1024, 100.*s->buf_max/stats.buffer_size);
386
	}
387 2
388
	if (((++s->writeouts)%WRITE_SUMMARY)==0) {
389
	    duration = (tv.tv_sec - s->tv_started.tv_sec) * 1000000 + (tv.tv_usec - s->tv_started.tv_usec);
390
	    expected = (tv.tv_sec - s->tv_started.tv_sec) * s->fps + round(1.*(tv.tv_usec - s->tv_started.tv_usec)*s->fps/1000000);
391
	    delta = expected - s->lost - s->frames;
392
    	    if ((delta > DELTA_TOLERANCE)||(delta < -DELTA_TOLERANCE))
393
    		printf(" *** Unexpected frame rate: %.2lf (%lu), delta: %li (%lu, %lu)\n", 1000000. * (s->frames + s->lost) / duration, s->fps, delta, s->lost + s->frames, expected); 
394
    		
395 3
    	    if (s->verbose >= 0) {
396
		printf("Total %6.2lf%% (% 8lu of % 8lu), %9.3lf GB at %8.3lf MB/s, buf:%6.2lf%%\n", 100. * s->lost / (s->lost + s->frames), s->lost, s->lost + s->frames, 1. * s->frames * s->frame_size / 1024 / 1024 / 1024, 1000000. * s->frames * s->frame_size / duration / 1024 / 1024,  100.*stats.buffer_max / stats.buffer_size);
397
	    }
398 2
	}
399
	
400
	s->buf_max = 0;
401
	memcpy(&s->tv_last_written, &tv, sizeof(struct timeval));
402
	s->last_frames = s->frames;
403
	s->last_lost = s->lost;
404
    }
405
    
406
    return 0;
407
}
408 1
409
410 3
int main(int argc, char* const argv[])
411 1
{
412
    int err;
413 2
414
#ifdef USE_FIFO
415 1
    GError *gerr;
416
    GThread *thr;
417 2
#endif /* USE_FIFO */
418
419 1
    setup_t setup;
420 3
421
    unsigned char c;
422
    const char *sptr;
423 1
    const char *out = "/dev/null";
424 3
    double mpix = 0;
425 2
    size_t width = 1024;
426
    size_t height = 768;
427 1
    size_t speed = 850;
428 3
    size_t size = 0;
429 14
    size_t uc = 0;
430 3
    size_t run_time = 0;
431
    size_t iters = 0x7FFFFFFF;
432
    size_t fw_buffer = 0;
433
    double fail_rate = 100.;
434
    size_t fpf = 0;
435
    int quiet = 0;
436
    
437 1
438 2
    fastwriter_stats_t stats;
439
440
    g_thread_init(NULL);
441
442
#ifdef USE_UFO_GENERATOR
443 1
    g_type_init();
444 2
#endif /* USE_UFO_GENERATOR */
445 1
446 3
447
448 14
    while ((c = getopt(argc, argv, "hqo:s:u:t:r:n:g:f:m:b:")) != (unsigned char)-1) {
449 3
	switch (c) {
450
	 case OPT_OUTPUT:
451
	    out = optarg;
452
	    break;
453
	 case OPT_BUFFER:
454
            fw_buffer = atol(optarg);
455
	    break;
456
         case OPT_SIZE:
457
            size = atol(optarg);
458
	    break;
459 14
	 case OPT_UC:
460
	    uc = atol(optarg);
461
	    break;
462 3
         case OPT_TIME:
463
            run_time = atol(optarg);
464
	    break;
465
         case OPT_FRAMES:
466
            iters = atol(optarg);
467
	    break;
468
         case OPT_RATE:
469
            speed = atoi(optarg);
470
            break;
471
         case OPT_GEOMETRY:
472
            sptr = strchr(optarg, 'x');
473
            if (sptr) {
474
        	width = atol(optarg);
475
        	height = atol(sptr + 1);
476
            } else {
477
        	mpix = atof(optarg);
478
            }
479
            break;
480
         case OPT_FPF:
481
            fpf = atol(optarg);
482
            break;
483
         case OPT_MISSING:
484
            fail_rate = atof(optarg);
485
            break;
486
        case OPT_QUIET:
487
    	    quiet = 1;
488
	    break;
489
         case OPT_HELP:
490
	    Usage(argc, argv, NULL);
491
     }
492 1
    }
493
494 2
#ifdef USE_FIFO
495 1
    unlink(fifo_name);
496
    g_assert(!mkfifo(fifo_name, S_IWUSR | S_IRUSR));
497 2
#endif /* USE_FIFO */
498 1
499 3
500
    memset(&setup, 0, sizeof(setup_t));
501
502
    if (quiet) set_verbosity(&setup, -1);
503
    set_output(&setup, out);
504
    
505
    if (mpix) set_pixels(&setup, mpix * 1000000);
506
    else set_dim(&setup, width, height);
507
508
    set_speed(&setup, speed * 1024 * 1024);
509
510
    if (size) set_size(&setup, size * 1024 * 1024 * 1024);
511
    else if (run_time) set_time(&setup, run_time);
512
    else set_iters(&setup, iters);
513
    
514
    set_fail_tolerance(&setup, fail_rate);
515
    set_frames_per_file(&setup, fpf);
516
517 14
    request_uncompressable_data(&setup, uc * 1024 * 1024);
518 3
519
    setup.fw = fastwriter_init(setup.fs, FASTWRITER_FLAGS_OVERWRITE);
520
    g_assert(setup.fw);
521
522
    if (fw_buffer) 
523
	fastwriter_set_buffer_size(setup.fw, fw_buffer * 1024 * 1024);
524
    else
525
	fastwriter_set_buffer_size(setup.fw, FASTWRITER_BUFFER_MAX);
526
    
527
    err = fastwriter_open(setup.fw, setup.current_output,  FASTWRITER_FLAGS_OVERWRITE);
528 1
    if (err) printf("FastWriter returned error %i\n", err);
529
    g_assert(!err);
530
531 3
532
    fastwriter_get_stats(setup.fw, &stats);
533
    if (!quiet)
534
	printf("*** Writing to %s, rate: %lu, data: %lu MB/s, buffer: %lu MB\n", out, setup.fps, speed, stats.buffer_size/1024/1024);
535 2
536
    void *buffer = malloc(setup.frame_size);
537 1
    g_assert(buffer);
538
539 2
#ifdef USE_FIFO
540 1
    thr = g_thread_create((GThreadFunc)run, &setup, 1, &gerr);
541
    g_assert(thr);
542
543
    while (!setup.run_started);
544
545
    int fd = open(fifo_name, O_RDONLY);
546
    g_assert(fd);
547
548 2
    ssize_t result = read(fd, buffer, setup.frame_size);
549 1
550
    while (result > 0) {
551 2
	callback(&setup, result, buffer);
552
        result = read(fd, buffer, setup.frame_size - setup.num_read);
553 1
    }
554
555 4
    if (!quiet)
556
	printf("Wrote %lu GB\n", setup.frame_size * setup.frames / 1024 / 1024 / 1024);
557 1
558
    g_thread_join(thr);
559
560
    close(fd);
561 2
#else /* USE_FIFO */
562
    run(&setup);
563
#endif /* USE_FIFO */
564 1
565
    free(buffer);
566 3
    fastwriter_close(setup.fw);
567
    fastwriter_destroy(setup.fw);
568 2
569
#ifdef USE_FIFO
570 1
    unlink(fifo_name);
571 2
#endif /* USE_FIFO */
572 1
573
    return 0;
574
}

Loggerhead 1.18.1 is a web-based interface for Bazaar branches