509 lines
13 KiB
C++
509 lines
13 KiB
C++
/*
|
|
* Copyright (c) 2023 Huawei Technologies Co.,Ltd.
|
|
*
|
|
* openGauss is licensed under Mulan PSL v2.
|
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
* You may obtain a copy of Mulan PSL v2 at:
|
|
*
|
|
* http://license.coscl.org.cn/MulanPSL2
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
* See the Mulan PSL v2 for more details.
|
|
* ---------------------------------------------------------------------------------------
|
|
*
|
|
* IDENTIFICATION
|
|
* src/include/og_record_time.h
|
|
*
|
|
* NOTES
|
|
* Some of this code used to record sql execute time.
|
|
*
|
|
* -------------------------------------------------------------------------
|
|
*/
|
|
|
|
#ifndef OG_RECORD_TIME_H
|
|
#define OG_RECORD_TIME_H
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "og_record_time_rely.h"
|
|
#include "knl/knl_session.h"
|
|
|
|
typedef enum TimeInfoType {
|
|
DB_TIME = 0, /*total elapsed time while dealing user command.*/
|
|
CPU_TIME, /*total cpu time used while dealing user command.*/
|
|
|
|
/*statistics of specific execution stage.*/
|
|
EXECUTION_TIME, /*total elapsed time of execution stage.*/
|
|
PARSE_TIME, /*total elapsed time of parse stage.*/
|
|
PLAN_TIME, /*total elapsed time of plan stage.*/
|
|
REWRITE_TIME, /*total elapsed time of rewrite stage.*/
|
|
|
|
/*statistics for plpgsql especially*/
|
|
PL_EXECUTION_TIME, /*total elapsed time of plpgsql exection.*/
|
|
PL_COMPILATION_TIME, /*total elapsed time of plpgsql compilation.*/
|
|
|
|
NET_SEND_TIME,
|
|
DATA_IO_TIME,
|
|
SRT1_Q,
|
|
SRT2_SIMPLE_QUERY,
|
|
SRT3_ANALYZE_REWRITE,
|
|
SRT4_PLAN_QUERY,
|
|
SRT5_LIGHT_QUERY,
|
|
SRT6_P,
|
|
SRT7_B,
|
|
SRT8_E,
|
|
SRT9_D,
|
|
SRT10_S,
|
|
SRT11_C,
|
|
SRT12_U,
|
|
SRT13_BEFORE_QUERY,
|
|
SRT14_AFTER_QUERY,
|
|
RTT_UNKNOWN,
|
|
TOTAL_TIME_INFO_TYPES
|
|
} TimeInfoType;
|
|
|
|
// some procedure use old postion, so we define this.
|
|
const TimeInfoType TOTAL_TIME_INFO_TYPES_P1 = SRT1_Q;
|
|
|
|
typedef enum NetInfoType {
|
|
NET_SEND_TIMES,
|
|
NET_SEND_N_CALLS,
|
|
NET_SEND_SIZE,
|
|
|
|
NET_RECV_TIMES,
|
|
NET_RECV_N_CALLS,
|
|
NET_RECV_SIZE,
|
|
|
|
NET_STREAM_SEND_TIMES,
|
|
NET_STREAM_SEND_N_CALLS,
|
|
NET_STREAM_SEND_SIZE,
|
|
|
|
NET_STREAM_RECV_TIMES,
|
|
NET_STREAM_RECV_N_CALLS,
|
|
NET_STREAM_RECV_SIZE,
|
|
|
|
TOTAL_NET_INFO_TYPES
|
|
} NetInfoType;
|
|
|
|
// this for easy add new record type for debug.
|
|
typedef enum SelfRecordType {
|
|
SRT_ALL
|
|
} SelfRecordType;
|
|
// the type of record time
|
|
typedef enum RecordTimeType {
|
|
TIME_INFO = 0,
|
|
NET_INFO,
|
|
SELF_INFO
|
|
} RecordTimeType;
|
|
|
|
const int TOTAL_RECORD_TYPES = TOTAL_TIME_INFO_TYPES + TOTAL_NET_INFO_TYPES + SRT_ALL;
|
|
// if left record time more than this, will print flag info.
|
|
const int64 DEFAULT_DB_TIME_BASELINE = 10; //ms
|
|
// the OgTimeDataStack depth
|
|
const int DEFAULT_TIME_DATA_STACK_DEPTH = 100;
|
|
// the default format length
|
|
const int DEFAULT_FORMAT_LENGTH = 1024;
|
|
const int INVALID_DEPTH = -1;
|
|
// the type of record.
|
|
class RecordType;
|
|
// the time base slice of type
|
|
class OgTimeDataVo;
|
|
// the time base vo format helper
|
|
class OgTimeDataFormatHelper;
|
|
// the time data vo stack
|
|
class OgTimeDataStack;
|
|
// the stat statics class
|
|
class OgRecordStat;
|
|
|
|
#define FORMAT_VO(vo) (OgTimeDataFormatHelper().format(vo))
|
|
|
|
#ifdef _cplusplus
|
|
extern "C" {
|
|
#endif
|
|
extern const char* TimeInfoTypeName[];
|
|
/**
|
|
* Get record stat instance, must be already init session before use it!
|
|
* */
|
|
OgRecordStat* og_get_record_stat();
|
|
|
|
/**
|
|
* Clean RecordState instance memory.
|
|
* @param code error code
|
|
* @param arg the input arg
|
|
*/
|
|
void og_record_time_cleanup(int code, Datum arg);
|
|
|
|
/**
|
|
* Reinit time record stat after set_long_jump
|
|
*/
|
|
void og_record_time_reinit();
|
|
|
|
/**
|
|
* Start time record, this will trigger DB_TIME begin event report.
|
|
* @return true if first started else already startted.
|
|
*/
|
|
bool og_time_record_start();
|
|
|
|
/**
|
|
* Stop time record, this will trigger DB_TIME end event report
|
|
* @return true if success stopped else already stopped.
|
|
*/
|
|
bool og_time_record_end();
|
|
|
|
/**
|
|
* Get if time record startted.
|
|
* @return true if stattted.
|
|
*/
|
|
bool og_time_record_is_started();
|
|
|
|
/**
|
|
* Get unique event id, id will continuously growing in a single statistic.
|
|
* @return the new event it.
|
|
*/
|
|
int64 og_get_time_unique_id();
|
|
|
|
/**
|
|
* Convert record_time to str.
|
|
* @param record_type the record type.
|
|
* @return const char* desc
|
|
*/
|
|
const char* og_record_time_type_str(const RecordType& record_type);
|
|
|
|
/**
|
|
* Convert int pos to str
|
|
* @param pos the postion of record type
|
|
* @return const char* desc
|
|
*/
|
|
const char* og_record_time_type_str(int pos);
|
|
|
|
#ifdef _cplusplus
|
|
}
|
|
#endif
|
|
|
|
class RecordType {
|
|
public:
|
|
explicit RecordType();
|
|
explicit RecordType(TimeInfoType time_info_type);
|
|
explicit RecordType(SelfRecordType self_typ);
|
|
explicit RecordType(NetInfoType net_info_type, ssize_t str_len);
|
|
/**
|
|
* Get which type of record it is. match the construct.
|
|
* @return
|
|
*/
|
|
RecordTimeType get_record_time_type() const;
|
|
|
|
/**
|
|
* The enum type to int.
|
|
* @return the enum type order.
|
|
*/
|
|
int get_type_code() const;
|
|
|
|
/**
|
|
* Only use in NET_INFO_TYPE.
|
|
* @return get the send net size len.
|
|
*/
|
|
ssize_t get_str_len() const;
|
|
|
|
/**
|
|
* Match the RecordTimeType split postion.
|
|
* @return matched RecordTimeType base pos.
|
|
*/
|
|
int get_init_pos() const;
|
|
|
|
/**
|
|
* Match the `og_record_time_type_str(int pos);` pos
|
|
* @return the pos of time_type_str
|
|
*/
|
|
int position() const;
|
|
|
|
/**
|
|
* Is the DB_TIME type. DB_TIME can't be trigger by user.
|
|
* @return true if current if DB_TIME event
|
|
*/
|
|
bool is_root_type() const;
|
|
|
|
bool operator==(TimeInfoType time_type) const;
|
|
bool operator!=(TimeInfoType time_type) const;
|
|
bool operator==(NetInfoType net_type) const;
|
|
bool operator!=(NetInfoType net_type) const;
|
|
bool operator==(SelfRecordType self_type) const;
|
|
bool operator!=(SelfRecordType self_type) const;
|
|
private:
|
|
RecordTimeType rtt_type;
|
|
int type_code;
|
|
ssize_t str_len;
|
|
};
|
|
|
|
class OgTimeDataVo {
|
|
public:
|
|
explicit OgTimeDataVo(): begin(0), end(0), depth(INVALID_DEPTH)
|
|
, record_type(RTT_UNKNOWN), other_cost(0), id(og_get_time_unique_id()) {}
|
|
explicit OgTimeDataVo(const RecordType& cur_record_type): begin(0), end(0), depth(INVALID_DEPTH)
|
|
, record_type(cur_record_type), other_cost(0), id(og_get_time_unique_id()) {}
|
|
|
|
/**
|
|
* Get this stage total time.
|
|
* @return total record time.
|
|
*/
|
|
int64 total() const
|
|
{
|
|
return end - begin;
|
|
}
|
|
|
|
/**
|
|
* Get this stage real time. sub child stage.
|
|
* @return
|
|
*/
|
|
int64 cost() const
|
|
{
|
|
return total() - other_cost;
|
|
}
|
|
|
|
/**
|
|
* Update child stage cost.
|
|
* @param cost
|
|
*/
|
|
void update_other_cost(int64 cost) {
|
|
this->other_cost += cost;
|
|
}
|
|
|
|
bool operator==(const OgTimeDataVo& compare) const {
|
|
return this->id == compare.id;
|
|
}
|
|
|
|
bool operator!=(const OgTimeDataVo& compare) const {
|
|
return !(*this == compare);
|
|
}
|
|
// NOTICE: we will push this class to stack(some std::stack use this to create new instance),
|
|
// so must implementation this operator.
|
|
OgTimeDataVo& operator=(const OgTimeDataVo& vo)
|
|
{
|
|
if (this != &vo) {
|
|
this->begin = vo.begin;
|
|
this->end = vo.end;
|
|
this->depth = vo.depth;
|
|
this->record_type = vo.record_type;
|
|
this->other_cost = vo.other_cost;
|
|
this->id = vo.id;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
public:
|
|
int64 begin;
|
|
int64 end;
|
|
int depth;
|
|
RecordType record_type;
|
|
int64 other_cost;
|
|
int64 id;
|
|
};
|
|
|
|
class OgTimeDataFormatHelper {
|
|
public:
|
|
const char* format(const OgTimeDataVo& vo);
|
|
private:
|
|
char format_str[DEFAULT_FORMAT_LENGTH];
|
|
};
|
|
|
|
class OgTimeDataStack {
|
|
public:
|
|
OgTimeDataStack(): cur_pos(-1) {}
|
|
OgTimeDataVo& top();
|
|
const OgTimeDataVo& top() const;
|
|
bool push(const OgTimeDataVo& vo);
|
|
void pop();
|
|
bool empty() const;
|
|
size_t size() const;
|
|
void reset();
|
|
private:
|
|
int cur_pos;
|
|
OgTimeDataVo data_list[DEFAULT_TIME_DATA_STACK_DEPTH];
|
|
};
|
|
|
|
class OgRecordOperator {
|
|
public:
|
|
/* You must be careful when auto_record = false, it means you need ensure enter/exit pair called!
|
|
* The only situation is in loop, like in timeRecordStart/End.
|
|
* if call stack not match, some time record will discard until `OgRecordStat.reset` is called!
|
|
* We encourage this approach: OgRecordOperator _local_opt(TimeInfoType);
|
|
*/
|
|
explicit OgRecordOperator(bool auto_record);
|
|
// `NOTICE`: only TimeInfoType will record time, NetInfoType time will calculate for parent TimeInfoType stage.
|
|
// SelfRecordType only for add new stage for debug.
|
|
explicit OgRecordOperator(TimeInfoType time_info_type);
|
|
explicit OgRecordOperator(NetInfoType net_info_type);
|
|
explicit OgRecordOperator(SelfRecordType self_type);
|
|
explicit OgRecordOperator(bool auto_record, NetInfoType net_type);
|
|
explicit OgRecordOperator(bool auto_record, TimeInfoType time_type);
|
|
explicit OgRecordOperator(bool auto_record, SelfRecordType self_type);
|
|
virtual ~OgRecordOperator();
|
|
void enter(TimeInfoType time_type=RTT_UNKNOWN);
|
|
void enter(NetInfoType net_type);
|
|
void enter(const RecordType& record_type);
|
|
void exit(TimeInfoType time_info_type=RTT_UNKNOWN);
|
|
void exit(NetInfoType net_type, ssize_t str_len);
|
|
void exit(const RecordType& record_type);
|
|
|
|
/**
|
|
* Only TIME_INFO_TYPE will record time. this only called after exit() to report new record again.
|
|
* @param net_type NET_INTO_TYPE type
|
|
* @param str_len the send size
|
|
*/
|
|
void report_duplicate(NetInfoType net_type, ssize_t str_len);
|
|
|
|
/**
|
|
* Get current record id.
|
|
* @return
|
|
*/
|
|
int64 get_record_id() const;
|
|
|
|
/**
|
|
* update new record id for reuse.
|
|
*/
|
|
void update_record_id();
|
|
|
|
/**
|
|
* If enable report stage event. if record not start or `time_record_level` != 0 , this will false.
|
|
* @return true if need report.
|
|
*/
|
|
bool report_enable() const;
|
|
private:
|
|
void init(bool auto_record, const RecordType& record_type);
|
|
private:
|
|
OgTimeDataVo base_record;
|
|
bool auto_record;
|
|
};
|
|
|
|
class OgRecordStat : public BaseObject {
|
|
public:
|
|
/**
|
|
* Bind old stat memory of local_time_info and loca_net_info
|
|
* @param local_time_info the TimeInfoType memory
|
|
* @param loca_net_info the NetInfoType memory
|
|
*/
|
|
OgRecordStat(int64* local_time_info, uint64* loca_net_info);
|
|
virtual ~OgRecordStat();
|
|
/**
|
|
* This used by DELETE_EX macro
|
|
*/
|
|
void Destroy();
|
|
|
|
/**
|
|
* Reset this instance.
|
|
*/
|
|
void reset();
|
|
|
|
/**
|
|
* Reinit after long jump
|
|
*/
|
|
void reinit();
|
|
|
|
/**
|
|
* Process stage event from `OgRecordOperator.enter`.
|
|
* @param data_record the record
|
|
*/
|
|
void report_start(const OgTimeDataVo& data_record);
|
|
|
|
/**
|
|
* Process stage event from `OgRecordOperator.exit`.
|
|
* @param record the record
|
|
*/
|
|
void report_end(const OgTimeDataVo& record);
|
|
|
|
/**
|
|
* Process start record time. this will trigger DB_TIME stage event.
|
|
* @return true if first startted.
|
|
*/
|
|
bool start_first_record_opt();
|
|
|
|
/**
|
|
* Process stop record time. this will trigger DB_TIME stage event.
|
|
* @return true if first stopped.
|
|
*/
|
|
bool free_first_record_opt();
|
|
|
|
/**
|
|
* Get the stage record time.
|
|
* @param type_info the stage
|
|
* @return record time.
|
|
*/
|
|
const int64 get_record_times(TimeInfoType type_info) const;
|
|
|
|
/**
|
|
* Get the DB_TIME stage record time.
|
|
* @return the DB_TIME stage time.
|
|
*/
|
|
const int64 get_db_time() const;
|
|
|
|
/**
|
|
* The root PgDataTimeVo instance, it's child_cost is equal DB_TIME stage.
|
|
* @return the root PgDataTimeVo instance.
|
|
*/
|
|
const OgTimeDataVo& get_root_time_data_vo() const;
|
|
|
|
/**
|
|
* Get if already start record.
|
|
* @return true if already startted.
|
|
*/
|
|
bool already_start() const;
|
|
|
|
// only for NetInfoType report.
|
|
void report_duplicate(OgTimeDataVo& record);
|
|
|
|
/**
|
|
* Incr record depth. eveny new report stage will increment it.
|
|
* @return current depth
|
|
*/
|
|
int increment_depth();
|
|
|
|
/**
|
|
* Decr record depth. after record end stage will decrement it.
|
|
*/
|
|
void decrement_depth();
|
|
|
|
/**
|
|
* Get new unique PgDataTimeVo id.
|
|
* @return the new id.
|
|
*/
|
|
int64 get_time_unique_id();
|
|
|
|
/**
|
|
* Print str, only for debug use.
|
|
*/
|
|
void print_self() const;
|
|
|
|
/**
|
|
* Get time record level for report_enable. 0-> default, all stage will report
|
|
* 1~10-> not record time.
|
|
* @return the level.
|
|
*/
|
|
int get_time_record_level() const;
|
|
|
|
/**
|
|
* Update time record level from session.
|
|
*/
|
|
void update_time_record_level();
|
|
|
|
bool log_enable(int level = LOG) const;
|
|
void log_vo(const char* tag, const OgTimeDataVo& vo) const;
|
|
void logtrace(int level, const char* fmt, ...) const;
|
|
private:
|
|
void update_record_time(const RecordType& record_type, int64 cost);
|
|
|
|
private:
|
|
OgTimeDataStack records_stack;
|
|
OgTimeDataStack pre_records_stack;
|
|
int64* local_time_info;
|
|
uint64* local_net_info;
|
|
int depth;
|
|
int64 time_unique_id;
|
|
int64 db_time_baseline;
|
|
int time_record_level;
|
|
StringInfo log_trace_msg;
|
|
OgRecordOperator first_record_opt;
|
|
bool record_start;
|
|
};
|
|
#endif
|