~ubuntu-branches/ubuntu/lucid/sreadahead/lucid

« back to all changes in this revision

Viewing changes to sreadahead.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant
  • Date: 2009-02-20 13:15:52 UTC
  • Revision ID: james.westby@ubuntu.com-20090220131552-h9uukunhsnztaasl
Tags: upstream-1.0
ImportĀ upstreamĀ versionĀ 1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * (C) Copyright 2008 Intel Corporation
 
3
 *
 
4
 * Author: Arjan van de Ven <arjan@linux.intel.com>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or
 
7
 * modify it under the terms of the GNU General Public License
 
8
 * as published by the Free Software Foundation; version 2
 
9
 * of the License.
 
10
 */
 
11
#define _GNU_SOURCE
 
12
 
 
13
#include <stdio.h>
 
14
#include <stdlib.h>
 
15
#include <stdint.h>
 
16
#include <unistd.h>
 
17
#include <sys/types.h>
 
18
#include <sys/stat.h>
 
19
#include <sys/mman.h>
 
20
#include <sys/times.h>
 
21
#include <string.h>
 
22
#include <pthread.h>
 
23
 
 
24
#include <fcntl.h>
 
25
#include <sys/types.h>
 
26
#include <sys/stat.h>
 
27
#include <sys/syscall.h>
 
28
#include <sys/mount.h>
 
29
#include <sys/signal.h>
 
30
#include <fcntl.h>
 
31
#include <errno.h>
 
32
 
 
33
#include <getopt.h>
 
34
 
 
35
#define VERSION "1.0"
 
36
 
 
37
#undef HAVE_IO_PRIO
 
38
#if defined(__i386__)
 
39
#  define HAVE_IO_PRIO
 
40
#  define __NR_ioprio_set 289
 
41
#elif defined(__x86_64__)
 
42
#  define HAVE_IO_PRIO
 
43
#  define __NR_ioprio_set 251
 
44
#else /* not fatal */
 
45
#  warn "Architecture does not support ioprio modification"
 
46
#endif
 
47
#define IOPRIO_WHO_PROCESS 1
 
48
#define IOPRIO_CLASS_IDLE 3
 
49
#define IOPRIO_CLASS_SHIFT 13
 
50
#define IOPRIO_IDLE_LOWEST (7 | (IOPRIO_CLASS_IDLE << IOPRIO_CLASS_SHIFT))
 
51
 
 
52
#define PACK_PATH       "/var/lib/sreadahead"
 
53
#define DEBUGFS_MNT     "/var/lib/sreadahead/debugfs"
 
54
#define PACK_FILE       "/var/lib/sreadahead/pack"
 
55
 
 
56
#define MAXR 40000      /* trace file can be long */
 
57
#define MAXFL 128
 
58
#define MAXRECS 6       /* reduce nr of fragments to this amount */
 
59
 
 
60
/*
 
61
 * By default, the kernel reads ahead for 128kb. This throws off our
 
62
 * measurements since we don't need the extra 128kb for each file.
 
63
 * On top of that, at the accelerated boot, we would be reading another
 
64
 * 128kb too much potentially, wasting a lot of time.
 
65
 *
 
66
 * By lowering the read_ahead_kb, we get more fragments (since they
 
67
 * are not glued together by the artifical kernel readahead). So
 
68
 * lowering this number too much doesn't actually gain much.
 
69
 *
 
70
 * XX kb seems to be a good balance with not too many fragments, but
 
71
 * keeping the total size low enough to make a difference.
 
72
 *
 
73
 * 8-16kb seems to be a good median value, with good total size savings
 
74
 * over anything higher. Lower sizes result in more separate blocks
 
75
 * and only minimal total size savings.
 
76
 */
 
77
#define RA_NORMAL 128   /* default read_ahead_kb size */
 
78
#define RA_SMALL  16    /* our tuned down value */
 
79
 
 
80
struct ra_record {
 
81
        uint32_t                offset;
 
82
        uint32_t                len;
 
83
};
 
84
 
 
85
/* disk format used, when reading pack */
 
86
struct ra_disk {
 
87
        char                    filename[MAXFL];
 
88
        struct ra_record        data[MAXRECS];
 
89
};
 
90
 
 
91
/* memory format used with sorting/filtering */
 
92
struct ra_struct {
 
93
        char                    filename[MAXFL];
 
94
        struct ra_record        data[MAXRECS];
 
95
        struct ra_struct        *next;
 
96
        struct ra_struct        *prev;
 
97
        int                     number;
 
98
};
 
99
 
 
100
static struct ra_struct *ra[MAXR];
 
101
static struct ra_disk rd[MAXR];
 
102
static struct ra_struct *first_ra;
 
103
static int racount = 0;
 
104
static int rdcount = 0;
 
105
static int fcount = 0;
 
106
static int rdsize = 0;
 
107
 
 
108
static unsigned int total_files = 0;
 
109
static unsigned int cursor = 0;
 
110
 
 
111
static int debug = 0;
 
112
 
 
113
 
 
114
static void readahead_set_len(int size)
 
115
{
 
116
        int unmount;
 
117
        int i = 0;
 
118
        char ractl[100];
 
119
        /* changes readahead size to "size" for local block devices */
 
120
 
 
121
        unmount = chdir("/sys/block");
 
122
        if (unmount != 0) {
 
123
                if (mount("sysfs", "/sys", "sysfs", 0, NULL) != 0) {
 
124
                        perror("Unable to mount sysfs\n");
 
125
                        /* non-fatal */
 
126
                        return;
 
127
                }
 
128
                chdir("/sys/block");
 
129
        }
 
130
 
 
131
        sprintf(ractl, "sda/queue/read_ahead_kb");
 
132
        while (i <= 3) {
 
133
                /* check first 4 sata discs */
 
134
                FILE *file = fopen(ractl, "w");
 
135
                if (file) {
 
136
                        fprintf(file, "%d", size);
 
137
                        fclose(file);
 
138
                }
 
139
                ractl[2]++; /* a -> b, etc */
 
140
                i++;
 
141
        }
 
142
 
 
143
        chdir("/");
 
144
 
 
145
        if (unmount != 0)
 
146
                umount("/sys");
 
147
}
 
148
 
 
149
static void readahead_one(int index)
 
150
{
 
151
        int fd;
 
152
        int i;
 
153
        char buf[128];
 
154
 
 
155
        fd = open(rd[index].filename, O_RDONLY|O_NOATIME);
 
156
        if (fd < 0)
 
157
                fd = open(rd[index].filename, O_RDONLY);
 
158
        if (fd < 0) {
 
159
                fprintf(stderr, "%s: open failed (%s)\n",
 
160
                        rd[index].filename, strerror_r(errno, buf, sizeof buf));
 
161
                return;
 
162
        }
 
163
 
 
164
        for (i = 0; i < MAXRECS; i++) {
 
165
                if (rd[index].data[i].len)
 
166
                        readahead(fd, rd[index].data[i].offset,
 
167
                                  rd[index].data[i].len);
 
168
        }
 
169
        close(fd);
 
170
}
 
171
 
 
172
static void *one_thread(void *ptr)
 
173
{
 
174
        while (1) {
 
175
                unsigned int mine;
 
176
 
 
177
                mine = __sync_fetch_and_add(&cursor, 1);
 
178
                if (mine < total_files)
 
179
                        readahead_one(mine);
 
180
                else
 
181
                        break;
 
182
        }
 
183
        return NULL;
 
184
}
 
185
 
 
186
static void sort_ra_by_name(void)
 
187
{
 
188
        int delta = 1;
 
189
 
 
190
        while (delta > 0) {
 
191
                int i;
 
192
                delta = 0;
 
193
                for (i = 0; i < racount - 1; i++) {
 
194
                        int c;
 
195
 
 
196
                        c = strcmp(ra[i]->filename, ra[i+1]->filename);
 
197
                        if (c > 0) {
 
198
                                struct ra_struct *tmp;
 
199
                                tmp = ra[i];
 
200
                                ra[i] = ra[i+1];
 
201
                                ra[i+1] = tmp;
 
202
                                delta++;
 
203
                        }
 
204
                }
 
205
        }
 
206
}
 
207
 
 
208
static void remove_dupes(void)
 
209
{
 
210
        int i;
 
211
        int j;
 
212
 
 
213
        for (i = 0; i < racount - 1; i++) {
 
214
                for (j = i + 1; j < racount; j++) {
 
215
                        if (!ra[i])
 
216
                                break;
 
217
 
 
218
                        if (strcmp(ra[i]->filename, ra[j]->filename) != 0) {
 
219
                                i = j - 1;
 
220
                                break;
 
221
                        }
 
222
                        if (ra[j]->next)
 
223
                                ra[j]->next->prev = ra[j]->prev;
 
224
                        if (ra[j]->prev)
 
225
                                ra[j]->prev->next = ra[j]->next;
 
226
                        free(ra[j]);
 
227
                        ra[j] = NULL;
 
228
                }
 
229
        }
 
230
}
 
231
 
 
232
static int smallest_gap(struct ra_record *record, int count)
 
233
{
 
234
        int i;
 
235
        int cur = 0, maxgap;
 
236
 
 
237
        maxgap = 1024*1024*512;
 
238
        
 
239
        for (i = 0; i < count; i++, record++) {
 
240
                if ((i + 1) < count) {
 
241
                        int gap;
 
242
                        gap = (record + 1)->offset - record->offset - record->len;
 
243
                        if (gap < maxgap) {
 
244
                                maxgap = gap;
 
245
                                cur = i;
 
246
                        }
 
247
                }
 
248
        }
 
249
        return cur;
 
250
}
 
251
 
 
252
static int merge_record(struct ra_record *record, int count, int to_merge)
 
253
{
 
254
        record[to_merge].len = record[to_merge+1].offset
 
255
                               + record[to_merge+1].len - record[to_merge].offset;
 
256
        memcpy(&record[to_merge+1], &record[to_merge+2],
 
257
                sizeof(struct ra_record) * (count-to_merge - 2));
 
258
        return count - 1;
 
259
}
 
260
 
 
261
static int reduce_blocks(struct ra_record *record, int count, int target)
 
262
{
 
263
        while (count > target) {
 
264
                int tomerge;
 
265
                tomerge = smallest_gap(record, count);
 
266
                count = merge_record(record, count, tomerge);
 
267
        }
 
268
        return count;
 
269
}
 
270
 
 
271
static int get_blocks(struct ra_struct *r)
 
272
{
 
273
        FILE *file;
 
274
        int fd;
 
275
        struct stat statbuf;
 
276
        void *mmapptr;
 
277
        unsigned char *mincorebuf;
 
278
        struct ra_record record[4096];
 
279
        int rcount = 0;
 
280
        int phase;
 
281
        uint32_t start = 0;
 
282
        int there = 0;
 
283
        int notthere = 0;
 
284
        int i;
 
285
 
 
286
        if (!r)
 
287
                goto remove;
 
288
 
 
289
        memset(record, 0, sizeof(record));
 
290
 
 
291
        file = fopen(r->filename, "r");
 
292
        if (!file)
 
293
                goto remove;
 
294
 
 
295
        fd = fileno(file);
 
296
        fstat(fd, &statbuf);
 
297
        mmapptr = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
 
298
 
 
299
        mincorebuf = malloc(statbuf.st_size/4096 + 1);
 
300
        mincore(mmapptr, statbuf.st_size, mincorebuf);
 
301
 
 
302
        if (mincorebuf[0]) {
 
303
                phase = 1;
 
304
                start = 0;
 
305
        } else {
 
306
                phase = 0;
 
307
        }
 
308
 
 
309
        for (i = 0; i <= statbuf.st_size; i += 4096) {
 
310
                if (mincorebuf[i / 4096])
 
311
                        there++;
 
312
                else
 
313
                        notthere++;
 
314
                if (phase == 1 && !mincorebuf[i / 4096]) {
 
315
                        phase = 0;
 
316
                        if (i > statbuf.st_size)
 
317
                                i = statbuf.st_size + 1;
 
318
                        record[rcount].offset = start;
 
319
                        record[rcount].len = i - 1 - start;
 
320
                        rcount++;
 
321
                        if (rcount >= 4000) rcount = 4000;
 
322
                } else if (phase == 0 && mincorebuf[i / 4096]) {
 
323
                        phase = 1;
 
324
                        start = i;
 
325
                }
 
326
        }
 
327
 
 
328
        if (phase == 1) {
 
329
                if (i > statbuf.st_size)
 
330
                        i = statbuf.st_size + 1;
 
331
                record[rcount].offset = start;
 
332
                record[rcount].len = i - 1 - start;
 
333
                rcount++;
 
334
        }
 
335
 
 
336
        free(mincorebuf);
 
337
        munmap(mmapptr, statbuf.st_size);
 
338
        fclose(file);
 
339
        
 
340
        rcount = reduce_blocks(record, rcount, MAXRECS);
 
341
        if (rcount > 0) {
 
342
                /* some empty files slip through */
 
343
                if (record[0].len == 0)
 
344
                        goto remove;
 
345
 
 
346
                if (debug) {
 
347
                        int tlen = 0;
 
348
                        int tc = 0;
 
349
                        while (tc < rcount) {
 
350
                                tlen += record[tc].len;
 
351
                                tc++;
 
352
                                fcount++;
 
353
                        }
 
354
                        rdsize += (tlen <= 0 ? 1024 : tlen);
 
355
                        printf("%s: %d fragment(s), %dkb, %3.1f%%\n",
 
356
                               r->filename, rcount,
 
357
                               (tlen <= 1024 ? 1024 : tlen) / 1024,
 
358
                               100.0 * there / (there + notthere));
 
359
                }
 
360
 
 
361
                memcpy(r->data, record, sizeof(r->data));
 
362
                return 1;
 
363
        }
 
364
 
 
365
remove:
 
366
        return 0;
 
367
}
 
368
 
 
369
static void get_ra_blocks(void)
 
370
{
 
371
        struct ra_struct *r = first_ra;
 
372
 
 
373
        while (r) {
 
374
                if (!get_blocks(r)) {
 
375
                        /* no blocks, remove from list */
 
376
                        if (r->next)
 
377
                                r->next->prev = r->prev;
 
378
                        if (r->prev)
 
379
                                r->prev->next = r->next;
 
380
                }
 
381
                r = r->next;
 
382
        }
 
383
}
 
384
 
 
385
static void trace_start(void)
 
386
{
 
387
        int ret;
 
388
        FILE *file;
 
389
        char buf[4096];
 
390
 
 
391
        /*
 
392
         * at this time during boot we can guarantee that things like
 
393
         * debugfs, sysfs are not mounted yet (at least they should be)
 
394
         * so we mount it temporarily to enable tracing, and umount
 
395
         */
 
396
        ret = mount("debugfs", DEBUGFS_MNT, "debugfs", 0, NULL);
 
397
        if (ret != 0) {
 
398
                perror("Unable to mount debugfs\n");
 
399
                exit(EXIT_FAILURE);
 
400
        }
 
401
 
 
402
        chdir(DEBUGFS_MNT);
 
403
 
 
404
        file = fopen("tracing/current_tracer", "w");
 
405
        if (!file) {
 
406
                perror("Unable to select tracer\n");
 
407
                exit(EXIT_FAILURE);
 
408
        }
 
409
        fprintf(file, "open");
 
410
        fclose(file);
 
411
 
 
412
        file = fopen("tracing/current_tracer", "r");
 
413
        fgets(buf, 4096, file);
 
414
        fclose(file);
 
415
        if (strcmp(buf, "open\n") != 0) {
 
416
                perror("Unable to select open tracer\n");
 
417
                exit(EXIT_FAILURE);
 
418
        }
 
419
 
 
420
        file = fopen("tracing/tracing_enabled", "w");
 
421
        if (!file) {
 
422
                perror("Unable to enable tracing\n");
 
423
                exit(EXIT_FAILURE);
 
424
        }
 
425
        fprintf(file, "1");
 
426
        fclose(file);
 
427
 
 
428
        file = fopen("tracing/tracing_enabled", "r");
 
429
        fgets(buf, 4096, file);
 
430
        fclose(file);
 
431
        if (strcmp(buf, "1\n") != 0) {
 
432
                perror("Enabling tracing failed\n");
 
433
                exit(EXIT_FAILURE);
 
434
        }
 
435
 
 
436
        chdir("/");
 
437
 
 
438
        umount(DEBUGFS_MNT);
 
439
 
 
440
        /* set this low, so we don't readahead way too much */
 
441
        readahead_set_len(RA_SMALL);
 
442
}
 
443
 
 
444
static void trace_stop(int signal)
 
445
{
 
446
        int unmount;
 
447
        int ret;
 
448
        char buf[4096];
 
449
        char filename[4096];
 
450
        FILE *file;
 
451
        struct ra_struct *r;
 
452
        struct tms start_time;
 
453
        struct tms stop_time;
 
454
 
 
455
        if (debug)
 
456
                times(&start_time);
 
457
 
 
458
        nice(20);
 
459
 
 
460
        /* return readahead size to normal */
 
461
        readahead_set_len(RA_NORMAL);
 
462
 
 
463
        /*
 
464
         * by now the init process should have mounted debugf on a logical
 
465
         * location like /sys/kernel/debug, but if not then we temporarily
 
466
         * re-mount it ourselves
 
467
         */
 
468
        unmount = chdir("/sys/kernel/debug/tracing");
 
469
        if (unmount != 0) {
 
470
                ret = mount("debugfs", DEBUGFS_MNT, "debugfs", 0, NULL);
 
471
                if (ret != 0) {
 
472
                        perror("Unable to mount debugfs\n");
 
473
                        exit(EXIT_FAILURE);
 
474
                }
 
475
                chdir(DEBUGFS_MNT);
 
476
        }
 
477
 
 
478
        /* stop tracing */
 
479
        file = fopen("tracing/tracing_enabled", "w");
 
480
        if (!file) {
 
481
                perror("Unable to disable tracing\n");
 
482
                /* non-fatal */
 
483
        } else {
 
484
                fprintf(file, "0");
 
485
                fclose(file);
 
486
        }
 
487
 
 
488
        file = fopen("tracing/trace", "r");
 
489
        if (!file) {
 
490
                perror("Unable to open trace file\n");
 
491
                exit(EXIT_FAILURE);
 
492
        }
 
493
 
 
494
        while (fgets(buf, 4095, file) != NULL) {
 
495
                char *start;
 
496
                char *len;
 
497
 
 
498
                if (buf[0] == '#')
 
499
                        continue;
 
500
 
 
501
                start = strchr(buf, '"') + 1;
 
502
                if (start == buf)
 
503
                        continue;
 
504
 
 
505
                len = strrchr(start, '"');
 
506
                strncpy(filename, start, len - start);
 
507
 
 
508
                filename[len - start] = '\0';
 
509
 
 
510
                /* ignore sys, dev, proc stuff */
 
511
                if (strncmp(filename, "/dev/", 5) == 0)
 
512
                        continue;
 
513
                if (strncmp(filename, "/sys/", 5) == 0)
 
514
                        continue;
 
515
                if (strncmp(filename, "/proc/", 6) == 0)
 
516
                        continue;
 
517
 
 
518
                if (racount >= MAXR) {
 
519
                        perror("Max records exceeded!");
 
520
                        break;
 
521
                }
 
522
 
 
523
                if (strlen(filename) <= MAXFL) {
 
524
                        struct ra_struct *tmp;
 
525
                        tmp = malloc(sizeof(struct ra_struct));
 
526
 
 
527
                        if (!tmp) {
 
528
                                perror("Out of memory\n");
 
529
                                exit(EXIT_FAILURE);
 
530
                        }
 
531
                        memset(tmp, 0, sizeof(struct ra_struct));
 
532
 
 
533
                        ra[racount] = tmp;
 
534
 
 
535
                        strcpy(ra[racount]->filename, filename);
 
536
                        if (racount > 0) {
 
537
                                ra[racount]->prev = ra[racount - 1];
 
538
                                ra[racount - 1]->next = ra[racount];
 
539
                        }
 
540
                        ra[racount]->number = racount;
 
541
                        racount++;
 
542
                }
 
543
        }
 
544
        fclose(file);
 
545
 
 
546
        if (debug)
 
547
                printf("Trace contained %d records\n", racount);
 
548
 
 
549
        first_ra = ra[0];
 
550
 
 
551
        chdir("/");
 
552
        if (unmount != 0) {
 
553
                umount(DEBUGFS_MNT);
 
554
        }
 
555
 
 
556
        /*
 
557
         * sort and filter duplicates, and get memory blocks
 
558
         */
 
559
        sort_ra_by_name();
 
560
        remove_dupes();
 
561
        get_ra_blocks();
 
562
 
 
563
        /*
 
564
         * and write out the new pack file
 
565
         */
 
566
        file = fopen(PACK_FILE, "w");
 
567
        if (!file) {
 
568
                perror("Unable to open output file\n");
 
569
                exit(EXIT_FAILURE);
 
570
        }
 
571
 
 
572
        r = first_ra;
 
573
        while (r) {
 
574
                fwrite(r->filename, MAXFL, 1, file);
 
575
                fwrite(r->data, sizeof(r->data), 1, file);
 
576
                r = r->next;
 
577
                rdcount++;
 
578
        }
 
579
        fclose(file);
 
580
        if (debug) {
 
581
                times(&stop_time);
 
582
                printf("Took %.3f seconds\n", (double)(stop_time.tms_utime -
 
583
                       start_time.tms_utime) / 1000.0f);
 
584
                printf("Total %d files, %dkb, %d fragments\n", rdcount,
 
585
 
 
586
                       rdsize / 1024, fcount);
 
587
        }
 
588
 
 
589
        exit(EXIT_SUCCESS);
 
590
}
 
591
 
 
592
static void print_usage(const char *name)
 
593
{
 
594
        printf("Usage: %s [OPTION...]\n", name);
 
595
        printf("  -d, --debug           Print debug output to stdout\n");
 
596
        printf("  -h, --help            Show this help message\n");
 
597
        printf("  -v, --version         Show version information and exit\n");
 
598
        exit(EXIT_SUCCESS);
 
599
}
 
600
 
 
601
static void print_version(void)
 
602
{
 
603
        printf("sreadahead version %s\n", VERSION);
 
604
        printf("Copyright (C) 2008, 2009 Intel Corporation\n");
 
605
        exit(EXIT_SUCCESS);
 
606
}
 
607
 
 
608
int main(int argc, char **argv)
 
609
{
 
610
        FILE *file;
 
611
        int pid = 0;
 
612
        pthread_t one, two, three, four;
 
613
 
 
614
        while (1) {
 
615
                static struct option opts[] = {
 
616
                        { "debug", 0, NULL, 'd' },
 
617
                        { "help", 0, NULL, 'h' },
 
618
                        { "version", 0, NULL, 'v' },
 
619
                        { 0, 0, NULL, 0 }
 
620
                };
 
621
                int c;
 
622
                int index = 0;
 
623
 
 
624
                c = getopt_long(argc, argv, "dhv", opts, &index);
 
625
                if (c == -1)
 
626
                        break;
 
627
                switch (c) {
 
628
                case 'd':
 
629
                        debug = 1;
 
630
                        break;
 
631
                case 'v':
 
632
                        print_version();
 
633
                        break;
 
634
                case 'h':
 
635
                        print_usage(argv[0]);
 
636
                        break;
 
637
                default:
 
638
                        ;
 
639
                }
 
640
        }
 
641
 
 
642
        file = fopen(PACK_FILE, "r");
 
643
        if (!file) {
 
644
                /* enable tracing open calls before we fork! */
 
645
                trace_start();
 
646
        
 
647
                if (!fork()) {
 
648
                        /* child */
 
649
                        signal(SIGUSR1, trace_stop);
 
650
                        /*
 
651
                         * "" 15 seconds should be enough for everyone to boot""
 
652
                         * -- Auke Kok, 2009
 
653
                         */
 
654
                        sleep(15);
 
655
                        /*
 
656
                         * abort if we don't get a signal, so we can stop
 
657
                         * the tracing and minimize the trace buffer size
 
658
                         */
 
659
                        signal(SIGUSR1, NULL);
 
660
                        trace_stop(0);
 
661
                } else {
 
662
                        return EXIT_SUCCESS;
 
663
                }
 
664
        }
 
665
 
 
666
        total_files = fread(&rd, sizeof(struct ra_disk), MAXR, file);
 
667
 
 
668
        if (ferror(file)) {
 
669
                perror("Can't open sreadahead pack file");
 
670
                return 1;
 
671
        }
 
672
        fclose(file);
 
673
 
 
674
#ifdef HAVE_IO_PRIO
 
675
        if (syscall(__NR_ioprio_set, IOPRIO_WHO_PROCESS, pid,
 
676
                    IOPRIO_IDLE_LOWEST) == -1)
 
677
                perror("Can not set IO priority to idle class");
 
678
#endif
 
679
 
 
680
        readahead_set_len(RA_SMALL);
 
681
 
 
682
        daemon(0,0);
 
683
 
 
684
        pthread_create(&one, NULL, one_thread, NULL);
 
685
        pthread_create(&two, NULL, one_thread, NULL);
 
686
        pthread_create(&three, NULL, one_thread, NULL);
 
687
        pthread_create(&four, NULL, one_thread, NULL);
 
688
 
 
689
        pthread_join(one, NULL);
 
690
        pthread_join(two, NULL);
 
691
        pthread_join(three, NULL);
 
692
        pthread_join(four, NULL);
 
693
 
 
694
        readahead_set_len(RA_NORMAL);
 
695
 
 
696
        return EXIT_SUCCESS;
 
697
}