Shadowrun: Awakened 29 September 2011 - Build 871
parallel_preorder.cpp
Go to the documentation of this file.
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 /* Example program that shows how to use parallel_do to do parallel preorder 
00030    traversal of a directed acyclic graph. */
00031 
00032 #include "tbb/parallel_do.h"
00033 #include "tbb/atomic.h"
00034 #include <vector>
00035 #include <algorithm>
00036 #include <cstring>
00037 #include <cstdio>
00038 #include "Graph.h"
00039 
00040 using namespace std;
00041 
00043 int ntrial = 50;
00044 
00045 class Body {
00046 public:
00047     Body() {};
00048 
00049     //------------------------------------------------------------------------
00050     // Following signatures are required by parallel_do
00051     //------------------------------------------------------------------------
00052     typedef Cell* argument_type;
00053 
00054     void operator()( Cell* c, tbb::parallel_do_feeder<Cell*>& feeder ) const {
00055         c->update();
00056         // Restore ref_count in preparation for subsequent traversal.
00057         c->ref_count = ArityOfOp[c->op];
00058         for( size_t k=0; k<c->successor.size(); ++k ) {
00059             Cell* successor = c->successor[k];
00060             if( 0 == --(successor->ref_count) ) {
00061                 feeder.add( successor );
00062             }
00063         }
00064     }
00065 };   
00066 
00067 void ParallelPreorderTraversal( const vector<Cell*>& root_set ) {
00068     tbb::parallel_do(root_set.begin(), root_set.end(),Body());
00069 }
00070 
00071 //------------------------------------------------------------------------
00072 // Test driver
00073 //------------------------------------------------------------------------
00074 
00075 #include <cctype>
00076 #include "tbb/task_scheduler_init.h"
00077 #include "tbb/tick_count.h"
00078 
00080 struct IntRange {
00081     int low;
00082     int high;
00083     void set_from_string( const char* s );
00084     IntRange( int low_, int high_ ) : low(low_), high(high_) {}
00085 };
00086 
00087 void IntRange::set_from_string( const char* s ) {
00088     char* end;
00089     high = low = strtol(s,&end,0);
00090     switch( *end ) {
00091     case ':': 
00092         high = strtol(end+1,0,0); 
00093         break;
00094     case '\0':
00095         break;
00096     default:
00097         printf("unexpected character = %c\n",*end);
00098     }
00099 }
00100 
00102 static IntRange NThread(1,4);
00103 
00105 static bool PauseFlag = false;
00106 
00108 void Usage(char * argv0) {
00109     fprintf(stderr, "Usage: %s [nthread [ntrials ['pause']]]\n", argv0);
00110     fprintf(stderr, "where nthread is a non-negative integer, or range of the form low:high [%d:%d]\n", NThread.low, NThread.high);
00111     fprintf(stderr, "ntrials is a positive integer. Default value is 50, reduce it (e.g. to 5) to shorten example run time\n");
00112     fprintf(stderr, "The application waits for user to hit return if 'pause' is specified\n");
00113 }
00114 
00116 static void ParseCommandLine( int argc, char* argv[] ) {
00117     int i = 1;
00118         if( i<argc && !isdigit(argv[i][0]) ) { 
00119         // Command line is garbled.
00120         Usage(argv[0]);
00121         exit(1);
00122     }
00123     if( i<argc )
00124         NThread.set_from_string(argv[i++]);
00125     if( i<argc && !isdigit(argv[i][0]) ) { 
00126         // Command line is garbled.
00127         Usage(argv[0]);
00128         exit(1);
00129     }
00130     if (i<argc) {
00131         ntrial = strtol(argv[i++], 0, 0);
00132     }
00133     if (ntrial == 0) {
00134         // Command line is garbled.
00135         Usage(argv[0]);
00136         exit(1);
00137     }
00138     if (i<argc && strcmp( argv[i], "pause" )==0 ) {
00139         PauseFlag = true;
00140     }
00141 }
00142 
00143 int main( int argc, char* argv[] ) {
00144     ParseCommandLine(argc,argv);
00145 
00146     // Start scheduler with given number of threads.
00147     for( int p=NThread.low; p<=NThread.high; ++p ) {
00148         tbb::task_scheduler_init init(p);
00149         srand(2);
00150         tbb::tick_count::interval_t interval;
00151         size_t total_root_set_size = 0;
00152         for( int trial=0; trial<ntrial; ++trial ) {
00153             Graph g;
00154             g.create_random_dag(1000);
00155             vector<Cell*> root_set;
00156             g.get_root_set(root_set);
00157             total_root_set_size += root_set.size();
00158 
00159             tbb::tick_count t0 = tbb::tick_count::now();
00160             for( int i=0; i<10; ++i ) {
00161                 ParallelPreorderTraversal(root_set);
00162             }
00163             tbb::tick_count t1 = tbb::tick_count::now();
00164 
00165             interval += t1-t0;
00166         }
00167         printf("%g seconds using %d threads (average of %g nodes in root_set)\n",interval.seconds(),p,(double)total_root_set_size/ntrial);
00168     }
00169 
00170     if (PauseFlag) {
00171         printf ("Press return key to exit");
00172         char c;
00173         int n = scanf("%c", &c);
00174         if( n!=1 ) {
00175             fprintf(stderr,"Fatal error: unexpected end of input\n");
00176             exit(1);
00177         }
00178     }
00179 
00180     return 0;
00181 }

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net