Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/user/testbin/psort/psort.c
734 views
1
/*
2
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3
* The President and Fellows of Harvard College.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of the University nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
/*
31
* psort - parallel sort.
32
*
33
* This is loosely based on some real parallel sort benchmarks, but
34
* because of various limitations of OS/161 it is massively
35
* inefficient. But that's ok; the goal is to stress the VM and buffer
36
* cache.
37
*/
38
39
#include <sys/types.h>
40
#include <sys/stat.h>
41
#include <sys/wait.h>
42
#include <stdio.h>
43
#include <stdarg.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <assert.h>
47
#include <unistd.h>
48
#include <fcntl.h>
49
#include <errno.h>
50
51
#ifndef RANDOM_MAX
52
/* Note: this is correct for OS/161 but not for some Unix C libraries */
53
#define RANDOM_MAX RAND_MAX
54
#endif
55
56
#define PATH_KEYS "sortkeys"
57
#define PATH_SORTED "output"
58
#define PATH_TESTDIR "psortdir"
59
#define PATH_RANDOM "rand:"
60
61
#define WORKNUM (128*1024)
62
63
64
static int workspace[WORKNUM];
65
66
static const char *progname;
67
68
static int numprocs = 4;
69
static int numkeys = 10000;
70
static long randomseed = 15432753;
71
72
static off_t correctsize;
73
static unsigned long checksum;
74
75
#define NOBODY (-1)
76
static int me = NOBODY;
77
78
////////////////////////////////////////////////////////////
79
80
static
81
void
82
sortints(int *v, int num)
83
{
84
int pivotval, pivotpoint, pivotcount;
85
int frontpos, readpos, endpos, i, j;
86
int tmp;
87
88
if (num < 2) {
89
return;
90
}
91
92
pivotpoint = num/2;
93
pivotval = v[pivotpoint];
94
pivotcount = 0;
95
96
frontpos = 0;
97
readpos = 0;
98
endpos = num;
99
while (readpos < endpos) {
100
if (v[readpos] < pivotval) {
101
v[frontpos++] = v[readpos++];
102
}
103
else if (v[readpos] == pivotval) {
104
readpos++;
105
pivotcount++;
106
}
107
else {
108
tmp = v[--endpos];
109
v[endpos] = v[readpos];
110
v[readpos] = tmp;
111
}
112
}
113
assert(readpos == endpos);
114
assert(frontpos + pivotcount == readpos);
115
116
for (i=frontpos; i<endpos; i++) {
117
v[i] = pivotval;
118
}
119
120
for (i=endpos, j=num-1; i<j; i++,j--) {
121
tmp = v[i];
122
v[i] = v[j];
123
v[j] = tmp;
124
}
125
126
sortints(v, frontpos);
127
sortints(&v[endpos], num-endpos);
128
}
129
130
////////////////////////////////////////////////////////////
131
132
static
133
void
134
initprogname(const char *av0)
135
{
136
if (av0) {
137
progname = strrchr(av0, '/');
138
if (progname) {
139
progname++;
140
}
141
else {
142
progname = av0;
143
}
144
}
145
else {
146
progname = "psort";
147
}
148
}
149
150
static
151
void
152
vscomplain(char *buf, size_t len, const char *fmt, va_list ap, int err)
153
{
154
size_t pos;
155
156
if (me >= 0) {
157
snprintf(buf, len, "%s: proc %d: ", progname, me);
158
}
159
else {
160
snprintf(buf, len, "%s: ", progname);
161
}
162
pos = strlen(buf);
163
164
vsnprintf(buf+pos, len-pos, fmt, ap);
165
pos = strlen(buf);
166
167
if (err >= 0) {
168
snprintf(buf+pos, len-pos, ": %s\n", strerror(err));
169
}
170
else {
171
snprintf(buf+pos, len-pos, "\n");
172
}
173
}
174
175
static
176
void
177
complainx(const char *fmt, ...)
178
{
179
char buf[256];
180
int unused;
181
va_list ap;
182
183
va_start(ap, fmt);
184
vscomplain(buf, sizeof(buf), fmt, ap, -1);
185
va_end(ap);
186
187
/* Write the message in one go so it's atomic */
188
unused = write(STDERR_FILENO, buf, strlen(buf));
189
}
190
191
static
192
void
193
complain(const char *fmt, ...)
194
{
195
char buf[256];
196
va_list ap;
197
int err = errno;
198
int unused;
199
200
va_start(ap, fmt);
201
vscomplain(buf, sizeof(buf), fmt, ap, err);
202
va_end(ap);
203
204
/* Write the message in one go so it's atomic */
205
unused = write(STDERR_FILENO, buf, strlen(buf));
206
}
207
208
////////////////////////////////////////////////////////////
209
210
static
211
int
212
doopen(const char *path, int flags, int mode)
213
{
214
int fd;
215
216
fd = open(path, flags, mode);
217
if (fd<0) {
218
complain("%s", path);
219
exit(1);
220
}
221
return fd;
222
}
223
224
static
225
void
226
doclose(const char *path, int fd)
227
{
228
if (close(fd)) {
229
complain("%s: close", path);
230
exit(1);
231
}
232
}
233
234
static
235
void
236
docreate(const char *path)
237
{
238
int fd;
239
240
fd = doopen(path, O_WRONLY|O_CREAT|O_TRUNC, 0664);
241
doclose(path, fd);
242
}
243
244
static
245
void
246
doremove(const char *path)
247
{
248
static int noremove;
249
250
if (noremove) {
251
return;
252
}
253
254
if (remove(path) < 0) {
255
if (errno == ENOSYS) {
256
/* Complain (and try) only once. */
257
noremove = 1;
258
}
259
complain("%s: remove", path);
260
}
261
}
262
263
static
264
off_t
265
getsize(const char *path)
266
{
267
struct stat buf;
268
int fd;
269
static int no_stat, no_fstat;
270
271
if (!no_stat) {
272
if (stat(path, &buf) == 0) {
273
return buf.st_size;
274
}
275
if (errno != ENOSYS) {
276
complain("%s: stat", path);
277
exit(1);
278
}
279
/* Avoid further "Unknown syscall 81" messages */
280
no_stat = 1;
281
}
282
283
fd = doopen(path, O_RDONLY, 0);
284
if (!no_fstat) {
285
if (fstat(fd, &buf) == 0) {
286
close(fd);
287
return buf.st_size;
288
}
289
if (errno != ENOSYS) {
290
complain("%s: stat", path);
291
exit(1);
292
}
293
/* Avoid further "Unknown syscall 82" messages */
294
no_fstat = 1;
295
}
296
297
/* otherwise, lseek */
298
if (lseek(fd, 0, SEEK_END) >= 0) {
299
buf.st_size = lseek(fd, 0, SEEK_CUR);
300
if (buf.st_size >= 0) {
301
return buf.st_size;
302
}
303
}
304
complain("%s: getting file size with lseek", path);
305
close(fd);
306
exit(1);
307
}
308
309
static
310
size_t
311
doread(const char *path, int fd, void *buf, size_t len)
312
{
313
int result;
314
315
result = read(fd, buf, len);
316
if (result < 0) {
317
complain("%s: read", path);
318
exit(1);
319
}
320
return (size_t) result;
321
}
322
323
static
324
void
325
doexactread(const char *path, int fd, void *buf, size_t len)
326
{
327
size_t result;
328
329
result = doread(path, fd, buf, len);
330
if (result != len) {
331
complainx("%s: read: short count", path);
332
exit(1);
333
}
334
}
335
336
static
337
void
338
dowrite(const char *path, int fd, const void *buf, size_t len)
339
{
340
int result;
341
342
result = write(fd, buf, len);
343
if (result < 0) {
344
complain("%s: write", path);
345
exit(1);
346
}
347
if ((size_t) result != len) {
348
complainx("%s: write: short count", path);
349
exit(1);
350
}
351
}
352
353
static
354
void
355
dolseek(const char *name, int fd, off_t offset, int whence)
356
{
357
if (lseek(fd, offset, whence) < 0) {
358
complain("%s: lseek", name);
359
exit(1);
360
}
361
}
362
363
#if 0 /* let's not require subdirs */
364
static
365
void
366
dochdir(const char *path)
367
{
368
if (chdir(path) < 0) {
369
complain("%s: chdir", path);
370
exit(1);
371
}
372
}
373
374
static
375
void
376
domkdir(const char *path, int mode)
377
{
378
if (mkdir(path, mode) < 0) {
379
complain("%s: mkdir", path);
380
exit(1);
381
}
382
}
383
#endif /* 0 */
384
385
static
386
pid_t
387
dofork(void)
388
{
389
pid_t pid;
390
391
pid = fork();
392
if (pid < 0) {
393
complain("fork");
394
/* but don't exit */
395
}
396
397
return pid;
398
}
399
400
////////////////////////////////////////////////////////////
401
402
static
403
int
404
dowait(int guy, pid_t pid)
405
{
406
int status, result;
407
408
result = waitpid(pid, &status, 0);
409
if (result < 0) {
410
complain("waitpid");
411
return -1;
412
}
413
if (WIFSIGNALED(status)) {
414
complainx("proc %d: signal %d", guy, WTERMSIG(status));
415
return -1;
416
}
417
assert(WIFEXITED(status));
418
status = WEXITSTATUS(status);
419
if (status) {
420
complainx("proc %d: exit %d", guy, status);
421
return -1;
422
}
423
return 0;
424
}
425
426
static
427
void
428
doforkall(const char *phasename, void (*func)(void))
429
{
430
int i, bad = 0;
431
pid_t pids[numprocs];
432
433
for (i=0; i<numprocs; i++) {
434
pids[i] = dofork();
435
if (pids[i] < 0) {
436
bad = 1;
437
}
438
else if (pids[i] == 0) {
439
/* child */
440
me = i;
441
func();
442
exit(0);
443
}
444
}
445
446
for (i=0; i<numprocs; i++) {
447
if (pids[i] > 0 && dowait(i, pids[i])) {
448
bad = 1;
449
}
450
}
451
452
if (bad) {
453
complainx("%s failed.", phasename);
454
exit(1);
455
}
456
}
457
458
static
459
void
460
seekmyplace(const char *name, int fd)
461
{
462
int keys_per, myfirst;
463
off_t offset;
464
465
keys_per = numkeys / numprocs;
466
myfirst = me*keys_per;
467
offset = myfirst * sizeof(int);
468
469
dolseek(name, fd, offset, SEEK_SET);
470
}
471
472
static
473
int
474
getmykeys(void)
475
{
476
int keys_per, myfirst, mykeys;
477
478
keys_per = numkeys / numprocs;
479
myfirst = me*keys_per;
480
mykeys = (me < numprocs-1) ? keys_per : numkeys - myfirst;
481
482
return mykeys;
483
}
484
485
////////////////////////////////////////////////////////////
486
487
static
488
unsigned long
489
checksum_file(const char *path)
490
{
491
int fd;
492
char buf[512];
493
size_t count, i;
494
unsigned long sum = 0;
495
496
fd = doopen(path, O_RDONLY, 0);
497
498
while ((count = doread(path, fd, buf, sizeof(buf))) > 0) {
499
for (i=0; i<count; i++) {
500
sum += (unsigned char) buf[i];
501
}
502
}
503
504
doclose(path, fd);
505
506
return sum;
507
}
508
509
////////////////////////////////////////////////////////////
510
511
static long *seeds;
512
513
static
514
void
515
genkeys_sub(void)
516
{
517
int fd, i, mykeys, keys_done, keys_to_do, value;
518
519
fd = doopen(PATH_KEYS, O_WRONLY, 0);
520
521
mykeys = getmykeys();
522
seekmyplace(PATH_KEYS, fd);
523
524
srandom(seeds[me]);
525
keys_done = 0;
526
while (keys_done < mykeys) {
527
keys_to_do = mykeys - keys_done;
528
if (keys_to_do > WORKNUM) {
529
keys_to_do = WORKNUM;
530
}
531
532
for (i=0; i<keys_to_do; i++) {
533
value = random();
534
535
// check bounds of value
536
assert(value >= 0);
537
assert(value <= RANDOM_MAX);
538
539
// do not allow the value to be zero or RANDOM_MAX
540
while (value == 0 || value == RANDOM_MAX) {
541
value = random();
542
}
543
544
workspace[i] = value;
545
}
546
547
dowrite(PATH_KEYS, fd, workspace, keys_to_do*sizeof(int));
548
keys_done += keys_to_do;
549
}
550
551
doclose(PATH_KEYS, fd);
552
}
553
554
static
555
void
556
genkeys(void)
557
{
558
long seedspace[numprocs];
559
int i;
560
561
/* Create the file. */
562
docreate(PATH_KEYS);
563
564
/* Generate random seeds for each subprocess. */
565
srandom(randomseed);
566
for (i=0; i<numprocs; i++) {
567
seedspace[i] = random();
568
}
569
570
/* Do it. */
571
seeds = seedspace;
572
doforkall("Initialization", genkeys_sub);
573
seeds = NULL;
574
575
/* Cross-check the size of the output. */
576
if (getsize(PATH_KEYS) != correctsize) {
577
complainx("%s: file is wrong size", PATH_KEYS);
578
exit(1);
579
}
580
581
/* Checksum the output. */
582
checksum = checksum_file(PATH_KEYS);
583
complainx("Checksum of unsorted keys: %ld", checksum);
584
}
585
586
////////////////////////////////////////////////////////////
587
588
static
589
const char *
590
binname(int a, int b)
591
{
592
static char rv[32];
593
snprintf(rv, sizeof(rv), "bin-%d-%d", a, b);
594
return rv;
595
}
596
597
static
598
const char *
599
mergedname(int a)
600
{
601
static char rv[32];
602
snprintf(rv, sizeof(rv), "merged-%d", a);
603
return rv;
604
}
605
606
static
607
void
608
bin(void)
609
{
610
int infd, outfds[numprocs];
611
const char *name;
612
int i, mykeys, keys_done, keys_to_do;
613
int key, pivot, binnum;
614
615
infd = doopen(PATH_KEYS, O_RDONLY, 0);
616
617
mykeys = getmykeys();
618
seekmyplace(PATH_KEYS, infd);
619
620
for (i=0; i<numprocs; i++) {
621
name = binname(me, i);
622
outfds[i] = doopen(name, O_WRONLY|O_CREAT|O_TRUNC, 0664);
623
}
624
625
pivot = (RANDOM_MAX / numprocs);
626
627
keys_done = 0;
628
while (keys_done < mykeys) {
629
keys_to_do = mykeys - keys_done;
630
if (keys_to_do > WORKNUM) {
631
keys_to_do = WORKNUM;
632
}
633
634
doexactread(PATH_KEYS, infd, workspace,
635
keys_to_do * sizeof(int));
636
637
for (i=0; i<keys_to_do; i++) {
638
key = workspace[i];
639
640
binnum = key / pivot;
641
if (key <= 0) {
642
complainx("proc %d: garbage key %d", me, key);
643
key = 0;
644
}
645
assert(binnum >= 0);
646
assert(binnum < numprocs);
647
dowrite("bin", outfds[binnum], &key, sizeof(key));
648
}
649
650
keys_done += keys_to_do;
651
}
652
doclose(PATH_KEYS, infd);
653
654
for (i=0; i<numprocs; i++) {
655
doclose(binname(me, i), outfds[i]);
656
}
657
}
658
659
static
660
void
661
sortbins(void)
662
{
663
const char *name;
664
int i, fd;
665
off_t binsize;
666
667
for (i=0; i<numprocs; i++) {
668
name = binname(me, i);
669
binsize = getsize(name);
670
if (binsize % sizeof(int) != 0) {
671
complainx("%s: bin size %ld no good", name,
672
(long) binsize);
673
exit(1);
674
}
675
if (binsize > (off_t) sizeof(workspace)) {
676
complainx("proc %d: %s: bin too large", me, name);
677
exit(1);
678
}
679
680
fd = doopen(name, O_RDWR, 0);
681
doexactread(name, fd, workspace, binsize);
682
683
sortints(workspace, binsize/sizeof(int));
684
685
dolseek(name, fd, 0, SEEK_SET);
686
dowrite(name, fd, workspace, binsize);
687
doclose(name, fd);
688
}
689
}
690
691
static
692
void
693
mergebins(void)
694
{
695
int infds[numprocs], outfd;
696
int values[numprocs], ready[numprocs];
697
const char *name, *outname;
698
int i, result;
699
int numready, place, val, worknum;
700
701
outname = mergedname(me);
702
outfd = doopen(outname, O_WRONLY|O_CREAT|O_TRUNC, 0664);
703
704
for (i=0; i<numprocs; i++) {
705
name = binname(i, me);
706
infds[i] = doopen(name, O_RDONLY, 0);
707
values[i] = 0;
708
ready[i] = 0;
709
}
710
711
worknum = 0;
712
713
while (1) {
714
numready = 0;
715
for (i=0; i<numprocs; i++) {
716
if (infds[i] < 0) {
717
continue;
718
}
719
720
if (!ready[i]) {
721
result = doread("bin", infds[i],
722
&val, sizeof(int));
723
if (result == 0) {
724
doclose("bin", infds[i]);
725
infds[i] = -1;
726
continue;
727
}
728
if ((size_t) result != sizeof(int)) {
729
complainx("%s: read: short count",
730
binname(i, me));
731
exit(1);
732
}
733
values[i] = val;
734
ready[i] = 1;
735
}
736
numready++;
737
}
738
if (numready == 0) {
739
break;
740
}
741
742
/* find the smallest */
743
place = -1;
744
for (i=0; i<numprocs; i++) {
745
if (!ready[i]) {
746
continue;
747
}
748
if (place < 0 || values[i] < val) {
749
val = values[i];
750
place = i;
751
}
752
}
753
assert(place >= 0);
754
755
workspace[worknum++] = val;
756
if (worknum >= WORKNUM) {
757
assert(worknum == WORKNUM);
758
dowrite(outname, outfd, workspace,
759
worknum * sizeof(int));
760
worknum = 0;
761
}
762
ready[place] = 0;
763
}
764
765
dowrite(outname, outfd, workspace, worknum * sizeof(int));
766
doclose(outname, outfd);
767
768
for (i=0; i<numprocs; i++) {
769
assert(infds[i] < 0);
770
}
771
}
772
773
static
774
void
775
assemble(void)
776
{
777
off_t mypos;
778
int i, fd;
779
const char *args[3];
780
781
mypos = 0;
782
for (i=0; i<me; i++) {
783
mypos += getsize(mergedname(i));
784
}
785
786
fd = doopen(PATH_SORTED, O_WRONLY, 0);
787
dolseek(PATH_SORTED, fd, mypos, SEEK_SET);
788
789
if (dup2(fd, STDOUT_FILENO) < 0) {
790
complain("dup2");
791
exit(1);
792
}
793
794
doclose(PATH_SORTED, fd);
795
796
args[0] = "cat";
797
args[1] = mergedname(me);
798
args[2] = NULL;
799
execv("/bin/cat", (char **) args);
800
complain("/bin/cat: exec");
801
exit(1);
802
}
803
804
static
805
void
806
checksize_bins(void)
807
{
808
off_t totsize;
809
int i, j;
810
811
totsize = 0;
812
for (i=0; i<numprocs; i++) {
813
for (j=0; j<numprocs; j++) {
814
totsize += getsize(binname(i, j));
815
}
816
}
817
if (totsize != correctsize) {
818
complain("Sum of bin sizes is wrong (%ld, should be %ld)",
819
(long) totsize, (long) correctsize);
820
exit(1);
821
}
822
}
823
824
static
825
void
826
checksize_merge(void)
827
{
828
off_t totsize;
829
int i;
830
831
totsize = 0;
832
for (i=0; i<numprocs; i++) {
833
totsize += getsize(mergedname(i));
834
}
835
if (totsize != correctsize) {
836
complain("Sum of merged sizes is wrong (%ld, should be %ld)",
837
(long) totsize, (long) correctsize);
838
exit(1);
839
}
840
}
841
842
static
843
void
844
sort(void)
845
{
846
unsigned long sortedsum;
847
int i, j;
848
849
/* Step 1. Toss into bins. */
850
doforkall("Tossing", bin);
851
checksize_bins();
852
complainx("Done tossing into bins.");
853
854
/* Step 2: Sort the bins. */
855
doforkall("Sorting", sortbins);
856
checksize_bins();
857
complainx("Done sorting the bins.");
858
859
/* Step 3: Merge corresponding bins. */
860
doforkall("Merging", mergebins);
861
checksize_merge();
862
complainx("Done merging the bins.");
863
864
/* Step 3a: delete the bins */
865
for (i=0; i<numprocs; i++) {
866
for (j=0; j<numprocs; j++) {
867
doremove(binname(i, j));
868
}
869
}
870
871
/* Step 4: assemble output file */
872
docreate(PATH_SORTED);
873
doforkall("Final assembly", assemble);
874
if (getsize(PATH_SORTED) != correctsize) {
875
complainx("%s: file is wrong size", PATH_SORTED);
876
exit(1);
877
}
878
879
/* Step 4a: delete the merged bins */
880
for (i=0; i<numprocs; i++) {
881
doremove(mergedname(i));
882
}
883
884
/* Step 5: Checksum the result. */
885
sortedsum = checksum_file(PATH_SORTED);
886
complainx("Checksum of sorted keys: %ld", sortedsum);
887
888
if (sortedsum != checksum) {
889
complainx("Sums do not match");
890
exit(1);
891
}
892
}
893
894
////////////////////////////////////////////////////////////
895
896
static
897
const char *
898
validname(int a)
899
{
900
static char rv[32];
901
snprintf(rv, sizeof(rv), "valid-%d", a);
902
return rv;
903
}
904
905
static
906
void
907
checksize_valid(void)
908
{
909
off_t totvsize, correctvsize;
910
int i;
911
912
correctvsize = (off_t) numprocs*2*sizeof(int);
913
914
totvsize = 0;
915
for (i=0; i<numprocs; i++) {
916
totvsize += getsize(validname(i));
917
}
918
if (totvsize != correctvsize) {
919
complainx("Sum of validation sizes is wrong "
920
"(%ld, should be %ld)",
921
(long) totvsize, (long) correctvsize);
922
exit(1);
923
}
924
}
925
926
static
927
void
928
dovalidate(void)
929
{
930
const char *name;
931
int fd, i, mykeys, keys_done, keys_to_do;
932
int key, smallest, largest;
933
934
name = PATH_SORTED;
935
fd = doopen(name, O_RDONLY, 0);
936
937
mykeys = getmykeys();
938
seekmyplace(name, fd);
939
940
smallest = RANDOM_MAX;
941
largest = 0;
942
943
keys_done = 0;
944
while (keys_done < mykeys) {
945
keys_to_do = mykeys - keys_done;
946
if (keys_to_do > WORKNUM) {
947
keys_to_do = WORKNUM;
948
}
949
950
doexactread(name, fd, workspace, keys_to_do * sizeof(int));
951
952
for (i=0; i<keys_to_do; i++) {
953
key = workspace[i];
954
955
if (key < 0) {
956
complain("%s: found negative key", name);
957
exit(1);
958
}
959
if (key == 0) {
960
complain("%s: found zero key", name);
961
exit(1);
962
}
963
if (key >= RANDOM_MAX) {
964
complain("%s: found too-large key", name);
965
exit(1);
966
}
967
968
if (key < smallest) {
969
smallest = key;
970
}
971
if (key > largest) {
972
largest = key;
973
}
974
}
975
976
keys_done += keys_to_do;
977
}
978
doclose(name, fd);
979
980
name = validname(me);
981
fd = doopen(name, O_WRONLY|O_CREAT|O_TRUNC, 0664);
982
dowrite(name, fd, &smallest, sizeof(smallest));
983
dowrite(name, fd, &largest, sizeof(largest));
984
doclose(name, fd);
985
}
986
987
static
988
void
989
validate(void)
990
{
991
int smallest, largest, prev_largest;
992
int i, fd;
993
const char *name;
994
995
doforkall("Validation", dovalidate);
996
checksize_valid();
997
998
prev_largest = 1;
999
1000
for (i=0; i<numprocs; i++) {
1001
name = validname(i);
1002
fd = doopen(name, O_RDONLY, 0);
1003
1004
doexactread(name, fd, &smallest, sizeof(int));
1005
doexactread(name, fd, &largest, sizeof(int));
1006
1007
if (smallest < 1) {
1008
complainx("Validation: block %d: bad SMALLEST", i);
1009
exit(1);
1010
}
1011
if (largest >= RANDOM_MAX) {
1012
complainx("Validation: block %d: bad LARGEST", i);
1013
exit(1);
1014
}
1015
if (smallest > largest) {
1016
complainx("Validation: block %d: SMALLEST > LARGEST",
1017
i);
1018
exit(1);
1019
}
1020
1021
if (smallest < prev_largest) {
1022
complain("Validation: block %d smallest key %d",
1023
i, smallest);
1024
complain("Validation: previous block largest key %d",
1025
prev_largest);
1026
complain("Validation failed");
1027
exit(1);
1028
}
1029
}
1030
1031
1032
for (i=0; i<numprocs; i++) {
1033
doremove(validname(i));
1034
}
1035
}
1036
1037
////////////////////////////////////////////////////////////
1038
1039
static
1040
void
1041
setdir(void)
1042
{
1043
#if 0 /* let's not require subdirs */
1044
domkdir(PATH_TESTDIR, 0775);
1045
dochdir(PATH_TESTDIR);
1046
#endif /* 0 */
1047
}
1048
1049
static
1050
void
1051
unsetdir(void)
1052
{
1053
doremove(PATH_KEYS);
1054
doremove(PATH_SORTED);
1055
#if 0 /* let's not require subdirs */
1056
dochdir("..");
1057
1058
if (rmdir(PATH_TESTDIR) < 0) {
1059
complain("%s: rmdir", PATH_TESTDIR);
1060
/* but don't exit */
1061
}
1062
#endif /* 0 */
1063
}
1064
1065
////////////////////////////////////////////////////////////
1066
1067
static
1068
void
1069
randomize(void)
1070
{
1071
int fd;
1072
1073
fd = doopen(PATH_RANDOM, O_RDONLY, 0);
1074
doexactread(PATH_RANDOM, fd, &randomseed, sizeof(randomseed));
1075
doclose(PATH_RANDOM, fd);
1076
}
1077
1078
static
1079
void
1080
usage(void)
1081
{
1082
complain("Usage: %s [-p procs] [-k keys] [-s seed] [-r]", progname);
1083
exit(1);
1084
}
1085
1086
static
1087
void
1088
doargs(int argc, char *argv[])
1089
{
1090
int i, ch, val, arg;
1091
1092
for (i=1; i<argc; i++) {
1093
if (argv[i][0] != '-') {
1094
usage();
1095
return;
1096
}
1097
ch = argv[i][1];
1098
switch (ch) {
1099
case 'p': arg = 1; break;
1100
case 'k': arg = 1; break;
1101
case 's': arg = 1; break;
1102
case 'r': arg = 0; break;
1103
default: usage(); return;
1104
}
1105
if (arg) {
1106
if (argv[i][2]) {
1107
val = atoi(argv[i]+2);
1108
}
1109
else {
1110
i++;
1111
if (!argv[i]) {
1112
complain("Option -%c requires an "
1113
"argument", ch);
1114
exit(1);
1115
}
1116
val = atoi(argv[i]);
1117
}
1118
switch (ch) {
1119
case 'p': numprocs = val; break;
1120
case 'k': numkeys = val; break;
1121
case 's': randomseed = val; break;
1122
default: assert(0); break;
1123
}
1124
}
1125
else {
1126
switch (ch) {
1127
case 'r': randomize(); break;
1128
default: assert(0); break;
1129
}
1130
}
1131
}
1132
}
1133
1134
int
1135
main(int argc, char *argv[])
1136
{
1137
initprogname(argc > 0 ? argv[0] : NULL);
1138
1139
doargs(argc, argv);
1140
correctsize = (off_t) (numkeys*sizeof(int));
1141
1142
setdir();
1143
1144
genkeys();
1145
sort();
1146
validate();
1147
complainx("Succeeded.");
1148
1149
unsetdir();
1150
1151
return 0;
1152
}
1153
1154