GenericEventHandler.hpp

00001 /*
00002 
00003 Copyright (C) University of Oxford, 2005-2009
00004 
00005 University of Oxford means the Chancellor, Masters and Scholars of the
00006 University of Oxford, having an administrative office at Wellington
00007 Square, Oxford OX1 2JD, UK.
00008 
00009 This file is part of Chaste.
00010 
00011 Chaste is free software: you can redistribute it and/or modify it
00012 under the terms of the GNU Lesser General Public License as published
00013 by the Free Software Foundation, either version 2.1 of the License, or
00014 (at your option) any later version.
00015 
00016 Chaste is distributed in the hope that it will be useful, but WITHOUT
00017 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
00019 License for more details. The offer of Chaste under the terms of the
00020 License is subject to the License being interpreted in accordance with
00021 English Law and subject to any action against the University of Oxford
00022 being under the jurisdiction of the English Courts.
00023 
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with Chaste. If not, see <http://www.gnu.org/licenses/>.
00026 
00027 */
00028 
00029 
00030 #ifndef GENERICEVENTHANDLER_HPP_
00031 #define GENERICEVENTHANDLER_HPP_
00032 
00033 #include <cassert>
00034 #include <ctime>
00035 #include <iostream>
00036 
00037 #include "Exception.hpp"
00038 #include "PetscTools.hpp"
00039 
00047 template <unsigned NUM_EVENTS, class CONCRETE>
00048 class GenericEventHandler
00049 {
00050 private:
00051     static std::vector<double> mCpuTime; 
00052     static std::vector<bool> mHasBegun; 
00053     static bool mEnabled; 
00054     static bool mInitialised; 
00057     inline static double GetCpuTime()
00058     {
00059         return clock();
00060     }
00061     
00067     inline static double ConvertTicksToMilliseconds(double clockTicks)
00068     {
00069         return clockTicks/(CLOCKS_PER_SEC/1000.0);
00070     }
00071     
00077     inline static double ConvertTicksToSeconds(double clockTicks)
00078     {
00079         return clockTicks/(CLOCKS_PER_SEC);
00080     }
00081     
00083     inline static void CheckVectorSizes()
00084     {
00085         if (!mInitialised)
00086         {
00087             mCpuTime.resize(NUM_EVENTS, 0.0);
00088             mHasBegun.resize(NUM_EVENTS, false);
00089             mInitialised = true;
00090         }
00091     }
00092 
00093 public:
00094 
00098     static void Reset()
00099     {
00100         CheckVectorSizes();
00101         for (unsigned event=0; event<NUM_EVENTS; event++)
00102         {
00103             mCpuTime[event] = 0.0;
00104             mHasBegun[event] = false;
00105         }
00106         Enable();
00107     }
00108 
00114     static void BeginEvent(unsigned event) throw (Exception)
00115     {
00116         assert(event<NUM_EVENTS);
00117         if (!mEnabled)
00118         {
00119             return;
00120         }
00121         CheckVectorSizes();
00122         if (mHasBegun[event])
00123         {
00124             std::string msg;
00125             msg += "The event associated with the counter for '";
00126             msg += CONCRETE::EventName[event];
00127             msg += "' had already begun when BeginEvent was called.";
00128             std::cerr << msg << std::endl << std::flush;
00129             Disable();
00130             return;
00131         }
00132         mCpuTime[event] -= GetCpuTime();
00133         mHasBegun[event] = true;
00134         //std::cout << PetscTools::GetMyRank()<<": Beginning " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00135     }
00136 
00142     static void EndEvent(unsigned event)
00143     {
00144         assert(event<NUM_EVENTS); 
00145         if (!mEnabled)
00146         {
00147             return;
00148         }
00149         CheckVectorSizes();
00150         if (!mHasBegun[event])
00151         {
00152             std::string msg;
00153             msg += "Error: The event associated with the counter for '";
00154             msg += CONCRETE::EventName[event];
00155             msg += "' had not begun when EndEvent was called.";
00156             EXCEPTION(msg);
00157         }
00158         mCpuTime[event] += GetCpuTime();
00159         mHasBegun[event] = false;
00160         //std::cout << PetscTools::GetMyRank()<<": Ending " << EVENT_NAME[event] << " @ " << (clock()/1000) << std::endl;
00161     }
00162 
00170     static double GetElapsedTime(unsigned event)
00171     {
00172         assert(event<NUM_EVENTS);
00173         if (!mEnabled)
00174         {
00175             return 0.0;
00176         }
00177         CheckVectorSizes();
00178         double ticks;
00179         if (mHasBegun[event])
00180         {
00181             ticks =  mCpuTime[event] + GetCpuTime();
00182         }
00183         else
00184         {
00185             ticks = mCpuTime[event];
00186         }
00187         return ConvertTicksToMilliseconds(ticks);
00188     }
00189 
00198     static void Report()
00199     {
00200         CheckVectorSizes();
00201         
00202         if (!mEnabled)
00203         {
00204             EXCEPTION("Asked to report on a disabled event handler.  Check for contributory errors above.");
00205         }
00206         
00207         const unsigned top_event = NUM_EVENTS-1;
00208         double total = ConvertTicksToSeconds(mCpuTime[top_event]);
00209         for (unsigned turn=0; turn<PetscTools::NumProcs(); turn++)
00210         {
00211             std::cout.flush();
00212             PetscTools::Barrier();
00213             if (turn == PetscTools::GetMyRank())
00214             {
00215                 if (!PetscTools::IsSequential())
00216                 {
00217                     // Report the process number at the beginning of the line
00218                     printf("%3i: ", turn); //5 chars
00219                 }
00220                 for (unsigned event=0; event<NUM_EVENTS; event++)
00221                 {
00222                     const double secs = ConvertTicksToSeconds(mCpuTime[event]);
00223                     printf("%7.2e ", secs);
00224                     printf("(%3.0f%%)  ", secs/total*100.0);
00225                 }
00226                 std::cout << "(seconds) \n";
00227             }
00228         }
00229         
00230         // If there is a collection of processes then report an average
00231         if (!PetscTools::IsSequential())
00232         {
00233             double total_cpu_time[NUM_EVENTS];
00234             MPI_Reduce(&mCpuTime[0], total_cpu_time, NUM_EVENTS, MPI_DOUBLE, 
00235                        MPI_SUM, 0, PETSC_COMM_WORLD);
00236             if (PetscTools::AmMaster())
00237             {
00238                 total = ConvertTicksToSeconds(total_cpu_time[top_event]);
00239                 printf("avg: "); //5 chars
00240                 for (unsigned event=0; event<NUM_EVENTS; event++)
00241                 {
00242                     const double secs = ConvertTicksToSeconds(total_cpu_time[event]);
00243                     printf("%7.2e ", secs/PetscTools::NumProcs());
00244                     printf("(%3.0f%%)  ", secs/total*100.0);
00245                 }
00246                 std::cout << "(seconds) \n";
00247             }
00248                 
00249             double max_cpu_time[NUM_EVENTS];
00250             MPI_Reduce(&mCpuTime[0], max_cpu_time, NUM_EVENTS, MPI_DOUBLE,
00251                        MPI_MAX, 0, PETSC_COMM_WORLD);
00252             if (PetscTools::AmMaster())
00253             {
00254                 total = ConvertTicksToSeconds(max_cpu_time[top_event]);
00255                 printf("max: "); //5 chars
00256                 for (unsigned event=0; event<NUM_EVENTS; event++)
00257                 {
00258                     const double secs = ConvertTicksToSeconds(max_cpu_time[event]);
00259                     printf("%7.2e ", secs);
00260                     printf("(%3.0f%%)  ", secs/total*100.0);
00261                 }
00262                 std::cout << "(seconds) \n";
00263             }
00264         }
00265         std::cout.flush();
00266         PetscTools::Barrier();
00267         std::cout.flush();
00268         
00269         Reset();
00270     }
00271 
00275     static void Headings()
00276     {
00277         CheckVectorSizes();
00278         // Make sure that all output (on all processes) is flushed
00279         std::cout.flush();
00280         PetscTools::Barrier();
00281         std::cout.flush();
00282         if (PetscTools::AmMaster())
00283         {
00284             if (!PetscTools::IsSequential())
00285             {
00286                 // Report the process number at the beginning of the line
00287                 printf("Proc "); //5 chars
00288             }
00289             for (unsigned event=0; event<NUM_EVENTS; event++)
00290             {
00291                 printf("%15s%2s", CONCRETE::EventName[event], "");
00292             }
00293             std::cout << "\n";
00294             std::cout.flush();
00295         }
00296     }
00297 
00301     static void Enable()
00302     {
00303         CheckVectorSizes();
00304         mEnabled = true;
00305     }
00306 
00308     static void Disable()
00309     {
00310         CheckVectorSizes();
00311         mEnabled = false;
00312     }
00313     
00315     static bool IsEnabled()
00316     {
00317         return mEnabled;
00318     }
00319 };
00320 
00321 template<unsigned NUM_EVENTS, class CONCRETE>
00322 std::vector<double> GenericEventHandler<NUM_EVENTS, CONCRETE>::mCpuTime;
00323 
00324 template<unsigned NUM_EVENTS, class CONCRETE>
00325 std::vector<bool> GenericEventHandler<NUM_EVENTS, CONCRETE>::mHasBegun;
00326 
00327 template<unsigned NUM_EVENTS, class CONCRETE>
00328 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mEnabled = true;
00329 
00330 template<unsigned NUM_EVENTS, class CONCRETE>
00331 bool GenericEventHandler<NUM_EVENTS, CONCRETE>::mInitialised = false;
00332 
00333 #endif /*GENERICEVENTHANDLER_HPP_*/

Generated on Wed Mar 18 12:51:50 2009 for Chaste by  doxygen 1.5.5