Mercurial > hg > release > heapstats-1.0
view agent/src/snapShotContainer.cpp @ 28:0a4a349799b0
Bug 1593: HeapStats agent handles concurrent mode failure incorrectly.
reviewed-by: ykubota
author | Yasumasa Suenaga <suenaga.yasumasa@lab.ntt.co.jp> |
---|---|
date | Thu, 21 Nov 2013 15:21:34 +0900 |
parents | 5a930f8c514b |
children |
line wrap: on
line source
/*! * \file snapshotContainer.cpp * \brief This file is used to add up using size every class. * Copyright (C) 2011-2013 Nippon Telegraph and Telephone Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <jni.h> #include <time.h> #include <pthread.h> #include "snapShotContainer.hpp" #include "util.hpp" #include "trapSender.hpp" #include "sorter.hpp" /*! * \brief Pthread mutex for instance control.<br> * <br> * This mutex used in below process.<br> * - TSnapShotContainer::getInstance @ snapShotContainer.cpp<br> * To get older snapShotContainer instance from stockQueue.<br> * - TSnapShotContainer::releaseInstance @ snapShotContainer.cpp<br> * To add used snapShotContainer instance to stockQueue.<br> */ pthread_mutex_t TSnapShotContainer::instanceLocker = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP; /*! * \brief Snapshot container instance stock queue. */ TSnapShotQueue *TSnapShotContainer::stockQueue = NULL; /*! * \brief Initialize snapshot caontainer class. * \return Is process succeed. */ bool TSnapShotContainer::globalInitialize(void) { try { stockQueue = new TSnapShotQueue(); } catch(...) { PRINT_WARN_MSG("Failure initialize snapshot container."); return false; } return true; } /*! * \brief Finalize snapshot caontainer class. */ void TSnapShotContainer::globalFinalize(void) { if (likely(stockQueue != NULL)) { /* Clear snapshot in queue. */ while (!stockQueue->empty()) { TSnapShotContainer *item = stockQueue->front(); /* Deallocate snapshot instance. */ delete item; stockQueue->pop(); } /* Deallocate stock queue. */ delete stockQueue; stockQueue = NULL; } } /*! * \brief Get snapshot container instance. * \return Snapshot container instance. * \warning Don't deallocate instance getting by this function.<br> * Please call "releaseInstance" method. */ TSnapShotContainer *TSnapShotContainer::getInstance(void) { TSnapShotContainer *result = NULL; bool isEmptyStock = true; ENTER_PTHREAD_SECTION(&instanceLocker) { isEmptyStock = stockQueue->empty(); } EXIT_PTHREAD_SECTION(&instanceLocker) /* If need create new instance. */ if (isEmptyStock) { /* Create new snapshot container instance. */ try { result = new TSnapShotContainer(); } catch(...) { result = NULL; } } else { ENTER_PTHREAD_SECTION(&instanceLocker) { /* Reuse snapshot container instance. */ result = stockQueue->front(); stockQueue->pop(); } EXIT_PTHREAD_SECTION(&instanceLocker) } return result; } /*! * \brief Release snapshot container instance.. * \param instance [in] Snapshot container instance. * \warning Don't access instance after called this function. */ void TSnapShotContainer::releaseInstance(TSnapShotContainer *instance) { /* Sanity check. */ if (unlikely(instance == NULL)) { return; } unsigned int stockCount = MAX_STOCK_COUNT; ENTER_PTHREAD_SECTION(&instanceLocker) { stockCount = stockQueue->size(); } EXIT_PTHREAD_SECTION(&instanceLocker) if (unlikely(stockCount >= MAX_STOCK_COUNT)) { /* Deallocate instance. */ delete instance; } else { /* Clear data. */ instance->clear(false); ENTER_PTHREAD_SECTION(&instanceLocker) { /* Keep instance. */ stockQueue->push(instance); } EXIT_PTHREAD_SECTION(&instanceLocker) } } /*! * \brief TSnapshotContainer constructor. */ TSnapShotContainer::TSnapShotContainer() : counterMap(), sshotContainerMap() { /* Header setting. */ this->_header.magicNumber = MAGIC_NUM; this->_header.byteOrderMark = BOM; this->_header.snapShotTime = 0; this->_header.size = 0; memset((void*)&this->_header.gcCause[0], 0, 80); int ret = posix_memalign((void **)&this->counterBuf, 16, sizeof(TObjectCounter)); if(ret != 0){ throw ret; } this->isCleared = true; this->counterBuf->count = 1; tlsLock = 0; pthread_key_create(&tlsKey, NULL); pthread_key_create(&snapShotKey, NULL); } /*! * \brief TSnapshotContainer destructor. */ TSnapShotContainer::~TSnapShotContainer(void) { /* Cleanup elements on counter map. */ for(TSizeMap::iterator it = counterMap.begin(); it != counterMap.end(); ++it){ free((*it).second); } /* Clean counter map. */ counterMap.clear(); /* Cleanup elements on sshotContainerMap */ for(TLocalSShotContainer::iterator itr = sshotContainerMap.begin(); itr != sshotContainerMap.end(); itr++){ delete itr->second; } sshotContainerMap.clear(); free(this->counterBuf); pthread_key_delete(snapShotKey); pthread_key_delete(tlsKey); } /*! * \brief Append new-class to container. * \param objData [in] New-class key object. * \return New-class data. */ TObjectCounter *TSnapShotContainer::pushNewClass(TObjectData *objData) { TObjectCounter *cur = NULL; int ret; ret = posix_memalign((void **)&cur, 16, 16 /* = sizeof(TObjectCounter) : 8x2 */); /* If failure allocate. */ if(unlikely(ret != 0)){ /* Adding empty to list is deny. */ PRINT_WARN_MSG("Couldn't allocate counter memory!"); return NULL; } /* zero clear */ #ifdef AVX if(likely(usableAVX)){ asm volatile("vpxor %%xmm0, %%xmm0, %%xmm0;" "vmovdqa %%xmm0, (%0);" : : "r" (cur) : "%xmm0"); } else #endif #ifndef __amd64__ #ifdef SSE2 if(unlikely(!usableSSE2)) #endif // SSE2 { cur->count = 0; cur->total_size = 0; } #ifdef SSE2 else #endif // SSE2 #endif // __amd64__ #ifdef SSE2 { asm volatile("pxor %%xmm0, %%xmm0;" "movdqa %%xmm0, (%0);" : : "r" (cur) : "%xmm0"); } #endif // SSE2 /* Set counter map. */ counterMap[objData] = cur; return cur; } /*! * \brief Set JVM performance info to header. * \param info [in] JVM running performance information. */ void TSnapShotContainer::setJvmInfo(TJvmInfo *info) { /* Sanity check. */ if (unlikely(info == NULL)) { PRINT_WARN_MSG("Couldn't get GC Information!"); return; } /* If GC cause is need. */ if (this->_header.cause == GC) { /* Copy GC cause. */ strcpy((char*)this->_header.gcCause, info->getGCCause()); this->_header.gcCauseLen = strlen((char*)this->_header.gcCause); /* Setting GC work time. */ this->_header.gcWorktime = info->getGCWorktime(); } else { /* Clear GC cause. */ this->_header.gcCauseLen = 1; this->_header.gcCause[0] = '\0'; /* GC no work. */ this->_header.gcWorktime = 0; } /* Setting header info from TJvmInfo. * Total memory (JVM_TotalMemory) should be called from outside of GC. * Comment of VM_ENTRY_BASE macro says as following: * ENTRY routines may lock, GC and throw exceptions * So we set TSnapShotFileHeader.totalHeapSize in TakeSnapShot() . */ this->_header.FGCCount = info->getFGCCount(); this->_header.YGCCount = info->getYGCCount(); this->_header.newAreaSize = info->getNewAreaSize(); this->_header.oldAreaSize = info->getOldAreaSize(); } /*! * \brief Clear snapshot data. */ void TSnapShotContainer::clear(bool isForce){ if(!isForce && this->isCleared){ return; } /* Phase1: clear parent counter */ for(TSizeMap::iterator it = counterMap.begin(); it != counterMap.end(); ++it){ /* Reset counter of all class. */ #ifdef AVX if(likely(usableAVX)){ asm volatile("vpxor %%xmm0, %%xmm0, %%xmm0;" "vmovdqa %%xmm0, (%0);" : : "r" (it->second) : "%xmm0"); } else #endif #ifndef __amd64__ #ifdef SSE2 if(unlikely(!usableSSE2)) #endif // SSE2 { it->second->count = 0; it->second->total_size = 0; } #ifdef SSE2 else #endif // SSE2 #endif // __amd64__ #ifdef SSE2 { asm volatile("pxor %%xmm0, %%xmm0;" "movdqa %%xmm0, (%0);" : : "r" (it->second) : "%xmm0"); } #endif // SSE2 } /* Phase2: clear counters in TLS */ for(TLocalSShotContainer::iterator itr = this->sshotContainerMap.begin(); itr != this->sshotContainerMap.end(); itr++){ itr->second->clear(true); } this->isCleared = true; } /*! * \brief Output GC statistics information. */ void TSnapShotContainer::printGCInfo(void) { /* Check Loglevel. */ if (arg.LogLevel < INFO) { return; } PRINT_INFO_MSG_HEADER_NOIF << "GC Statistics Information " << NEWLINE; /* GC cause and GC worktime show only raised GC. */ if (this->_header.cause == GC) { PRINT_INFO_MSG_HEADER_NOIF << "GC Cause : '" << (char*)this->_header.gcCause << "' , " << "GC Worktime : " << this->_header.gcWorktime << "msec " << NEWLINE; } /* Output GC count. */ PRINT_INFO_MSG_HEADER_NOIF << "GC Count FullGC:" << this->_header.FGCCount << " / YoungGC:" << this->_header.YGCCount << NEWLINE; /* Output heap size status. */ PRINT_INFO_MSG_HEADER_NOIF << "Area using size New:" << this->_header.newAreaSize << "byte" << " / Old:" << this->_header.oldAreaSize << "byte" << " / Total:" << this->_header.totalHeapSize << "byte" << NEWLINE; } /*! * \brief Merge all sshotContainerMap data to this counterMap */ void TSnapShotContainer::mergeChildren(void){ SpinLockWait(&tlsLock); { for(TLocalSShotContainer::iterator itr = sshotContainerMap.begin(); itr != sshotContainerMap.end(); itr++){ for(TSizeMap::iterator itr2 = itr->second->counterMap.begin(); itr2 != itr->second->counterMap.end(); itr2++){ TObjectCounter *objCounter = counterMap[itr2->first]; if(objCounter == NULL){ objCounter = pushNewClass(itr2->first); } FastInc(objCounter, itr2->second); } } } SpinLockRelease(&tlsLock); }