Stxxl  1.4.0
algo/test_parallel_sort.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002  *  algo/test_parallel_sort.cpp
00003  *
00004  *  Part of the STXXL. See http://stxxl.sourceforge.net
00005  *
00006  *  Copyright (C) 2007, 2009 Johannes Singler <singler@ira.uka.de>
00007  *  Copyright (C) 2008, 2009 Andreas Beckmann <beckmann@cs.uni-frankfurt.de>
00008  *
00009  *  Distributed under the Boost Software License, Version 1.0.
00010  *  (See accompanying file LICENSE_1_0.txt or copy at
00011  *  http://www.boost.org/LICENSE_1_0.txt)
00012  **************************************************************************/
00013 
00014 //! \example algo/test_parallel_sort.cpp
00015 //! This is an example of how to use the parallelized sorting algorithm.
00016 //! Setting all the parameters in optional, just compiling with either MCSTL
00017 //! or parallel mode suffices.
00018 
00019 #define MCSTL_QUICKSORT_WORKAROUND 0
00020 
00021 #if !defined(STXXL_NOT_CONSIDER_SORT_MEMORY_OVERHEAD)
00022 #define STXXL_NOT_CONSIDER_SORT_MEMORY_OVERHEAD 0
00023 #endif
00024 
00025 #include <algorithm>
00026 #include <functional>
00027 #include <limits>
00028 
00029 #include <stxxl/vector>
00030 #include <stxxl/stream>
00031 #include <stxxl/scan>
00032 #include <stxxl/sort>
00033 
00034 #ifdef __MCSTL__
00035 #include <mcstl.h>
00036 #endif
00037 
00038 
00039 const unsigned long long megabyte = 1024 * 1024;
00040 
00041 //const int block_size = STXXL_DEFAULT_BLOCK_SIZE(my_type);
00042 const int block_size = 4 * megabyte;
00043 
00044 #define RECORD_SIZE 16
00045 #define MAGIC 123
00046 
00047 stxxl::unsigned_type run_size;
00048 stxxl::unsigned_type buffer_size;
00049 
00050 struct my_type
00051 {
00052     typedef unsigned long long key_type;
00053 
00054     key_type _key;
00055     key_type _load;
00056     char _data[RECORD_SIZE - 2 * sizeof(key_type)];
00057     key_type key() const { return _key; }
00058 
00059     my_type() { }
00060     my_type(key_type __key) : _key(__key) { }
00061     my_type(key_type __key, key_type __load) : _key(__key), _load(__load) { }
00062 
00063     void operator = (const key_type & __key) { _key = __key; }
00064     void operator = (const my_type & mt)
00065     {
00066         _key = mt._key;
00067         _load = mt._load;
00068     }
00069 };
00070 
00071 bool operator < (const my_type & a, const my_type & b);
00072 
00073 inline bool operator < (const my_type & a, const my_type & b)
00074 {
00075     return a.key() < b.key();
00076 }
00077 
00078 inline bool operator == (const my_type & a, const my_type & b)
00079 {
00080     return a.key() == b.key();
00081 }
00082 
00083 inline std::ostream & operator << (std::ostream & o, const my_type & obj)
00084 {
00085     o << obj._key << "/" << obj._load;
00086     return o;
00087 }
00088 
00089 struct cmp_less_key : public std::less<my_type>
00090 {
00091     my_type min_value() const { return my_type(std::numeric_limits<my_type::key_type>::min(), MAGIC); }
00092     my_type max_value() const { return my_type(std::numeric_limits<my_type::key_type>::max(), MAGIC); }
00093 };
00094 
00095 typedef stxxl::vector<my_type, 4, stxxl::lru_pager<8>, block_size, STXXL_DEFAULT_ALLOC_STRATEGY> vector_type;
00096 
00097 stxxl::unsigned_type checksum(vector_type & input)
00098 {
00099     stxxl::unsigned_type sum = 0;
00100     for (vector_type::const_iterator i = input.begin(); i != input.end(); ++i)
00101         sum += (*i)._key;
00102     return sum;
00103 }
00104 
00105 void linear_sort_normal(vector_type & input)
00106 {
00107     stxxl::unsigned_type sum1 = checksum(input);
00108 
00109     stxxl::stats_data stats_begin(*stxxl::stats::get_instance());
00110     double start = stxxl::timestamp();
00111 
00112     stxxl::sort(input.begin(), input.end(), cmp_less_key(), run_size);
00113 
00114     double stop = stxxl::timestamp();
00115     std::cout << stxxl::stats_data(*stxxl::stats::get_instance()) - stats_begin;
00116 
00117     stxxl::unsigned_type sum2 = checksum(input);
00118 
00119     std::cout << sum1 << " ?= " << sum2 << std::endl;
00120 
00121     STXXL_MSG((stxxl::is_sorted<vector_type::const_iterator>(input.begin(), input.end()) ? "OK" : "NOT SORTED"));
00122 
00123     std::cout << "Linear sorting normal took " << (stop - start) << " seconds." << std::endl;
00124 }
00125 
00126 void linear_sort_streamed(vector_type & input, vector_type & output)
00127 {
00128     stxxl::unsigned_type sum1 = checksum(input);
00129 
00130     stxxl::stats_data stats_begin(*stxxl::stats::get_instance());
00131     double start = stxxl::timestamp();
00132 
00133     typedef __typeof__(stxxl::stream::streamify(input.begin(), input.end())) input_stream_type;
00134 
00135     input_stream_type input_stream = stxxl::stream::streamify(input.begin(), input.end());
00136 
00137 
00138     typedef cmp_less_key comparator_type;
00139     comparator_type cl;
00140 
00141     typedef stxxl::stream::sort<input_stream_type, comparator_type, block_size> sort_stream_type;
00142 
00143     sort_stream_type sort_stream(input_stream, cl, run_size);
00144 
00145     vector_type::iterator o = stxxl::stream::materialize(sort_stream, output.begin(), output.end());
00146     assert(o == output.end());
00147 
00148     double stop = stxxl::timestamp();
00149     std::cout << stxxl::stats_data(*stxxl::stats::get_instance()) - stats_begin;
00150 
00151     stxxl::unsigned_type sum2 = checksum(output);
00152 
00153     std::cout << sum1 << " ?= " << sum2 << std::endl;
00154     if (sum1 != sum2)
00155         STXXL_MSG("WRONG DATA");
00156 
00157     STXXL_MSG((stxxl::is_sorted<vector_type::const_iterator>(output.begin(), output.end(), comparator_type()) ? "OK" : "NOT SORTED"));
00158 
00159     std::cout << "Linear sorting streamed took " << (stop - start) << " seconds." << std::endl;
00160 }
00161 
00162 
00163 int main(int argc, const char ** argv)
00164 {
00165     if (argc < 6) {
00166         std::cout << "Usage: " << argv[0] << " [n in MiB] [p threads] [M in MiB] [sorting algorithm: m | q | qb | s] [merging algorithm: p | s | n]" << std::endl;
00167         return -1;
00168     }
00169 
00170     stxxl::config::get_instance();
00171 
00172 #if STXXL_PARALLEL_MULTIWAY_MERGE
00173     STXXL_MSG("STXXL_PARALLEL_MULTIWAY_MERGE");
00174 #endif
00175     unsigned long megabytes_to_process = atoi(argv[1]);
00176     int p = atoi(argv[2]);
00177     stxxl::unsigned_type memory_to_use = (stxxl::unsigned_type)atoi(argv[3]) * megabyte;
00178     run_size = memory_to_use;
00179     buffer_size = memory_to_use / 16;
00180 #ifdef STXXL_PARALLEL_MODE
00181     omp_set_num_threads(p);
00182     __gnu_parallel::_Settings parallel_settings(__gnu_parallel::_Settings::get());
00183 
00184     parallel_settings.merge_splitting = __gnu_parallel::EXACT;
00185     parallel_settings.merge_minimal_n = 10000;
00186     parallel_settings.merge_oversampling = 10;
00187 
00188     parallel_settings.multiway_merge_algorithm = __gnu_parallel::LOSER_TREE;
00189     parallel_settings.multiway_merge_splitting = __gnu_parallel::EXACT;
00190     parallel_settings.multiway_merge_oversampling = 10;
00191     parallel_settings.multiway_merge_minimal_n = 10000;
00192     parallel_settings.multiway_merge_minimal_k = 2;
00193     if (!strcmp(argv[4], "q"))                  //quicksort
00194         parallel_settings.sort_algorithm = __gnu_parallel::QS;
00195     else if (!strcmp(argv[4], "qb"))            //balanced quicksort
00196         parallel_settings.sort_algorithm = __gnu_parallel::QS_BALANCED;
00197     else if (!strcmp(argv[4], "m"))             //merge sort
00198         parallel_settings.sort_algorithm = __gnu_parallel::MWMS;
00199     else /*if(!strcmp(argv[4], "s"))*/          //sequential (default)
00200     {
00201         parallel_settings.sort_algorithm = __gnu_parallel::QS;
00202         parallel_settings.sort_minimal_n = memory_to_use;
00203     }
00204 
00205     if (!strcmp(argv[5], "p"))          //parallel
00206     {
00207         stxxl::SETTINGS::native_merge = false;
00208         //parallel_settings.multiway_merge_minimal_n = 1024;    //leave as default
00209     }
00210     else if (!strcmp(argv[5], "s"))                                             //sequential
00211     {
00212         stxxl::SETTINGS::native_merge = false;
00213         parallel_settings.multiway_merge_minimal_n = memory_to_use;             //too much to be called
00214     }
00215     else /*if(!strcmp(argv[5], "n"))*/                                          //native (default)
00216         stxxl::SETTINGS::native_merge = true;
00217 
00218     parallel_settings.multiway_merge_minimal_k = 2;
00219 
00220     __gnu_parallel::_Settings::set(parallel_settings);
00221     assert(&__gnu_parallel::_Settings::get() != &parallel_settings);
00222 
00223     if (0)
00224         printf("%d %p: mwms %d, q %d, qb %d",
00225                __gnu_parallel::_Settings::get().sort_algorithm,
00226                &__gnu_parallel::_Settings::get().sort_algorithm,
00227                __gnu_parallel::MWMS,
00228                __gnu_parallel::QS,
00229                __gnu_parallel::QS_BALANCED);
00230 #elif defined(__MCSTL__)
00231     mcstl::HEURISTIC::num_threads = p;
00232     mcstl::HEURISTIC::force_sequential = false;
00233 
00234     mcstl::HEURISTIC::merge_splitting = mcstl::HEURISTIC::EXACT;
00235     mcstl::HEURISTIC::merge_minimal_n = 10000;
00236     mcstl::HEURISTIC::merge_oversampling = 10;
00237 
00238     mcstl::HEURISTIC::multiway_merge_algorithm = mcstl::HEURISTIC::LOSER_TREE;
00239     mcstl::HEURISTIC::multiway_merge_splitting = mcstl::HEURISTIC::EXACT;
00240     mcstl::HEURISTIC::multiway_merge_oversampling = 10;
00241     mcstl::HEURISTIC::multiway_merge_minimal_n = 10000;
00242     mcstl::HEURISTIC::multiway_merge_minimal_k = 2;
00243     if (!strcmp(argv[4], "q"))                                       //quicksort
00244         mcstl::HEURISTIC::sort_algorithm = mcstl::HEURISTIC::QS;
00245     else if (!strcmp(argv[4], "qb"))                                 //balanced quicksort
00246         mcstl::HEURISTIC::sort_algorithm = mcstl::HEURISTIC::QS_BALANCED;
00247     else if (!strcmp(argv[4], "m"))                                  //merge sort
00248         mcstl::HEURISTIC::sort_algorithm = mcstl::HEURISTIC::MWMS;
00249     else /*if(!strcmp(argv[4], "s"))*/                               //sequential (default)
00250     {
00251         mcstl::HEURISTIC::sort_algorithm = mcstl::HEURISTIC::QS;
00252         mcstl::HEURISTIC::sort_minimal_n = memory_to_use;
00253     }
00254 
00255     if (!strcmp(argv[5], "p"))                                       //parallel
00256     {
00257         stxxl::SETTINGS::native_merge = false;
00258         //mcstl::HEURISTIC::multiway_merge_minimal_n = 1024;         //leave as default
00259     }
00260     else if (!strcmp(argv[5], "s"))                                  //sequential
00261     {
00262         stxxl::SETTINGS::native_merge = false;
00263         mcstl::HEURISTIC::multiway_merge_minimal_n = memory_to_use;  //too much to be called
00264     }
00265     else /*if(!strcmp(argv[5], "n"))*/                               //native (default)
00266         stxxl::SETTINGS::native_merge = true;
00267 
00268     mcstl::HEURISTIC::multiway_merge_minimal_k = 2;
00269 #endif
00270 
00271     std::cout << "Sorting " << megabytes_to_process << " MiB of data ("
00272               << (megabytes_to_process * megabyte / sizeof(my_type)) << " elements) using "
00273               << (memory_to_use / megabyte) << " MiB of internal memory and "
00274               << p << " thread(s), block size "
00275               << block_size << ", element size " << sizeof(my_type) << std::endl;
00276 
00277     const stxxl::int64 n_records =
00278         stxxl::int64(megabytes_to_process) * stxxl::int64(megabyte) / sizeof(my_type);
00279     vector_type input(n_records);
00280 
00281     stxxl::stats_data stats_begin(*stxxl::stats::get_instance());
00282     double generate_start = stxxl::timestamp();
00283 
00284     stxxl::generate(input.begin(), input.end(), stxxl::random_number64(), memory_to_use / STXXL_DEFAULT_BLOCK_SIZE(my_type));
00285 
00286     double generate_stop = stxxl::timestamp();
00287     std::cout << stxxl::stats_data(*stxxl::stats::get_instance()) - stats_begin;
00288 
00289     std::cout << "Generating took " << (generate_stop - generate_start) << " seconds." << std::endl;
00290 
00291     STXXL_MSG(((stxxl::is_sorted<vector_type::const_iterator>(input.begin(), input.end())) ? "OK" : "NOT SORTED"));
00292 
00293     {
00294         vector_type output(n_records);
00295 
00296         linear_sort_streamed(input, output);
00297         linear_sort_normal(input);
00298     }
00299 
00300     return 0;
00301 }
00302 // vim: et:ts=4:sw=4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines