psort.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158
  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. * psort - parallel sort.
  31. *
  32. * This is loosely based on some real parallel sort benchmarks, but
  33. * because of various limitations of OS/161 it is massively
  34. * inefficient. But that's ok; the goal is to stress the VM and buffer
  35. * cache.
  36. */
  37. #include <sys/types.h>
  38. #include <sys/stat.h>
  39. #include <sys/wait.h>
  40. #include <stdio.h>
  41. #include <stdarg.h>
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #include <assert.h>
  45. #include <unistd.h>
  46. #include <fcntl.h>
  47. #include <errno.h>
  48. #ifndef RANDOM_MAX
  49. /* Note: this is correct for OS/161 but not for some Unix C libraries */
  50. #define RANDOM_MAX RAND_MAX
  51. #endif
  52. #define PATH_KEYS "sortkeys"
  53. #define PATH_SORTED "output"
  54. #define PATH_TESTDIR "psortdir"
  55. #define PATH_RANDOM "rand:"
  56. #define WORKNUM (128*1024)
  57. static int workspace[WORKNUM];
  58. static const char *progname;
  59. static int numprocs = 4;
  60. static int numkeys = 10000;
  61. static long randomseed = 15432753;
  62. static off_t correctsize;
  63. static unsigned long checksum;
  64. #define NOBODY (-1)
  65. static int me = NOBODY;
  66. ////////////////////////////////////////////////////////////
  67. static
  68. void
  69. sortints(int *v, int num)
  70. {
  71. int pivotval, pivotpoint, pivotcount;
  72. int frontpos, readpos, endpos, i, j;
  73. int tmp;
  74. if (num < 2) {
  75. return;
  76. }
  77. pivotpoint = num/2;
  78. pivotval = v[pivotpoint];
  79. pivotcount = 0;
  80. frontpos = 0;
  81. readpos = 0;
  82. endpos = num;
  83. while (readpos < endpos) {
  84. if (v[readpos] < pivotval) {
  85. v[frontpos++] = v[readpos++];
  86. }
  87. else if (v[readpos] == pivotval) {
  88. readpos++;
  89. pivotcount++;
  90. }
  91. else {
  92. tmp = v[--endpos];
  93. v[endpos] = v[readpos];
  94. v[readpos] = tmp;
  95. }
  96. }
  97. assert(readpos == endpos);
  98. assert(frontpos + pivotcount == readpos);
  99. for (i=frontpos; i<endpos; i++) {
  100. v[i] = pivotval;
  101. }
  102. for (i=endpos, j=num-1; i<j; i++,j--) {
  103. tmp = v[i];
  104. v[i] = v[j];
  105. v[j] = tmp;
  106. }
  107. sortints(v, frontpos);
  108. sortints(&v[endpos], num-endpos);
  109. }
  110. ////////////////////////////////////////////////////////////
  111. static
  112. void
  113. initprogname(const char *av0)
  114. {
  115. if (av0) {
  116. progname = strrchr(av0, '/');
  117. if (progname) {
  118. progname++;
  119. }
  120. else {
  121. progname = av0;
  122. }
  123. }
  124. else {
  125. progname = "psort";
  126. }
  127. }
  128. static
  129. void
  130. vscomplain(char *buf, size_t len, const char *fmt, va_list ap, int err)
  131. {
  132. size_t pos;
  133. if (me >= 0) {
  134. snprintf(buf, len, "%s: proc %d: ", progname, me);
  135. }
  136. else {
  137. snprintf(buf, len, "%s: ", progname);
  138. }
  139. pos = strlen(buf);
  140. vsnprintf(buf+pos, len-pos, fmt, ap);
  141. pos = strlen(buf);
  142. if (err >= 0) {
  143. snprintf(buf+pos, len-pos, ": %s\n", strerror(err));
  144. }
  145. else {
  146. snprintf(buf+pos, len-pos, "\n");
  147. }
  148. }
  149. static
  150. void
  151. complainx(const char *fmt, ...)
  152. {
  153. int rc;
  154. char buf[256];
  155. va_list ap;
  156. va_start(ap, fmt);
  157. vscomplain(buf, sizeof(buf), fmt, ap, -1);
  158. va_end(ap);
  159. /* Write the message in one go so it's atomic */
  160. rc = write(STDERR_FILENO, buf, strlen(buf));
  161. /* suppress compiler warning about setting but not
  162. using rc */
  163. (void)rc;
  164. }
  165. static
  166. void
  167. complain(const char *fmt, ...)
  168. {
  169. int rc;
  170. char buf[256];
  171. va_list ap;
  172. int err = errno;
  173. va_start(ap, fmt);
  174. vscomplain(buf, sizeof(buf), fmt, ap, err);
  175. va_end(ap);
  176. /* Write the message in one go so it's atomic */
  177. rc = write(STDERR_FILENO, buf, strlen(buf));
  178. /* suppress compiler warning about setting but not
  179. using rc */
  180. (void)rc;
  181. }
  182. ////////////////////////////////////////////////////////////
  183. static
  184. int
  185. doopen(const char *path, int flags, int mode)
  186. {
  187. int fd;
  188. fd = open(path, flags, mode);
  189. if (fd<0) {
  190. complain("%s", path);
  191. exit(1);
  192. }
  193. return fd;
  194. }
  195. static
  196. void
  197. doclose(const char *path, int fd)
  198. {
  199. if (close(fd)) {
  200. complain("%s: close", path);
  201. exit(1);
  202. }
  203. }
  204. static
  205. void
  206. docreate(const char *path)
  207. {
  208. int fd;
  209. fd = doopen(path, O_WRONLY|O_CREAT|O_TRUNC, 0664);
  210. doclose(path, fd);
  211. }
  212. static
  213. void
  214. doremove(const char *path)
  215. {
  216. static int noremove;
  217. if (noremove) {
  218. return;
  219. }
  220. if (remove(path) < 0) {
  221. if (errno == ENOSYS) {
  222. /* Complain (and try) only once. */
  223. noremove = 1;
  224. }
  225. complain("%s: remove", path);
  226. }
  227. }
  228. static
  229. off_t
  230. getsize(const char *path)
  231. {
  232. struct stat buf;
  233. int fd;
  234. static int no_stat, no_fstat;
  235. if (!no_stat) {
  236. if (stat(path, &buf) == 0) {
  237. return buf.st_size;
  238. }
  239. if (errno != ENOSYS) {
  240. complain("%s: stat", path);
  241. exit(1);
  242. }
  243. /* Avoid further "Unknown syscall 81" messages */
  244. no_stat = 1;
  245. }
  246. fd = doopen(path, O_RDONLY, 0);
  247. if (!no_fstat) {
  248. if (fstat(fd, &buf) == 0) {
  249. close(fd);
  250. return buf.st_size;
  251. }
  252. if (errno != ENOSYS) {
  253. complain("%s: stat", path);
  254. exit(1);
  255. }
  256. /* Avoid further "Unknown syscall 82" messages */
  257. no_fstat = 1;
  258. }
  259. /* otherwise, lseek */
  260. if (lseek(fd, 0, SEEK_END) >= 0) {
  261. buf.st_size = lseek(fd, 0, SEEK_CUR);
  262. if (buf.st_size >= 0) {
  263. return buf.st_size;
  264. }
  265. }
  266. complain("%s: getting file size with lseek", path);
  267. close(fd);
  268. exit(1);
  269. }
  270. static
  271. size_t
  272. doread(const char *path, int fd, void *buf, size_t len)
  273. {
  274. int result;
  275. result = read(fd, buf, len);
  276. if (result < 0) {
  277. complain("%s: read", path);
  278. exit(1);
  279. }
  280. return (size_t) result;
  281. }
  282. static
  283. void
  284. doexactread(const char *path, int fd, void *buf, size_t len)
  285. {
  286. size_t result;
  287. result = doread(path, fd, buf, len);
  288. if (result != len) {
  289. complainx("%s: read: short count", path);
  290. exit(1);
  291. }
  292. }
  293. static
  294. void
  295. dowrite(const char *path, int fd, const void *buf, size_t len)
  296. {
  297. int result;
  298. result = write(fd, buf, len);
  299. if (result < 0) {
  300. complain("%s: write", path);
  301. exit(1);
  302. }
  303. if ((size_t) result != len) {
  304. complainx("%s: write: short count", path);
  305. exit(1);
  306. }
  307. }
  308. static
  309. void
  310. dolseek(const char *name, int fd, off_t offset, int whence)
  311. {
  312. if (lseek(fd, offset, whence) < 0) {
  313. complain("%s: lseek", name);
  314. exit(1);
  315. }
  316. }
  317. #if 0 /* let's not require subdirs */
  318. static
  319. void
  320. dochdir(const char *path)
  321. {
  322. if (chdir(path) < 0) {
  323. complain("%s: chdir", path);
  324. exit(1);
  325. }
  326. }
  327. static
  328. void
  329. domkdir(const char *path, int mode)
  330. {
  331. if (mkdir(path, mode) < 0) {
  332. complain("%s: mkdir", path);
  333. exit(1);
  334. }
  335. }
  336. #endif /* 0 */
  337. static
  338. pid_t
  339. dofork(void)
  340. {
  341. pid_t pid;
  342. pid = fork();
  343. if (pid < 0) {
  344. complain("fork");
  345. /* but don't exit */
  346. }
  347. return pid;
  348. }
  349. ////////////////////////////////////////////////////////////
  350. static
  351. int
  352. dowait(int guy, pid_t pid)
  353. {
  354. int status, result;
  355. result = waitpid(pid, &status, 0);
  356. if (result < 0) {
  357. complain("waitpid");
  358. return -1;
  359. }
  360. if (WIFSIGNALED(status)) {
  361. complainx("proc %d: signal %d", guy, WTERMSIG(status));
  362. return -1;
  363. }
  364. assert(WIFEXITED(status));
  365. status = WEXITSTATUS(status);
  366. if (status) {
  367. complainx("proc %d: exit %d", guy, status);
  368. return -1;
  369. }
  370. return 0;
  371. }
  372. static
  373. void
  374. doforkall(const char *phasename, void (*func)(void))
  375. {
  376. int i, bad = 0;
  377. pid_t pids[numprocs];
  378. for (i=0; i<numprocs; i++) {
  379. pids[i] = dofork();
  380. if (pids[i] < 0) {
  381. bad = 1;
  382. }
  383. else if (pids[i] == 0) {
  384. /* child */
  385. me = i;
  386. func();
  387. exit(0);
  388. }
  389. }
  390. for (i=0; i<numprocs; i++) {
  391. if (pids[i] > 0 && dowait(i, pids[i])) {
  392. bad = 1;
  393. }
  394. }
  395. if (bad) {
  396. complainx("%s failed.", phasename);
  397. exit(1);
  398. }
  399. }
  400. static
  401. void
  402. seekmyplace(const char *name, int fd)
  403. {
  404. int keys_per, myfirst;
  405. off_t offset;
  406. keys_per = numkeys / numprocs;
  407. myfirst = me*keys_per;
  408. offset = myfirst * sizeof(int);
  409. dolseek(name, fd, offset, SEEK_SET);
  410. }
  411. static
  412. int
  413. getmykeys(void)
  414. {
  415. int keys_per, myfirst, mykeys;
  416. keys_per = numkeys / numprocs;
  417. myfirst = me*keys_per;
  418. mykeys = (me < numprocs-1) ? keys_per : numkeys - myfirst;
  419. return mykeys;
  420. }
  421. ////////////////////////////////////////////////////////////
  422. static
  423. unsigned long
  424. checksum_file(const char *path)
  425. {
  426. int fd;
  427. char buf[512];
  428. size_t count, i;
  429. unsigned long sum = 0;
  430. fd = doopen(path, O_RDONLY, 0);
  431. while ((count = doread(path, fd, buf, sizeof(buf))) > 0) {
  432. for (i=0; i<count; i++) {
  433. sum += (unsigned char) buf[i];
  434. }
  435. }
  436. doclose(path, fd);
  437. return sum;
  438. }
  439. ////////////////////////////////////////////////////////////
  440. static long *seeds;
  441. static
  442. void
  443. genkeys_sub(void)
  444. {
  445. int fd, i, mykeys, keys_done, keys_to_do, value;
  446. fd = doopen(PATH_KEYS, O_WRONLY, 0);
  447. mykeys = getmykeys();
  448. seekmyplace(PATH_KEYS, fd);
  449. srandom(seeds[me]);
  450. keys_done = 0;
  451. while (keys_done < mykeys) {
  452. keys_to_do = mykeys - keys_done;
  453. if (keys_to_do > WORKNUM) {
  454. keys_to_do = WORKNUM;
  455. }
  456. for (i=0; i<keys_to_do; i++) {
  457. value = random();
  458. // check bounds of value
  459. assert(value >= 0);
  460. assert(value <= RANDOM_MAX);
  461. // do not allow the value to be zero or RANDOM_MAX
  462. while (value == 0 || value == RANDOM_MAX) {
  463. value = random();
  464. }
  465. workspace[i] = value;
  466. }
  467. dowrite(PATH_KEYS, fd, workspace, keys_to_do*sizeof(int));
  468. keys_done += keys_to_do;
  469. }
  470. doclose(PATH_KEYS, fd);
  471. }
  472. static
  473. void
  474. genkeys(void)
  475. {
  476. long seedspace[numprocs];
  477. int i;
  478. /* Create the file. */
  479. docreate(PATH_KEYS);
  480. /* Generate random seeds for each subprocess. */
  481. srandom(randomseed);
  482. for (i=0; i<numprocs; i++) {
  483. seedspace[i] = random();
  484. }
  485. /* Do it. */
  486. seeds = seedspace;
  487. doforkall("Initialization", genkeys_sub);
  488. seeds = NULL;
  489. /* Cross-check the size of the output. */
  490. if (getsize(PATH_KEYS) != correctsize) {
  491. complainx("%s: file is wrong size", PATH_KEYS);
  492. exit(1);
  493. }
  494. /* Checksum the output. */
  495. checksum = checksum_file(PATH_KEYS);
  496. complainx("Checksum of unsorted keys: %ld", checksum);
  497. }
  498. ////////////////////////////////////////////////////////////
  499. static
  500. const char *
  501. binname(int a, int b)
  502. {
  503. static char rv[32];
  504. snprintf(rv, sizeof(rv), "bin-%d-%d", a, b);
  505. return rv;
  506. }
  507. static
  508. const char *
  509. mergedname(int a)
  510. {
  511. static char rv[32];
  512. snprintf(rv, sizeof(rv), "merged-%d", a);
  513. return rv;
  514. }
  515. static
  516. void
  517. bin(void)
  518. {
  519. int infd, outfds[numprocs];
  520. const char *name;
  521. int i, mykeys, keys_done, keys_to_do;
  522. int key, pivot, binnum;
  523. infd = doopen(PATH_KEYS, O_RDONLY, 0);
  524. mykeys = getmykeys();
  525. seekmyplace(PATH_KEYS, infd);
  526. for (i=0; i<numprocs; i++) {
  527. name = binname(me, i);
  528. outfds[i] = doopen(name, O_WRONLY|O_CREAT|O_TRUNC, 0664);
  529. }
  530. pivot = (RANDOM_MAX / numprocs);
  531. keys_done = 0;
  532. while (keys_done < mykeys) {
  533. keys_to_do = mykeys - keys_done;
  534. if (keys_to_do > WORKNUM) {
  535. keys_to_do = WORKNUM;
  536. }
  537. doexactread(PATH_KEYS, infd, workspace,
  538. keys_to_do * sizeof(int));
  539. for (i=0; i<keys_to_do; i++) {
  540. key = workspace[i];
  541. binnum = key / pivot;
  542. if (key <= 0) {
  543. complainx("proc %d: garbage key %d", me, key);
  544. key = 0;
  545. }
  546. assert(binnum >= 0);
  547. assert(binnum < numprocs);
  548. dowrite("bin", outfds[binnum], &key, sizeof(key));
  549. }
  550. keys_done += keys_to_do;
  551. }
  552. doclose(PATH_KEYS, infd);
  553. for (i=0; i<numprocs; i++) {
  554. doclose(binname(me, i), outfds[i]);
  555. }
  556. }
  557. static
  558. void
  559. sortbins(void)
  560. {
  561. const char *name;
  562. int i, fd;
  563. off_t binsize;
  564. for (i=0; i<numprocs; i++) {
  565. name = binname(me, i);
  566. binsize = getsize(name);
  567. if (binsize % sizeof(int) != 0) {
  568. complainx("%s: bin size %ld no good", name,
  569. (long) binsize);
  570. exit(1);
  571. }
  572. if (binsize > (off_t) sizeof(workspace)) {
  573. complainx("proc %d: %s: bin too large", me, name);
  574. exit(1);
  575. }
  576. fd = doopen(name, O_RDWR, 0);
  577. doexactread(name, fd, workspace, binsize);
  578. sortints(workspace, binsize/sizeof(int));
  579. dolseek(name, fd, 0, SEEK_SET);
  580. dowrite(name, fd, workspace, binsize);
  581. doclose(name, fd);
  582. }
  583. }
  584. static
  585. void
  586. mergebins(void)
  587. {
  588. int infds[numprocs], outfd;
  589. int values[numprocs], ready[numprocs];
  590. const char *name, *outname;
  591. int i, result;
  592. int numready, place, val, worknum;
  593. outname = mergedname(me);
  594. outfd = doopen(outname, O_WRONLY|O_CREAT|O_TRUNC, 0664);
  595. for (i=0; i<numprocs; i++) {
  596. name = binname(i, me);
  597. infds[i] = doopen(name, O_RDONLY, 0);
  598. values[i] = 0;
  599. ready[i] = 0;
  600. }
  601. worknum = 0;
  602. while (1) {
  603. numready = 0;
  604. for (i=0; i<numprocs; i++) {
  605. if (infds[i] < 0) {
  606. continue;
  607. }
  608. if (!ready[i]) {
  609. result = doread("bin", infds[i],
  610. &val, sizeof(int));
  611. if (result == 0) {
  612. doclose("bin", infds[i]);
  613. infds[i] = -1;
  614. continue;
  615. }
  616. if ((size_t) result != sizeof(int)) {
  617. complainx("%s: read: short count",
  618. binname(i, me));
  619. exit(1);
  620. }
  621. values[i] = val;
  622. ready[i] = 1;
  623. }
  624. numready++;
  625. }
  626. if (numready == 0) {
  627. break;
  628. }
  629. /* find the smallest */
  630. place = -1;
  631. for (i=0; i<numprocs; i++) {
  632. if (!ready[i]) {
  633. continue;
  634. }
  635. if (place < 0 || values[i] < val) {
  636. val = values[i];
  637. place = i;
  638. }
  639. }
  640. assert(place >= 0);
  641. workspace[worknum++] = val;
  642. if (worknum >= WORKNUM) {
  643. assert(worknum == WORKNUM);
  644. dowrite(outname, outfd, workspace,
  645. worknum * sizeof(int));
  646. worknum = 0;
  647. }
  648. ready[place] = 0;
  649. }
  650. dowrite(outname, outfd, workspace, worknum * sizeof(int));
  651. doclose(outname, outfd);
  652. for (i=0; i<numprocs; i++) {
  653. assert(infds[i] < 0);
  654. }
  655. }
  656. static
  657. void
  658. assemble(void)
  659. {
  660. off_t mypos;
  661. int i, fd;
  662. const char *args[3];
  663. mypos = 0;
  664. for (i=0; i<me; i++) {
  665. mypos += getsize(mergedname(i));
  666. }
  667. fd = doopen(PATH_SORTED, O_WRONLY, 0);
  668. dolseek(PATH_SORTED, fd, mypos, SEEK_SET);
  669. if (dup2(fd, STDOUT_FILENO) < 0) {
  670. complain("dup2");
  671. exit(1);
  672. }
  673. doclose(PATH_SORTED, fd);
  674. args[0] = "cat";
  675. args[1] = mergedname(me);
  676. args[2] = NULL;
  677. execv("/bin/cat", (char **) args);
  678. complain("/bin/cat: exec");
  679. exit(1);
  680. }
  681. static
  682. void
  683. checksize_bins(void)
  684. {
  685. off_t totsize;
  686. int i, j;
  687. totsize = 0;
  688. for (i=0; i<numprocs; i++) {
  689. for (j=0; j<numprocs; j++) {
  690. totsize += getsize(binname(i, j));
  691. }
  692. }
  693. if (totsize != correctsize) {
  694. complain("Sum of bin sizes is wrong (%ld, should be %ld)",
  695. (long) totsize, (long) correctsize);
  696. exit(1);
  697. }
  698. }
  699. static
  700. void
  701. checksize_merge(void)
  702. {
  703. off_t totsize;
  704. int i;
  705. totsize = 0;
  706. for (i=0; i<numprocs; i++) {
  707. totsize += getsize(mergedname(i));
  708. }
  709. if (totsize != correctsize) {
  710. complain("Sum of merged sizes is wrong (%ld, should be %ld)",
  711. (long) totsize, (long) correctsize);
  712. exit(1);
  713. }
  714. }
  715. static
  716. void
  717. sort(void)
  718. {
  719. unsigned long sortedsum;
  720. int i, j;
  721. /* Step 1. Toss into bins. */
  722. doforkall("Tossing", bin);
  723. checksize_bins();
  724. complainx("Done tossing into bins.");
  725. /* Step 2: Sort the bins. */
  726. doforkall("Sorting", sortbins);
  727. checksize_bins();
  728. complainx("Done sorting the bins.");
  729. /* Step 3: Merge corresponding bins. */
  730. doforkall("Merging", mergebins);
  731. checksize_merge();
  732. complainx("Done merging the bins.");
  733. /* Step 3a: delete the bins */
  734. for (i=0; i<numprocs; i++) {
  735. for (j=0; j<numprocs; j++) {
  736. doremove(binname(i, j));
  737. }
  738. }
  739. /* Step 4: assemble output file */
  740. docreate(PATH_SORTED);
  741. doforkall("Final assembly", assemble);
  742. if (getsize(PATH_SORTED) != correctsize) {
  743. complainx("%s: file is wrong size", PATH_SORTED);
  744. exit(1);
  745. }
  746. /* Step 4a: delete the merged bins */
  747. for (i=0; i<numprocs; i++) {
  748. doremove(mergedname(i));
  749. }
  750. /* Step 5: Checksum the result. */
  751. sortedsum = checksum_file(PATH_SORTED);
  752. complainx("Checksum of sorted keys: %ld", sortedsum);
  753. if (sortedsum != checksum) {
  754. complainx("Sums do not match");
  755. exit(1);
  756. }
  757. }
  758. ////////////////////////////////////////////////////////////
  759. static
  760. const char *
  761. validname(int a)
  762. {
  763. static char rv[32];
  764. snprintf(rv, sizeof(rv), "valid-%d", a);
  765. return rv;
  766. }
  767. static
  768. void
  769. checksize_valid(void)
  770. {
  771. off_t totvsize, correctvsize;
  772. int i;
  773. correctvsize = (off_t) numprocs*2*sizeof(int);
  774. totvsize = 0;
  775. for (i=0; i<numprocs; i++) {
  776. totvsize += getsize(validname(i));
  777. }
  778. if (totvsize != correctvsize) {
  779. complainx("Sum of validation sizes is wrong "
  780. "(%ld, should be %ld)",
  781. (long) totvsize, (long) correctvsize);
  782. exit(1);
  783. }
  784. }
  785. static
  786. void
  787. dovalidate(void)
  788. {
  789. const char *name;
  790. int fd, i, mykeys, keys_done, keys_to_do;
  791. int key, smallest, largest;
  792. name = PATH_SORTED;
  793. fd = doopen(name, O_RDONLY, 0);
  794. mykeys = getmykeys();
  795. seekmyplace(name, fd);
  796. smallest = RANDOM_MAX;
  797. largest = 0;
  798. keys_done = 0;
  799. while (keys_done < mykeys) {
  800. keys_to_do = mykeys - keys_done;
  801. if (keys_to_do > WORKNUM) {
  802. keys_to_do = WORKNUM;
  803. }
  804. doexactread(name, fd, workspace, keys_to_do * sizeof(int));
  805. for (i=0; i<keys_to_do; i++) {
  806. key = workspace[i];
  807. if (key < 0) {
  808. complain("%s: found negative key", name);
  809. exit(1);
  810. }
  811. if (key == 0) {
  812. complain("%s: found zero key", name);
  813. exit(1);
  814. }
  815. if (key >= RANDOM_MAX) {
  816. complain("%s: found too-large key", name);
  817. exit(1);
  818. }
  819. if (key < smallest) {
  820. smallest = key;
  821. }
  822. if (key > largest) {
  823. largest = key;
  824. }
  825. }
  826. keys_done += keys_to_do;
  827. }
  828. doclose(name, fd);
  829. name = validname(me);
  830. fd = doopen(name, O_WRONLY|O_CREAT|O_TRUNC, 0664);
  831. dowrite(name, fd, &smallest, sizeof(smallest));
  832. dowrite(name, fd, &largest, sizeof(largest));
  833. doclose(name, fd);
  834. }
  835. static
  836. void
  837. validate(void)
  838. {
  839. int smallest, largest, prev_largest;
  840. int i, fd;
  841. const char *name;
  842. doforkall("Validation", dovalidate);
  843. checksize_valid();
  844. prev_largest = 1;
  845. for (i=0; i<numprocs; i++) {
  846. name = validname(i);
  847. fd = doopen(name, O_RDONLY, 0);
  848. doexactread(name, fd, &smallest, sizeof(int));
  849. doexactread(name, fd, &largest, sizeof(int));
  850. if (smallest < 1) {
  851. complainx("Validation: block %d: bad SMALLEST", i);
  852. exit(1);
  853. }
  854. if (largest >= RANDOM_MAX) {
  855. complainx("Validation: block %d: bad LARGEST", i);
  856. exit(1);
  857. }
  858. if (smallest > largest) {
  859. complainx("Validation: block %d: SMALLEST > LARGEST",
  860. i);
  861. exit(1);
  862. }
  863. if (smallest < prev_largest) {
  864. complain("Validation: block %d smallest key %d",
  865. i, smallest);
  866. complain("Validation: previous block largest key %d",
  867. prev_largest);
  868. complain("Validation failed");
  869. exit(1);
  870. }
  871. }
  872. for (i=0; i<numprocs; i++) {
  873. doremove(validname(i));
  874. }
  875. }
  876. ////////////////////////////////////////////////////////////
  877. static
  878. void
  879. setdir(void)
  880. {
  881. #if 0 /* let's not require subdirs */
  882. domkdir(PATH_TESTDIR, 0775);
  883. dochdir(PATH_TESTDIR);
  884. #endif /* 0 */
  885. }
  886. static
  887. void
  888. unsetdir(void)
  889. {
  890. doremove(PATH_KEYS);
  891. doremove(PATH_SORTED);
  892. #if 0 /* let's not require subdirs */
  893. dochdir("..");
  894. if (rmdir(PATH_TESTDIR) < 0) {
  895. complain("%s: rmdir", PATH_TESTDIR);
  896. /* but don't exit */
  897. }
  898. #endif /* 0 */
  899. }
  900. ////////////////////////////////////////////////////////////
  901. static
  902. void
  903. randomize(void)
  904. {
  905. int fd;
  906. fd = doopen(PATH_RANDOM, O_RDONLY, 0);
  907. doexactread(PATH_RANDOM, fd, &randomseed, sizeof(randomseed));
  908. doclose(PATH_RANDOM, fd);
  909. }
  910. static
  911. void
  912. usage(void)
  913. {
  914. complain("Usage: %s [-p procs] [-k keys] [-s seed] [-r]", progname);
  915. exit(1);
  916. }
  917. static
  918. void
  919. doargs(int argc, char *argv[])
  920. {
  921. int i, ch, val, arg;
  922. for (i=1; i<argc; i++) {
  923. if (argv[i][0] != '-') {
  924. usage();
  925. return;
  926. }
  927. ch = argv[i][1];
  928. switch (ch) {
  929. case 'p': arg = 1; break;
  930. case 'k': arg = 1; break;
  931. case 's': arg = 1; break;
  932. case 'r': arg = 0; break;
  933. default: usage(); return;
  934. }
  935. if (arg) {
  936. if (argv[i][2]) {
  937. val = atoi(argv[i]+2);
  938. }
  939. else {
  940. i++;
  941. if (!argv[i]) {
  942. complain("Option -%c requires an "
  943. "argument", ch);
  944. exit(1);
  945. }
  946. val = atoi(argv[i]);
  947. }
  948. switch (ch) {
  949. case 'p': numprocs = val; break;
  950. case 'k': numkeys = val; break;
  951. case 's': randomseed = val; break;
  952. default: assert(0); break;
  953. }
  954. }
  955. else {
  956. switch (ch) {
  957. case 'r': randomize(); break;
  958. default: assert(0); break;
  959. }
  960. }
  961. }
  962. }
  963. int
  964. main(int argc, char *argv[])
  965. {
  966. initprogname(argc > 0 ? argv[0] : NULL);
  967. doargs(argc, argv);
  968. correctsize = (off_t) (numkeys*sizeof(int));
  969. setdir();
  970. genkeys();
  971. sort();
  972. validate();
  973. complainx("Succeeded.");
  974. unsetdir();
  975. return 0;
  976. }