commandCache.cpp

00001 
00002 /* Copyright (c) 2006-2009, Stefan Eilemann <eile@equalizergraphics.com> 
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *  
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  * 
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #include "commandCache.h"
00019 
00020 #include "command.h"
00021 #include "node.h"
00022 #include "packets.h"
00023 
00024 using namespace std;
00025 
00026 #define COMPACT
00027 //#define PROFILE
00028 // 31300 hits, 35 misses, 297640 lookups, 126976b allocated in 31 packets
00029 // 31300 hits, 35 misses, 49228 lookups, 135168b allocated in 34 packets
00030 
00031 namespace eq
00032 {
00033 namespace net
00034 {
00035 CommandCache::CommandCache()
00036 {
00037     for( size_t i = 0; i < CACHE_ALL; ++i )
00038     {
00039         _caches[ i ].push_back( new Command );
00040         _positions[ i ] = 0;
00041     }
00042 }
00043 
00044 CommandCache::~CommandCache()
00045 {
00046     flush();
00047 
00048     for( size_t i = 0; i < CACHE_ALL; ++i )
00049     {
00050         EQASSERT( _caches[i].size() == 1 );
00051         delete _caches[i].front();
00052         _caches[i].clear();
00053     }
00054 }
00055 
00056 void CommandCache::flush()
00057 {
00058     for( size_t i = 0; i < CACHE_ALL; ++i )
00059     {
00060         CommandVector& cache = _caches[ i ];
00061         for( CommandVector::const_iterator j = cache.begin(); 
00062              j != cache.end(); ++j )
00063         {
00064             delete *j;
00065         }
00066         cache.clear();
00067         _positions[ i ] = 0;
00068         cache.push_back( new Command );
00069     }
00070 }
00071 
00072 #ifdef PROFILE
00073 namespace
00074 {
00075 static base::a_int32_t _hits;
00076 static base::a_int32_t _misses;
00077 static base::a_int32_t _lookups;
00078 }
00079 #endif
00080 
00081 Command& CommandCache::alloc( NodePtr node, NodePtr localNode, 
00082                               const uint64_t size )
00083 {
00084     CHECK_THREAD( _thread );
00085 
00086     const Cache which = (size > Packet::minSize) ? CACHE_BIG : CACHE_SMALL;
00087     CommandVector& cache = _caches[ which ];
00088     size_t& i = _positions[ which ];
00089 
00090     EQASSERT( !cache.empty( ));
00091 
00092 #ifdef COMPACT
00093     const unsigned highWater = (which == CACHE_BIG) ? 10 : 1000;
00094     if( cache.size() > highWater && (i%10) == 0 )
00095     {
00096         int64_t keepFree( 30 * 1024 * 1024 );
00097         keepFree = EQ_MAX( keepFree, 10 );
00098 #  ifdef PROFILE
00099         size_t freed( 0 );
00100 #  endif
00101 
00102         for( i = 0; i < cache.size(); ++i )
00103         {
00104             const Command* cmd = cache[i];
00105             if( !cmd->isFree( ))
00106                 continue;
00107             
00108             if( keepFree > 0 )
00109             {
00110                 keepFree -= cmd->getAllocationSize();
00111                 continue;
00112             }
00113 
00114             cache.erase( cache.begin() + i );
00115             delete cmd;
00116 #  ifdef PROFILE
00117             ++freed;
00118 #  endif
00119         }
00120 #  ifdef PROFILE
00121         EQINFO << "Freed " << freed << " packets, remaining " << cache.size()
00122                << std::endl;
00123 #  endif
00124     }
00125 #endif
00126 
00127     const size_t cacheSize = cache.size();        
00128     i = i % cacheSize;
00129 
00130     const size_t end = i + cacheSize;
00131     
00132     for( ++i; i <= end; ++i )
00133     {
00134 #ifdef PROFILE
00135         ++_lookups;
00136 #endif
00137         
00138         Command* command = cache[ i%cacheSize ];
00139         if( command->isFree( ))
00140         {
00141 #ifdef PROFILE
00142             const long hits = ++_hits;
00143             if( (hits%1000) == 0 )
00144             {
00145                 size_t mem( 0 );
00146                 size_t free( 0 );
00147                 size_t packets( 0 );
00148 
00149                 for( size_t j = 0; j < CACHE_ALL; ++j )
00150                 {
00151                     CommandVector& cache1 = _caches[ j ];
00152                     packets += cache1.size();
00153 
00154                     for( CommandVector::const_iterator k = cache1.begin(); 
00155                          k != cache1.end(); ++k )
00156                     {
00157                         const Command* cmd = *k;
00158                         mem += cmd->_packetAllocSize;
00159                         if( cmd->isFree( ))
00160                             ++free;
00161                     }
00162                 }
00163                 
00164                 EQINFO << _hits << " hits, " << _misses << " misses, "
00165                        << _lookups << " lookups, " << mem << "b allocated in "
00166                        << packets << " packets (" << free << " free)"
00167                        << std::endl;
00168             }
00169 #endif
00170             command->alloc( node, localNode, size );
00171             return *command;
00172         }
00173     }
00174 
00175 #ifdef PROFILE
00176     ++_misses;
00177 #endif
00178     
00179     const size_t add = (cacheSize >> 3) + 1;
00180     for( size_t j = 0; j < add; ++j )
00181         cache.push_back( new Command );
00182 
00183     Command* command = cache.back();
00184     command->alloc( node, localNode, size );
00185     return *command;
00186 }
00187 
00188 }
00189 }
Generated on Sat Feb 6 12:59:46 2010 for Equalizer 0.9.1 by  doxygen 1.6.1