Stxxl
1.4.0
|
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() != ¶llel_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