/* UpTools v8.6 * * Copyright (c) 2005-2012 Fundacion Universidad de Palermo (Argentina). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. Neither the name of the copyright holder nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: 'This product includes software developed by the * "Universidad de Palermo, Argentina" (http://www.palermo.edu/).' * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <UpTools/UpThreadWorkDistributor.h> #include <UpTools/UpArch.h> #include <iostream> #include <unistd.h> using namespace std; #define MINSIZE_DOUBLE 600000 #define DEFAULTDATASIZE 8000000 #define DEFAULTTHREADCOUNT 8 // #define USE_WAITCOMPLETION 1 #ifndef USE_WAITCOMPLETION UpSemaphore sem(0); #endif // This class sums the numbers in the semi-open interval [begin,end). // Example: if begin=1 and end=4 then the result will be 1+2+3=6. // This class is going to be split and distributed between various threads // by the UpThreadWorkDistributor in order to accelerate its work. // (Of course it is much faster to use the well known formula to // calculate this, but this program is a simple example to test the // acceleration of the work by splitting it and ditributing it // between several threads). class SplittableSum : public UpWorkSplittable { private: unsigned long long begin, end; unsigned long long *saveResult; unsigned long long result; unsigned long long size; UpTimeVal* uptv; public: SplittableSum(unsigned long long _begin,unsigned long long _end, unsigned long long *_saveResult=0, UpTimeVal* _uptv=0) : begin(_begin), end(_end), saveResult(_saveResult), size(end-begin), uptv(_uptv) { } ~SplittableSum() { if( uptv!=0 ) *uptv = duration; if( saveResult ) { // UpThreadWorkDistributor will delete this work, so we save // the result if it is the base work *saveResult=result; #ifndef USE_WAITCOMPLETION // we need to unblock main thread using the semaphore here if(saveResult) sem.post(); #endif } } SplittableSum* split() { // if( size<MINSIZE_DOUBLE ) return 0; size >>=1; // unsigned long long middle( begin+size ); // we do not set saveResult on splitted instances of this work SplittableSum* ret( new SplittableSum( middle, end, 0, 0 ) ); end = middle; return ret; } void action() { register unsigned long long res( 0 ); for( register unsigned long long x( begin ) ; x<end ; ++x ) res += x; result = res; } void join( UpWorkSplittable* s ) { result += ((SplittableSum*)s)->result; } char joinType() { //return 't'; return 's'; } bool exceedHwThreads() { return true; } void show(ostream& o) const { o<<'('<<begin<<'-'<<(end-1)<<')'; } }; int main(int argc, char *argv[]) { unsigned long long dataSize( DEFAULTDATASIZE ); unsigned int threadCount( DEFAULTTHREADCOUNT ); if( argc>1 ) threadCount << string(argv[1]); if( argc>2 ) dataSize << string(argv[2]); if( threadCount>32 ) threadCount=32; cout<<"Usage: "<<argv[0]<<" [threadCount] [endOfSum]"<<endl; cout<<"Summing up numbers from 1 to "<<dataSize<<" using " <<threadCount<<" threads"<<endl; UpThreadWorkDistributor ld(threadCount); ld.setWorkMemoryLength(10); unsigned long long result( 0 ); UpTimeVal duration; // UpThreadWorkDistributor will delete this work after completing it SplittableSum* sp ( new SplittableSum( 1, dataSize+1, &result, &duration ) ); cout<<"processing data..."; #if USE_WAITCOMPLETION // *** case 1 *************************************************************** // We call ld.processWork(...) with waitCompletion. // The work will be distributed between the threads owned by the // UpThreadWorkDistributor *and* the calling thread, so ld.processWork(..) // will return after completing the work ld.processWork( sp, true ); // *** end of case 1 ********************************************************* #else // *** case 2 ************************************************************** // We call processWork without waitCompletion. // The work will be distributed between the threads owned by the // UpThreadWorkDistributor only. ld.processWork(...) will return immediately // without waiting the work to complete. ld.processWork( sp ); // So we block this thread on a semaphore waiting for the finished work // to unblock us sem.wait(); /* ** end of case 2 ********************************************************/ #endif std::string txt; txt << "result: " << result << "\ndata processing duration: " << duration << " checkValue = " << ( (result==(dataSize*(dataSize+1)/2)) ? "OK" : "ERR" ); cout<<txt<<endl; return 0; }