Advertisement
Guest User

florent

a guest
Sep 29th, 2009
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 21.82 KB | None | 0 0
  1. #ifndef _GNU_SOURCE
  2. #   define _GNU_SOURCE
  3. #endif
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include <errno.h>
  7. #include <sys/types.h>
  8. #include <sys/stat.h>
  9. #include <unistd.h>
  10. #include <getopt.h>
  11. #include <string.h>
  12. #include <pthread.h>
  13. #include <sys/mman.h>
  14.  
  15. #ifdef STATS
  16. #include <sys/time.h>
  17. #endif
  18.  
  19. #define MIN_LINES_FOR_THREADS ((size_t) 5000)
  20. #define FIND_PIVOTS_ELEMS ((size_t) 1000)
  21.  
  22. /* Print progress messages */
  23. static int verbose = 0;
  24. /* Number of threads to use */
  25. static size_t threads = 0;
  26. /* Strings are \0-terminated */
  27. static int zero_terminated = 0;
  28.  
  29. /* Read the file line by line with getdelim (e.g. for reading on stdin) */
  30. #define READ_BY_LINE            0
  31. /* Copy the file into a malloc'd buffer */
  32. #define READ_BY_BLOCK           1
  33. /* mmap the file */
  34. #define READ_BY_MMAPED_BLOCK    2
  35.  
  36. /* Buffer or mapping for READ_BY_BLOCK and READ_BY_MMAPED_BLOCK */
  37. static void *read_buf;
  38. /* Size of read_buf */
  39. static size_t read_buf_length;
  40. /* Set to 1 if the lines are malloc'd and don't point to read_buf */
  41. static int lines_are_copied = 0;
  42. /* The address of the last line if it was malloc'd and lines_are_copied == 0 */
  43. static char* last_line = NULL;
  44.  
  45. #ifdef STATS
  46. /* A comparison counter per thread */
  47. static __thread unsigned long cmps = 0;
  48.  
  49. /* Some timer manipulation macros */
  50. #   define INIT_TIMER(t) ({\
  51.     struct itimerval *__t = (t); \
  52.     __t->it_value.tv_sec = __INT_MAX__; \
  53.     __t->it_value.tv_usec = 0; \
  54.     __t->it_interval.tv_sec = 0; \
  55.     __t->it_interval.tv_usec = 0; \
  56.     setitimer(ITIMER_REAL, __t, NULL); \
  57.     })
  58.  
  59. #   define GET_T(t) ({\
  60.     struct itimerval *__t = (t); \
  61.     getitimer(ITIMER_REAL, __t); \
  62.     })
  63.  
  64. #   define DIFF_T0_T1(t0,t1,diff) ({\
  65.     struct itimerval *__t0 = (t0); \
  66.     struct itimerval *__t1 = (t1); \
  67.     unsigned long __diff; \
  68.     __diff = (__t0->it_value.tv_sec - __t1->it_value.tv_sec) * 1000000L; \
  69.     __diff += (__t0->it_value.tv_usec - __t1->it_value.tv_usec); \
  70.     diff = __diff;\
  71.     })
  72.  
  73. #   define RESET_TIMER(t) ({\
  74.     struct itimerval *__t = (t); \
  75.     __t->it_value.tv_sec = 0; \
  76.     __t->it_value.tv_usec = 0; \
  77.     __t->it_interval.tv_sec = 0; \
  78.     __t->it_interval.tv_usec = 0; \
  79.     setitimer(ITIMER_REAL, __t, NULL); \
  80.     })
  81. #endif /* STATS */
  82.  
  83. /* The string comparison function */
  84. int (*str_compare)(const char *, const char *) = strcmp;
  85.  
  86. /* Parameters for thread_sort */
  87. struct thread_params {
  88.     char **start; // start of the buffer to sort
  89.     size_t len; // length of the buffer
  90. #ifdef STATS
  91.     unsigned long cmps;
  92. #endif
  93. };
  94.  
  95. /* A working thread and its parameters */
  96. struct thread_data {
  97.     struct thread_params params;
  98.     pthread_t thread;
  99. };
  100.  
  101. struct pivot_data {
  102.     size_t i; // index of the line
  103.     char *s; // line
  104. };
  105.  
  106. /* Read the file line by line and copy the lines into a char ** array */
  107. static char ** read_by_lines(FILE *in, size_t *length) {
  108.     char **lines, **tmp_lines;
  109.     size_t lines_len = 0;
  110.     size_t nlines = 0;
  111.     char *buf = NULL, *buf_cpy;
  112.     size_t buflen = 0;
  113.     size_t i;
  114.     ssize_t r;
  115.     int delim;
  116.  
  117.     // all the lines are malloc'd
  118.     lines_are_copied = 1;
  119.  
  120.     lines = NULL;
  121.  
  122.     if (zero_terminated)
  123.         delim = '\0';
  124.     else
  125.         delim = '\n';
  126.  
  127.     while (1) {
  128.         r = getdelim(&buf, &buflen, delim, in);
  129.         /* r doesn't count the terminating \0 but the buffer is always
  130.          * 0-terminated (buf[r] == 0) */
  131.         if (r >= 0) {
  132.             // replace the delimiter by \0
  133.             if (r >= 1 && buf[r - 1] == delim) {
  134.                 buf[r - 1] = '\0';
  135.                 r--;
  136.             }
  137.             if (r == 0) {
  138.                 continue;
  139.             }
  140.  
  141.             if (lines_len == nlines) {
  142.                 // expand the lines buffer
  143.                 lines_len += 1 << 13;
  144.                 tmp_lines = realloc(lines, lines_len * sizeof(char *));
  145.                 if (tmp_lines == NULL) {
  146.                     perror("realloc");
  147.                     for (i = 0; i < nlines; i++) {
  148.                         free(lines[i]);
  149.                     }
  150.                     free(lines);
  151.                     free(buf);
  152.                     return NULL;
  153.                 }
  154.                 lines = tmp_lines;
  155.             }
  156.  
  157.             // copy the buffer from getline
  158.             buf_cpy = malloc(r + 1);
  159.             if (buf_cpy == NULL) {
  160.                 perror("malloc");
  161.                 for (i = 0; i < nlines; i++) {
  162.                     free(lines[i]);
  163.                 }
  164.                 free(lines);
  165.                 free(buf);
  166.                 return NULL;
  167.             }
  168.             memcpy(buf_cpy, buf, r + 1);
  169.  
  170.             lines[nlines] = buf_cpy;
  171.             nlines++;
  172.         }
  173.         else {
  174.             break;
  175.         }
  176.     }
  177.  
  178.     *length = nlines;
  179.     free(buf);
  180.     return lines;
  181. }
  182.  
  183. /* Read the file from the buffer pmap and build a char ** array with the lines.
  184.  * is_ro: the buffer is read only (mmap)
  185.  *
  186.  * If the buffer is read only and the delimiter is \n, the lines are copied and
  187.  * lines_are_copied is set. Otherwise the lines point to pmap and the delimiters
  188.  * are replaced by \0.
  189.  *
  190.  * When the lines are not copied, the last line of the file may need to be
  191.  * allocated regardless to add a trailing 0 byte. In this case last_line is set
  192.  * to this buffer.
  193.  */
  194. static char ** read_block(void *pmap, size_t file_length, size_t *length,
  195.         int is_ro) {
  196.     char **lines, **tmp_lines;
  197.     size_t lines_len = 0;
  198.     size_t nlines = 0;
  199.     size_t i, r;
  200.     char *buf;
  201.     char delim;
  202.     char *b = pmap, *e = pmap;
  203.     char *map_end = ((char *) pmap) + file_length - 1;
  204.  
  205.     if (zero_terminated || !is_ro)
  206.         lines_are_copied = 0;
  207.     else
  208.         lines_are_copied = 1;
  209.  
  210.     lines = NULL;
  211.  
  212.     if (zero_terminated)
  213.         delim = '\0';
  214.     else
  215.         delim = '\n';
  216.  
  217.     while (e <= map_end) {
  218.         if (*e == delim || e == map_end) {
  219.             // line length from b to e included
  220.             r = e - b + 1;
  221.             if (r == 1) {
  222.                 b = e + 1;
  223.                 continue;
  224.             }
  225.  
  226.             if (lines_len == nlines) {
  227.                 // expand the buffer
  228.                 lines_len += 1 << 13;
  229.                 tmp_lines = realloc(lines, lines_len * sizeof(char *));
  230.                 if (tmp_lines == NULL) {
  231.                     perror("realloc");
  232.                     if (lines_are_copied)
  233.                         for (i = 0; i < nlines; i++) {
  234.                             free(lines[i]);
  235.                         }
  236.                     free(lines);
  237.                     return NULL;
  238.                 }
  239.                 lines = tmp_lines;
  240.             }
  241.  
  242.             if (lines_are_copied) {
  243.                 // missing delimiter at the end of the file
  244.                 if (*e != delim)
  245.                     r++;
  246.                 buf = malloc(r);
  247.                 if (buf == NULL) {
  248.                     perror("malloc");
  249.                     for (i = 0; i < nlines; i++) {
  250.                         free(lines[i]);
  251.                     }
  252.                     free(lines);
  253.                     return NULL;
  254.                 }
  255.                 memcpy(buf, b, r - 1);
  256.                 buf[r - 1] = '\0';
  257.                 lines[nlines] = buf;
  258.             }
  259.             else { // zero_terminated || !is_ro
  260.                 if (e == map_end && *e != delim) {
  261.                     buf = malloc(r + 1);
  262.                     if (buf == NULL) {
  263.                         perror("malloc");
  264.                         free(lines);
  265.                         return NULL;
  266.                     }
  267.                     memcpy(buf, b, r);
  268.                     buf[r] = '\0';
  269.                     lines[nlines] = buf;
  270.                     last_line = buf;
  271.                 }
  272.                 else if (zero_terminated) {
  273.                     lines[nlines] = b;
  274.                 }
  275.                 else {
  276.                     *e = '\0';
  277.                     lines[nlines] = b;
  278.                 }
  279.             }
  280.  
  281.             nlines++;
  282.             b = e + 1;
  283.         }
  284.         e++;
  285.     }
  286.  
  287.     *length = nlines;
  288.     return lines;
  289. }
  290.  
  291. /* Read the file with the given read method */
  292. static char ** read_file(FILE *in, size_t *length, int read_method) {
  293.     int fd;
  294.     struct stat statbuf;
  295.     int i;
  296.     size_t r;
  297.  
  298.     if (read_method == READ_BY_LINE) {
  299.         return read_by_lines(in, length);
  300.     }
  301.     else {
  302.         fd = fileno(in);
  303.         i = fstat(fd, &statbuf);
  304.         if (i == -1) {
  305.             perror("fstat");
  306.             return NULL;
  307.         }
  308.         read_buf_length = statbuf.st_size;
  309.  
  310.         if (read_method == READ_BY_BLOCK) {
  311.             read_buf = malloc(read_buf_length);
  312.             if (read_buf == NULL) {
  313.                 perror("malloc");
  314.                 return NULL;
  315.             }
  316.             r = fread(read_buf, 1, read_buf_length, in);
  317.             if (r != read_buf_length) {
  318.                 perror("fread");
  319.                 free(read_buf);
  320.                 return NULL;
  321.             }
  322.             return read_block(read_buf, read_buf_length, length, 0);
  323.         }
  324.         else if (read_method == READ_BY_MMAPED_BLOCK) {
  325.             read_buf = mmap(NULL, read_buf_length, PROT_READ, MAP_PRIVATE
  326.                     | MAP_POPULATE, fd, 0);
  327.             if (read_buf == MAP_FAILED) {
  328.                 perror("mmap");
  329.                 return NULL;
  330.             }
  331.             return read_block(read_buf, read_buf_length, length, 1);
  332.         }
  333.     }
  334.     return NULL;
  335. }
  336.  
  337. /* Free a lines buffer and the resources used by the read method */
  338. static void free_read(char ** lines, size_t length, int read_method) {
  339.     size_t i;
  340.  
  341.     if (lines_are_copied) {
  342.         for (i = 0; i < length; i++)
  343.             free(lines[i]);
  344.     }
  345.     else if (last_line != NULL)
  346.         free(last_line);
  347.     free(lines);
  348.  
  349.     if (read_method == READ_BY_BLOCK)
  350.         free(read_buf);
  351.     else if (read_method == READ_BY_MMAPED_BLOCK)
  352.         munmap(read_buf, read_buf_length);
  353. }
  354.  
  355. /* Write the line buffer into 'out' */
  356. static int write_lines(FILE *out, char **lines, size_t len) {
  357.     size_t i;
  358.     int r;
  359.     char delim;
  360.  
  361.     if (zero_terminated)
  362.         delim = '\0';
  363.     else
  364.         delim = '\n';
  365.  
  366.     for (i = 0; i < len; i++) {
  367.         r = fprintf(out, "%s%c", lines[i], delim);
  368.         if (r < 0) {
  369.             perror("fprintf");
  370.             return -1;
  371.         }
  372.     }
  373.     return 0;
  374. }
  375.  
  376. /* Basic comparison with str_compare */
  377. static int cmp_lines(const void *p1, const void *p2) {
  378. #ifdef STATS
  379.     cmps++;
  380. #endif
  381.     return str_compare(*(char * const *) p1, *(char * const *) p2);
  382. }
  383.  
  384. /* A worker thread sorting a part of the line buffer */
  385. static void * thread_sort(void *args) {
  386.     struct thread_params * params = (struct thread_params *) args;
  387.     qsort(params->start, params->len, sizeof(char *), cmp_lines);
  388. #ifdef STATS
  389.     params->cmps = cmps;
  390. #endif
  391.     return NULL;
  392. }
  393.  
  394. /* This comparison function operates over struct pivot_data elements */
  395. static int cmp_pivot(const void *p1, const void *p2) {
  396.     const struct pivot_data *d1 = (const struct pivot_data *) p1;
  397.     const struct pivot_data *d2 = (const struct pivot_data *) p2;
  398. #ifdef STATS
  399.     cmps++;
  400. #endif
  401.     return str_compare(d1->s, d2->s);
  402. }
  403.  
  404. /* This function sort the FIND_PIVOTS_ELEMS first elements of lines in a
  405.  * temporary array and take n regularly spaced values that can be used as pivots
  406.  * to build a partition.
  407.  */
  408. static int find_pivots(char **lines, size_t *indexes, size_t n_pivots) {
  409.     size_t i, s, n;
  410.     struct pivot_data *tmp = malloc(FIND_PIVOTS_ELEMS
  411.             * sizeof(struct pivot_data));
  412.     if (tmp == NULL) {
  413.         perror("malloc");
  414.         return -1;
  415.     }
  416.     for (i = 0; i < FIND_PIVOTS_ELEMS; i++) {
  417.         tmp[i].i = i;
  418.         tmp[i].s = lines[i];
  419.     }
  420.     qsort(tmp, FIND_PIVOTS_ELEMS, sizeof(struct pivot_data), cmp_pivot);
  421.     s = FIND_PIVOTS_ELEMS / (n_pivots + 1);
  422.     n = 0;
  423.     for (i = 0; i < n_pivots; i++) {
  424.         n += s;
  425.         indexes[i] = tmp[n].i;
  426.     }
  427.     free(tmp);
  428.     return 0;
  429. }
  430.  
  431. /* Adapted quicksort's partition function.
  432.  * The function works on lines[offset:n-offset-1]
  433.  * The pivot is pivots[pivots_i]
  434.  * The next pivots' indexes in pivots[pivots_i+1:pivots_n-1] are updated
  435.  */
  436. static size_t partition(char **lines, size_t *pivots, size_t pivots_i,
  437.         size_t pivots_n, size_t n, size_t offset) {
  438.     size_t i, j, k;
  439.     size_t p;
  440.     char *tmp;
  441.  
  442.     lines += offset;
  443.     n -= offset;
  444.     i = 0;
  445.     j = n - 1;
  446.  
  447.     p = pivots[pivots_i] - offset;
  448.  
  449.     tmp = lines[j];
  450.     lines[j] = lines[p];
  451.     lines[p] = tmp;
  452.  
  453.     while (1) {
  454. #ifdef STATS
  455.         while (cmps++, str_compare(lines[i], lines[n - 1]) < 0)
  456.             i++;
  457.         while (cmps++, str_compare(lines[j], lines[n - 1]) >= 0)
  458.             j--;
  459. #else
  460.         while (str_compare(lines[i], lines[n - 1]) < 0)
  461.         i++;
  462.         while (str_compare(lines[j], lines[n - 1]) >= 0)
  463.         j--;
  464. #endif
  465.  
  466.         if (i > j)
  467.             break;
  468.  
  469.         tmp = lines[j];
  470.         lines[j] = lines[i];
  471.         lines[i] = tmp;
  472.  
  473.         // update the indexes of the next pivots
  474.         for (k = pivots_i + 1; k < pivots_n; k++) {
  475.             if (pivots[k] - offset == i) {
  476.                 pivots[k] = j + offset;
  477.                 break;
  478.             }
  479.         }
  480.     }
  481.  
  482.     tmp = lines[i];
  483.     lines[i] = lines[n - 1];
  484.     lines[n - 1] = tmp;
  485.  
  486.     return i + offset;
  487. }
  488.  
  489. static int do_sort(char **lines, size_t lines_length) {
  490.     struct thread_data *th_data = NULL;
  491.     size_t offset, i;
  492.     int r;
  493.  
  494.     if (!threads || threads == 1) {
  495.         qsort(lines, lines_length, sizeof(char *), cmp_lines);
  496.     }
  497.     else {
  498.         th_data = malloc(threads * sizeof(struct thread_data));
  499.         if (th_data == NULL) {
  500.             perror("malloc");
  501.             return -1;
  502.         }
  503.  
  504.         size_t * pivots = malloc((threads - 1) * sizeof(size_t));
  505.         if (pivots == NULL) {
  506.             perror("malloc");
  507.             free(th_data);
  508.             return -1;
  509.         }
  510.  
  511.         /* Find (threads - 1) pivots */
  512.         if (find_pivots(lines, pivots, threads - 1) != 0) {
  513.             free(th_data);
  514.             free(pivots);
  515.             return -1;
  516.         }
  517.  
  518.         /* Build a first partition with the pivots
  519.          * ......p1...p2.... ....pn-1.......
  520.          */
  521.         for (i = 0; i < threads - 1; i++) {
  522.             if (i == 0) {
  523.                 offset = 0;
  524.             }
  525.             else {
  526.                 offset = pivots[i - 1];
  527.             }
  528.             pivots[i] = partition(lines, pivots, i, threads - 1, lines_length,
  529.                     offset);
  530.         }
  531.  
  532.         /* Start a thread on each sub part */
  533.         for (i = 0; i < threads; i++) {
  534.             if (i == 0) {
  535.                 th_data[i].params.start = &(lines[0]);
  536.                 th_data[i].params.len = pivots[0];
  537.             }
  538.             else if (i == threads - 1) {
  539.                 th_data[i].params.start = &(lines[pivots[threads - 2]]);
  540.                 th_data[i].params.len = lines_length - pivots[threads - 2];
  541.             }
  542.             else {
  543.                 th_data[i].params.start = &(lines[pivots[i - 1]]);
  544.                 th_data[i].params.len = pivots[i] - pivots[i - 1];
  545.             }
  546.  
  547.             r = pthread_create(&th_data[i].thread, NULL, thread_sort,
  548.                     &th_data[i].params);
  549.             if (r > 0)
  550.                 abort();
  551.         }
  552.  
  553.         /* Wait for completion */
  554.         for (i = 0; i < threads; i++) {
  555.             pthread_join(th_data[i].thread, NULL);
  556. #ifdef STATS
  557.             cmps += th_data[i].params.cmps;
  558. #endif
  559.         }
  560.  
  561.         free(th_data);
  562.         free(pivots);
  563.     }
  564.  
  565.     return 0;
  566. }
  567.  
  568. static void usage(void) {
  569.     fprintf(stderr, "Usage: sortfile [OPTION]... input_file [output_file]\n\n");
  570.     fprintf(stderr, "Options:\n");
  571.     fprintf(stderr, " -c, --coll                   "
  572.         "use 'strcoll' to order the lines\n");
  573.     fprintf(stderr, " -h, --help                   "
  574.         "this help message\n");
  575.     fprintf(stderr, " -m, --mmap                   "
  576.         "Use mmap to read the input file (if not stdin)\n");
  577.     fprintf(stderr, " -t, --threaded=N             "
  578.         "number of threads to use\n");
  579.     fprintf(stderr, " -v, --verbose                "
  580.         "print progress messages to stderr\n");
  581.     fprintf(stderr, " -V, --vers                   "
  582.         "use 'strverscmp' to order the lines\n");
  583.     fprintf(stderr, " -z, --zero                   "
  584.         "end lines with a 0 byte, not with a newline\n");
  585.     fprintf(stderr, "\n");
  586.     fprintf(stderr, "Use \"-\" instead of the input or output file to use "
  587.         "respectively stdin or stdout. If the output file is omitted, the "
  588.         "output is written to stdout.\n");
  589.     fprintf(stderr, "The default comparison function is 'strcmp'.\n");
  590.     fprintf(stderr, "Only when using -m on a file with 0-terminated lines, the"
  591.         " data are not copied into the process memory. Otherwise the file "
  592.         "has to be entirely buffered.\n");
  593. }
  594.  
  595. int main(int argc, char *argv[]) {
  596.     int exit_status = EXIT_FAILURE;
  597.     int opt;
  598.     int r;
  599.     const char *in_filename, *out_filename;
  600.     FILE *in_file, *out_file;
  601.  
  602. #ifdef STATS
  603.     struct itimerval t0, t1;
  604.     unsigned long int diff_read = 0;
  605.     unsigned long int diff_sort = 0;
  606.     unsigned long int diff_write = 0;
  607. #endif
  608.  
  609.     long tmp_long;
  610.  
  611.     char ** lines;
  612.     size_t lines_length = 0;
  613.     int read_method = READ_BY_BLOCK;
  614.  
  615.     struct option long_options[] = { { "help", 0, NULL, 'h' }, { "verbose", 0,
  616.             NULL, 'v' }, { "threads", 1, NULL, 't' }, { "coll", 0, NULL, 'c' },
  617.             { "vers", 0, NULL, 'V' }, { "mmap", 0, NULL, 'm' }, { "zero", 0,
  618.                     NULL, 'z' }, { 0, 0, 0, 0 } };
  619.  
  620.     while ((opt = getopt_long(argc, argv, "hcVvt:mz", long_options, NULL)) >= 0) {
  621.         switch (opt) {
  622.             case 'v':
  623.                 verbose = 1;
  624.                 break;
  625.             case 't':
  626.                 errno = 0;
  627.                 tmp_long = strtol(optarg, (char **) NULL, 10);
  628.                 if (errno != 0) {
  629.                     perror("strtol");
  630.                     exit(EXIT_FAILURE);
  631.                 }
  632.                 if (tmp_long < 1) {
  633.                     fprintf(stderr, "Number of threads must be >= 1\n");
  634.                     exit(EXIT_FAILURE);
  635.                 }
  636.                 threads = tmp_long;
  637.                 break;
  638.             case 'c':
  639.                 str_compare = strcoll;
  640.                 break;
  641.             case 'V':
  642.                 str_compare = strverscmp;
  643.                 break;
  644.             case 'm':
  645.                 read_method = READ_BY_MMAPED_BLOCK;
  646.                 break;
  647.             case 'z':
  648.                 zero_terminated = 1;
  649.                 break;
  650.             case 'h':
  651.                 usage();
  652.                 exit(EXIT_SUCCESS);
  653.                 break;
  654.             default:
  655.                 usage();
  656.                 exit(EXIT_FAILURE);
  657.                 break;
  658.         }
  659.     }
  660.  
  661.     argv += optind;
  662.     argc -= optind;
  663.  
  664.     if (argc != 1 && argc != 2) {
  665.         usage();
  666.         exit(EXIT_FAILURE);
  667.     }
  668.  
  669.     in_filename = argv[0];
  670.     if (argc == 2)
  671.         out_filename = argv[1];
  672.     else
  673.         out_filename = "-";
  674.  
  675.     /* Open the input and output files */
  676.     if (strcmp(in_filename, "-") != 0) {
  677.         in_file = fopen(in_filename, "r");
  678.         if (in_file == NULL) {
  679.             perror("fopen");
  680.             exit(EXIT_FAILURE);
  681.         }
  682.     }
  683.     else {
  684.         in_file = stdin;
  685.         in_filename = "stdin";
  686.         read_method = READ_BY_LINE;
  687.     }
  688.     if (strcmp(out_filename, "-") != 0) {
  689.         out_file = fopen(out_filename, "w");
  690.         if (out_file == NULL) {
  691.             perror("fopen");
  692.             exit(EXIT_FAILURE);
  693.         }
  694.     }
  695.     else {
  696.         out_file = stdout;
  697.         out_filename = "stdout";
  698.     }
  699.  
  700.     /* Read input */
  701.     if (verbose)
  702.         fprintf(stderr, "Reading from '%s'...\n", in_filename);
  703. #ifdef STATS
  704.     INIT_TIMER(&t0);
  705.     GET_T(&t0);
  706. #endif
  707.     lines = read_file(in_file, &lines_length, read_method);
  708. #ifdef STATS
  709.     GET_T(&t1);
  710.     DIFF_T0_T1(&t0,&t1,diff_read);
  711. #endif
  712.     if (lines == NULL) {
  713.         goto close_end;
  714.     }
  715.     if (verbose) {
  716.         fprintf(stderr, "  Read %zd lines.\n", lines_length);
  717.     }
  718.  
  719.     /* The WTF cases... */
  720.     if (lines_length < threads)
  721.         threads = lines_length;
  722.     if (lines_length < FIND_PIVOTS_ELEMS)
  723.         threads = 0;
  724.  
  725.     if (lines_length < MIN_LINES_FOR_THREADS)
  726.         threads = 0;
  727.  
  728.     /* Sorting */
  729.     if (verbose) {
  730.         if (!threads || threads == 1)
  731.             fprintf(stderr, "Sorting...\n");
  732.         else
  733.             fprintf(stderr, "Sorting with %zd threads...\n", threads);
  734.     }
  735. #ifdef STATS
  736.     INIT_TIMER(&t0);
  737.     GET_T(&t0);
  738. #endif
  739.     r = do_sort(lines, lines_length);
  740. #ifdef STATS
  741.     GET_T(&t1);
  742.     DIFF_T0_T1(&t0,&t1,diff_sort);
  743. #endif
  744.     if (r == -1)
  745.         goto free_end;
  746.  
  747.     /* Write output */
  748.     if (verbose)
  749.         fprintf(stderr, "Writting output to '%s'...\n", out_filename);
  750. #ifdef STATS
  751.     INIT_TIMER(&t0);
  752.     GET_T(&t0);
  753. #endif
  754.     r = write_lines(out_file, lines, lines_length);
  755. #ifdef STATS
  756.     GET_T(&t1);
  757.     DIFF_T0_T1(&t0,&t1,diff_write);
  758. #endif
  759.     if (r < 0) {
  760.         goto free_end;
  761.     }
  762.  
  763.     exit_status = EXIT_SUCCESS;
  764.  
  765. #ifdef STATS
  766.     RESET_TIMER(&t0);
  767.     fprintf(stderr, "Stats:\n");
  768.     fprintf(stderr, "  comparisons: %zd\n", cmps);
  769.     fprintf(stderr, "  read time: %.03fs\n", diff_read / 1000000.);
  770.     fprintf(stderr, "  sort time: %.03fs\n", diff_sort / 1000000.);
  771.     fprintf(stderr, "  write time: %.03fs\n", diff_write / 1000000.);
  772. #endif
  773.  
  774.     free_end:
  775.  
  776.     if (verbose)
  777.         fprintf(stderr, "Cleaning...\n");
  778.     free_read(lines, lines_length, read_method);
  779.  
  780.     close_end:
  781.  
  782.     fclose(in_file);
  783.     fclose(out_file);
  784.  
  785.     return exit_status;
  786. }
  787.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement