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