Mercurial > hg > release > heapstats-1.1
view agent/src/snapShotContainer.hpp @ 18:9c57b65d193b
Bug 1718: Reduce CPU cycles for child oop traversal.
reviewed-by: ykubota
author | Yasumasa Suenaga <suenaga.yasumasa@lab.ntt.co.jp> |
---|---|
date | Fri, 28 Mar 2014 13:28:38 +0900 |
parents | bfde41acb148 |
children | eafa619db958 |
line wrap: on
line source
/*! * \file snapshotContainer.hpp * \brief This file is used to add up using size every class. * Copyright (C) 2011-2014 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 "oopUtil.hpp" #include "jvmInfo.hpp" /* Magic number macro. */ /*! * \brief Magic number of snapshot file format.<br /> * 49 ... Format of simple snapshot.<br /> * 60 ... Format of snapshot has class refferrence information.<br /> * 61 ... Format of snapshot has metaspace information.<br /> * \warning Don't change output snapshot format, if you change this value. */ #define MAGIC_NUM 61 /* 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. */ TOopType oopType; /*!< Type of class. */ jlong clsLoaderId; /*!< Class loader instance id. */ jlong clsLoaderTag; /*!< Class loader class tag. */ bool isRemoved; /*!< Class is already unloaded. */ jlong instanceSize; /*!< Class size if this class is instanceKlass. */ } TObjectData; /*! * \brief This structure stored child class size information. */ struct TChildClassCounter{ TObjectCounter *counter; /*!< Java inner class object. */ TObjectData *objData; /*!< Class information. */ TChildClassCounter *next; /*!< Pointer of next object. */ unsigned int callCount; /*!< Call count. */ }; /*! * \brief This structure stored class and children class size information. */ typedef struct{ TObjectCounter *counter; /*!< Java inner class object. */ TChildClassCounter *child; /*!< Child class informations. */ volatile int spinlock; /*!< Spin lock object. */ TOopMapBlock *offsets; /*!< Offset list. */ int offsetCount; /*!< Count of offset list. */ } TClassCounter; /*! * \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. */ jlong metaspaceUsage; /*!< Usage of PermGen or Metaspace. */ jlong metaspaceCapacity; /*!< Max capacity of PermGen or Metaspace. */ } 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*, TClassCounter*, TNumericalHasher<void*> > TSizeMap; /*! * \brief This class is stored class object usage on heap. */ class TSnapShotContainer; /*! * \brief This type is for TSnapShotContainer in Thread-Local-Storage. */ typedef std::tr1::unordered_map<pthread_t, TSnapShotContainer*, TNumericalHasher<pthread_t> > TLocalSnapShotContainer; /*! * \brief This class is stored class object usage on heap. */ class TSnapShotContainer { public: /*! * \brief Initialize snapshot caontainer class. * \return Is process succeed. * \warning Please call only once from main thread. */ static bool globalInitialize(void); /*! * \brief Finalize snapshot caontainer class. * \warning Please call only once from main thread. */ 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 without lock. * \param counter [in] Increment target class. * \param size [in] Increment object size. */ inline void FastInc(TObjectCounter *counter, jlong size){ counter->count++; counter->total_size += size; } /*! * \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 addInc(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) : "%xmm0"); } else #endif // AVX. #ifdef SSE4_1 if (likely(usableSSE4_1)) { asm volatile( "movntdqa (%1), %%xmm0;" "paddq (%0), %%xmm0;" "movdqa %%xmm0, (%0);" : : "r" (counter), "r" (operand) : "%xmm0"); } else #endif // SSE4_1. #ifndef __amd64__ if(unlikely(!usableSSE2)){ counter->count += operand->count; counter->total_size += operand->total_size; } else #endif { asm volatile( "movdqa (%1), %%xmm0;" "paddq (%0), %%xmm0;" "movdqa %%xmm0, (%0);" : : "r" (counter), "r" (operand) : "%xmm0"); } } /*! * \brief Find class data. * \param objData [in] Class key object. * \return Found class data. * Value is null, if class is not found. */ inline TClassCounter *findClass(TObjectData *objData) { TSizeMap::iterator it = counterMap.find(objData); return (it != counterMap.end()) ? (*it).second : NULL; } /*! * \brief Find child class data. * \param clsCounter [in] Parent class counter object. * \param klassOop [in] Child class key object. * \return Found class data. * Value is null, if class is not found. */ inline TChildClassCounter *findChildClass( TClassCounter *clsCounter, void *klassOop){ TChildClassCounter *prevCounter = NULL; TChildClassCounter *morePrevCounter = NULL; TChildClassCounter *counter = clsCounter->child; if(counter == NULL){ return NULL; } /* Search children class list. */ while(counter->objData->klassOop != klassOop){ morePrevCounter = prevCounter; prevCounter = counter; counter = counter->next; if(counter == NULL){ return NULL; } } /* LFU (Least Frequently Used). */ if (counter != NULL) { counter->callCount++; /* If counter need move to list head. */ if (prevCounter != NULL && prevCounter->callCount <= counter->callCount) { prevCounter->next = counter->next; if (morePrevCounter != NULL) { /* Move to near list head. */ morePrevCounter->next = counter; } else { /* Move list head. */ clsCounter->child = counter; } counter->next = prevCounter; } } return counter; } /*! * \brief Append new-class to container. * \param objData [in] New-class key object. * \return New-class data. */ virtual TClassCounter *pushNewClass(TObjectData *objData); /*! * \brief Append new-child-class to container. * \param clsCounter [in] Parent class counter object. * \param objData [in] New-child-class key object. * \return New-class data. */ virtual TChildClassCounter *pushNewChildClass( TClassCounter *clsCounter, TObjectData *objData); /*! * \brief Output GC statistics information. */ void printGCInfo(void); /*! * \brief Clear snapshot data. */ void clear(bool isForce); /*! * \brief Get local snapshot container with each threads. * \return Local snapshot container instance for this thread. */ inline TSnapShotContainer *getLocalContainer(void) { TSnapShotContainer *result = NULL; /* Get root and local snapshot conatiner. */ result = (TSnapShotContainer *)pthread_getspecific( snapShotContainerKey); /* If not exists local container. */ if (unlikely(result == NULL)) { pthread_t selfThreadId = pthread_self(); /* Get snapshot container's spin lock. */ spinLockWait(&lockval); { TLocalSnapShotContainer::iterator it = containerMap.find(selfThreadId); if (it != containerMap.end()) { result = (*it).second; } } /* Release snapshot container's spin lock. */ spinLockRelease(&lockval); if (unlikely(result == NULL)) { try { result = new TSnapShotContainer(false); } catch(...) { /* Maybe raise badalloc exception. */ return NULL; } /* Get snapshot container's spin lock. */ spinLockWait(&lockval); { try { containerMap[selfThreadId] = result; } catch(...) { /* Failed to add map. Maybe no more free memory. */ delete result; result = NULL; } } /* Release snapshot container's spin lock. */ spinLockRelease(&lockval); } /* Set local snapshot conatiner. */ pthread_setspecific(snapShotContainerKey, result); } return result; } /*! * \brief Merge children data. */ virtual void mergeChildren(void); /*! * \brief Set "isCleared" flag. */ inline void setIsCleared(bool flag){ this->isCleared = flag; } protected: /*! * \brief TSnapshotContainer constructor. */ TSnapShotContainer(bool isParent = true); /*! * \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. */ TLocalSnapShotContainer containerMap; RELEASE_ONLY(private:) /*! * \brief Snapshot header. */ volatile TSnapShotFileHeader _header; /*! * \brief SpinLock variable for each snapshot class container. */ volatile int lockval; /*! * \brief The thread key for map of local snapshot containers. */ pthread_key_t snapShotContainerKey; /*! * \brief Is this container is parent container ? */ bool isParentContainer; /*! * \brief Is this container is cleared ? */ volatile bool isCleared; }; #endif // _SNAPSHOT_CONTAINER_HPP