view agent/src/classContainer.hpp @ 22:6fec95209844

Bug 1522: Add Java heap alert. reviewed-by: shintak
author Yasumasa Suenaga <suenaga.yasumasa@lab.ntt.co.jp>
date Mon, 19 Aug 2013 10:40:21 +0900
parents ea356e72d922
children 296461a953ac
line wrap: on
line source

/*!
 * \file classContainer.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 CLASS_CONTAINER_HPP
#define CLASS_CONTAINER_HPP

#include <limits.h>
#include <sys/time.h>
#include <string.h>
#include <jni.h>
#include <pthread.h>
#include <tr1/unordered_map>
#include <deque>

#include "util.hpp"
#include "trapSender.hpp"
#include "jvmInfo.hpp"
#include "sorter.hpp"
#include "snapShotContainer.hpp"

/*!
 * \brief This structure stored size of a class used in heap.
 */
typedef struct{
  jlong tag;   /*!< Pointer of TObjectData.                */
  jlong usage; /*!< Class using total size.                */
  jlong delta; /*!< Class delta size from before snapshot. */
} THeapDelta;

/*!
 * \brief This type is for map stored class information.
 */
typedef std::tr1::unordered_map<void*, TObjectData*,
                                TNumericalHasher<void *> > TClassMap;

/*!
 * \brief This type is for TClassContainer in Thread-Local-Storage.
 */
class TClassContainer;
typedef std::deque<TClassContainer*> TLocalClassContainer;

/*!
 * \brief Memory usage alert types.
 */
typedef enum{
  ALERT_JAVA_HEAP
} TMemoryUsageAlertType;

/*!
 * \brief This class is stored class information.<br>
 *        e.g. class-name, class instance count, size, etc...
 */
class TClassContainer {
  public:
    /*!
     * \brief TClassContainer constructor.
     */
    TClassContainer(TClassContainer *base = NULL, bool needToClr = true);
    /*!
     * \brief TClassContainer destructor.
     */
    virtual ~TClassContainer(void);
    
    /*!
     * \brief Append new-class to container.
     * \param klassOop [in] New class oop.
     * \return New-class data.
     */
    TObjectData *pushNewClass(void *klassOop);
    TObjectData *pushNewClass(void *klassOop, TObjectData *objData);
    
    /*!
     * \brief Remove class from container.
     * \param target [in] Remove class data.
     */
    void popClass(TObjectData *target);
    
    /*!
     * \brief Search class from container.
     * \param klassOop [in] Target class oop.
     * \return Class data of target class.
     */
    inline TObjectData *findClass(void *klassOop) {
      
      /* Search class data. */
      TClassMap::iterator it;
      bool notFound;

      SpinLockWait(&lockval);
      {
        it = classMap->find(klassOop);
        notFound = (it == classMap->end());
      }
      SpinLockRelease(&lockval);

      return notFound ? NULL : it->second;
    }
    
    /*!
     * \brief Update class oop.
     * \param oldKlassOop [in] Target old class oop.
     * \param newKlassOop [in] Target new class oop.
     * \return Class data of target class.
     */
    inline void updateClass(void *oldKlassOop, void *newKlassOop) {

      /* Get class container's spin lock. */
      SpinLockWait(&lockval);
      {
        /* Search class data. */
        TClassMap::iterator it = classMap->find(oldKlassOop);
        if(it != classMap->end()){
          TObjectData *cur = (*it).second;

          /* Remove old klassOop. */
          classMap->erase(it);

          try{
            /* Update class data. */
            (*classMap)[newKlassOop] = cur;
            cur->klassOop = newKlassOop;
          }
          catch(...){
            /*
             * Maybe failed to allocate memory
             * at "std::map::operator[]".
             */
          }
        }
      }
      /* Release class container's spin lock. */
      SpinLockRelease(&lockval);

      /* Get spin lock of containers queue. */
      SpinLockWait(&tlsLock);
      {
        TLocalClassContainer::iterator it = classContainerInTLS.begin();
        /* Broadcast to each local container. */
        for(; it != classContainerInTLS.end(); it++){
          (*it)->updateClass(oldKlassOop, newKlassOop);
        }
      }
      /* Release spin lock of containers queue. */
      SpinLockRelease(&tlsLock);

    }

    /*!
     * \brief Get TLS ClassContainer
     */
    inline TClassContainer *getTLSContainer(void){
      TClassContainer *result = (TClassContainer *)pthread_getspecific(tlsKey);

      if(unlikely(result == NULL)){
        result = new TClassContainer(this, false);
        pthread_setspecific(tlsKey, result);

        SpinLockWait(&tlsLock);
        {
          classContainerInTLS.push_back(result);
        }
        SpinLockRelease(&tlsLock);

      }

      return result;
    }
    
    /*!
     * \brief Get class entries count.
     * \return Entries count of class information.
     */
    inline size_t getContainerSize(void) {
      size_t result;

      SpinLockWait(&lockval);
      {
        result = this->classMap->size();
      }
      SpinLockRelease(&lockval);

      return result;
    }
    
    /*!
     * \brief Remove all-class from container.
     */
    void allClear(void);
    /*!
     * \brief Output all-class information to file.
     * \param snapshot [in] Snapshot instance.
     * \return Sorted-class size information.
     */
    virtual TSorter<THeapDelta> *afterTakeSnapShot(TSnapShotContainer *snapshot);

  protected:
    /*!
     * \brief ClassContainer in TLS of each threads.
     */
    TLocalClassContainer classContainerInTLS;
    
  private:
    /*!
     * \brief SNMP trap sender.
     */
    TTrapSender *pSender;

    /*!
     * \brief Maps of class counting record.
     */
    TClassMap *classMap;
    
    /*!
     * \brief ClassContainer TLS key.
     */
    pthread_key_t tlsKey;

    /*!
     * \brief SpinLock variable.
     */
    int lockval;

    /*!
     * \brief SpinLock variable for TLS.
     */
    int tlsLock;

    /*!
     * \brief Do we need to clear at destructor?
     */
    bool needToClear;

};

#endif // CLASS_CONTAINER_HPP