Skip to content

File perf_monitor.h

File List > base > perf_monitor.h

Go to the documentation of this file

/*
 * Copyright 2008 Search Solution Corporation
 * Copyright 2016 CUBRID Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */


/*
 * perf_monitor.h - Monitor execution statistics at Client
 */

#ifndef _PERF_MONITOR_H_
#define _PERF_MONITOR_H_

#ident "$Id$"

#if defined (SERVER_MODE)
#include "connection_defs.h"
#include "dbtype_def.h"
#endif /* SERVER_MODE */
#if defined (SERVER_MODE) || defined (SA_MODE)
#include "log_impl.h"
#endif // SERVER_MODE or SA_MODE
#include "memory_alloc.h"
#include "porting_inline.hpp"
#include "storage_common.h"
#include "thread_compat.hpp"
#include "tsc_timer.h"

#include <assert.h>
#include <stdio.h>
#if !defined(WINDOWS)
#include <sys/time.h>
#endif /* WINDOWS */
#include <time.h>

/* EXPORTED GLOBAL DEFINITIONS */
#define MAX_DIAG_DATA_VALUE     0xfffffffffffffLL

#define MAX_SERVER_THREAD_COUNT         500
#define MAX_SERVER_NAMELENGTH           256
#define SH_MODE 0644

/* Statistics activation flags */
typedef enum
{
  PERFMON_ACTIVATION_FLAG_DEFAULT = 0x00000000,
  PERFMON_ACTIVATION_FLAG_DETAILED_BTREE_PAGE = 0x00000001,
  PERFMON_ACTIVATION_FLAG_MVCC_SNAPSHOT = 0x00000002,
  PERFMON_ACTIVATION_FLAG_LOCK_OBJECT = 0x00000004,
  PERFMON_ACTIVATION_FLAG_PB_HASH_ANCHOR = 0x00000008,
  PERFMON_ACTIVATION_FLAG_PB_VICTIMIZATION = 0x00000010,
  PERFMON_ACTIVATION_FLAG_THREAD = 0x00000020,
  PERFMON_ACTIVATION_FLAG_DAEMONS = 0x00000040,
  PERFMON_ACTIVATION_FLAG_FLUSHED_BLOCK_VOLUMES = 0x00000080,
  PERFMON_ACTIVATION_FLAG_LOG_RECOVERY_REDO_MAIN = 0x00000100,
  PERFMON_ACTIVATION_FLAG_LOG_RECOVERY_REDO_ASYNC = 0x00000200,

  /* must update when adding new conditions */
  PERFMON_ACTIVATION_FLAG_LAST = PERFMON_ACTIVATION_FLAG_LOG_RECOVERY_REDO_ASYNC,

  PERFMON_ACTIVATION_FLAG_MAX_VALUE = (PERFMON_ACTIVATION_FLAG_LAST << 1) - 1
} PERFMON_ACTIVATION_FLAG;

/* PERF_MODULE_TYPE x PERF_PAGE_TYPE x PAGE_FETCH_MODE x HOLDER_LATCH_MODE x COND_FIX_TYPE */
#define PERF_PAGE_FIX_COUNTERS \
  ((PERF_MODULE_CNT) * (PERF_PAGE_CNT) * (PERF_PAGE_MODE_CNT) * (PERF_HOLDER_LATCH_CNT) * (PERF_CONDITIONAL_FIX_CNT))

#define PERF_PAGE_PROMOTE_COUNTERS \
  ((PERF_MODULE_CNT) * (PERF_PAGE_CNT) * (PERF_PROMOTE_CONDITION_CNT) * (PERF_HOLDER_LATCH_CNT) * (2 /* success */))

/* PERF_MODULE_TYPE x PAGE_TYPE x DIRTY_OR_CLEAN x DIRTY_OR_CLEAN x READ_OR_WRITE_OR_MIX */
#define PERF_PAGE_UNFIX_COUNTERS \
  ((PERF_MODULE_CNT) * (PERF_PAGE_CNT) * 2 * 2 * (PERF_HOLDER_LATCH_CNT))

#define PERF_PAGE_LOCK_TIME_COUNTERS PERF_PAGE_FIX_COUNTERS

#define PERF_PAGE_HOLD_TIME_COUNTERS \
  ((PERF_MODULE_CNT) * (PERF_PAGE_CNT) * (PERF_PAGE_MODE_CNT) * (PERF_HOLDER_LATCH_CNT))

#define PERF_PAGE_FIX_TIME_COUNTERS PERF_PAGE_FIX_COUNTERS

#define PERF_PAGE_FIX_STAT_OFFSET(module,page_type,page_found_mode,latch_mode,cond_type) \
  ((module) * (PERF_PAGE_CNT) * (PERF_PAGE_MODE_CNT) * (PERF_HOLDER_LATCH_CNT) * (PERF_CONDITIONAL_FIX_CNT) \
    + (page_type) * (PERF_PAGE_MODE_CNT) * (PERF_HOLDER_LATCH_CNT) * (PERF_CONDITIONAL_FIX_CNT) \
    + (page_found_mode) * (PERF_HOLDER_LATCH_CNT) * (PERF_CONDITIONAL_FIX_CNT) \
    + (latch_mode) * (PERF_CONDITIONAL_FIX_CNT) + (cond_type))

#define PERF_PAGE_PROMOTE_STAT_OFFSET(module,page_type,promote_cond,holder_latch,success) \
  ((module) * (PERF_PAGE_CNT) * (PERF_PROMOTE_CONDITION_CNT) * (PERF_HOLDER_LATCH_CNT) * 2 /* success */ \
    + (page_type) * (PERF_PROMOTE_CONDITION_CNT) * (PERF_HOLDER_LATCH_CNT) * 2 /* success */ \
    + (promote_cond) * (PERF_HOLDER_LATCH_CNT) * 2 /* success */ \
    + (holder_latch) * 2 /* success */ \
    + success)

#define PERF_PAGE_UNFIX_STAT_OFFSET(module,page_type,buf_dirty,dirtied_by_holder,holder_latch) \
  ((module) * (PERF_PAGE_CNT) * 2 * 2 * (PERF_HOLDER_LATCH_CNT) \
   + (page_type) * 2 * 2 * (PERF_HOLDER_LATCH_CNT) \
   + (buf_dirty) * 2 * (PERF_HOLDER_LATCH_CNT) \
   + (dirtied_by_holder) * (PERF_HOLDER_LATCH_CNT) \
   + (holder_latch))

#define PERF_PAGE_LOCK_TIME_OFFSET(module,page_type,page_found_mode,latch_mode,cond_type) \
  PERF_PAGE_FIX_STAT_OFFSET (module, page_type, page_found_mode, latch_mode, cond_type)

#define PERF_PAGE_HOLD_TIME_OFFSET(module,page_type,page_found_mode,latch_mode)\
  ((module) * (PERF_PAGE_CNT) * (PERF_PAGE_MODE_CNT) * (PERF_HOLDER_LATCH_CNT) \
    + (page_type) * (PERF_PAGE_MODE_CNT) * (PERF_HOLDER_LATCH_CNT) \
    + (page_found_mode) * (PERF_HOLDER_LATCH_CNT) \
    + (latch_mode))

#define PERF_PAGE_FIX_TIME_OFFSET(module,page_type,page_found_mode,latch_mode,cond_type) \
  PERF_PAGE_FIX_STAT_OFFSET (module, page_type, page_found_mode, latch_mode, cond_type)

#define PERF_MVCC_SNAPSHOT_COUNTERS \
  (PERF_SNAPSHOT_CNT * PERF_SNAPSHOT_RECORD_TYPE_CNT * PERF_SNAPSHOT_VISIBILITY_CNT)

#define PERF_MVCC_SNAPSHOT_OFFSET(snapshot,rec_type,visibility) \
  ((snapshot) * PERF_SNAPSHOT_RECORD_TYPE_CNT * PERF_SNAPSHOT_VISIBILITY_CNT \
   + (rec_type) * PERF_SNAPSHOT_VISIBILITY_CNT + (visibility))

#define PERF_OBJ_LOCK_STAT_COUNTERS (SCH_M_LOCK + 1)
#define PERF_DWB_FLUSHED_BLOCK_VOLUMES_CNT 10

#define SAFE_DIV(a, b) ((b) == 0 ? 0 : (a) / (b))

/* Count & timer values. */
#define PSTAT_COUNTER_TIMER_COUNT_VALUE(startvalp) (startvalp)
#define PSTAT_COUNTER_TIMER_TOTAL_TIME_VALUE(startvalp) ((startvalp) + 1)
#define PSTAT_COUNTER_TIMER_MAX_TIME_VALUE(startvalp) ((startvalp) + 2)
#define PSTAT_COUNTER_TIMER_AVG_TIME_VALUE(startvalp) ((startvalp) + 3)

#if !defined(SERVER_MODE)
#if !defined(LOG_TRAN_INDEX)
#define LOG_TRAN_INDEX
extern int log_Tran_index;  /* Index onto transaction table for current thread of execution (client) */
#endif /* !LOG_TRAN_INDEX */
#endif /* !SERVER_MODE */

#if defined (SERVER_MODE)
// todo - remove from here
#if !defined(LOG_FIND_THREAD_TRAN_INDEX)
#define LOG_FIND_THREAD_TRAN_INDEX(thrd) \
  ((thrd) ? (thrd)->tran_index : logtb_get_current_tran_index())
#endif
#else
#if !defined(LOG_FIND_THREAD_TRAN_INDEX)
#define LOG_FIND_THREAD_TRAN_INDEX(thrd) (log_Tran_index)
#endif
#endif

typedef enum
{
  PERF_MODULE_SYSTEM = 0,
  PERF_MODULE_USER,
  PERF_MODULE_VACUUM,

  PERF_MODULE_CNT
} PERF_MODULE_TYPE;

typedef enum
{
  PERF_HOLDER_LATCH_READ = 0,
  PERF_HOLDER_LATCH_WRITE,
  PERF_HOLDER_LATCH_MIXED,

  PERF_HOLDER_LATCH_CNT
} PERF_HOLDER_LATCH;

typedef enum
{
  PERF_CONDITIONAL_FIX = 0,
  PERF_UNCONDITIONAL_FIX_NO_WAIT,
  PERF_UNCONDITIONAL_FIX_WITH_WAIT,

  PERF_CONDITIONAL_FIX_CNT
} PERF_CONDITIONAL_FIX_TYPE;

typedef enum
{
  PERF_PROMOTE_ONLY_READER,
  PERF_PROMOTE_SHARED_READER,

  PERF_PROMOTE_CONDITION_CNT
} PERF_PROMOTE_CONDITION;

typedef enum
{
  PERF_PAGE_MODE_OLD_LOCK_WAIT = 0,
  PERF_PAGE_MODE_OLD_NO_WAIT,
  PERF_PAGE_MODE_NEW_LOCK_WAIT,
  PERF_PAGE_MODE_NEW_NO_WAIT,
  PERF_PAGE_MODE_OLD_IN_BUFFER,

  PERF_PAGE_MODE_CNT
} PERF_PAGE_MODE;

/* extension of PAGE_TYPE (storage_common.h) - keep value compatibility */
typedef enum
{
  PERF_PAGE_UNKNOWN = 0,    /* used for initialized page */
  PERF_PAGE_FTAB,       /* file allocset table page */
  PERF_PAGE_HEAP,       /* heap page */
  PERF_PAGE_VOLHEADER,      /* volume header page */
  PERF_PAGE_VOLBITMAP,      /* volume bitmap page */
  PERF_PAGE_QRESULT,        /* query result page */
  PERF_PAGE_EHASH,      /* ehash bucket/dir page */
  PERF_PAGE_OVERFLOW,       /* overflow page (with ovf_keyval) */
  PERF_PAGE_AREA,       /* area page */
  PERF_PAGE_CATALOG,        /* catalog page */
  PERF_PAGE_BTREE_GENERIC,  /* b+tree index (uninitialized) */
  PERF_PAGE_LOG,        /* NONE - log page (unused) */
  PERF_PAGE_DROPPED_FILES,  /* Dropped files page.  */
  PERF_PAGE_VACUUM_DATA,    /* Vacuum data */
  PERF_PAGE_BTREE_ROOT,     /* b+tree root index page */
  PERF_PAGE_BTREE_OVF,      /* b+tree overflow index page */
  PERF_PAGE_BTREE_LEAF,     /* b+tree leaf index page */
  PERF_PAGE_BTREE_NONLEAF,  /* b+tree nonleaf index page */
  PERF_PAGE_CNT
} PERF_PAGE_TYPE;

typedef enum
{
  PERF_SNAPSHOT_SATISFIES_DELETE = 0,
  PERF_SNAPSHOT_SATISFIES_DIRTY,
  PERF_SNAPSHOT_SATISFIES_SNAPSHOT,
  PERF_SNAPSHOT_SATISFIES_VACUUM,

  PERF_SNAPSHOT_CNT
} PERF_SNAPSHOT_TYPE;

typedef enum
{
  PERF_SNAPSHOT_RECORD_INSERTED_VACUUMED = 0,   /* already vacuumed */
  PERF_SNAPSHOT_RECORD_INSERTED_CURR_TRAN,  /* needs commit and vacuum */
  PERF_SNAPSHOT_RECORD_INSERTED_OTHER_TRAN, /* needs commit and vacuum */
  PERF_SNAPSHOT_RECORD_INSERTED_COMMITED,   /* commited, needs vacuum */
  PERF_SNAPSHOT_RECORD_INSERTED_COMMITED_LOST,  /* commited, unvacuumed/lost */

  PERF_SNAPSHOT_RECORD_INSERTED_DELETED,    /* inserted, than deleted */

  PERF_SNAPSHOT_RECORD_DELETED_CURR_TRAN,   /* deleted by current tran */
  PERF_SNAPSHOT_RECORD_DELETED_OTHER_TRAN,  /* deleted by other active tran */
  PERF_SNAPSHOT_RECORD_DELETED_COMMITTED,   /* deleted, and committed */
  PERF_SNAPSHOT_RECORD_DELETED_COMMITTED_LOST,  /* deleted, and committed, unvacuumed/lost */

  PERF_SNAPSHOT_RECORD_TYPE_CNT
} PERF_SNAPSHOT_RECORD_TYPE;

typedef enum
{
  PERF_SNAPSHOT_INVISIBLE = 0,
  PERF_SNAPSHOT_VISIBLE,

  PERF_SNAPSHOT_VISIBILITY_CNT
} PERF_SNAPSHOT_VISIBILITY;

typedef enum
{
  PSTAT_BASE = -1,      /* not a real entry. just to avoid compile warnings */

  /* Execution statistics for the file io */
  PSTAT_FILE_NUM_CREATES = 0,
  PSTAT_FILE_NUM_REMOVES,
  PSTAT_FILE_NUM_IOREADS,
  PSTAT_FILE_NUM_IOWRITES,
  PSTAT_FILE_NUM_IOSYNCHES,
  PSTAT_FILE_IOSYNC_ALL,
  PSTAT_FILE_NUM_PAGE_ALLOCS,
  PSTAT_FILE_NUM_PAGE_DEALLOCS,

  /* Page buffer basic module */
  /* Execution statistics for the page buffer manager */
  PSTAT_PB_NUM_FETCHES,
  PSTAT_PB_NUM_DIRTIES,
  PSTAT_PB_NUM_IOREADS,
  PSTAT_PB_NUM_IOWRITES,
  PSTAT_PB_NUM_FLUSHED,
  /* peeked stats */
  PSTAT_PB_PRIVATE_QUOTA,
  PSTAT_PB_PRIVATE_COUNT,
  PSTAT_PB_FIXED_CNT,
  PSTAT_PB_DIRTY_CNT,
  PSTAT_PB_LRU1_CNT,
  PSTAT_PB_LRU2_CNT,
  PSTAT_PB_LRU3_CNT,
  PSTAT_PB_VICT_CAND,

  /* Execution statistics for the log manager */
  PSTAT_LOG_NUM_FETCHES,
  PSTAT_LOG_NUM_IOREADS,
  PSTAT_LOG_NUM_IOWRITES,
  PSTAT_LOG_NUM_APPENDRECS,
  PSTAT_LOG_NUM_ARCHIVES,
  PSTAT_LOG_NUM_START_CHECKPOINTS,
  PSTAT_LOG_NUM_END_CHECKPOINTS,
  PSTAT_LOG_NUM_WALS,
  PSTAT_LOG_NUM_REPLACEMENTS_IOWRITES,
  PSTAT_LOG_NUM_REPLACEMENTS,

  /* Execution statistics for the lock manager */
  PSTAT_LK_NUM_ACQUIRED_ON_PAGES,
  PSTAT_LK_NUM_ACQUIRED_ON_OBJECTS,
  PSTAT_LK_NUM_CONVERTED_ON_PAGES,  /* obsolete? */
  PSTAT_LK_NUM_CONVERTED_ON_OBJECTS,
  PSTAT_LK_NUM_RE_REQUESTED_ON_PAGES,   /* obsolete? */
  PSTAT_LK_NUM_RE_REQUESTED_ON_OBJECTS,
  PSTAT_LK_NUM_WAITED_ON_PAGES,
  PSTAT_LK_NUM_WAITED_ON_OBJECTS,
  PSTAT_LK_NUM_WAITED_TIME_ON_OBJECTS,  /* include this to avoid client-server compat issue even if extended stats are
                     * disabled */

  /* Execution statistics for transactions */
  PSTAT_TRAN_NUM_COMMITS,
  PSTAT_TRAN_NUM_ROLLBACKS,
  PSTAT_TRAN_NUM_SAVEPOINTS,
  PSTAT_TRAN_NUM_START_TOPOPS,
  PSTAT_TRAN_NUM_END_TOPOPS,
  PSTAT_TRAN_NUM_INTERRUPTS,
  PSTAT_TRAN_NUM_PPCACHE_HITS,
  PSTAT_TRAN_NUM_PPCACHE_MISS,
  PSTAT_TRAN_NUM_TOPOP_PPCACHE_HITS,
  PSTAT_TRAN_NUM_TOPOP_PPCACHE_MISS,

  /* Execution statistics for the btree manager */
  PSTAT_BT_NUM_INSERTS,
  PSTAT_BT_NUM_DELETES,
  PSTAT_BT_NUM_UPDATES,
  PSTAT_BT_NUM_COVERED,
  PSTAT_BT_NUM_NONCOVERED,
  PSTAT_BT_NUM_RESUMES,
  PSTAT_BT_NUM_MULTI_RANGE_OPT,
  PSTAT_BT_NUM_SPLITS,
  PSTAT_BT_NUM_MERGES,
  PSTAT_BT_NUM_GET_STATS,

  PSTAT_BT_ONLINE_LOAD,
  PSTAT_BT_ONLINE_INSERT_TASK,
  PSTAT_BT_ONLINE_PREPARE_TASK,
  PSTAT_BT_ONLINE_INSERT_LEAF,

  PSTAT_BT_ONLINE_NUM_INSERTS,
  PSTAT_BT_ONLINE_NUM_INSERTS_SAME_PAGE_HOLD,
  PSTAT_BT_ONLINE_NUM_RETRY,
  PSTAT_BT_ONLINE_NUM_RETRY_NICE,

  /* Execution statistics for the query manager */
  PSTAT_QM_NUM_SELECTS,
  PSTAT_QM_NUM_INSERTS,
  PSTAT_QM_NUM_DELETES,
  PSTAT_QM_NUM_UPDATES,
  PSTAT_QM_NUM_SSCANS,
  PSTAT_QM_NUM_ISCANS,
  PSTAT_QM_NUM_LSCANS,
  PSTAT_QM_NUM_SETSCANS,
  PSTAT_QM_NUM_METHSCANS,
  PSTAT_QM_NUM_NLJOINS,
  PSTAT_QM_NUM_MJOINS,
  PSTAT_QM_NUM_HASHJOINS,
  PSTAT_QM_NUM_HASHJOINS_PARTITIONED,
  PSTAT_QM_NUM_HASHJOINS_PARALLEL,

  PSTAT_QM_NUM_OBJFETCHES,
  PSTAT_QM_NUM_HOLDABLE_CURSORS,

  /* Execution statistics for external sort */
  PSTAT_SORT_NUM_IO_PAGES,
  PSTAT_SORT_NUM_DATA_PAGES,

  /* Execution statistics for network communication */
  PSTAT_NET_NUM_REQUESTS,

  /* flush control stat */
  PSTAT_FC_NUM_PAGES,
  PSTAT_FC_NUM_LOG_PAGES,
  PSTAT_FC_TOKENS,

  /* prior lsa info */
  PSTAT_PRIOR_LSA_LIST_SIZE,    /* kbytes */
  PSTAT_PRIOR_LSA_LIST_MAXED,
  PSTAT_PRIOR_LSA_LIST_REMOVED,

  /* HA replication delay */
  PSTAT_HA_REPL_DELAY,

  /* Execution statistics for Plan cache */
  PSTAT_PC_NUM_ADD,
  PSTAT_PC_NUM_LOOKUP,
  PSTAT_PC_NUM_HIT,
  PSTAT_PC_NUM_MISS,
  PSTAT_PC_NUM_FULL,
  PSTAT_PC_NUM_DELETE,
  PSTAT_PC_NUM_INVALID_XASL_ID,
  PSTAT_PC_NUM_CACHE_ENTRIES,

  PSTAT_VAC_NUM_VACUUMED_LOG_PAGES,
  PSTAT_VAC_NUM_TO_VACUUM_LOG_PAGES,
  PSTAT_VAC_NUM_PREFETCH_REQUESTS_LOG_PAGES,
  PSTAT_VAC_NUM_PREFETCH_HITS_LOG_PAGES,

  /* Track heap modify counters. */
  PSTAT_HEAP_HOME_INSERTS,
  PSTAT_HEAP_BIG_INSERTS,
  PSTAT_HEAP_ASSIGN_INSERTS,
  PSTAT_HEAP_HOME_DELETES,
  PSTAT_HEAP_HOME_MVCC_DELETES,
  PSTAT_HEAP_HOME_TO_REL_DELETES,
  PSTAT_HEAP_HOME_TO_BIG_DELETES,
  PSTAT_HEAP_REL_DELETES,
  PSTAT_HEAP_REL_MVCC_DELETES,
  PSTAT_HEAP_REL_TO_HOME_DELETES,
  PSTAT_HEAP_REL_TO_BIG_DELETES,
  PSTAT_HEAP_REL_TO_REL_DELETES,
  PSTAT_HEAP_BIG_DELETES,
  PSTAT_HEAP_BIG_MVCC_DELETES,
  PSTAT_HEAP_HOME_UPDATES,
  PSTAT_HEAP_HOME_TO_REL_UPDATES,
  PSTAT_HEAP_HOME_TO_BIG_UPDATES,
  PSTAT_HEAP_REL_UPDATES,
  PSTAT_HEAP_REL_TO_HOME_UPDATES,
  PSTAT_HEAP_REL_TO_REL_UPDATES,
  PSTAT_HEAP_REL_TO_BIG_UPDATES,
  PSTAT_HEAP_BIG_UPDATES,
  PSTAT_HEAP_HOME_VACUUMS,
  PSTAT_HEAP_BIG_VACUUMS,
  PSTAT_HEAP_REL_VACUUMS,
  PSTAT_HEAP_INSID_VACUUMS,
  PSTAT_HEAP_REMOVE_VACUUMS,

  /* Track heap modify timers. */
  PSTAT_HEAP_INSERT_PREPARE,
  PSTAT_HEAP_INSERT_EXECUTE,
  PSTAT_HEAP_INSERT_LOG,
  PSTAT_HEAP_DELETE_PREPARE,
  PSTAT_HEAP_DELETE_EXECUTE,
  PSTAT_HEAP_DELETE_LOG,
  PSTAT_HEAP_UPDATE_PREPARE,
  PSTAT_HEAP_UPDATE_EXECUTE,
  PSTAT_HEAP_UPDATE_LOG,
  PSTAT_HEAP_VACUUM_PREPARE,
  PSTAT_HEAP_VACUUM_EXECUTE,
  PSTAT_HEAP_VACUUM_LOG,

  /* Execution statistics for the heap manager */
  /* best space info */
  PSTAT_HEAP_STATS_SYNC_BESTSPACE,
  PSTAT_HF_NUM_STATS_ENTRIES,
  PSTAT_HF_NUM_STATS_MAXED,
  PSTAT_HF_BEST_SPACE_ADD,
  PSTAT_HF_BEST_SPACE_DEL,
  PSTAT_HF_BEST_SPACE_FIND,
  PSTAT_HF_HEAP_FIND_PAGE_BEST_SPACE,
  PSTAT_HF_HEAP_FIND_BEST_PAGE,

  /* B-tree ops detailed statistics. */
  PSTAT_BT_FIX_OVF_OIDS,
  PSTAT_BT_UNIQUE_RLOCKS,
  PSTAT_BT_UNIQUE_WLOCKS,
  PSTAT_BT_LEAF,
  PSTAT_BT_TRAVERSE,
  PSTAT_BT_FIND_UNIQUE,
  PSTAT_BT_FIND_UNIQUE_TRAVERSE,
  PSTAT_BT_RANGE_SEARCH,
  PSTAT_BT_RANGE_SEARCH_TRAVERSE,
  PSTAT_BT_INSERT,
  PSTAT_BT_INSERT_TRAVERSE,
  PSTAT_BT_DELETE,
  PSTAT_BT_DELETE_TRAVERSE,
  PSTAT_BT_MVCC_DELETE,
  PSTAT_BT_MVCC_DELETE_TRAVERSE,
  PSTAT_BT_MARK_DELETE,
  PSTAT_BT_MARK_DELETE_TRAVERSE,
  PSTAT_BT_UNDO_INSERT,
  PSTAT_BT_UNDO_INSERT_TRAVERSE,
  PSTAT_BT_UNDO_DELETE,
  PSTAT_BT_UNDO_DELETE_TRAVERSE,
  PSTAT_BT_UNDO_MVCC_DELETE,
  PSTAT_BT_UNDO_MVCC_DELETE_TRAVERSE,
  PSTAT_BT_VACUUM,
  PSTAT_BT_VACUUM_TRAVERSE,
  PSTAT_BT_VACUUM_INSID,
  PSTAT_BT_VACUUM_INSID_TRAVERSE,

  /* Vacuum master/worker timers. */
  PSTAT_VAC_MASTER,
  PSTAT_VAC_JOB,
  PSTAT_VAC_WORKER_PROCESS_LOG,
  PSTAT_VAC_WORKER_EXECUTE,

  /* Log statistics */
  PSTAT_LOG_SNAPSHOT_TIME_COUNTERS,
  PSTAT_LOG_SNAPSHOT_RETRY_COUNTERS,
  PSTAT_LOG_TRAN_COMPLETE_TIME_COUNTERS,
  PSTAT_LOG_OLDEST_MVCC_TIME_COUNTERS,
  PSTAT_LOG_OLDEST_MVCC_RETRY_COUNTERS,

  /* Computed statistics */
  /* ((pb_num_fetches - pb_num_ioreads) x 100 / pb_num_fetches) x 100 */
  PSTAT_PB_HIT_RATIO,
  /* ((log_num_fetches - log_num_ioreads) x 100 / log_num_fetches) x 100 */
  PSTAT_LOG_HIT_RATIO,
  /* ((fetches of vacuum - fetches of vacuum not found in PB) x 100 / fetches of vacuum) x 100 */
  PSTAT_VACUUM_DATA_HIT_RATIO,
  /* (100 x Number of unfix with of dirty pages of vacuum / total num of unfixes from vacuum) x 100 */
  PSTAT_PB_VACUUM_EFFICIENCY,
  /* (100 x Number of unfix from vacuum / total num of unfix) x 100 */
  PSTAT_PB_VACUUM_FETCH_RATIO,
  /* total time to acquire page lock (stored as 10 usec unit, displayed as miliseconds) */
  PSTAT_PB_PAGE_LOCK_ACQUIRE_TIME_10USEC,
  /* total time to acquire page hold (stored as 10 usec unit, displayed as miliseconds) */
  PSTAT_PB_PAGE_HOLD_ACQUIRE_TIME_10USEC,
  /* total time to acquire page fix (stored as 10 usec unit, displayed as miliseconds) */
  PSTAT_PB_PAGE_FIX_ACQUIRE_TIME_10USEC,
  /* ratio of time required to allocate a buffer for a page : (100 x (fix_time - lock_time - hold_time) / fix_time) x
   * 100 */
  PSTAT_PB_PAGE_ALLOCATE_TIME_RATIO,
  /* total successful promotions */
  PSTAT_PB_PAGE_PROMOTE_SUCCESS,
  /* total failed promotions */
  PSTAT_PB_PAGE_PROMOTE_FAILED,
  /* total promotion time */
  PSTAT_PB_PAGE_PROMOTE_TOTAL_TIME_10USEC,

  /* Page buffer extended */
  /* detailed unfix module */
  PSTAT_PB_UNFIX_VOID_TO_PRIVATE_TOP,
  PSTAT_PB_UNFIX_VOID_TO_PRIVATE_MID,
  PSTAT_PB_UNFIX_VOID_TO_SHARED_MID,
  PSTAT_PB_UNFIX_LRU_ONE_PRV_TO_SHR_MID,
  PSTAT_PB_UNFIX_LRU_TWO_PRV_TO_SHR_MID,
  PSTAT_PB_UNFIX_LRU_THREE_PRV_TO_SHR_MID,
  PSTAT_PB_UNFIX_LRU_TWO_PRV_KEEP,
  PSTAT_PB_UNFIX_LRU_TWO_SHR_KEEP,
  PSTAT_PB_UNFIX_LRU_TWO_PRV_TO_TOP,
  PSTAT_PB_UNFIX_LRU_TWO_SHR_TO_TOP,
  PSTAT_PB_UNFIX_LRU_THREE_PRV_TO_TOP,
  PSTAT_PB_UNFIX_LRU_THREE_SHR_TO_TOP,
  PSTAT_PB_UNFIX_LRU_ONE_PRV_KEEP,
  PSTAT_PB_UNFIX_LRU_ONE_SHR_KEEP,
  /* vacuum */
  PSTAT_PB_UNFIX_VOID_TO_PRIVATE_TOP_VAC,
  PSTAT_PB_UNFIX_LRU_ONE_KEEP_VAC,
  PSTAT_PB_UNFIX_LRU_TWO_KEEP_VAC,
  PSTAT_PB_UNFIX_LRU_THREE_KEEP_VAC,
  /* aout */
  PSTAT_PB_UNFIX_VOID_AOUT_FOUND,
  PSTAT_PB_UNFIX_VOID_AOUT_NOT_FOUND,
  PSTAT_PB_UNFIX_VOID_AOUT_FOUND_VAC,
  PSTAT_PB_UNFIX_VOID_AOUT_NOT_FOUND_VAC,
  /* hash anchor */
  PSTAT_PB_NUM_HASH_ANCHOR_WAITS,
  PSTAT_PB_TIME_HASH_ANCHOR_WAIT,
  /* flushing */
  PSTAT_PB_FLUSH_COLLECT,
  PSTAT_PB_FLUSH_FLUSH,
  PSTAT_PB_FLUSH_SLEEP,
  PSTAT_PB_FLUSH_COLLECT_PER_PAGE,
  PSTAT_PB_FLUSH_FLUSH_PER_PAGE,
  PSTAT_PB_FLUSH_PAGE_FLUSHED,
  PSTAT_PB_FLUSH_SEND_DIRTY_TO_POST_FLUSH,
  PSTAT_PB_NUM_SKIPPED_FLUSH,
  PSTAT_PB_NUM_SKIPPED_NEED_WAL,
  PSTAT_PB_NUM_SKIPPED_ALREADY_FLUSHED,
  PSTAT_PB_NUM_SKIPPED_FIXED_OR_HOT,
  PSTAT_PB_COMPENSATE_FLUSH,
  PSTAT_PB_ASSIGN_DIRECT_BCB,
  PSTAT_PB_WAKE_FLUSH_WAITER,
  /* allocate and victim assignments */
  PSTAT_PB_ALLOC_BCB,
  PSTAT_PB_ALLOC_BCB_SEARCH_VICTIM,
  PSTAT_PB_ALLOC_BCB_COND_WAIT_HIGH_PRIO,
  PSTAT_PB_ALLOC_BCB_COND_WAIT_LOW_PRIO,
  PSTAT_PB_ALLOC_BCB_PRIORITIZE_VACUUM,
  PSTAT_PB_VICTIM_USE_INVALID_BCB,
  /* direct assignments */
  PSTAT_PB_VICTIM_SEARCH_OWN_PRIVATE_LISTS,
  PSTAT_PB_VICTIM_SEARCH_OTHERS_PRIVATE_LISTS,
  PSTAT_PB_VICTIM_SEARCH_SHARED_LISTS,
  PSTAT_PB_VICTIM_ASSIGN_DIRECT_VACUUM_VOID,
  PSTAT_PB_VICTIM_ASSIGN_DIRECT_VACUUM_LRU,
  PSTAT_PB_VICTIM_ASSIGN_DIRECT_FLUSH,
  PSTAT_PB_VICTIM_ASSIGN_DIRECT_PANIC,
  PSTAT_PB_VICTIM_ASSIGN_DIRECT_ADJUST,
  PSTAT_PB_VICTIM_ASSIGN_DIRECT_ADJUST_TO_VACUUM,
  PSTAT_PB_VICTIM_ASSIGN_DIRECT_SEARCH_FOR_FLUSH,
  /* successful searches */
  PSTAT_PB_VICTIM_SHARED_LRU_SUCCESS,
  PSTAT_PB_OWN_VICTIM_PRIVATE_LRU_SUCCESS,
  PSTAT_PB_VICTIM_OTHER_PRIVATE_LRU_SUCCESS,
  /* failed searches */
  PSTAT_PB_VICTIM_SHARED_LRU_FAIL,
  PSTAT_PB_VICTIM_OWN_PRIVATE_LRU_FAIL,
  PSTAT_PB_VICTIM_OTHER_PRIVATE_LRU_FAIL,
  PSTAT_PB_VICTIM_ALL_LRU_FAIL,
  /* search lru's */
  PSTAT_PB_VICTIM_GET_FROM_LRU,
  PSTAT_PB_VICTIM_GET_FROM_LRU_LIST_WAS_EMPTY,
  PSTAT_PB_VICTIM_GET_FROM_LRU_FAIL,
  PSTAT_PB_VICTIM_GET_FROM_LRU_BAD_HINT,
  /* lock-free circular queues with lru lists having victims */
  PSTAT_PB_LFCQ_LRU_PRV_GET_CALLS,
  PSTAT_PB_LFCQ_LRU_PRV_GET_EMPTY,
  PSTAT_PB_LFCQ_LRU_PRV_GET_BIG,
  PSTAT_PB_LFCQ_LRU_SHR_GET_CALLS,
  PSTAT_PB_LFCQ_LRU_SHR_GET_EMPTY,

  /* DWB statistics */
  PSTAT_DWB_FLUSH_BLOCK_TIME_COUNTERS,
  PSTAT_DWB_FILE_SYNC_HELPER_TIME_COUNTERS,
  PSTAT_DWB_FLUSH_BLOCK_COND_WAIT,
  PSTAT_DWB_FLUSH_BLOCK_SORT_TIME_COUNTERS,
  PSTAT_DWB_DECACHE_PAGES_AFTER_WRITE,
  PSTAT_DWB_WAIT_FLUSH_BLOCK_TIME_COUNTERS,
  PSTAT_DWB_WAIT_FILE_SYNC_HELPER_TIME_COUNTERS,
  PSTAT_DWB_FLUSH_FORCE_TIME_COUNTERS,

  /* LOG LZ4 compress statistics */
  PSTAT_LOG_LZ4_COMPRESS_TIME_COUNTERS,
  PSTAT_LOG_LZ4_DECOMPRESS_TIME_COUNTERS,

  /* peeked stats */
  PSTAT_PB_WAIT_THREADS_HIGH_PRIO,
  PSTAT_PB_WAIT_THREADS_LOW_PRIO,
  PSTAT_PB_FLUSHED_BCBS_WAIT_FOR_ASSIGN,
  PSTAT_PB_LFCQ_BIG_PRV_NUM,
  PSTAT_PB_LFCQ_PRV_NUM,
  PSTAT_PB_LFCQ_SHR_NUM,
  PSTAT_PB_AVOID_DEALLOC_CNT,
  PSTAT_PB_AVOID_VICTIM_CNT,

  /* Redo recovery statistics */
  PSTAT_LOG_REDO_ASYNC,
  PSTAT_LOG_REDO_FUNC_EXEC,

  /* Execution statistics for regu var evaluation */
  PSTAT_REGU_EVAL_TIME_10USEC,
  PSTAT_REGU_NUM_FETCHES,
  PSTAT_REGU_NUM_IOREADS,
  PSTAT_REGU_NUM_CALL_EVALS,

  /* Complex statistics */
  PSTAT_PBX_FIX_COUNTERS,
  PSTAT_PBX_PROMOTE_COUNTERS,
  PSTAT_PBX_PROMOTE_TIME_COUNTERS,
  PSTAT_PBX_UNFIX_COUNTERS,
  PSTAT_PBX_LOCK_TIME_COUNTERS,
  PSTAT_PBX_HOLD_TIME_COUNTERS,
  PSTAT_PBX_FIX_TIME_COUNTERS,
  PSTAT_MVCC_SNAPSHOT_COUNTERS,
  PSTAT_OBJ_LOCK_TIME_COUNTERS,
  PSTAT_THREAD_STATS,
  PSTAT_THREAD_DAEMON_STATS,
  PSTAT_DWB_FLUSHED_BLOCK_NUM_VOLUMES,
  PSTAT_LOAD_THREAD_STATS,

  PSTAT_COUNT
} PERF_STAT_ID;

/* All globals on statistics will be here. */
typedef struct pstat_global PSTAT_GLOBAL;
struct pstat_global
{
  int n_stat_values;

  UINT64 *global_stats;

  int n_trans;
  UINT64 **tran_stats;

  bool *is_watching;
#if !defined (HAVE_ATOMIC_BUILTINS)
  pthread_mutex_t watch_lock;
#endif              /* !HAVE_ATOMIC_BUILTINS */

  INT32 n_watchers;

  bool initialized;
  int activation_flag;
};

extern PSTAT_GLOBAL pstat_Global;

typedef enum
{
  PSTAT_ACCUMULATE_SINGLE_VALUE,    /* A single accumulator value. */
  PSTAT_PEEK_SINGLE_VALUE,  /* A single value peeked from database. */
  /* TODO: Currently this type of statistics is set by active workers. I think in
   *       most cases we could peek it at "compute". There can be two approaches:
   *       if f_compute is provided, it is read at compute phase. If not, the
   *       existing value is used and it must be set by active workers.
   */
  PSTAT_COUNTER_TIMER_VALUE,    /* A counter/timer. Counter is incremented, timer is accumulated, max time
                 * is compared with all registered timers and average time is computed.
                 */
  PSTAT_COMPUTED_RATIO_VALUE,   /* Value is computed based on other values in statistics. A ratio is obtained
                 * at the end.
                 */
  PSTAT_COMPLEX_VALUE       /* A "complex" value. The creator must handle loading, adding, dumping and
                 * computing values.
                 */
} PSTAT_VALUE_TYPE;

/* PSTAT_METADATA
 * This structure will keep meta-data information on each statistic we are monitoring.
 */
typedef struct pstat_metadata PSTAT_METADATA;

typedef void (*PSTAT_DUMP_IN_FILE_FUNC) (FILE *, const UINT64 * stat_vals);
typedef void (*PSTAT_DUMP_IN_BUFFER_FUNC) (char **, const UINT64 * stat_vals, int *remaining_size);
typedef int (*PSTAT_LOAD_FUNC) (void);

struct pstat_metadata
{
  /* These members must be set. */
  PERF_STAT_ID psid;
  const char *stat_name;
  PSTAT_VALUE_TYPE valtype;

  /* These members are computed at startup. */
  int start_offset;
  int n_vals;

  PSTAT_DUMP_IN_FILE_FUNC f_dump_in_file;
  PSTAT_DUMP_IN_BUFFER_FUNC f_dump_in_buffer;
  PSTAT_LOAD_FUNC f_load;
};

extern PSTAT_METADATA pstat_Metadata[];

typedef struct diag_sys_config DIAG_SYS_CONFIG;
struct diag_sys_config
{
  int Executediag;
  int DiagSM_ID_server;
  int server_long_query_time;   /* min 1 sec */
};

typedef struct t_diag_monitor_db_value T_DIAG_MONITOR_DB_VALUE;
struct t_diag_monitor_db_value
{
  INT64 query_open_page;
  INT64 query_opened_page;
  INT64 query_slow_query;
  INT64 query_full_scan;
  INT64 conn_cli_request;
  INT64 conn_aborted_clients;
  INT64 conn_conn_req;
  INT64 conn_conn_reject;
  INT64 buffer_page_write;
  INT64 buffer_page_read;
  INT64 lock_deadlock;
  INT64 lock_request;
};

typedef struct t_diag_monitor_cas_value T_DIAG_MONITOR_CAS_VALUE;
struct t_diag_monitor_cas_value
{
  INT64 reqs_in_interval;
  INT64 transactions_in_interval;
  INT64 query_in_interval;
  int active_sessions;
};

/* Monitor config related structure */

typedef struct monitor_cas_config MONITOR_CAS_CONFIG;
struct monitor_cas_config
{
  char head;
  char body[2];
};

typedef struct monitor_server_config MONITOR_SERVER_CONFIG;
struct monitor_server_config
{
  char head[2];
  char body[8];
};

typedef struct t_client_monitor_config T_CLIENT_MONITOR_CONFIG;
struct t_client_monitor_config
{
  MONITOR_CAS_CONFIG cas;
  MONITOR_SERVER_CONFIG server;
};

/* Shared memory data struct */

typedef struct t_shm_diag_info_server T_SHM_DIAG_INFO_SERVER;
struct t_shm_diag_info_server
{
  int magic;
  int num_thread;
  int magic_key;
  char servername[MAX_SERVER_NAMELENGTH];
  T_DIAG_MONITOR_DB_VALUE thread[MAX_SERVER_THREAD_COUNT];
};

enum t_diag_shm_mode
{
  DIAG_SHM_MODE_ADMIN = 0,
  DIAG_SHM_MODE_MONITOR = 1
};
typedef enum t_diag_shm_mode T_DIAG_SHM_MODE;

enum t_diag_server_type
{
  DIAG_SERVER_DB = 00000,
  DIAG_SERVER_CAS = 10000,
  DIAG_SERVER_DRIVER = 20000,
  DIAG_SERVER_RESOURCE = 30000
};
typedef enum t_diag_server_type T_DIAG_SERVER_TYPE;

extern void perfmon_server_dump_stats (const UINT64 * stats, FILE * stream, const char *substr);
extern void perfmon_server_dump_stats_to_buffer (const UINT64 * stats, char *buffer, int buf_size, const char *substr);
extern void perfmon_trace_dump_stats_to_buffer (const UINT64 * stats, char *buffer, int buf_size, int trace_level);

extern void perfmon_get_current_times (time_t * cpu_usr_time, time_t * cpu_sys_time, time_t * elapsed_time);

extern int perfmon_calc_diff_stats (UINT64 * stats_diff, UINT64 * new_stats, UINT64 * old_stats, bool need_pgbuf_stat);
extern int perfmon_calc_diff_stats_for_trace (UINT64 * stats_diff, UINT64 * new_stats, UINT64 * old_stats);
extern int perfmon_initialize (int num_trans);
extern void perfmon_finalize (void);
extern int perfmon_get_number_of_statistic_values (void);
extern UINT64 *perfmon_allocate_values (void);
extern char *perfmon_allocate_packed_values_buffer (void);
extern void perfmon_copy_values (UINT64 * src, UINT64 * dest);

#if defined (SERVER_MODE) || defined (SA_MODE)
extern void perfmon_start_watch (THREAD_ENTRY * thread_p);
extern void perfmon_stop_watch (THREAD_ENTRY * thread_p);
extern void perfmon_er_log_current_stats (THREAD_ENTRY * thread_p);
extern void perfmon_initialize_parallel_stats (THREAD_ENTRY * thread_p);
extern void perfmon_destroy_parallel_stats (THREAD_ENTRY * thread_p);
#endif /* SERVER_MODE || SA_MODE */

STATIC_INLINE bool perfmon_is_perf_tracking (void) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE bool perfmon_is_perf_tracking_and_active (int activation_flag) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE bool perfmon_is_perf_tracking_force (bool always_collect) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_add_stat (THREAD_ENTRY * thread_p, PERF_STAT_ID psid, UINT64 amount)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_add_stat_to_global (PERF_STAT_ID psid, UINT64 amount) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_add_at_offset (THREAD_ENTRY * thread_p, int offset, UINT64 amount)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_add_at_offset_to_local (THREAD_ENTRY * thread_p, int offset, UINT64 amount)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_inc_stat (THREAD_ENTRY * thread_p, PERF_STAT_ID psid) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_inc_stat_to_global (PERF_STAT_ID psid) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_set_stat (THREAD_ENTRY * thread_p, PERF_STAT_ID psid, int statval, bool check_watchers)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_set_at_offset (THREAD_ENTRY * thread_p, int offset, int statval, bool check_watchers)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_add_at_offset_to_global (int offset, UINT64 amount) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_set_stat_to_global (PERF_STAT_ID psid, int statval) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_set_at_offset_to_global (int offset, int statval) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_merge_child_stats_to_parent_stats (THREAD_ENTRY * thread_p) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_merge_parallel_stats_to_tran_stats (THREAD_ENTRY * thread_p) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_time_at_offset (THREAD_ENTRY * thread_p, int offset, UINT64 timediff)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_time_bulk_at_offset (THREAD_ENTRY * thread_p, int offset, UINT64 timediff, UINT64 count)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_time_stat (THREAD_ENTRY * thread_p, PERF_STAT_ID psid, UINT64 timediff)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE int perfmon_get_activation_flag (void) __attribute__ ((ALWAYS_INLINE));
extern char *perfmon_pack_stats (char *buf, UINT64 * stats);
extern char *perfmon_unpack_stats (char *buf, UINT64 * stats);

STATIC_INLINE void perfmon_diff_timeval (struct timeval *elapsed, struct timeval *start, struct timeval *end)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_add_timeval (struct timeval *total, struct timeval *start, struct timeval *end)
  __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_update_min_timeval (struct timeval *min, struct timeval *tv) __attribute__ ((ALWAYS_INLINE));
STATIC_INLINE void perfmon_update_max_timeval (struct timeval *max, struct timeval *tv) __attribute__ ((ALWAYS_INLINE));

#ifdef __cplusplus
/* TODO: it looks ugly now, but it should be fixed with stat tool patch */

/*
 *  Add/set stats section.
 */

/*
 * perfmon_add_stat () - Accumulate amount to statistic.
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * psid (in)     : Statistic ID.
 * amount (in)   : Amount to add.
 */
STATIC_INLINE void
perfmon_add_stat (THREAD_ENTRY * thread_p, PERF_STAT_ID psid, UINT64 amount)
{
  assert (PSTAT_BASE < psid && psid < PSTAT_COUNT);

  if (!perfmon_is_perf_tracking ())
    {
      /* No need to collect statistics since no one is interested. */
      return;
    }

  assert (pstat_Metadata[psid].valtype == PSTAT_ACCUMULATE_SINGLE_VALUE);

  /* Update statistics. */
  perfmon_add_at_offset (thread_p, pstat_Metadata[psid].start_offset, amount);
}

/*
 * perfmon_add_stat_to_global () - Accumulate amount only to global statistic.
 *
 * return    : Void.
 * psid (in)     : Statistic ID.
 * amount (in)   : Amount to add.
 */
STATIC_INLINE void
perfmon_add_stat_to_global (PERF_STAT_ID psid, UINT64 amount)
{
  assert (PSTAT_BASE < psid && psid < PSTAT_COUNT);

  if (!pstat_Global.initialized)
    {
      return;
    }

  assert (pstat_Metadata[psid].valtype == PSTAT_ACCUMULATE_SINGLE_VALUE);

  /* Update statistics. */
  perfmon_add_at_offset_to_global (pstat_Metadata[psid].start_offset, amount);
}

/*
 * perfmon_inc_stat () - Increment statistic value by 1.
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * psid (in)     : Statistic ID.
 */
STATIC_INLINE void
perfmon_inc_stat (THREAD_ENTRY * thread_p, PERF_STAT_ID psid)
{
  perfmon_add_stat (thread_p, psid, 1);
}

/*
 * perfmon_inc_stat_to_global () - Increment global statistic value by 1.
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * psid (in)     : Statistic ID.
 */
STATIC_INLINE void
perfmon_inc_stat_to_global (PERF_STAT_ID psid)
{
  perfmon_add_stat_to_global (psid, 1);
}

/*
 * perfmon_add_at_offset () - Add amount to statistic in global/local at offset.
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * offset (in)   : Offset to statistics value.
 * amount (in)   : Amount to add.
 */
STATIC_INLINE void
perfmon_add_at_offset (THREAD_ENTRY * thread_p, int offset, UINT64 amount)
{
#if defined (SERVER_MODE) || defined (SA_MODE)
  int tran_index;
#endif /* SERVER_MODE || SA_MODE */

  assert (offset >= 0 && offset < pstat_Global.n_stat_values);
  assert (pstat_Global.initialized);

  /* Update global statistic. */
  ATOMIC_INC_64 (&(pstat_Global.global_stats[offset]), amount);

#if defined (SERVER_MODE) || defined (SA_MODE)
  /* Update local statistic */
  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
  if ((tran_index >= 0 && tran_index < pstat_Global.n_trans) && pstat_Global.is_watching[tran_index])
    {
      if (thread_p != NULL && thread_p->m_uses_px_stats)
    {
      assert (thread_p->m_px_orig_thread_entry != NULL);
      if (thread_p->m_px_stats != NULL)
        {
          thread_p->m_px_stats[offset] += amount;
        }
      else
        {
          /* Add only to global_stats;  
           * need to check later if tran_stats is required in parallel thread */
          assert (!thread_p->on_trace);
        }
    }
      else
    {
      assert (pstat_Global.tran_stats[tran_index] != NULL);
      pstat_Global.tran_stats[tran_index][offset] += amount;
    }
    }
#endif /* SERVER_MODE || SA_MODE */
}

/*
 * perfmon_add_at_offset_to_local () - Add amount to statistic in local at offset.
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * offset (in)   : Offset to statistics value.
 * amount (in)   : Amount to add.
 */
STATIC_INLINE void
perfmon_add_at_offset_to_local (THREAD_ENTRY * thread_p, int offset, UINT64 amount)
{
#if defined (SERVER_MODE) || defined (SA_MODE)
  int tran_index;
#endif /* SERVER_MODE || SA_MODE */

  assert (offset >= 0 && offset < pstat_Global.n_stat_values);
  assert (pstat_Global.initialized);

#if defined (SERVER_MODE) || defined (SA_MODE)
  /* Update local statistic */
  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
  assert (tran_index >= 0 && tran_index < pstat_Global.n_trans);
  if (pstat_Global.is_watching[tran_index])
    {
      if (thread_p != NULL && thread_p->m_uses_px_stats)
    {
      assert (thread_p->m_px_orig_thread_entry != NULL);
      if (thread_p->m_px_stats != NULL)
        {
          thread_p->m_px_stats[offset] += amount;
        }
      else
        {
          /* Add only to global_stats;  
           * need to check later if tran_stats is required in parallel thread */
          assert (!thread_p->on_trace);
        }
    }
      else
    {
      assert (pstat_Global.tran_stats[tran_index] != NULL);
      pstat_Global.tran_stats[tran_index][offset] += amount;
    }
    }
#endif /* SERVER_MODE || SA_MODE */
}

/*
 * perfmon_add_at_offset_to_global () - Add amount to statistic in global
 *
 * return    : Void.
 * offset (in)   : Offset to statistics value.
 * amount (in)   : Amount to add.
 */
STATIC_INLINE void
perfmon_add_at_offset_to_global (int offset, UINT64 amount)
{
  assert (offset >= 0 && offset < pstat_Global.n_stat_values);
  assert (pstat_Global.initialized);

  /* Update global statistic. */
  ATOMIC_INC_64 (&(pstat_Global.global_stats[offset]), amount);
}

/*
 * perfmon_set_stat () - Set statistic value.
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * psid (in)     : Statistic ID.
 * statval (in)  : New statistic value.
 * always_collect (in): Flag that tells that we should always collect statistics
 */
STATIC_INLINE void
perfmon_set_stat (THREAD_ENTRY * thread_p, PERF_STAT_ID psid, int statval, bool always_collect)
{
  assert (PSTAT_BASE < psid && psid < PSTAT_COUNT);

  if (!perfmon_is_perf_tracking_force (always_collect))
    {
      /* No need to collect statistics since no one is interested. */
      return;
    }

  assert (pstat_Metadata[psid].valtype == PSTAT_PEEK_SINGLE_VALUE);

  perfmon_set_at_offset (thread_p, pstat_Metadata[psid].start_offset, statval, always_collect);
}

/*
 * perfmon_set_at_offset () - Set statistic value in global/local at offset.
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * offset (in)   : Offset to statistic value.
 * statval (in)  : New statistic value.
 * always_collect (in): Flag that tells that we should always collect statistics
 */
STATIC_INLINE void
perfmon_set_at_offset (THREAD_ENTRY * thread_p, int offset, int statval, bool always_collect)
{
#if defined (SERVER_MODE) || defined (SA_MODE)
  int tran_index;
#endif /* SERVER_MODE || SA_MODE */

  assert (offset >= 0 && offset < pstat_Global.n_stat_values);
  assert (pstat_Global.initialized);

  /* Update global statistic. */
  ATOMIC_TAS_64 (&(pstat_Global.global_stats[offset]), statval);

#if defined (SERVER_MODE) || defined (SA_MODE)
  /* Update local statistic */
  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
  assert (tran_index >= 0 && tran_index < pstat_Global.n_trans);
  if (always_collect || pstat_Global.is_watching[tran_index])
    {
      assert (pstat_Global.tran_stats[tran_index] != NULL);
      pstat_Global.tran_stats[tran_index][offset] = statval;
    }
#endif /* SERVER_MODE || SA_MODE */
}

/*
 * perfmon_set_stat_to_global () - Set statistic value only for global statistics
 *
 * return    : Void.
 * psid (in)     : Statistic ID.
 * statval (in)  : New statistic value.
 */
STATIC_INLINE void
perfmon_set_stat_to_global (PERF_STAT_ID psid, int statval)
{
  assert (PSTAT_BASE < psid && psid < PSTAT_COUNT);

  if (!pstat_Global.initialized)
    {
      return;
    }

  assert (pstat_Metadata[psid].valtype == PSTAT_PEEK_SINGLE_VALUE);

  perfmon_set_at_offset_to_global (pstat_Metadata[psid].start_offset, statval);
}

/*
 * perfmon_set_at_offset_to_global () - Set statistic value in global offset.
 *
 * return    : Void.
 * offset (in)   : Offset to statistic value.
 * statval (in)  : New statistic value.
 */
STATIC_INLINE void
perfmon_set_at_offset_to_global (int offset, int statval)
{
  assert (offset >= 0 && offset < pstat_Global.n_stat_values);
  assert (pstat_Global.initialized);

  /* Update global statistic. */
  ATOMIC_TAS_64 (&(pstat_Global.global_stats[offset]), statval);
}

/*
 * perfmon_merge_child_stats_to_parent_stats () - Merge child statistics to parent statistics.
 *
 * return    : Void.
 * thread_p (in) : Child thread entry.
 */
STATIC_INLINE void
perfmon_merge_child_stats_to_parent_stats (THREAD_ENTRY * thread_p)
{
#if defined (SERVER_MODE)
  assert (thread_p != NULL);

  if (thread_p->m_px_stats == NULL)
    {
      assert (false);
      return;
    }

  THREAD_ENTRY *main_thread_p = thread_get_main_thread (thread_p);

  if (main_thread_p == thread_p)
    {
      return;
    }

  /*
   * m_px_stats should be NULL.
   * perfmon_initialize_parallel_stats is a temporary safeguard.
   * TODO: replace with assert().
   */
  if (main_thread_p->m_px_stats == NULL)
    {
      perfmon_initialize_parallel_stats (main_thread_p);
    }

  /* immutable */
  static const int offsets[] = {
    pstat_Metadata[PSTAT_PB_NUM_FETCHES].start_offset,
    pstat_Metadata[PSTAT_PB_NUM_IOREADS].start_offset,
    pstat_Metadata[PSTAT_PB_PAGE_FIX_ACQUIRE_TIME_10USEC].start_offset
  };

  const int stats_cnt = sizeof (offsets) / sizeof (offsets[0]);

  pthread_mutex_lock (&(main_thread_p->m_px_stats_mutex));
  for (int stats_index = 0; stats_index < stats_cnt; stats_index++)
    {
      const int offset = offsets[stats_index];
      main_thread_p->m_px_stats[offset] += thread_p->m_px_stats[offset];
      thread_p->m_px_stats[offset] = 0;
    }
  pthread_mutex_unlock (&(main_thread_p->m_px_stats_mutex));
#endif /* SERVER_MODE */
}

/*
 * perfmon_merge_parallel_stats_to_tran_stats () - Merge parallel statistics to transaction statistics.
 *
 * return    : Void.
 * thread_p (in) : Main thread entry.
 */
STATIC_INLINE void
perfmon_merge_parallel_stats_to_tran_stats (THREAD_ENTRY * thread_p)
{
#if defined (SERVER_MODE)
  assert (thread_p != NULL);

  if (thread_p->m_px_stats == NULL)
    {
      assert (false);
      return;
    }

  if (thread_p->m_uses_px_stats)
    {
      return;
    }

  THREAD_ENTRY *main_thread_p = thread_get_main_thread (thread_p);

  /* Skip if not the top-level parent. */
  if (main_thread_p != thread_p)
    {
      return;
    }

  /* immutable */
  static const int offsets[] = {
    pstat_Metadata[PSTAT_PB_NUM_FETCHES].start_offset,
    pstat_Metadata[PSTAT_PB_NUM_IOREADS].start_offset,
    pstat_Metadata[PSTAT_PB_PAGE_FIX_ACQUIRE_TIME_10USEC].start_offset
  };

  const int stats_cnt = sizeof (offsets) / sizeof (offsets[0]);

  for (int stats_index = 0; stats_index < stats_cnt; stats_index++)
    {
      const int offset = offsets[stats_index];
      perfmon_add_at_offset_to_local (thread_p, offset, thread_p->m_px_stats[offset]);
      thread_p->m_px_stats[offset] = 0;
    }
#endif /* SERVER_MODE */
}

/*
 * perfmon_time_stat () - Register statistic timer value. Counter, total time and maximum time are updated.
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * psid (in)     : Statistic ID.
 * timediff (in) : Time difference to register.
 */
STATIC_INLINE void
perfmon_time_stat (THREAD_ENTRY * thread_p, PERF_STAT_ID psid, UINT64 timediff)
{
  assert (pstat_Global.initialized);
  assert (PSTAT_BASE < psid && psid < PSTAT_COUNT);

  assert (pstat_Metadata[psid].valtype == PSTAT_COUNTER_TIMER_VALUE);

  perfmon_time_at_offset (thread_p, pstat_Metadata[psid].start_offset, timediff);
}

/*
 * perfmon_time_at_offset () - Register timer statistics in global/local at offset.
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * offset (in)   : Offset to timer values.
 * timediff (in) : Time difference to add to timer.
 *
 * NOTE: There will be three values modified: counter, total time and max time.
 */
STATIC_INLINE void
perfmon_time_at_offset (THREAD_ENTRY * thread_p, int offset, UINT64 timediff)
{
  /* Update global statistics */
  UINT64 *statvalp = NULL;
  UINT64 max_time;
#if defined (SERVER_MODE) || defined (SA_MODE)
  int tran_index;
#endif /* SERVER_MODE || SA_MODE */

  assert (offset >= 0 && offset < pstat_Global.n_stat_values);
  assert (pstat_Global.initialized);

  /* Update global statistics. */
  statvalp = pstat_Global.global_stats + offset;
  ATOMIC_INC_64 (PSTAT_COUNTER_TIMER_COUNT_VALUE (statvalp), 1ULL);
  ATOMIC_INC_64 (PSTAT_COUNTER_TIMER_TOTAL_TIME_VALUE (statvalp), timediff);
  do
    {
      max_time = ATOMIC_LOAD_64 (PSTAT_COUNTER_TIMER_MAX_TIME_VALUE (statvalp));
      if (max_time >= timediff)
    {
      /* No need to change max_time. */
      break;
    }
    }
  while (!ATOMIC_CAS_64 (PSTAT_COUNTER_TIMER_MAX_TIME_VALUE (statvalp), max_time, timediff));
  /* Average is not computed here. */

#if defined (SERVER_MODE) || defined (SA_MODE)
  /* Update local statistic */
  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
  assert (tran_index >= 0 && tran_index < pstat_Global.n_trans);
  if (pstat_Global.is_watching[tran_index])
    {
      assert (pstat_Global.tran_stats[tran_index] != NULL);
      statvalp = pstat_Global.tran_stats[tran_index] + offset;
      (*PSTAT_COUNTER_TIMER_COUNT_VALUE (statvalp)) += 1;
      (*PSTAT_COUNTER_TIMER_TOTAL_TIME_VALUE (statvalp)) += timediff;
      max_time = *PSTAT_COUNTER_TIMER_MAX_TIME_VALUE (statvalp);
      if (max_time < timediff)
    {
      (*PSTAT_COUNTER_TIMER_MAX_TIME_VALUE (statvalp)) = timediff;
    }
    }
#endif /* SERVER_MODE || SA_MODE */
}

/*
 * perfmon_time_bulk_stat () - Register statistic timer value. Counter, total time and maximum time are updated.
 *                             Used to count and time multiple units at once (as opposed to perfmon_time_stat which
 *                             increments count by one).
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * psid (in)     : Statistic ID.
 * timediff (in) : Time difference to register.
 * count (in)    : Unit count.
 */
STATIC_INLINE void
perfmon_time_bulk_stat (THREAD_ENTRY * thread_p, PERF_STAT_ID psid, UINT64 timediff, UINT64 count)
{
  assert (pstat_Global.initialized);
  assert (PSTAT_BASE < psid && psid < PSTAT_COUNT);

  assert (pstat_Metadata[psid].valtype == PSTAT_COUNTER_TIMER_VALUE);

  perfmon_time_bulk_at_offset (thread_p, pstat_Metadata[psid].start_offset, timediff, count);
}

/*
 * perfmon_time_bulk_at_offset () - Register timer statistics in global/local at offset for multiple units at once.
 *
 * return    : Void.
 * thread_p (in) : Thread entry.
 * offset (in)   : Offset to timer values.
 * timediff (in) : Time difference to add to timer.
 * count (in)    : Unit count timed at once
 *
 * NOTE: There will be three values modified: counter, total time and max time.
 */
STATIC_INLINE void
perfmon_time_bulk_at_offset (THREAD_ENTRY * thread_p, int offset, UINT64 timediff, UINT64 count)
{
  /* Update global statistics */
  UINT64 *statvalp = NULL;
  UINT64 max_time;
  UINT64 time_per_unit;
#if defined (SERVER_MODE) || defined (SA_MODE)
  int tran_index;
#endif /* SERVER_MODE || SA_MODE */

  assert (offset >= 0 && offset < pstat_Global.n_stat_values);
  assert (pstat_Global.initialized);

  if (count == 0)
    {
      return;
    }
  time_per_unit = timediff / count;

  /* Update global statistics. */
  statvalp = pstat_Global.global_stats + offset;
  ATOMIC_INC_64 (PSTAT_COUNTER_TIMER_COUNT_VALUE (statvalp), count);
  ATOMIC_INC_64 (PSTAT_COUNTER_TIMER_TOTAL_TIME_VALUE (statvalp), timediff);
  do
    {
      max_time = ATOMIC_LOAD_64 (PSTAT_COUNTER_TIMER_MAX_TIME_VALUE (statvalp));
      if (max_time >= time_per_unit)
    {
      /* No need to change max_time. */
      break;
    }
    }
  while (!ATOMIC_CAS_64 (PSTAT_COUNTER_TIMER_MAX_TIME_VALUE (statvalp), max_time, time_per_unit));
  /* Average is not computed here. */

#if defined (SERVER_MODE) || defined (SA_MODE)
  /* Update local statistic */
  tran_index = LOG_FIND_THREAD_TRAN_INDEX (thread_p);
  assert (tran_index >= 0 && tran_index < pstat_Global.n_trans);
  if (pstat_Global.is_watching[tran_index])
    {
      assert (pstat_Global.tran_stats[tran_index] != NULL);
      statvalp = pstat_Global.tran_stats[tran_index] + offset;
      (*PSTAT_COUNTER_TIMER_COUNT_VALUE (statvalp)) += count;
      (*PSTAT_COUNTER_TIMER_TOTAL_TIME_VALUE (statvalp)) += timediff;
      max_time = *PSTAT_COUNTER_TIMER_MAX_TIME_VALUE (statvalp);
      if (max_time < time_per_unit)
    {
      (*PSTAT_COUNTER_TIMER_MAX_TIME_VALUE (statvalp)) = time_per_unit;
    }
    }
#endif /* SERVER_MODE || SA_MODE */
}

/*
 * perfmon_get_activation_flag - Get the activation flag
 *
 * return: int
 */
STATIC_INLINE int
perfmon_get_activation_flag (void)
{
  return pstat_Global.activation_flag;
}

/*
 * perfmon_is_perf_tracking () - Returns true if there are active threads
 *
 * return    : true or false
 */
STATIC_INLINE bool
perfmon_is_perf_tracking (void)
{
  return pstat_Global.initialized && pstat_Global.n_watchers > 0;
}

/*
 * perfmon_is_perf_tracking_and_active () - Returns true if there are active threads
 *                      and the activation_flag of the extended statistic is activated
 *
 * return           : true or false
 * activation_flag (in) : activation flag for extended statistic
 *
 */
STATIC_INLINE bool
perfmon_is_perf_tracking_and_active (int activation_flag)
{
  return perfmon_is_perf_tracking () && (activation_flag & pstat_Global.activation_flag);
}


/*
 * perfmon_is_perf_tracking_force () - Skips the check for active threads if the always_collect
 *                     flag is set to true
 *
 * return           : true or false
 * always_collect (in)  : flag that tells that we should always collect statistics
 *
 */
STATIC_INLINE bool
perfmon_is_perf_tracking_force (bool always_collect)
{
  return pstat_Global.initialized && (always_collect || pstat_Global.n_watchers > 0);
}

#endif /* __cplusplus */

#if defined(CS_MODE) || defined(SA_MODE)
/* Client execution statistic structure */
typedef struct perfmon_client_stat_info PERFMON_CLIENT_STAT_INFO;
struct perfmon_client_stat_info
{
  time_t cpu_start_usr_time;
  time_t cpu_start_sys_time;
  time_t elapsed_start_time;
  UINT64 *base_server_stats;
  UINT64 *current_server_stats;
  UINT64 *old_global_stats;
  UINT64 *current_global_stats;
};

extern bool perfmon_Iscollecting_stats;

extern int perfmon_start_stats (bool for_all_trans);
extern int perfmon_stop_stats (void);
extern void perfmon_reset_stats (void);
extern int perfmon_print_stats (FILE * stream);
extern int perfmon_print_global_stats (FILE * stream, bool cumulative, const char *substr);
extern int perfmon_get_stats (void);
extern int perfmon_get_global_stats (void);
#endif /* CS_MODE || SA_MODE */

STATIC_INLINE void
perfmon_diff_timeval (struct timeval *elapsed, struct timeval *start, struct timeval *end)
{
  elapsed->tv_sec = end->tv_sec - start->tv_sec;
  elapsed->tv_usec = end->tv_usec - start->tv_usec;

  if (elapsed->tv_usec < 0)
    {
      elapsed->tv_sec--;
      elapsed->tv_usec += 1000000;
    }
}

STATIC_INLINE void
perfmon_add_timeval (struct timeval *total, struct timeval *start, struct timeval *end)
{
  if (end->tv_usec - start->tv_usec >= 0)
    {
      total->tv_usec += end->tv_usec - start->tv_usec;
      total->tv_sec += end->tv_sec - start->tv_sec;
    }
  else
    {
      total->tv_usec += 1000000 + (end->tv_usec - start->tv_usec);
      total->tv_sec += end->tv_sec - start->tv_sec - 1;
    }

  total->tv_sec += total->tv_usec / 1000000;
  total->tv_usec %= 1000000;
}

STATIC_INLINE void
perfmon_update_min_timeval (struct timeval *min, struct timeval *tv)
{
  assert (min != NULL);
  assert (tv != NULL);

  if (tv->tv_sec < min->tv_sec || (tv->tv_sec == min->tv_sec && tv->tv_usec < min->tv_usec))
    {
      *min = *tv;
    }
}

STATIC_INLINE void
perfmon_update_max_timeval (struct timeval *max, struct timeval *tv)
{
  assert (max != NULL);
  assert (tv != NULL);

  if (tv->tv_sec > max->tv_sec || (tv->tv_sec == max->tv_sec && tv->tv_usec > max->tv_usec))
    {
      *max = *tv;
    }
}

#define TO_MSEC(elapsed) \
  ((int)(((elapsed).tv_sec * 1000) + (int) ((elapsed).tv_usec / 1000)))

#if defined (EnableThreadMonitoring)
#define MONITOR_WAITING_THREAD(elapsed) \
    (prm_get_integer_value (PRM_ID_MNT_WAITING_THREAD) > 0 \
     && ((elapsed).tv_sec * 1000 + (elapsed).tv_usec / 1000) \
         > prm_get_integer_value (PRM_ID_MNT_WAITING_THREAD))
#else
#define MONITOR_WAITING_THREAD(elapsed) (0)
#endif

#if defined (SERVER_MODE) || defined (SA_MODE)
typedef struct perf_utime_tracker PERF_UTIME_TRACKER;
struct perf_utime_tracker
{
  bool is_perf_tracking;
  TSC_TICKS start_tick;
  TSC_TICKS end_tick;
};
#define PERF_UTIME_TRACKER_INITIALIZER { false, {0}, {0} }
#define PERF_UTIME_TRACKER_START(thread_p, track) \
  do \
    { \
      (track)->is_perf_tracking = perfmon_is_perf_tracking (); \
      if ((track)->is_perf_tracking) tsc_getticks (&(track)->start_tick); \
    } \
  while (false)
/* Time trackers - perfmon_time_stat is called. */
#define PERF_UTIME_TRACKER_TIME(thread_p, track, psid) \
  do \
    { \
      if (!(track)->is_perf_tracking) break; \
      tsc_getticks (&(track)->end_tick); \
      perfmon_time_stat (thread_p, psid, tsc_elapsed_utime ((track)->end_tick,  (track)->start_tick)); \
    } \
  while (false)
#define PERF_UTIME_TRACKER_TIME_AND_RESTART(thread_p, track, psid) \
  do \
    { \
      if (!(track)->is_perf_tracking) break; \
      tsc_getticks (&(track)->end_tick); \
      perfmon_time_stat (thread_p, psid, tsc_elapsed_utime ((track)->end_tick,  (track)->start_tick)); \
      (track)->start_tick = (track)->end_tick; \
    } \
  while (false)
/* Bulk time trackers - perfmon_time_bulk_stat is called. */
#define PERF_UTIME_TRACKER_BULK_TIME(thread_p, track, psid, count) \
  do \
    { \
      if (!(track)->is_perf_tracking) break; \
      tsc_getticks (&(track)->end_tick); \
      perfmon_time_bulk_stat (thread_p, psid, tsc_elapsed_utime ((track)->end_tick, (track)->start_tick), count); \
    } \
  while (false)
#define PERF_UTIME_TRACKER_BULK_TIME_AND_RESTART(thread_p, track, psid, count) \
  do \
    { \
      if (!(track)->is_perf_tracking) break; \
      tsc_getticks (&(track)->end_tick); \
      perfmon_time_bulk, stat (thread_p, psid, tsc_elapsed_utime ((track)->end_tick,  (track)->start_tick), count); \
      (track)->start_tick = (track)->end_tick; \
    } \
  while (false)

/* Time accumulators only - perfmon_add_stat is called. */
/* todo: PERF_UTIME_TRACKER_ADD_TIME is never used and PERF_UTIME_TRACKER_ADD_TIME_AND_RESTART is similar to
 * PERF_UTIME_TRACKER_TIME_AND_RESTART. they were supposed to collect just timers, but now have changed */
#define PERF_UTIME_TRACKER_ADD_TIME(thread_p, track, psid) \
  do \
    { \
      if (!(track)->is_perf_tracking) break; \
      tsc_getticks (&(track)->end_tick); \
      perfmon_time_stat (thread_p, psid, (int) tsc_elapsed_utime ((track)->end_tick,  (track)->start_tick)); \
    } \
  while (false)
#define PERF_UTIME_TRACKER_ADD_TIME_AND_RESTART(thread_p, track, psid) \
  do \
    { \
      if (!(track)->is_perf_tracking) break; \
      tsc_getticks (&(track)->end_tick); \
      perfmon_time_stat (thread_p, psid, (int) tsc_elapsed_utime ((track)->end_tick,  (track)->start_tick)); \
      (track)->start_tick = (track)->end_tick; \
    } \
  while (false)
#endif /* defined (SERVER_MODE) || defined (SA_MODE) */

#if defined(SERVER_MODE) || defined (SA_MODE)
/*
 * Statistics at file io level
 */
extern bool perfmon_server_is_stats_on (THREAD_ENTRY * thread_p);

extern UINT64 perfmon_get_from_statistic (THREAD_ENTRY * thread_p, const int statistic_id);

extern void perfmon_lk_waited_time_on_objects (THREAD_ENTRY * thread_p, int lock_mode, UINT64 amount);

extern UINT64 perfmon_get_stats_and_clear (THREAD_ENTRY * thread_p, const char *stat_name);

extern void perfmon_pbx_fix (THREAD_ENTRY * thread_p, int page_type, int page_found_mode, int latch_mode,
                 int cond_type);
extern void perfmon_pbx_promote (THREAD_ENTRY * thread_p, int page_type, int promote_cond, int holder_latch,
                 int success, UINT64 amount);
extern void perfmon_pbx_unfix (THREAD_ENTRY * thread_p, int page_type, int buf_dirty, int dirtied_by_holder,
                   int holder_latch);
extern void perfmon_pbx_lock_acquire_time (THREAD_ENTRY * thread_p, int page_type, int page_found_mode, int latch_mode,
                       int cond_type, UINT64 amount);
extern void perfmon_pbx_hold_acquire_time (THREAD_ENTRY * thread_p, int page_type, int page_found_mode, int latch_mode,
                       UINT64 amount);
extern void perfmon_pbx_fix_acquire_time (THREAD_ENTRY * thread_p, int page_type, int page_found_mode, int latch_mode,
                      int cond_type, UINT64 amount);
extern void perfmon_mvcc_snapshot (THREAD_ENTRY * thread_p, int snapshot, int rec_type, int visibility);
extern void perfmon_db_flushed_block_volumes (THREAD_ENTRY * thread_p, int num_volumes);

#endif /* SERVER_MODE || SA_MODE */

#endif /* _PERF_MONITOR_H_ */