Mercurial > hg > release > heapstats-1.0
view agent/src/snapShotContainer.hpp @ 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.hpp * \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. * */ #ifndef _SNAPSHOT_CONTAINER_HPP #define _SNAPSHOT_CONTAINER_HPP #include <limits.h> #include <sys/time.h> #include <string.h> #include <jni.h> #include <pthread.h> #include <tr1/unordered_map> #include <queue> #include "util.hpp" #include "jvmInfo.hpp" /* Magic number macro. */ /*! * \brief Magic number of snapshot file format. */ #define MAGIC_NUM '1' /* Endian macro. */ #ifdef WORDS_BIGENDIAN /*! * \brief Endian macro. this machine is big endian.<br> * e.g. SPARC, PowerPC, etc... */ #define BOM 'B' #else /*! * \brief Endian macro. this machine is little endian.<br> * e.g. i386, AMD64, etc.. */ #define BOM 'L' #endif /*! * \brief This structure stored class size and number of class-instance. */ #pragma pack(push, 1) typedef struct{ jlong count; /*!< Class instance count. */ jlong total_size; /*!< Class total use size. */ } TObjectCounter; /*! * \brief This structure stored class information. */ typedef struct{ jlong tag; /*!< Class tag. */ jlong classNameLen; /*!< Class name. */ char *className; /*!< Class name length. */ void *klassOop; /*!< Java inner class object. */ jlong oldTotalSize; /*!< Class old total use size. */ } TObjectData; /*! * \brief This structure stored snapshot information. */ typedef struct{ char magicNumber; /*!< Magic number for format. */ char byteOrderMark; /*!< Express byte order. */ jlong snapShotTime; /*!< Datetime of take snapshot. */ jlong size; /*!< Class entries count. */ jint cause; /*!< Cause of snapshot. */ jlong gcCauseLen; /*!< Length of GC cause. */ char gcCause[80]; /*!< String about GC casue. */ jlong FGCCount; /*!< Full-GC count. */ jlong YGCCount; /*!< Young-GC count. */ jlong gcWorktime; /*!< GC worktime. */ jlong newAreaSize; /*!< New area using size. */ jlong oldAreaSize; /*!< Old area using size. */ jlong totalHeapSize; /*!< Total heap size. */ } TSnapShotFileHeader; #pragma pack(pop) /*! * \brief This class is stored class object usage on heap. */ class TSnapShotContainer; /*! * \brief This type is for queue store snapshot information. */ typedef std::queue<TSnapShotContainer*> TSnapShotQueue; /*! * \brief This type is for map stored size information. */ typedef std::tr1::unordered_map<TObjectData*, TObjectCounter*, TNumericalHasher<TObjectData *> > TSizeMap; /*! * \brief This type is for TSnapShotContainer in Thread-Local-Storage. */ class TSnapShotContainer; typedef std::tr1::unordered_map<pthread_t, TSnapShotContainer*, TNumericalHasher<pthread_t> > TLocalSShotContainer; /*! * \brief This class is stored class object usage on heap. */ class TSnapShotContainer { public: /*! * \brief Initialize snapshot caontainer class. * \return Is process succeed. */ static bool globalInitialize(void); /*! * \brief Finalize snapshot caontainer class. */ static void globalFinalize(void); /*! * \brief Get snapshot container instance. * \return Snapshot container instance. * \warning Don't deallocate instance getting by this function.<br> * Please call "releaseInstance" method. */ static TSnapShotContainer *getInstance(void); /*! * \brief Release snapshot container instance.. * \param instance [in] Snapshot container instance. * \warning Don't access instance after called this function. */ static void releaseInstance(TSnapShotContainer *instance); /*! * \brief Get class entries count. * \return Entries count of class information. */ inline size_t getContainerSize(void) { return this->_header.size; } /*! * \brief Set time of take snapshot. * \param t [in] Datetime of take snapshot. */ inline void setSnapShotTime(jlong t) { this->_header.snapShotTime = t; } /*! * \brief Set snapshot cause. * \param cause [in] Cause of snapshot. */ inline void setSnapShotCause(TInvokeCause cause) { this->_header.cause = cause; } /*! * \brief Set total size of Java Heap. * \param size [in] Total size of Java Heap. */ inline void setTotalSize(jlong size) { this->_header.totalHeapSize = size; } /*! * \brief Set JVM performance info to header. * \param info [in] JVM running performance information. */ void setJvmInfo(TJvmInfo *info); /*! * \brief Get snapshot header. * \return Snapshot header. */ inline TSnapShotFileHeader *getHeader(void) { return (TSnapShotFileHeader *)&this->_header; } /*! * \brief Increment instance count and using size atomically. * \param counter [in] Increment target class. * \param size [in] Increment object size. */ inline void Inc(TObjectCounter *counter, jlong size) { #ifdef __amd64__ asm volatile("lock addq $1, %0;" "lock addq %2, %1;" : "+m" (counter->count), "+m" (counter->total_size) : "r" (size) : "cc"); #else // __i386__ asm volatile("lock addl $1, %0;" /* Lower 32bit */ "lock adcl $0, 4+%0;" /* Upper 32bit */ " movl %2, %%eax;" "lock addl %%eax, %1;" /* Lower 32bit */ " movl 4+%2, %%eax;" "lock adcl %%eax, 4+%1;" /* Upper 32bit */ : "+o" (counter->count), "+o" (counter->total_size) : "o" (size) : "%eax", "cc"); #endif } /*! * \brief Increment instance count and using size. * \param counter [in] Increment target class. * \param operand [in] Right-hand operand (SRC operand). * This value must be aligned 16bytes. */ inline void FastInc(TObjectCounter *counter, TObjectCounter *operand){ #ifdef AVX if(likely(usableAVX)){ asm volatile("vmovntdqa (%1), %%xmm0;" "vpaddq (%0), %%xmm0, %%xmm0;" "vmovdqa %%xmm0, (%0);" : : "r" (counter), "r" (operand) : "cc", "%xmm0"); } else #endif #ifdef SSE4_1 if(likely(usableSSE4_1)){ asm volatile("movntdqa (%1), %%xmm0;" "paddq (%0), %%xmm0;" "movdqa %%xmm0, (%0);" : : "r" (counter), "r" (operand) : "cc", "%xmm0"); } else #endif #ifndef __amd64__ #ifdef SSE2 if(unlikely(!usableSSE2)) #endif // SSE2 { counter->count += operand->count; counter->total_size += operand->total_size; } #ifdef SSE2 else #endif // SSE2 #endif // __amd64__ #ifdef SSE2 { asm volatile("movdqa (%1), %%xmm0;" "paddq (%0), %%xmm0;" "movdqa %%xmm0, (%0);" : : "r" (counter), "r" (operand) : "cc", "%xmm0"); } #endif // SSE2 } /*! * \brief Increment instance count and using size. * \param counter [in] Increment target class. * \param size [in] Size of target. */ inline void FastInc(TObjectCounter *counter, jlong size){ this->counterBuf->total_size = size; this->FastInc(counter, this->counterBuf); } /*! * \brief Find class data. * \param objData [in] Class key object. * \return Found class data. * Value is null, if class is not found. */ inline TObjectCounter *findClass(TObjectData *objData) { TSizeMap::iterator it = counterMap.find(objData); return (it != counterMap.end()) ? it->second : NULL; } /*! * \brief Append new-class to container. * \param objData [in] New-class key object. * \return New-class data. */ TObjectCounter *pushNewClass(TObjectData *objData); /*! * \brief Output GC statistics information. */ void printGCInfo(void); /*! * \brief Clear snapshot data. */ void clear(bool isForce); /*! * \brief Get TLS SnapShotContainer. */ inline TSnapShotContainer *getTLSContainer(void){ TSnapShotContainer *nowSnapShot, *result; nowSnapShot = (TSnapShotContainer *)pthread_getspecific(snapShotKey); result = (TSnapShotContainer *)pthread_getspecific(tlsKey); if(unlikely((nowSnapShot != this) || (result == NULL))){ TLocalSShotContainer::iterator itr; bool NotFound = false; SpinLockWait(&tlsLock); { itr = sshotContainerMap.find(pthread_self()); NotFound = (itr == sshotContainerMap.end()); } SpinLockRelease(&tlsLock); if(unlikely(NotFound)){ result = new TSnapShotContainer(); SpinLockWait(&tlsLock); { sshotContainerMap[pthread_self()] = result; } SpinLockRelease(&tlsLock); } else{ result = itr->second; } pthread_setspecific(snapShotKey, this); pthread_setspecific(tlsKey, result); } return result; } /*! * \brief Merge children data. */ void mergeChildren(void); /*! * \brief Set "isCleared" flag. */ inline void setIsCleared(bool flag){ this->isCleared = flag; } protected: /*! * \brief TSnapshotContainer constructor. */ TSnapShotContainer(); /*! * \brief TSnapshotContainer destructor. */ virtual ~TSnapShotContainer(void); /*! * \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> */ static pthread_mutex_t instanceLocker; /*! * \brief Snapshot container instance stock queue. */ static TSnapShotQueue *stockQueue; /*! * \brief Max limit count of snapshot container instance. */ const static unsigned int MAX_STOCK_COUNT = 2; /*! * \brief Maps of counter of each java class. */ TSizeMap counterMap; /*! * \brief Maps of TSnapShotContainer and thread. */ TLocalSShotContainer sshotContainerMap; private: /*! * \brief Snapshot header. */ volatile TSnapShotFileHeader _header; /* \brief TObjectCounter buffer */ TObjectCounter *counterBuf; /*! * \brief SpinLock variable. */ int tlsLock; /*! * \brief SnapShotContainer TLS key. */ pthread_key_t tlsKey; /*! * \brief Now processing SnapShotContainer in TLS. */ pthread_key_t snapShotKey; /*! * \brief Is this container is cleared ? */ volatile bool isCleared; }; #endif // _SNAPSHOT_CONTAINER_HPP