view agent/src/jvmInfo.hpp @ 39:c1b7b75d1930

Bug 1844: Agent should be adapted new HotSpot versioning: JDK-8030011 reviewed-by: ykubota
author Yasumasa Suenaga <yasuenag@gmail.com>
date Tue, 17 Jun 2014 23:20:20 +0900
parents fa4bbeb769a3
children b1930d079140
line wrap: on
line source

/*!
 * \file jvmInfo.hpp
 * \brief This file is used to get JVM performance information.
 * 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 JVMINFO_H
#define JVMINFO_H

#include <jni.h>
#include <jvmti.h>
#include <string.h>

#include <stdint.h>

#include "util.hpp"


/*!
 * \brief Make HotSpot version
 */
#define MAKE_HS_VERSION(major, minor, micro, build) \
               (((major) << 24) | ((minor) << 16) | ((micro) << 8) | (build))

/*!
 * \brief JVM performance header info.
 */
typedef struct {
  jint   magic;          /*!< Magic number. - 0xcafec0c0 (bigEndian)      */
  jbyte  byte_order;     /*!< Byte order of the buffer.                   */
  jbyte  major_version;  /*!< Major version numbers.                      */
  jbyte  minor_version;  /*!< Minor version numbers.                      */
  jbyte  accessible;     /*!< Ready to access.                            */
  jint   used;           /*!< Number of PerfData memory bytes used.       */
  jint   overflow;       /*!< Number of bytes of overflow.                */
  jlong  mod_time_stamp; /*!< Time stamp of last structural modification. */
  jint   entry_offset;   /*!< Offset of the first PerfDataEntry.          */
  jint   num_entries;    /*!< Number of allocated PerfData entries.       */
} PerfDataPrologue;

/*!
 * \brief Entry of JVM performance informations.
 */
typedef struct {
  jint entry_length;      /*!< Entry length in bytes.                       */
  jint name_offset;       /*!< Offset of the data item name.                */
  jint vector_length;     /*!< Length of the vector. If 0, then scalar.     */
  jbyte data_type;        /*!< Type of the data item. -
                               'B','Z','J','I','S','C','D','F','V','L','['  */
  jbyte flags;            /*!< Flags indicating misc attributes.            */
  jbyte data_units;       /*!< Unit of measure for the data type.           */
  jbyte data_variability; /*!< Variability classification of data type.     */
  jint  data_offset;      /*!< Offset of the data item.                     */
} PerfDataEntry;

/*!
 * \brief Function type definition for JVM internal functions.<br>
 *        JVM_MaxMemory() / JVM_TotalMemory() / etc...
 * \return Memory size.
 */
typedef jlong (JNICALL *TGetMemoryFunc)(void);

/*!
 * \brief Value of gc cause when failure get GC cause.
 */
const static char UNKNOWN_GC_CAUSE[16] __attribute__((aligned(16)))
                                                       = "unknown GCCause";

/*!
 * \brief Size of GC cause.
 */
const static int MAXSIZE_GC_CAUSE = 80;


/* memcpy for gccause */

/* Strcpy with AVX (80 bytes).
 * Sandy Bridge can two load operations per cycle.
 * So we should execute sequentially 2-load / 1-store ops.
 *   Intel 64 and IA-32 Architectures Optimization Reference Manual
 *     3.6.1.1 Make Use of Load Bandwidth in Intel Microarchitecture
 *     Code Name Sandy Bridge
*/
#define AVX_MEMCPY_GCCAUSE(dest, src) \
  "vlddqu    " src ",      %%ymm0;" \
  "vlddqu  32" src ",      %%ymm1;" \
  "vlddqu  64" src ",      %%xmm2;" \
  "vmovdqa    %%ymm0,    " dest ";" \
  "vmovdqa    %%ymm1,  32" dest ";" \
  "vmovdqa    %%xmm2,  64" dest ";"

/* Strcpy with SSE (80 bytes). */
#define SSE_MEMCPY_GCCAUSE(op, dest, src) \
  op "    " src ",      %%xmm0;" \
  op "  16" src ",      %%xmm1;" \
  "movdqa  %%xmm0,    " dest ";" \
  op "  32" src ",      %%xmm0;" \
  "movdqa  %%xmm1,  16" dest ";" \
  op "  48" src ",      %%xmm1;" \
  "movdqa  %%xmm0,  32" dest ";" \
  op "  64" src ",      %%xmm0;" \
  "movdqa  %%xmm1,  48" dest ";" \
  "movdqa  %%xmm0,  64" dest ";"


/*!
 * \brief This class is used to get JVM performance information.
 */
class TJvmInfo{
  public:
    
    /*!
     * \brief TJvmInfo constructor.
     */
    TJvmInfo();
    /*!
     * \brief TJvmInfo destructor.
     */
    virtual ~TJvmInfo();
    
    /*!
     * \brief   Get heap memory size (New + Old)
     *          through the JVM internal function.
     * \return  Heap memory size.
     */
    inline jlong getMaxMemory(void) {
      return (this->maxMemFunc == NULL) ? -1 : (*this->maxMemFunc)();
    }
    
    /*!
     * \brief   Get total allocated heap memory size.
     * \return  Heap memory size.
     * \warning CAUTION!!: This function must be called 
     *          after "VMInit" JVMTI event!<br>
     *          JVM_TotalMemory() is used "JavaThread" object.
     */
    inline jlong getTotalMemory(void) {
      return (this->totalMemFunc == NULL) ? -1 : (*this->totalMemFunc)();
    }
    
    /*!
     * \brief Get new generation size.
     * \return Size of new generation of heap.
     */
    inline jlong getNewAreaSize(void) {
      return (this->_edenSize != NULL && this->_sur0Size != NULL
                                              && this->_sur1Size != NULL)
        ? *this->_edenSize + *this->_sur0Size + *this->_sur1Size : -1;
    };
    
    /*!
     * \brief Get tenured generation size.
     * \return Size of tenured generation of heap.
     */
    inline jlong getOldAreaSize(void) {
      return (this->_oldSize != NULL) ? *this->_oldSize : -1;
    };
    
    /*!
     * \brief Get raised full-GC count.
     * \return Raised full-GC count.
     */
    inline jlong getFGCCount(void) {
      return (this->_nowFGC != NULL) ? *this->_nowFGC : -1;
    };
    
    /*!
     * \brief Get raised young-GC count.
     * \return Raised young-GC count.
     */
    inline jlong getYGCCount(void) {
      return (this->_nowYGC != NULL) ? *this->_nowYGC : -1;
    };
    
    /*!
     * \brief Load string of GC cause.
     */
    inline void loadGCCause(void) {
      
      /* If got GC cause address. */
      if(likely(this->_gcCause != NULL)){
      #ifdef AVX
        if(likely(usableAVX)){
          asm volatile(
          /* Strcpy with AVX (80 bytes). */
            AVX_MEMCPY_GCCAUSE("(%0)", "(%1)")
            :
            : "c" (this->gcCause),  /* GC Cause container. */
              "d" (this->_gcCause)  /* GC Cause address.   */
            : "cc", "%xmm2" /* ,"%ymm0", "%ymm1" */
                      );
        }
        else
      #endif // AVX.
      #ifdef SSE3
        if(likely(usableSSE3)){
          asm volatile(
          /* Strcpy with SSE2 (80 bytes). */
            SSE_MEMCPY_GCCAUSE("lddqu", "(%0)", "(%1)")
            :
            : "c" (this->gcCause),  /* GC Cause container. */
              "d" (this->_gcCause)  /* GC Cause address.   */
            : "cc", "%xmm0", "%xmm1"
          );
        }
        else
      #endif // SSE3.
      #ifndef __amd64__
      #ifdef SSE2
        if(!unlikely(!usableSSE2))
      #endif // SSE2
        {
          __builtin_memcpy(this->gcCause, this->_gcCause, MAXSIZE_GC_CAUSE);
        }
      #ifdef SSE2
        else
      #endif // SSE2
      #endif // __amd64__
      #ifdef SSE2
        {
          asm volatile(
          /* Strcpy with SSE2 (80 bytes). */
            SSE_MEMCPY_GCCAUSE("movdqu", "(%0)", "(%1)")
            :
            : "c" (this->gcCause),  /* GC Cause container. */
              "d" (this->_gcCause)  /* GC Cause address.   */
            : "cc", "%xmm0", "%xmm1"
          );
        }
      #endif // SSE2.

      }

    };
    
    /*!
     * \brief Reset stored gc information.
     */
    inline void resumeGCinfo(void) {
      /* Reset gc cause string. */
      this->SetUnknownGCCause();
      /* Refresh elapsed GC work time. */
      elapFGCTime = (this->_FGCTime != NULL) ? *this->_FGCTime : -1;
      elapYGCTime = (this->_YGCTime != NULL) ? *this->_YGCTime : -1;
      /* Reset full-GC flag. */
      this->fullgcFlag = false;
    };
    
    /*!
     * \brief Get GC cause string.
     * \return GC cause string.
     */
    inline char* getGCCause(void) {
      return this->gcCause;
    };
    
    /*!
     * \brief Get last GC worktime(msec).
     * \return Last GC work time.
     */
    inline jlong getGCWorktime(void) {
      jlong nowTime;
      jlong result = 0;
      /* Get time tick frequency. */
      jlong freqTime = (this->_freqTime != NULL) ? (*this->_freqTime / 1000) : 1;
      
      /* Check GC type. */
      if (fullgcFlag) {
        nowTime = (this->_FGCTime != NULL) ? *this->_FGCTime : 0;
        result = (nowTime >= 0) ? nowTime - elapFGCTime : 0;
      } else {
        nowTime = (this->_YGCTime != NULL) ? *this->_YGCTime : 0;
        result = (nowTime >= 0) ? nowTime - elapYGCTime : 0;
      }
      
      /* Calculate work time. */
      return (result / freqTime);
    };
    
    /*!
     * \brief Set full-GC flag.
     * \param isFullGC [in] Is raised full-GC ?
     */
    inline void setFullGCFlag(bool isFullGC ) {
      this->fullgcFlag = isFullGC;
    }
    
    /*!
     * \brief Detect delayed GC-informaion address.
     */
    void detectDelayInfoAddress(void);
    
    /*!
     * \brief Get finished conflict count.
     * \return It's count of finished conflict of monitor.
     */
    inline jlong getSyncPark(void) {
      return ((_syncPark == NULL) ? -1 : *_syncPark);
    }
    
    /*!
     * \brief Get live thread count.
     * \return Now living thread count.
     */
    inline jlong getThreadLive(void) {
      return ((_threadLive == NULL) ? -1: *_threadLive);
    }
    
    /*!
     * \brief Get safepoint time.
     * \return Total work time in safepoint.
     */
    inline jlong getSafepointTime(void) {
      /* Get time tick frequency. */
      jlong freqTime = (this->_freqTime != NULL) ? (*this->_freqTime / 1000) : 1;
      
      return ((_safePointTime == NULL) ? -1 : *_safePointTime / freqTime);
    }
    
    /*!
     * \brief Get safepoint count.
     * \return Count of work in safepoint.
     */
    inline jlong getSafepoints(void) {
      return ((_safePoints == NULL) ? -1 : *_safePoints);
    }
    
    /*!
     * \brief Get JVM version.
     * \return JVM version.
     */
    inline char *getVmVersion(void) {
      return this->_vmVersion;
    }

    /*!
     * \brief Set JVM version as uint value.
     */
    inline void setHSVersion(unsigned int val){
      this->_hsVersion = val;
    }

    /*!
     * \brief Get JVM version as uint value.
     */
    inline unsigned int getHSVersion(void){
      return this->_hsVersion;
    }

    /*!
     * \brief Decision for 7046558: G1: concurrent marking optimizations.
     * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7046558
     * http://hg.openjdk.java.net/hsx/hotspot-gc/hotspot/rev/842b840e67db
     */
    inline bool isAfterCR7046558(void){
      // hs22.0-b03
      return (this->_hsVersion >= MAKE_HS_VERSION(22, 0, 0, 3));
    }

    /*!
     * \brief Decision for 6964458: Reimplement class meta-data storage to use native memory
     *        (PermGen Removal)
     * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6964458
     * http://hg.openjdk.java.net/hsx/hotspot-rt-gate/hotspot/rev/da91efe96a93
     */
    inline bool isAfterCR6964458(void){
      // hs25.0-b01
      return (this->_hsVersion >= MAKE_HS_VERSION(25, 0, 0, 1));
    }

    /*!
     * \brief Decision for CR8000213: NPG: Should have renamed arrayKlass and typeArrayKlass
     * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8000213
     * http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/d8ce2825b193
     */
    inline bool isAfterCR8000213(void){
      // hs25.0-b04
      return (this->_hsVersion >= MAKE_HS_VERSION(25, 0, 0, 4));
    }

    /*!
     * \brief Decision for 8003424: Enable Class Data Sharing for CompressedOops
     * http://bugs.sun.com/view_bug.do?bug_id=8003424
     * http://hg.openjdk.java.net/hsx/hotspot-rt/hotspot/rev/740e263c80c6
     */
    inline bool isAfterCR8003424(void){
      // hs25.0-b46
      return (this->_hsVersion >= MAKE_HS_VERSION(25, 0, 0, 46));
    }

    /*!
     * \brief Decision for 8015107: NPG: Use consistent naming for metaspace concepts
     * https://bugs.openjdk.java.net/browse/JDK-8015107
     */
    inline bool isAfterCR8015107(void){
      // hs25.0-b51
      return (this->_hsVersion >= MAKE_HS_VERSION(25, 0, 0, 51));
    }

    /*!
     * \brief Get JVM name.
     * \return JVM name.
     */
    inline char *getVmName(void) {
      return this->_vmName;
    }
    /*!
     * \brief Get JVM class path.
     * \return JVM class path.
     */
    inline char *getClassPath(void) {
      return this->_classPath;
    }
    /*!
     * \brief Get JVM endorsed path.
     * \return JVM endorsed path.
     */
    inline char *getEndorsedPath(void) {
      return this->_endorsedPath;
    }
    /*!
     * \brief Get Java version.
     * \return Java version.
     */
    inline char *getJavaVersion(void) {
      return this->_javaVersion;
    }
    /*!
     * \brief Get JAVA_HOME.
     * \return JAVA_HOME.
     */
    inline char *getJavaHome(void) {
      return this->_javaHome;
    }
    /*!
     * \brief Get JVM boot class path.
     * \return JVM boot class path.
     */
    inline char *getBootClassPath(void) {
      return this->_bootClassPath;
    }
    /*!
     * \brief Get JVM arguments.
     * \return JVM arguments.
     */
    inline char *getVmArgs(void) {
      return this->_vmArgs;
    }
    /*!
     * \brief Get JVM flags.
     * \return JVM flags.
     */
    inline char *getVmFlags(void) {
      return this->_vmFlags;
    }
    /*!
     * \brief Get Java application arguments.
     * \return Java application arguments.
     */
    inline char *getJavaCommand(void) {
      return this->_javaCommand;
    }
    /*!
     * \brief Get JVM running timetick.
     * \return JVM running timetick.
     */
    inline jlong getTickTime(void) {
      /* Get time tick frequency. */
      jlong freqTime = (this->_freqTime != NULL) ? (*this->_freqTime / 1000) : 1;
      
      return ((_tickTime == NULL) ? -1 : *_tickTime / freqTime);
    }
  
  #ifdef USE_VMSTRUCTS
    
    /*!
     * \brief Detect GC-informaion address.<br>
     *        Use external VM structure.
     * \sa "jdk/src/share/classes/sun/tools/jstat/resources/jstat_options"
     */
    void detectInfoAddress(void);
  #else
    
    /*!
     * \brief Detect GC-informaion address.<br>
     *        Use performance data file.
     * \param env [in] JNI environment object.
     * \sa "jdk/src/share/classes/sun/tools/jstat/resources/jstat_options"
     */
    void detectInfoAddress(JNIEnv *env);
  #endif

    inline void SetUnknownGCCause(void){

    #ifdef AVX
      if(likely(usableAVX)){
        asm volatile("vmovdqa   (%1), %%xmm0;"
                     "vmovdqa %%xmm0,   (%0);"
          : : "a" (this->gcCause), "c" (UNKNOWN_GC_CAUSE) : "%xmm0");
      }
      else
    #endif // AVX.
    #ifndef __amd64__
    #ifdef SSE2
      if(unlikely(!usableSSE2))
    #endif // SSE2
      {
        memcpy(this->gcCause, UNKNOWN_GC_CAUSE, 16);
      }
    #ifdef SSE2
      else
    #endif // SSE2
    #endif // __amd64__
    #ifdef SSE2
      {
        asm volatile("movdqa   (%1), %%xmm0;"
                     "movdqa %%xmm0,   (%0);"
          : : "a" (this->gcCause), "c" (UNKNOWN_GC_CAUSE) : "%xmm0");
      }
    #endif // SSE2

    }

 protected:
    
    /*!
     * \brief Address of java.lang.getMaxMemory().
     */
    TGetMemoryFunc maxMemFunc;
    
    /*!
     * \brief Address of java.lang.getTotalMemory().
     */
    TGetMemoryFunc totalMemFunc;
    
  #ifdef USE_VMSTRUCTS
    /*!
     * \brief Get JVM performance data address.<br>
     *        Use external VM structure.
     * \return JVM performance data address.
     */
    virtual ptrdiff_t getPerfMemoryAddress(void);
  #else
    
    /*!
     * \brief Search JVM performance data address in memory.
     * \param path [in] Path of hsperfdata.
     * \return JVM performance data address.
     */
    ptrdiff_t findPerfMemoryAddress(char *path);
    
    /*!
     * \brief Get JVM performance data address.<br>
     *        Use performance data file.
     * \param env [in] JNI environment object.
     * \return JVM performance data address.
     */
    virtual ptrdiff_t getPerfMemoryAddress(JNIEnv *env);
  #endif
   
  private:
    /*!
     * \brief JVM running performance data pointer.
     */
    ptrdiff_t perfAddr;
    /*!
     * \brief Now Full-GC count.
     */
    jlong *_nowFGC;
    /*!
     * \brief Now Young-GC count.
     */
    jlong *_nowYGC;
    /*!
     * \brief Now eden space size.
     */
    jlong *_edenSize;
    /*!
     * \brief Now survivor 0 space size.
     */
    jlong *_sur0Size;
    /*!
     * \brief Now survivor 1 space size.
     */
    jlong *_sur1Size;
    /*!
     * \brief Tenured generation space size.
     */
    jlong *_oldSize;
    /*!
     * \brief Total Full-GC work time.
     */
    jlong *_FGCTime;
    /*!
     * \brief Total Young-GC work time.
     */
    jlong *_YGCTime;
    /*!
     * \brief Elapsed Full-GC work time.
     */
    jlong elapFGCTime;
    /*!
     * \brief Elapsed Young-GC work time.
     */
    jlong elapYGCTime;
    /*!
     * \brief Frequency timetick.
     */
    jlong *_freqTime;
    /*!
     * \brief GC cause.
     */
    char *_gcCause;
    /*!
     * \brief Stored GC cause.
     */
    char *gcCause;
    /*!
     * \brief Full-GC flag. Used by getGCWorktime().
     */
    bool fullgcFlag;
    /*!
     * \brief Log data loaded flag.
     */
    bool loadLogFlag;
    /*!
     * \brief Delay log data loaded flag.
     */
    bool loadDelayLogFlag;
    
    /*!
     * \brief It's count of finished conflict of monitor.
     */
    jlong *_syncPark;
    /*!
     * \brief Now living thread count.
     */
    jlong *_threadLive;
    /*!
     * \brief Total work time in safepoint.
     */
    jlong *_safePointTime;
    /*!
     * \brief Count of work in safepoint.
     */
    jlong *_safePoints;
    
    /*!
     * \brief JVM version.
     */
    char *_vmVersion;

     /*!
     * \brief JVM version as uint
     */
    unsigned int _hsVersion;

    /*!
     * \brief JVM name.
     */
    char *_vmName;
    /*!
     * \brief JVM class path.
     */
    char *_classPath;
    /*!
     * \brief JVM endorsed path.
     */
    char *_endorsedPath;
    /*!
     * \brief Java version.
     */
    char *_javaVersion;
    /*!
     * \brief JAVA_HOME.
     */
    char *_javaHome;
    /*!
     * \brief JVM boot class path.
     */
    char *_bootClassPath;
    /*!
     * \brief JVM arguments.
     */
    char *_vmArgs;
    /*!
     * \brief JVM flags.
     */
    char *_vmFlags;
    /*!
     * \brief Java application arguments.
     */
    char *_javaCommand;
    /*!
     * \brief JVM running timetick.
     */
    jlong *_tickTime;

};

#endif //JVMINFO_H