![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 00027 */ 00028 00029 // 00030 // Example program that reads a file of decimal integers in text format 00031 // and changes each to its square. 00032 // 00033 #include "tbb/pipeline.h" 00034 #include "tbb/tick_count.h" 00035 #include "tbb/task_scheduler_init.h" 00036 #include "tbb/tbb_allocator.h" 00037 #include <cstring> 00038 #include <cstdlib> 00039 #include <cstdio> 00040 #include <cctype> 00041 00042 using namespace std; 00043 00045 00047 class TextSlice { 00049 char* logical_end; 00051 char* physical_end; 00052 public: 00054 static TextSlice* allocate( size_t max_size ) { 00055 // +1 leaves room for a terminating null character. 00056 TextSlice* t = (TextSlice*)tbb::tbb_allocator<char>().allocate( sizeof(TextSlice)+max_size+1 ); 00057 t->logical_end = t->begin(); 00058 t->physical_end = t->begin()+max_size; 00059 return t; 00060 } 00062 void free() { 00063 tbb::tbb_allocator<char>().deallocate((char*)this,sizeof(TextSlice)+(physical_end-begin())+1); 00064 } 00066 char* begin() {return (char*)(this+1);} 00068 char* end() {return logical_end;} 00070 size_t size() const {return logical_end-(char*)(this+1);} 00072 size_t avail() const {return physical_end-logical_end;} 00074 void append( char* first, char* last ) { 00075 memcpy( logical_end, first, last-first ); 00076 logical_end += last-first; 00077 } 00079 void set_end( char* p ) {logical_end=p;} 00080 }; 00081 00082 const size_t MAX_CHAR_PER_INPUT_SLICE = 4000; 00083 static const char* InputFileName = "input.txt"; 00084 static const char* OutputFileName = "output.txt"; 00085 00086 class MyInputFilter: public tbb::filter { 00087 public: 00088 MyInputFilter( FILE* input_file_ ); 00089 ~MyInputFilter(); 00090 private: 00091 FILE* input_file; 00092 TextSlice* next_slice; 00093 /*override*/ void* operator()(void*); 00094 }; 00095 00096 MyInputFilter::MyInputFilter( FILE* input_file_ ) : 00097 filter(serial_in_order), 00098 input_file(input_file_), 00099 next_slice( TextSlice::allocate( MAX_CHAR_PER_INPUT_SLICE ) ) 00100 { 00101 } 00102 00103 MyInputFilter::~MyInputFilter() { 00104 next_slice->free(); 00105 } 00106 00107 void* MyInputFilter::operator()(void*) { 00108 // Read characters into space that is available in the next slice. 00109 size_t m = next_slice->avail(); 00110 size_t n = fread( next_slice->end(), 1, m, input_file ); 00111 if( !n && next_slice->size()==0 ) { 00112 // No more characters to process 00113 return NULL; 00114 } else { 00115 // Have more characters to process. 00116 TextSlice& t = *next_slice; 00117 next_slice = TextSlice::allocate( MAX_CHAR_PER_INPUT_SLICE ); 00118 char* p = t.end()+n; 00119 if( n==m ) { 00120 // Might have read partial number. If so, transfer characters of partial number to next slice. 00121 while( p>t.begin() && isdigit(p[-1]) ) 00122 --p; 00123 next_slice->append( p, t.end()+n ); 00124 } 00125 t.set_end(p); 00126 return &t; 00127 } 00128 } 00129 00131 class MyTransformFilter: public tbb::filter { 00132 public: 00133 MyTransformFilter(); 00134 /*override*/void* operator()( void* item ); 00135 }; 00136 00137 MyTransformFilter::MyTransformFilter() : 00138 tbb::filter(parallel) 00139 {} 00140 00141 /*override*/void* MyTransformFilter::operator()( void* item ) { 00142 TextSlice& input = *static_cast<TextSlice*>(item); 00143 // Add terminating null so that strtol works right even if number is at end of the input. 00144 *input.end() = '\0'; 00145 char* p = input.begin(); 00146 TextSlice& out = *TextSlice::allocate( 2*MAX_CHAR_PER_INPUT_SLICE ); 00147 char* q = out.begin(); 00148 for(;;) { 00149 while( p<input.end() && !isdigit(*p) ) 00150 *q++ = *p++; 00151 if( p==input.end() ) 00152 break; 00153 long x = strtol( p, &p, 10 ); 00154 // Note: no overflow checking is needed here, as we have twice the 00155 // input string length, but the square of a non-negative integer n 00156 // cannot have more than twice as many digits as n. 00157 long y = x*x; 00158 sprintf(q,"%ld",y); 00159 q = strchr(q,0); 00160 } 00161 out.set_end(q); 00162 input.free(); 00163 return &out; 00164 } 00165 00167 class MyOutputFilter: public tbb::filter { 00168 FILE* my_output_file; 00169 public: 00170 MyOutputFilter( FILE* output_file ); 00171 /*override*/void* operator()( void* item ); 00172 }; 00173 00174 MyOutputFilter::MyOutputFilter( FILE* output_file ) : 00175 tbb::filter(serial_in_order), 00176 my_output_file(output_file) 00177 { 00178 } 00179 00180 void* MyOutputFilter::operator()( void* item ) { 00181 TextSlice& out = *static_cast<TextSlice*>(item); 00182 size_t n = fwrite( out.begin(), 1, out.size(), my_output_file ); 00183 if( n!=out.size() ) { 00184 fprintf(stderr,"Can't write into file '%s'\n", OutputFileName); 00185 exit(1); 00186 } 00187 out.free(); 00188 return NULL; 00189 } 00190 00191 static int NThread = tbb::task_scheduler_init::automatic; 00192 static bool is_number_of_threads_set = false; 00193 00194 void Usage() 00195 { 00196 fprintf( stderr, "Usage:\tsquare [input-file [output-file [nthread]]]\n"); 00197 } 00198 00199 int ParseCommandLine( int argc, char* argv[] ) { 00200 // Parse command line 00201 if( argc> 4 ){ 00202 Usage(); 00203 return 0; 00204 } 00205 if( argc>=2 ) InputFileName = argv[1]; 00206 if( argc>=3 ) OutputFileName = argv[2]; 00207 if( argc>=4 ) { 00208 NThread = strtol(argv[3],0,0); 00209 if( NThread<1 ) { 00210 fprintf(stderr,"nthread set to %d, but must be at least 1\n",NThread); 00211 return 0; 00212 } 00213 is_number_of_threads_set = true; //Number of threads is set explicitly 00214 } 00215 return 1; 00216 } 00217 00218 int run_pipeline( int nthreads ) 00219 { 00220 FILE* input_file = fopen(InputFileName,"r"); 00221 if( !input_file ) { 00222 perror( InputFileName ); 00223 Usage(); 00224 return 0; 00225 } 00226 FILE* output_file = fopen(OutputFileName,"w"); 00227 if( !output_file ) { 00228 perror( OutputFileName ); 00229 return 0; 00230 } 00231 00232 // Create the pipeline 00233 tbb::pipeline pipeline; 00234 00235 // Create file-reading writing stage and add it to the pipeline 00236 MyInputFilter input_filter( input_file ); 00237 pipeline.add_filter( input_filter ); 00238 00239 // Create capitalization stage and add it to the pipeline 00240 MyTransformFilter transform_filter; 00241 pipeline.add_filter( transform_filter ); 00242 00243 // Create file-writing stage and add it to the pipeline 00244 MyOutputFilter output_filter( output_file ); 00245 pipeline.add_filter( output_filter ); 00246 00247 // Run the pipeline 00248 tbb::tick_count t0 = tbb::tick_count::now(); 00249 // Need more than one token in flight per thread to keep all threads 00250 // busy; 2-4 works 00251 pipeline.run( nthreads*4 ); 00252 tbb::tick_count t1 = tbb::tick_count::now(); 00253 00254 fclose( output_file ); 00255 fclose( input_file ); 00256 00257 if (is_number_of_threads_set) { 00258 printf("threads = %d time = %g\n", nthreads, (t1-t0).seconds()); 00259 } else { 00260 if ( nthreads == 1 ){ 00261 printf("serial run time = %g\n", (t1-t0).seconds()); 00262 } else { 00263 printf("parallel run time = %g\n", (t1-t0).seconds()); 00264 } 00265 } 00266 return 1; 00267 } 00268 00269 int main( int argc, char* argv[] ) { 00270 if(!ParseCommandLine( argc, argv )) 00271 return 1; 00272 if (is_number_of_threads_set) { 00273 // Start task scheduler 00274 tbb::task_scheduler_init init( NThread ); 00275 if(!run_pipeline (NThread)) 00276 return 1; 00277 } else { // Number of threads wasn't set explicitly. Run serial and parallel version 00278 { // serial run 00279 tbb::task_scheduler_init init_serial(1); 00280 if(!run_pipeline (1)) 00281 return 1; 00282 } 00283 { // parallel run (number of threads is selected automatically) 00284 tbb::task_scheduler_init init_parallel; 00285 if(!run_pipeline (init_parallel.default_num_threads())) 00286 return 1; 00287 } 00288 } 00289 return 0; 00290 }
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.