MySQL 8.4.2
Source Code Documentation
|
MySQL performance schema instrumentation interface.
Any code can be instrumented with the performance schema, regardless of the kind of code used:
The instrumentation interface consist of two layers:
In each case, the API may expand into different code paths, and use different ABI infrastructure, depending on how the code is built. In each case, the API exposed is consistent: instrumented source code is the same, regardless of where it is built.
The following sections details what happens technically for each type of code. The same instrumentation (a mutex) is used, to illustrate.
Assume some existing code using a mutex, for example for linux
MySQL already provides some wrappers, to make the code platform independent, as in
Code using my_mutex_t
is not instrumented for performance measurement.
To instrument the code, use a mysql_mutex_t
instead. All the APIs provided are meant to be used as a simple replacement.
The server code can be built with or without each kind of instrumentation.
If cmake is configured with -DDISABLE_PSI_MUTEX
, the mutex instrumentation is not compiled. In this case, HAVE_PSI_MUTEX_INTERFACE
is not defined, so that mysql_mutex_lock()
expands into
In other words, when not building with instrumentation, mysql_mutex_lock()
is simply replaced with the actual call to my_mutex_lock()
,
When building with the mutex instrumentation enabled (the default), mysql_mutex_lock()
expands into this sequence.
For a given instrumentation point in the API, the basic coding pattern used is:
An opaque "locker" pointer is returned by (a), that is given to (c). This pointer helps the implementation to keep context, for performances.
The following code fragment is annotated to show how in detail this pattern in implemented, when the instrumentation is compiled in statically. In this case, the PSI_MUTEX_CALL
macro expands to a function call, which results in
When the performance schema is disabled at runtime, the m_psi
pointer is NULL
, so the extra overhead is one if statement.
When the performance schema is enabled at runtime, the m_psi
pointer points to the actual instrumentation added to the mutex, and two extra calls are present on the code path:
pfs_start_mutex_wait_v1()
before the operationpfs_end_mutex_wait_v1()
after the operationBoth these calls are static, and point directly to the performance_schema implementation.
Inside a plugin, PSI_MUTEX_CALL
expands to a call using a function pointer. This is to decouple the plugin binary from the implementation, to avoid having hard coded references to symbols like pfs_start_mutex_wait_v1() from the plugin library (either shared or static).
The plugin library, however, still depends on a symbol to be provided by the server, in this case psi_mutex_service
.
This solution works overall, but has some limitations.
The goal when compiling a component is to have zero linker dependencies on the server code, and have technical dependencies described as references to services instead.
Another goal is to compile code the same way, independently of the technical choices affecting the implementation (pthread mutexes or native windows critical sections, SAFE_MUTEX debug helpers or not, etc)
For the mutex instrumentation in particular, the pattern used is to have a service that delegates all decisions to the server code. For this reason, all the parameters that might or might not be needed depending on the ultimate implementation (such as FILE
and LINE
for SAFE_MUTEX
) are provided in all cases.
In a component, the code is instrumented using a different header file, everything else is the same.
The call to mysql_mutex_lock()
expands into
In the component metadata, the dependency on the mutex service needs to be declared explicitly, as in:
When the component is loaded:
mysql_service_mysql_mutex_v1
pointer.From this point, code compiled in the component can be executed normally, and calls to mysql_mutex_lock()
land into the service implementation, which is a simple instrumented mutex lock compiled in the server.
The current list of instrumentation provided by the performance schema is as follows:
Scope | User code | Implementation entry point | ||
---|---|---|---|---|
Server or Plugin | Component | Server or Plugin | Component | |
Mutex (high level) | #include "mysql/psi/mysql_mutex.h" mysql_mutex_lock() | #include "mysql/components/services/mysql_mutex.h" mysql_mutex_lock() | PSI_mutex_bootstrap | |
Rwlock (high level) | #include "mysql/psi/mysql_rwlock.h" mysql_rwlock_rdlock() | #include "mysql/components/services/mysql_rwlock.h" mysql_rwlock_rdlock() | PSI_rwlock_bootstrap | |
Conditions (high level) | #include "mysql/psi/mysql_cond.h" mysql_cond_wait() | #include "mysql/components/services/mysql_cond.h" mysql_cond_wait() | PSI_cond_bootstrap | |
Mutex (low level) | #include "mysql/psi/psi_mutex.h" PSI_MUTEX_CALL(start_mutex_wait)(...) PSI_MUTEX_CALL(end_mutex_wait)(...) | #include "mysql/components/services/psi_mutex.h" PSI_MUTEX_CALL(start_mutex_wait)(...) PSI_MUTEX_CALL(end_mutex_wait)(...) | PSI_mutex_bootstrap | |
Rwlock (low level) | #include "mysql/psi/psi_rwlock.h" PSI_RWLOCK_CALL(start_rwlock_rdwait)(...) PSI_RWLOCK_CALL(end_rwlock_rdwait)(...) | #include "mysql/components/services/psi_rwlock.h" PSI_RWLOCK_CALL(start_rwlock_rdwait)(...) PSI_RWLOCK_CALL(end_rwlock_rdwait)(...) | PSI_rwlock_bootstrap | |
Conditions (low level) | #include "mysql/psi/mysql_cond.h" PSI_COND_CALL(start_cond_wait)(...) PSI_COND_CALL(end_cond_wait)(...) | #include "mysql/components/services/psi_cond.h" PSI_COND_CALL(start_cond_wait)(...) PSI_COND_CALL(end_cond_wait)(...) | PSI_cond_bootstrap | |
Errors | #include "mysql/psi/psi_error.h" PSI_ERROR_CALL(log_error)(...) | #include "mysql/components/services/psi_error.h" PSI_ERROR_CALL(log_error)(...) | PSI_error_bootstrap | |
File | #include "mysql/psi/psi_file.h" PSI_FILE_CALL(start_file_wait)(...) PSI_FILE_CALL(end_file_wait)(...) | #include "mysql/components/services/psi_file.h" PSI_FILE_CALL(start_file_wait)(...) PSI_FILE_CALL(end_file_wait)(...) | PSI_file_bootstrap | |
Idle | #include "mysql/psi/psi_idle.h" PSI_IDLE_CALL(start_idle_wait)(...) PSI_IDLE_CALL(end_idle_wait)(...) | #include "mysql/components/services/psi_idle.h" PSI_IDLE_CALL(start_idle_wait)(...) PSI_IDLE_CALL(end_idle_wait)(...) | PSI_idle_bootstrap | |
Metadata locks | #include "mysql/psi/psi_mdl.h" PSI_METADATA_CALL(start_metadata_wait)(...) PSI_METADATA_CALL(end_metadata_wait)(...) | #include "mysql/components/services/psi_mdl.h" PSI_METADATA_CALL(start_metadata_wait)(...) PSI_METADATA_CALL(end_metadata_wait)(...) | PSI_mdl_bootstrap | |
Memory | #include "mysql/psi/psi_memory.h" PSI_MEMORY_CALL(memory_alloc)(...) PSI_MEMORY_CALL(memory_free)(...) | #include "mysql/components/services/psi_memory.h" PSI_MEMORY_CALL(memory_alloc)(...) PSI_MEMORY_CALL(memory_free)(...) | PSI_memory_bootstrap | |
Socket | #include "mysql/psi/psi_socket.h" PSI_SOCKET_CALL(start_socket_wait)(...) PSI_SOCKET_CALL(end_socket_wait)(...) | #include "mysql/components/services/psi_socket.h" PSI_SOCKET_CALL(start_socket_wait)(...) PSI_SOCKET_CALL(end_socket_wait)(...) | PSI_socket_bootstrap | |
Stage | #include "mysql/psi/psi_stage.h" PSI_STAGE_CALL(start_stage)(...) | #include "mysql/components/services/psi_stage.h" PSI_STAGE_CALL(start_stage)(...) | PSI_stage_bootstrap | |
Statement | #include "mysql/psi/psi_statement.h" PSI_STATEMENT_CALL(start_statement)(...) PSI_STATEMENT_CALL(end_statement)(...) Extra helpers available: MYSQL_START_STATEMENT() MYSQL_END_STATEMENT() | #include "mysql/components/services/psi_statement.h" PSI_STATEMENT_CALL(start_statement)(...) PSI_STATEMENT_CALL(end_statement)(...) | PSI_statement_bootstrap | |
Table | #include "mysql/psi/psi_table.h" PSI_TABLE_CALL(start_table_io_wait)(...) PSI_TABLE_CALL(end_table_io_wait)(...) | #include "mysql/components/services/psi_table.h" PSI_TABLE_CALL(start_table_io_wait)(...) PSI_TABLE_CALL(end_table_io_wait)(...) | PSI_table_bootstrap | |
System | #include "mysql/psi/psi_system.h" PSI_SYSTEM_CALL(plugin_unload)(...) | #include "mysql/components/services/psi_system.h" PSI_SYSTEM_CALL(plugin_unload)(...) | PSI_system_bootstrap | |
Thread | #include "mysql/psi/psi_thread.h" PSI_THREAD_CALL(spawn_thread)(...) PSI_THREAD_CALL(delete_thread)(...) | #include "mysql/components/services/psi_thread.h" PSI_THREAD_CALL(spawn_thread)(...) PSI_THREAD_CALL(delete_thread)(...) | PSI_thread_bootstrap | |
Transaction | #include "mysql/psi/psi_transaction.h" PSI_TRANSACTION_CALL(start_transaction)(...) PSI_TRANSACTION_CALL(end_transaction)(...) | #include "mysql/components/services/psi_transaction.h" PSI_TRANSACTION_CALL(start_transaction)(...) PSI_TRANSACTION_CALL(end_transaction)(...) | PSI_transaction_bootstrap | |
Data locks | #include "mysql/psi/psi_data_lock.h" PSI_DATA_LOCK_CALL(register_data_lock)(...) PSI_DATA_LOCK_CALL(unregister_data_lock)(...) | Not available as a service. | PSI_data_lock_bootstrap | Not available as a service. |
TLS Channels | #include "mysql/psi/psi_tls_channel.h" PSI_TLS_CHANNEL_CALL(register_tls_channel)(...) PSI_TLS_CHANNEL_CALL(unregister_tls_channel)(...) | #include "mysql/components/services/psi_tls_channel.h" PSI_TLS_CHANNEL_CALL(register_tls_channel)(...) PSI_TLS_CHANNEL_CALL(unregister_tls_channel)(...) | PSI_tls_channel_bootstrap |