mirror of
https://github.com/isar/libmdbx.git
synced 2024-10-29 23:19:20 +08:00
mdbx: переделка page_alloc_slowpath()
с добавлением профилирования GC.
This commit is contained in:
parent
acaa1d82d9
commit
f680c99116
81
mdbx.h
81
mdbx.h
@ -2561,9 +2561,6 @@ struct MDBX_envinfo {
|
||||
msync; /**< Number of explicit msync-to-disk operations (not a pages) */
|
||||
uint64_t
|
||||
fsync; /**< Number of explicit fsync-to-disk operations (not a pages) */
|
||||
uint64_t
|
||||
gcrtime_seconds16dot16; /**< Time spent loading and searching inside
|
||||
GC (aka FreeDB) in 1/65536 of second */
|
||||
} mi_pgop_stat;
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
@ -3713,8 +3710,8 @@ struct MDBX_commit_latency {
|
||||
/** \brief Duration of preparation (commit child transactions, update
|
||||
* sub-databases records and cursors destroying). */
|
||||
uint32_t preparation;
|
||||
/** \brief Duration of GC/freeDB handling & updation. */
|
||||
uint32_t gc;
|
||||
/** \brief Duration of GC update by wall clock. */
|
||||
uint32_t gc_wallclock;
|
||||
/** \brief Duration of internal audit if enabled. */
|
||||
uint32_t audit;
|
||||
/** \brief Duration of writing dirty/modified data pages to a filesystem,
|
||||
@ -3727,6 +3724,80 @@ struct MDBX_commit_latency {
|
||||
uint32_t ending;
|
||||
/** \brief The total duration of a commit. */
|
||||
uint32_t whole;
|
||||
/** \brief User-mode CPU time spent on GC update. */
|
||||
uint32_t gc_cputime;
|
||||
|
||||
/** \brief Информация для профилирования работы GC.
|
||||
* \note Статистика является общей для всех процессов работающих с одним
|
||||
* файлом БД и хранится в LCK-файле. Данные аккумулируются при фиксации всех
|
||||
* транзакций, но только в сборках libmdbx c установленной опцией
|
||||
* \ref MDBX_ENABLE_PROFGC. Собранная статистика возвращаются любому процессу
|
||||
* при использовании \ref mdbx_txn_commit_ex() и одновременно обнуляется
|
||||
* при завершении транзакций верхнего уровня (не вложенных). */
|
||||
struct {
|
||||
/** \brief Количество итераций обновления GC,
|
||||
* больше 1 если были повторы/перезапуски. */
|
||||
uint32_t wloops;
|
||||
/** \brief Количество итераций слияния записей GC. */
|
||||
uint32_t coalescences;
|
||||
/** \brief Количество уничтожений предыдущих надежных/устойчивых
|
||||
* точек фиксации при работе в режиме \ref MDBX_UTTERLY_NOSYNC. */
|
||||
uint32_t wipes;
|
||||
/** \brief Количество принудительных фиксаций на диск
|
||||
* во избежания приращения БД при работе вне режима
|
||||
* \ref MDBX_UTTERLY_NOSYNC. */
|
||||
uint32_t flushes;
|
||||
/** \brief Количество обращений к механизму Handle-Slow-Readers
|
||||
* во избежания приращения БД.
|
||||
* \see MDBX_hsr_func */
|
||||
uint32_t kicks;
|
||||
|
||||
/** \brief Счетчик выполнения по медленному пути (slow path execution count)
|
||||
* GC ради данных пользователя. */
|
||||
uint32_t work_counter;
|
||||
/** \brief Время "по настенным часам" затраченное на чтение и поиск внутри
|
||||
* GC ради данных пользователя. */
|
||||
uint32_t work_rtime_monotonic;
|
||||
/** \brief Монотонное время по "настенным часам" затраченное
|
||||
* на подготовку страниц извлекаемых из GC для данных пользователя,
|
||||
* включая подкачку с диска. */
|
||||
uint32_t work_xtime_monotonic;
|
||||
/** \brief Время ЦПУ в режиме пользователе затраченное на чтение и поиск
|
||||
* внтури GC ради данных пользователя. */
|
||||
uint32_t work_rtime_cpu;
|
||||
/** \brief Количество итераций поиска внутри GC при выделении страниц
|
||||
* ради данных пользователя. */
|
||||
uint32_t work_rsteps;
|
||||
/** \brief Количество запросов на выделение последовательностей страниц
|
||||
* ради данных пользователя. */
|
||||
uint32_t work_xpages;
|
||||
/** \brief Количество страничных промахов (page faults) внутри GC
|
||||
* при выделении и подготовки страниц для данных пользователя. */
|
||||
uint32_t work_majflt;
|
||||
|
||||
/** \brief Счетчик выполнения по медленному пути (slow path execution count)
|
||||
* GC для целей поддержки и обновления самой GC. */
|
||||
uint32_t self_counter;
|
||||
/** \brief Время "по настенным часам" затраченное на чтение и поиск внутри
|
||||
* GC для целей поддержки и обновления самой GC. */
|
||||
uint32_t self_rtime_monotonic;
|
||||
/** \brief Монотонное время по "настенным часам" затраченное на подготовку
|
||||
* страниц извлекаемых из GC для целей поддержки и обновления самой GC,
|
||||
* включая подкачку с диска. */
|
||||
uint32_t self_xtime_monotonic;
|
||||
/** \brief Время ЦПУ в режиме пользователе затраченное на чтение и поиск
|
||||
* внтури GC для целей поддержки и обновления самой GC. */
|
||||
uint32_t self_rtime_cpu;
|
||||
/** \brief Количество итераций поиска внутри GC при выделении страниц
|
||||
* для целей поддержки и обновления самой GC. */
|
||||
uint32_t self_rsteps;
|
||||
/** \brief Количество запросов на выделение последовательностей страниц
|
||||
* для самой GC. */
|
||||
uint32_t self_xpages;
|
||||
/** \brief Количество страничных промахов (page faults) внутри GC
|
||||
* при выделении и подготовки страниц для самой GC. */
|
||||
uint32_t self_majflt;
|
||||
} gc_prof;
|
||||
};
|
||||
#ifndef __cplusplus
|
||||
/** \ingroup c_statinfo */
|
||||
|
@ -5,8 +5,8 @@ N | MASK | ENV | TXN | DB | PUT | DBI | NOD
|
||||
2 |0000 0004|ALLOC_NEW |TXN_DIRTY |DUPSORT | |DBI_FRESH |F_DUPDATA|P_OVERFLOW| |
|
||||
3 |0000 0008|ALLOC_SLOT |TXN_SPILLS |INTEGERKEY| |DBI_CREAT | |P_META | |
|
||||
4 |0000 0010|ALLOC_FAKE |TXN_HAS_CHILD |DUPFIXED |NOOVERWRITE|DBI_VALID | |P_BAD | |
|
||||
5 |0000 0020| | |INTEGERDUP|NODUPDATA |DBI_USRVALID| |P_LEAF2 | |
|
||||
6 |0000 0040| | |REVERSEDUP|CURRENT |DBI_DUPDATA | |P_SUBP | |
|
||||
5 |0000 0020| |TXN_UPDATE_GC |INTEGERDUP|NODUPDATA |DBI_USRVALID| |P_LEAF2 | |
|
||||
6 |0000 0040| |TXN_FROZEN_RE |REVERSEDUP|CURRENT |DBI_DUPDATA | |P_SUBP | |
|
||||
7 |0000 0080| | | |ALLDUPS |DBI_AUDITED | | | |
|
||||
8 |0000 0100| _MAY_MOVE | | | | | | | <= |
|
||||
9 |0000 0200| _MAY_UNMAP| | | | | | | <= |
|
||||
|
1189
src/core.c
1189
src/core.c
File diff suppressed because it is too large
Load Diff
@ -578,10 +578,30 @@ typedef struct MDBX_page {
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#if MDBX_ENABLE_PGOP_STAT
|
||||
typedef struct profgc_stat {
|
||||
/* Монотонное время по "настенным часам"
|
||||
* затраченное на чтение и поиск внутри GC */
|
||||
uint64_t rtime_monotonic;
|
||||
/* Монотонное время по "настенным часам" затраченное
|
||||
* на подготовку страниц извлекаемых из GC, включая подкачку с диска. */
|
||||
uint64_t xtime_monotonic;
|
||||
/* Процессорное время в режим пользователя
|
||||
* затраченное на чтение и поиск внутри GC */
|
||||
uint64_t rtime_cpu;
|
||||
/* Количество итераций чтения-поиска внутри GC при выделении страниц */
|
||||
uint32_t rsteps;
|
||||
/* Количество запросов на выделение последовательностей страниц,
|
||||
* т.е. когда запрашивает выделение больше одной страницы */
|
||||
uint32_t xpages;
|
||||
/* Счетчик выполнения по медленному пути (slow path execution count) */
|
||||
uint32_t spe_counter;
|
||||
/* page faults (hard page faults) */
|
||||
uint32_t majflt;
|
||||
} profgc_stat_t;
|
||||
|
||||
/* Statistics of page operations overall of all (running, completed and aborted)
|
||||
* transactions */
|
||||
typedef struct {
|
||||
typedef struct pgop_stat {
|
||||
MDBX_atomic_uint64_t newly; /* Quantity of a new pages added */
|
||||
MDBX_atomic_uint64_t cow; /* Quantity of pages copied for update */
|
||||
MDBX_atomic_uint64_t clone; /* Quantity of parent's dirty pages clones
|
||||
@ -592,15 +612,32 @@ typedef struct {
|
||||
MDBX_atomic_uint64_t unspill; /* Quantity of unspilled/reloaded pages */
|
||||
MDBX_atomic_uint64_t
|
||||
wops; /* Number of explicit write operations (not a pages) to a disk */
|
||||
MDBX_atomic_uint64_t
|
||||
gcrtime; /* Time spending for reading/searching GC (aka FreeDB). The
|
||||
unit/scale is platform-depended, see osal_monotime(). */
|
||||
MDBX_atomic_uint64_t
|
||||
msync; /* Number of explicit msync/flush-to-disk operations */
|
||||
MDBX_atomic_uint64_t
|
||||
fsync; /* Number of explicit fsync/flush-to-disk operations */
|
||||
} MDBX_pgop_stat_t;
|
||||
#endif /* MDBX_ENABLE_PGOP_STAT */
|
||||
|
||||
/* Статистика для профилирования GC.
|
||||
* Логически эти данные может быть стоит вынести в другую структуру,
|
||||
* но разница будет сугубо косметическая. */
|
||||
struct {
|
||||
/* Затраты на поддержку данных пользователя */
|
||||
profgc_stat_t work;
|
||||
/* Затраты на поддержку и обновления самой GC */
|
||||
profgc_stat_t self;
|
||||
/* Итераций обновления GC,
|
||||
* больше 1 если были повторы/перезапуски */
|
||||
uint32_t wloops;
|
||||
/* Итерации слияния записей GC */
|
||||
uint32_t coalescences;
|
||||
/* Уничтожения steady-точек фиксации в MDBX_UTTERLY_NOSYNC */
|
||||
uint32_t wipes;
|
||||
/* Сбросы данные на диск вне MDBX_UTTERLY_NOSYNC */
|
||||
uint32_t flushes;
|
||||
/* Попытки пнуть тормозящих читателей */
|
||||
uint32_t kicks;
|
||||
} gc_prof;
|
||||
} pgop_stat_t;
|
||||
|
||||
#if MDBX_LOCKING == MDBX_LOCKING_WIN32FILES
|
||||
#define MDBX_CLOCK_SIGN UINT32_C(0xF10C)
|
||||
@ -738,11 +775,9 @@ typedef struct MDBX_lockinfo {
|
||||
|
||||
MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
|
||||
|
||||
#if MDBX_ENABLE_PGOP_STAT
|
||||
/* Statistics of costly ops of all (running, completed and aborted)
|
||||
* transactions */
|
||||
MDBX_pgop_stat_t mti_pgop_stat;
|
||||
#endif /* MDBX_ENABLE_PGOP_STAT*/
|
||||
pgop_stat_t mti_pgop_stat;
|
||||
|
||||
MDBX_ALIGNAS(MDBX_CACHELINE_SIZE) /* cacheline ----------------------------*/
|
||||
|
||||
@ -962,9 +997,13 @@ struct MDBX_txn {
|
||||
/* Additional flag for sync_locked() */
|
||||
#define MDBX_SHRINK_ALLOWED UINT32_C(0x40000000)
|
||||
|
||||
#define MDBX_TXN_UPDATE_GC 0x20 /* GC is being updated */
|
||||
#define MDBX_TXN_FROZEN_RE 0x40 /* list of reclaimed-pgno must not altered */
|
||||
|
||||
#define TXN_FLAGS \
|
||||
(MDBX_TXN_FINISHED | MDBX_TXN_ERROR | MDBX_TXN_DIRTY | MDBX_TXN_SPILLS | \
|
||||
MDBX_TXN_HAS_CHILD | MDBX_TXN_INVALID)
|
||||
MDBX_TXN_HAS_CHILD | MDBX_TXN_INVALID | MDBX_TXN_UPDATE_GC | \
|
||||
MDBX_TXN_FROZEN_RE)
|
||||
|
||||
#if (TXN_FLAGS & (MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS)) || \
|
||||
((MDBX_TXN_RW_BEGIN_FLAGS | MDBX_TXN_RO_BEGIN_FLAGS | TXN_FLAGS) & \
|
||||
@ -1023,8 +1062,8 @@ struct MDBX_txn {
|
||||
struct {
|
||||
meta_troika_t troika;
|
||||
/* In write txns, array of cursors for each DB */
|
||||
pgno_t *reclaimed_pglist; /* Reclaimed GC pages */
|
||||
txnid_t last_reclaimed; /* ID of last used record */
|
||||
pgno_t *relist; /* Reclaimed GC pages */
|
||||
txnid_t last_reclaimed; /* ID of last used record */
|
||||
#if MDBX_ENABLE_REFUND
|
||||
pgno_t loose_refund_wl /* FIXME: describe */;
|
||||
#endif /* MDBX_ENABLE_REFUND */
|
||||
@ -1100,9 +1139,7 @@ struct MDBX_cursor {
|
||||
#define C_SUB 0x04 /* Cursor is a sub-cursor */
|
||||
#define C_DEL 0x08 /* last op was a cursor_del */
|
||||
#define C_UNTRACK 0x10 /* Un-track cursor when closing */
|
||||
#define C_RECLAIMING 0x20 /* GC lookup is prohibited */
|
||||
#define C_GCFREEZE 0x40 /* reclaimed_pglist must not be updated */
|
||||
uint8_t mc_flags; /* see mdbx_cursor */
|
||||
uint8_t mc_flags;
|
||||
|
||||
/* Cursor checking flags. */
|
||||
#define CC_BRANCH 0x01 /* same as P_BRANCH for CHECK_LEAF_TYPE() */
|
||||
@ -1113,7 +1150,7 @@ struct MDBX_cursor {
|
||||
#define CC_LEAF2 0x20 /* same as P_LEAF2 for CHECK_LEAF_TYPE() */
|
||||
#define CC_RETIRING 0x40 /* refs to child pages may be invalid */
|
||||
#define CC_PAGECHECK 0x80 /* perform page checking, see MDBX_VALIDATION */
|
||||
uint8_t mc_checking; /* page checking level */
|
||||
uint8_t mc_checking;
|
||||
|
||||
MDBX_page *mc_pg[CURSOR_STACK]; /* stack of pushed pages */
|
||||
indx_t mc_ki[CURSOR_STACK]; /* stack of page indices */
|
||||
|
@ -73,6 +73,13 @@
|
||||
#error MDBX_ENABLE_REFUND must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_REFUND */
|
||||
|
||||
/** Controls profiling of GC search and updates. */
|
||||
#ifndef MDBX_ENABLE_PROFGC
|
||||
#define MDBX_ENABLE_PROFGC 0
|
||||
#elif !(MDBX_ENABLE_PROFGC == 0 || MDBX_ENABLE_PROFGC == 1)
|
||||
#error MDBX_ENABLE_PROFGC must be defined as 0 or 1
|
||||
#endif /* MDBX_ENABLE_PROFGC */
|
||||
|
||||
/** Controls gathering statistics for page operations. */
|
||||
#ifndef MDBX_ENABLE_PGOP_STAT
|
||||
#define MDBX_ENABLE_PGOP_STAT 1
|
||||
|
55
src/osal.c
55
src/osal.c
@ -18,6 +18,7 @@
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
#include <psapi.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#if !MDBX_WITHOUT_MSVC_CRT && defined(_DEBUG)
|
||||
@ -2700,6 +2701,60 @@ MDBX_INTERNAL_FUNC uint64_t osal_monotime(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC uint64_t osal_cputime(size_t *optional_page_faults) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (optional_page_faults) {
|
||||
PROCESS_MEMORY_COUNTERS pmc;
|
||||
*optional_page_faults =
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))
|
||||
? pmc.PageFaultCount
|
||||
: 0;
|
||||
}
|
||||
FILETIME unused, usermode;
|
||||
if (GetThreadTimes(GetCurrentThread(),
|
||||
/* CreationTime */ &unused,
|
||||
/* ExitTime */ &unused,
|
||||
/* KernelTime */ &unused,
|
||||
/* UserTime */ &usermode)) {
|
||||
/* one second = 10_000_000 * 100ns = 78125 * (1 << 7) * 100ns;
|
||||
* result = (h * f / 10_000_000) << 32) + l * f / 10_000_000 =
|
||||
* = ((h * f) >> 7) / 78125) << 32) + ((l * f) >> 7) / 78125;
|
||||
* 1) {h, l} *= f;
|
||||
* 2) {h, l} >>= 7;
|
||||
* 3) result = ((h / 78125) << 32) + l / 78125; */
|
||||
uint64_t l = usermode.dwLowDateTime * performance_frequency.QuadPart;
|
||||
uint64_t h = usermode.dwHighDateTime * performance_frequency.QuadPart;
|
||||
l = h << (64 - 7) | l >> 7;
|
||||
h = h >> 7;
|
||||
return ((h / 78125) << 32) + l / 78125;
|
||||
}
|
||||
#elif defined(RUSAGE_THREAD) || defined(RUSAGE_LWP)
|
||||
#ifndef RUSAGE_THREAD
|
||||
#define RUSAGE_THREAD RUSAGE_LWP /* Solaris */
|
||||
#endif
|
||||
struct rusage usage;
|
||||
if (getrusage(RUSAGE_THREAD, &usage) == 0) {
|
||||
if (optional_page_faults)
|
||||
*optional_page_faults = usage.ru_majflt;
|
||||
return usage.ru_utime.tv_sec * UINT64_C(1000000000) +
|
||||
usage.ru_utime.tv_usec * 1000u;
|
||||
}
|
||||
if (optional_page_faults)
|
||||
*optional_page_faults = 0;
|
||||
#elif defined(CLOCK_THREAD_CPUTIME_ID)
|
||||
if (optional_page_faults)
|
||||
*optional_page_faults = 0;
|
||||
struct timespec ts;
|
||||
if (likely(clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0))
|
||||
return ts.tv_sec * UINT64_C(1000000000) + ts.tv_nsec;
|
||||
#else
|
||||
/* FIXME */
|
||||
if (optional_page_faults)
|
||||
*optional_page_faults = 0;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
static void bootid_shake(bin128_t *p) {
|
||||
|
@ -620,6 +620,7 @@ osal_pthread_mutex_lock(pthread_mutex_t *mutex) {
|
||||
#endif /* !Windows */
|
||||
|
||||
MDBX_INTERNAL_FUNC uint64_t osal_monotime(void);
|
||||
MDBX_INTERNAL_FUNC uint64_t osal_cputime(size_t *optional_page_faults);
|
||||
MDBX_INTERNAL_FUNC uint64_t osal_16dot16_to_monotime(uint32_t seconds_16dot16);
|
||||
MDBX_INTERNAL_FUNC uint32_t osal_monotime_to_16dot16(uint64_t monotime);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user