view agent/src/util.hpp @ 16:6086194b2867

Bug 1467: Full mode log archiving does not work when using fifo pipe for gc log reviewed-by: ykubota, shintak
author Yasumasa Suenaga <suenaga.yasumasa@lab.ntt.co.jp>
date Mon, 17 Mar 2014 19:52:45 +0900
parents b21d5eef58f0
children 8008ab68f482
line wrap: on
line source

/*!
 * \file util.hpp
 * \brief This file is utilities.
 * 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 UTIL_HPP
#define UTIL_HPP

#include <sys/time.h>
#include <jni.h>
#include <jvmti.h>
#include <pthread.h>
#include <stddef.h>
#include <sys/types.h>

#include <iostream>


/* STDOUT/ERR helper macro. */

/*!
 * \brief Standard output macro.
 */
#define STDOUT std::cout
/*!
 * \brief Standard error output macro.
 */
#define STDERR std::cerr
/*!
 * \brief Output newline code macro.
 */
#define NEWLINE std::endl
/*!
 * \brief Standard ouput width adjustment macro.
 */
#define STDOUT_WIDTH_ADJ(x) std::cout.width((x))
/*!
 * \brief Standard output force output macro.
 */
#define FLUSH_STDOUT std::cout.flush()
/*!
 * \brief Standard error output force output macro.
 */
#define FLUSH_STDERR std::cerr.flush()

/*!
 * \brief Critical message header macro.
 */
#define PRINT_CRIT_MSG_HEADER \
    if (arg.LogLevel >= CRIT) STDERR << "heapstats CRIT: "

/*!
 * \brief Critical message macro.
 */
#define PRINT_CRIT_MSG(msg) \
    PRINT_CRIT_MSG_HEADER << (msg) << NEWLINE

/* Warning message. */

/*!
 * \brief Warning message header macro.
 */
#define PRINT_WARN_MSG_HEADER \
    if (arg.LogLevel >= WARN) STDERR << "heapstats WARN: "

/*!
 * \brief Warning message macro.
 */
#define PRINT_WARN_MSG(msg) \
    PRINT_WARN_MSG_HEADER << (msg) << NEWLINE

/*!
 * \brief Warning message macro for file open failed.
 */
#define PRINT_FAIL_OPENFILE_MSG(filename, errnum) \
    PRINT_WARN_MSG_HEADER << "Counldn't open a file." \
        << " file:\"" << (filename) << "\"" \
        << " cause:\"" << strerror((errnum)) << "\"" << NEWLINE

/*!
 * \brief Warning message macro for file create failed.
 */
#define PRINT_FAIL_CREATEFILE_MSG(filename, errnum) \
    PRINT_WARN_MSG_HEADER << "Counldn't create a file." \
        << " file:\"" << (filename) << "\"" \
        << " cause:\"" << strerror((errnum)) << "\"" << NEWLINE

/*!
 * \brief Warning message macro for file output is failed.
 */
#define PRINT_FAIL_WRITE_MSG(filename, errnum) \
    PRINT_WARN_MSG_HEADER << "Failed to outputting to file." \
        << " file:\"" << (filename) << "\"" \
        << " cause:\"" << strerror((errnum)) << "\"" \
        << NEWLINE

/*!
 * \brief Warning message and errno macro.
 */
#define PRINT_WARN_MSG_AND_ERRNO(msg, errnum) \
    char error_string[1024]; \
    strerror_r(errnum, error_string, 1024); \
    PRINT_WARN_MSG_HEADER << (msg) \
        << " cause:\"" << error_string << "\"" << NEWLINE

/* Info message. */

/*!
 * \brief Info message header force macro.
 */
#define PRINT_INFO_MSG_HEADER_NOIF \
    STDOUT << "heapstats INFO: "

/*!
 * \brief Info message header macro.
 */
#define PRINT_INFO_MSG_HEADER \
    if (arg.LogLevel >= INFO) PRINT_INFO_MSG_HEADER_NOIF

/*!
 * \brief Info message macro.
 */
#define PRINT_INFO_MSG(msg) \
    PRINT_INFO_MSG_HEADER << (msg) << NEWLINE

/* Debug message. */

/*!
 * \brief Debug message header force macro.
 */
#define PRINT_DEBUG_MSG_HEADER_NOIF \
    STDOUT << "heapstats DEBUG: "

/*!
 * \brief Debug message header macro.
 */
#define PRINT_DEBUG_MSG_HEADER \
    if (arg.LogLevel >= DEBUG) PRINT_DEBUG_MSG_HEADER_NOIF

/*!
 * \brief Debug message macro.
 */
#define PRINT_DEBUG_MSG(msg) \
    PRINT_DEBUG_MSG_HEADER << (msg) << NEWLINE

/* Branch prediction. */

/*!
 * \brief Positive branch prediction.
 */
#define likely(x)   __builtin_expect(!!(x), 1)

/*!
 * \brief Negative branch prediction.
 */
#define unlikely(x) __builtin_expect(!!(x), 0)

/* Critical section helper macro for pthread mutex. */

/*!
 * \brief Enter critical pthread section macro.
 */
#define ENTER_PTHREAD_SECTION(monitor) \
    if (unlikely(pthread_mutex_lock((monitor)) != 0)) { \
        PRINT_WARN_MSG("Entering mutex failed!"); \
    } else {

/*!
 * \brief Exit critical pthread section macro.
 */
#define EXIT_PTHREAD_SECTION(monitor) \
        if (unlikely(pthread_mutex_unlock((monitor)) != 0)) { \
            PRINT_WARN_MSG("Exiting mutex failed!"); \
        } \
    }

/*!
 * \brief Calculate align macro.
 *        from hotspot/src/share/vm/utilities/globalDefinitions.hpp
 */
#define ALIGN_SIZE_UP(size, alignment) \
    (((size) + ((alignment) - 1)) & ~((alignment) - 1))

#ifdef __LP64__
    
    /*!
     * \brief Format string for jlong.<br />
     *        At "LP64" java environment, jlong is defined as "long int".
     */
    #define JLONG_FORMAT_STR "%ld"
#else
    
    /*!
     * \brief Format string for jlong.<br />
     *        At most java environment, jlong is defined as "long long int".
     */
    #define JLONG_FORMAT_STR "%lld"
#endif

#ifdef DEBUG
    
    /*!
     * \brief This macro for statement only debug.
     */
    #define DEBUG_ONLY(statement) statement
    
    /*!
     * \brief This macro for statement only release.
     */
    #define RELEASE_ONLY(statement) 
#else
    
    /*!
     * \brief This macro for statement only debug.
     */
    #define DEBUG_ONLY(statement) 
    
    /*!
     * \brief This macro for statement only release.
     */
    #define RELEASE_ONLY(statement) statement
#endif

/*!
 * \brief Debug macro.
 */
#define STATEMENT_BY_MODE(debug_state, release_state) \
    DEBUG_ONLY(debug_state) RELEASE_ONLY(release_state)

/* Typedef. */

/*!
 * \brief Causes of function invoking.
 */
typedef enum{
    GC                = 1, /*!< Invoke by Garbage Collection.     */
    DataDumpRequest   = 2, /*!< Invoke by user dump request.      */
    Interval          = 3, /*!< Invoke by timer interval.         */
    Signal            = 4, /*!< Invoke by user's signal.          */
    AnotherSignal     = 5, /*!< Invoke by user's another signal.  */
    ResourceExhausted = 6, /*!< Invoke by JVM resource exhausted. */
    ThreadExhausted   = 7, /*!< Invoke by thread exhausted.       */
    OccurredDeadlock  = 8  /*!< Invoke by occured deadlock.       */
} TInvokeCause;

/*!
 * \brief Ranking Order.<br>
 *        This order affects heap alert.
 */
typedef enum{
    DELTA, /*!< Ranking is sorted by delta from before snapshot. */
    USAGE  /*!< Ranking is sorted by heap using size.            */
} TRankOrder;

/*!
 * \brief Logging Level.
 */
typedef enum{
    CRIT = 1,
    /*!< Level for  FATAL   error log. This's displayed by all means. */
    WARN = 2,
    /*!< Level for runnable error log. e.g. Heap-Alert                */
    INFO = 3,
    /*!< Level for  normal  info  log. e.g. Heap-Ranking              */
    DEBUG = 4
    /*!< Level for  debug  info  log.                                 */
} TLogLevel;

/*!
 * \brief HeapStats configure setting structure.
 */
typedef struct{
    bool attach;             /*!< Flag of agent attach enable.                */
    char *FileName;          /*!< Output snapshot file name.                  */
    char *heapLogFile;       /*!< Output common log file name.                */
    char *archiveFile;       /*!< Output archive log file name.               */
    bool reduceSnapShot;     /*!< Is reduced snapshot.                        */
    bool triggerOnFullGC;    /*!< Make snapshot is triggered by full-GC.      */
    bool triggerOnDump;      /*!< Make snapshot is triggered by dump request. */
    bool triggerOnLogError;  /*!< Logging on JVM error(Resoure exhausted).    */
    bool triggerOnLogSignal; /*!< Logging on received signal.                 */
    bool triggerOnLogLock;   /*!< Logging on occurred deadlock.               */
    int RankLevel;           /*!< Count of show ranking.                      */
    TLogLevel LogLevel;      /*!< Output log level.                           */
    TRankOrder order;        /*!< Order of ranking.                           */
    int AlertPercentage;     /*!< Percentage of trigger alert in heap.        */
    jlong AlertThreshold;    /*!< Size of trigger alert in heap.              */
    int HeapAlertPercentage; /*!< Alert percentage of javaHeapAlert.          */
    jlong HeapAlertThreshold;/*!< Trigger usage for javaHeapAlert.            */
    jlong MetaspaceThreshold;/*!< Trigger usage for javaMetaspaceAlert.       */
    jlong TimerInterval;     /*!< Interval of periodic snapshot.              */
    jlong LogInterval;       /*!< Interval of periodic logging.               */
    bool firstCollect;       /*!< Logging on JVM error only first time.       */
    bool isFirstCollected;   /*!< Flag of already logged on JVM error.        */
    char* logSignalNormal;   /*!< Name of signal logging about process.       */
    char* logSignalAll;      /*!< Name of signal logging about environment.   */
    char* reloadSignal;      /*!< Name of signal reload configuration file.   */
    bool snmpSend;           /*!< Flag of SNMP trap send enable.              */
    char* snmpTarget;        /*!< SNMP trap send target.                      */
    char* snmpComName;       /*!< SNMP trap community name.                   */
    char* logDir;            /*!< Path of working directory for log archive.  */
    char* archiveCommand;    /*!< Command was execute to making log archive.  */
    bool killOnError;        /*!< Abort JVM on resoure exhausted or deadlock. */
} TArguments;

/*!
 * \brief Java thread information structure.
 */
typedef struct{
    char *name;    /*!< Name of java thread.             */
    bool isDaemon; /*!< Flag of thread is daemon thread. */
    int priority;  /*!< Priority of thread in java.      */
    char *state;   /*!< String about thread state.       */
} TJavaThreadInfo;

/*!
 * \brief Java method information structure in stack frame.
 */
typedef struct{
    char *methodName; /*!< Name of class method.                               */
    char *className;  /*!< Name of class is declaring method.                  */
    bool isNative;    /*!< Flag of method is native.                           */
    char *sourceFile; /*!< Name of file name is declaring class.               */
    int lineNumber;   /*!< Line number of method's executing position in file. */
} TJavaStackMethodInfo;

/* Extern variables. */

/*!
 * \brief Agent attach mode flag.
 *        Value is true, if agent is attached by on-demand-attach.
 *        Value is false, if agent is attached by command line.
 */
extern bool isOnDemandAttached;

/*!
 * \brief HeapStats configurations.
 */
extern TArguments arg;

/* CPU instruction set flag. */

/*!
 * \brief SSE2 instruction usable flag.
 */
extern bool usableSSE2;

/*!
 * \brief SSE3 instruction usable flag.
 */
extern bool usableSSE3;

/*!
 * \brief SSSE3 instruction usable flag.
 */
extern bool usableSSSE3;

/*!
 * \brief SSE4.1 instruction usable flag.
 */
extern bool usableSSE4_1;

/*!
 * \brief SSE4.2 instruction usable flag.
 */
extern bool usableSSE4_2;

/*!
 * \brief Intel AVX instruction usable flag.
 */
extern bool usableAVX;

/*!
 * \brief Page size got from sysconf.
 */
extern long systemPageSize;

/*!
 * \brief Interval of check signal by signal watch timer.(msec)
 */
const unsigned int SIG_WATCHER_INTERVAL = 0;

/* Export functions. */

/*!
 * \brief JVMTI error detector.
 * \param jvmti [in] JVMTI envrionment object.
 * \param error [in] JVMTI error code.
 * \return Param "error" is error code?(true/false)
 */
bool isError(jvmtiEnv *jvmti, jvmtiError error);

/*!
 * \brief Set config to default.
 */
void initSetting(void);
/*!
 * \brief Free config memory.
 * \param targetArg [in,out] Deallocate target settings.
 */
void freeSetting(TArguments *targetArg);
/*!
 * \brief Inherited config from old config.
 * \param newArg [in,out] New argument settings.
 * \param oldArg [in,out] Old argument settings.
 */
void inheritedSetting(TArguments *newArg, TArguments *oldArg);

/*!
 * \brief Load configuration from file.
 * \param filename [in] Read configuration file path.
 */
void loadConfiguration(const char *filename);

/*!
 * \brief Print setting information.
 */
void printSetting(void);

/*!
 * \brief Get system information.
 * \param env [in] JNI envrionment.
 * \param key [in] System property key.
 * \return String of system property.
 */
char *GetSystemProperty(JNIEnv *env, const char *key);

/*!
 * \brief Get ClassUnload event index.
 * \param jvmti [in] JVMTI envrionment object.
 * \return ClassUnload event index.
 * \sa     hotspot/src/share/vm/prims/jvmtiExport.cpp<br>
 *         hotspot/src/share/vm/prims/jvmtiEventController.cpp<br>
 *         hotspot/src/share/vm/prims/jvmti.xml<br>
 *         in JDK.
 */
jint GetClassUnloadingExtEventIndex(jvmtiEnv *jvmti);

/*!
 * \brief Verify CPU instruction set.
 */
void verifyInstructSet(void);

/*!
 * \brief Replace old string in new string on string.
 * \param str    [in] Process target string.
 * \param oldStr [in] Targer of replacing.
 * \param newStr [in] A string will replace existing string.
 * \return String invoked replace.<br>Don't forget deallocate.
 */
char *strReplase(char const* str, char const* oldStr, char const* newStr);

/*!
 * \brief Get now date and time.
 * \return Mili-second elapsed time from 1970/1/1 0:00:00.
 */
jlong getNowTimeSec(void);

/*!
 * \brief Check signal is supported by JVM.
 * \param sigName [in] Name of signal.
 * \return Signal is supported, if value is true.
 *         Otherwise, value is false.
 * \sa Please see below JDK source about JVM supported signal.<br>
 *     hotspot/src/os/linux/vm/jvm_linux.cpp
 */
bool isSupportSignal(char const* sigName);

/*!
 * \brief A little sleep.
 * \param sec  [in] Second of sleep range.
 * \param nsec [in] Nano second of sleep range.
 */
void littleSleep(const long int sec, const long int nsec);

/*!
 * \brief Get thread information.
 * \param jvmti  [in]  JVMTI environment object.
 * \param env    [in]  JNI environment object.
 * \param thread [in]  Thread object in java.
 * \param info   [out] Record stored thread information.
 */
void getThreadDetailInfo(jvmtiEnv *jvmti, JNIEnv* env, jthread thread,
    TJavaThreadInfo *info);

/*!
 * \brief Get method information in designed stack frame.
 * \param jvmti [in]  JVMTI environment object.
 * \param env   [in]  JNI environment object.
 * \param frame [in]  method stack frame.
 * \param info  [out] Record stored method information in stack frame.
 */
void getMethodFrameInfo(jvmtiEnv *jvmti, JNIEnv* env, jvmtiFrameInfo frame,
    TJavaStackMethodInfo *info);

/*!
 * \brief Wait spin lock.
 * \param aLock [in] Target integer lock.
 */
inline void spinLockWait(volatile int *aLock) {
    asm volatile(
        "1:"
            "xorl %%eax, %%eax;"
            "pause;"
            "lock cmpxchgl %1, (%0);"
            "jnz 1b;"
        : "+r" (aLock) : "r" (1) : "cc", "memory", "%eax");
};

/*!
 * \brief Release spin lock.
 * \param aLock [in] Target integer lock.
 */
inline void spinLockRelease(volatile int *aLock) {
    asm volatile(
        "xorl %%eax, %%eax;"
        "lock xchgl %%eax, (%0);"
        : "+r" (aLock) : : "cc", "memory", "%eax");
};

/*!
 * \brief Handling Java Exception if exists.
 * \param env [in] JNI environment object.
 */
inline void handlePendingException(JNIEnv *env) {
    /* If exists execption in java. */
    if (env->ExceptionOccurred() != NULL) {
        
        /* Clear execption in java. */
        env->ExceptionDescribe();
        env->ExceptionClear();
    }
};

/*!
 * \brief Add to address.
 * \param addr [in] Target address.
 * \param inc  [in] Incremental integer value.
 * \return The address added increment value.
 */
inline void *incAddress(void *addr, off_t inc) {
    return (void*)((ptrdiff_t)addr + inc);
};

/* Classes. */

/*!
 * \brief Hasher class for std::tr1::unordered_map.
 *        This template class will be used when key is numeric type.
 *        (int, pointer, etc)
 */
template<typename T> class TNumericalHasher {
    public:
        
        /*!
         * \brief Get hash value from designated value.
         *        This function always return convert to integer only.
         * \param val [in] Hash source data.
         * \return Hash value.
         */
        size_t operator()(const T &val) const {
            return (size_t)val;
        };
};

#endif