pax_global_header00006660000000000000000000000064137643107640014525gustar00rootroot0000000000000052 comment=26145374a11ba651cb1858423c42ec1b0080253f pg_stat_kcache-REL2_2_0/000077500000000000000000000000001376431076400151725ustar00rootroot00000000000000pg_stat_kcache-REL2_2_0/.gitignore000066400000000000000000000000631376431076400171610ustar00rootroot00000000000000*.o *.a *.so *.pc *~ pg_stat_kcache-*.zip results/ pg_stat_kcache-REL2_2_0/CHANGELOG.md000066400000000000000000000056211376431076400170070ustar00rootroot00000000000000## 2.2.0 (2020-12-10) **New features**: - Add pg_stat_kcache.track option, similar to pg_stat_statements (Julien Rouhaud and github user mikecaat) - Add pg_stat_kcache.track_planning, similar to pg_stat_statements, to track usge during planning, and maintain 2 sets of counters, depending on whether it was during planning or execution. Requires PostgreSQL 13 or above (Julien Rouhaud, github user mikecaat) - Add a new "top" column, and accumulate resource usage in different entries depending on whether queries are executed at top level or at nested statements. (github user mikecaat and Julien Rouhaud) ## 2.1.3 (2020-07-16) **Bugfix**: - Fix memory corruption introduced in v2.1.2 that can cause a PostgreSQL crash (Julien Rouhaud, thanks to github user tbe, Nikolay Samokhvalov and Andreas Seltenreich for reporting the issue and the extensive checking) ## 2.1.2 (2020-07-08) **Bugfix**: - Accumulate counters for parallel workers too (Julien Rouhaud, thanks to Atsushi Torikoshi for the report) ## 2.1.1 (2018-07-28) **Bugfix**: - Fix usage increase, used to keep the most frequent entries in memory (Julien Rouhaud) **Miscellaneous**: - Allow PG_CONFIG value to be found on command-line (edechaux) - Warn users about incorrect GUC (Julien Rouhaud) - Add debian packaging (Julien Rouhaud) ## 2.1.0 (2018-07-17) **NOTE**: This version requires a change to the on-disk format. After installing the new version restarting PostgreSQL, any previously accumulated statistics will be reset. - Add support for architecture that don't provide getrusage(2), such as windows. Only user time and system time will be available on such platforms (Julien Rouhaud). - Expose more fields of getrusage(2). Depending on the platform, some of these fields are not maintained (Julien Rouhaud). - Add a workaround for sampling problems with getrusage(), new parameter pg_stat_kcache.linux_hz is added. By default, this parameter is discovered at server startup (Ronan Dunklau). - Add compatibility with PostgreSQL 11 (Thomas Reiss) - Fix issue when concurrently created entries for the same user, db and queryid could lost some execution counters (Mael Rimbault) - Do not install docs anymore (Ronan Dunklau) ## 2.0.3 (2016-10-03) - Add PG 9.6 compatibility - Fix issues in shared memory estimation, which could prevent starting postgres or reduce the amount of possible locks (thanks to Jean-Sébastien BACQ for the report) - Add hint of possible reasons pgss.max could not be retrieved, which could prevent starting postgres ## 2.0.2 (2015-03-17) - Fix another bug with 32 bits builds (thanks to Alain Delorme for reporting it) ## 2.0.1 (2015-03-16) - Fix a bug with 32 bits builds (thanks to Alain Delorme for reporting it) ## 2.0 (2015-01-30) - Handle stats per database, user, query ## 1.0 (2014-02-26) - Initial release pg_stat_kcache-REL2_2_0/CONTRIBUTORS.md000066400000000000000000000003411376431076400174470ustar00rootroot00000000000000 * Thomas Reiss * Julien Rouhaud * Alain Delorme * Guillaume Lelarge * Jean-Sébastien Bacq * Maël Rimbault * edechaux * Felix Geisendörfer * github user atorik * github user tbe * github user mikecaat pg_stat_kcache-REL2_2_0/LICENSE000066400000000000000000000017461376431076400162070ustar00rootroot00000000000000Copyright (c) 2014-2017, Dalibo Copyright (c) 2018-2020, The PoWA-team Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. pg_stat_kcache-REL2_2_0/META.json000066400000000000000000000021331376431076400166120ustar00rootroot00000000000000{ "name": "pg_stat_kcache", "abstract": "An extension gathering CPU and disk acess statistics", "version": "__VERSION__", "maintainer": "Julien Rouhaud ", "license": "postgresql", "release_status": "stable", "provides": { "pg_stat_kcache": { "abstract": "An extension gathering CPU and disk acess statistics", "file": "pg_stat_kcache.sql", "docfile": "README.rst", "version": "__VERSION__" } }, "resources": { "bugtracker": { "web": "http://github.com/powa-team/pg_stat_kcache/issues/" }, "repository": { "url": "git://github.com/powa-team/pg_stat_kcache.git", "web": "http://github.com/powa-team/pg_stat_kcache/", "type": "git" } }, "prereqs": { "runtime": { "requires": { "PostgreSQL": "9.4.0" } } }, "generated_by": "Julien Rouhaud", "meta-spec": { "version": "1.0.0", "url": "http://pgxn.org/meta/spec.txt" }, "tags": [ "monitoring", "CPU", "disk" ] } pg_stat_kcache-REL2_2_0/Makefile000066400000000000000000000016231376431076400166340ustar00rootroot00000000000000EXTENSION = pg_stat_kcache EXTVERSION = $(shell grep default_version $(EXTENSION).control | sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/") TESTS = $(wildcard test/sql/*.sql) REGRESS = $(patsubst test/sql/%.sql,%,$(TESTS)) REGRESS_OPTS = --inputdir=test PG_CONFIG ?= pg_config MODULE_big = pg_stat_kcache OBJS = pg_stat_kcache.o all: release-zip: all git archive --format zip --prefix=pg_stat_kcache-${EXTVERSION}/ --output ./pg_stat_kcache-${EXTVERSION}.zip HEAD unzip ./pg_stat_kcache-$(EXTVERSION).zip rm ./pg_stat_kcache-$(EXTVERSION).zip rm ./pg_stat_kcache-$(EXTVERSION)/.gitignore sed -i -e "s/__VERSION__/$(EXTVERSION)/g" ./pg_stat_kcache-$(EXTVERSION)/META.json zip -r ./pg_stat_kcache-$(EXTVERSION).zip ./pg_stat_kcache-$(EXTVERSION)/ rm ./pg_stat_kcache-$(EXTVERSION) -rf DATA = $(wildcard *--*.sql) PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) pg_stat_kcache-REL2_2_0/README.rst000066400000000000000000001170151376431076400166660ustar00rootroot00000000000000pg_stat_kcache ============== Features -------- Gathers statistics about real reads and writes done by the filesystem layer. It is provided in the form of an extension for PostgreSQL >= 9.4., and requires pg_stat_statements extension to be installed. PostgreSQL 9.4 or more is required as previous version of provided pg_stat_statements didn't expose the queryid field. Installation ============ Compiling --------- The module can be built using the standard PGXS infrastructure. For this to work, the ``pg_config`` program must be available in your $PATH. Instruction to install follows:: git clone https://github.com/powa-team/pg_stat_kcache.git cd pg_stat_kcache make make install PostgreSQL setup ---------------- The extension is now available. But, as it requires some shared memory to hold its counters, the module must be loaded at PostgreSQL startup. Thus, you must add the module to ``shared_preload_libraries`` in your ``postgresql.conf``. You need a server restart to take the change into account. As this extension depends on pg_stat_statements, it also need to be added to ``shared_preload_libraries``. Add the following parameters into you ``postgresql.conf``:: # postgresql.conf shared_preload_libraries = 'pg_stat_statements,pg_stat_kcache' Once your PostgreSQL cluster is restarted, you can install the extension in every database where you need to access the statistics:: mydb=# CREATE EXTENSION pg_stat_kcache; Configuration ============= The following GUCs can be configured, in ``postgresql.conf``: - *pg_stat_kcache.linux_hz* (int, default -1): informs pg_stat_kcache of the linux CONFIG_HZ config option. This is used by pg_stat_kcache to compensate for sampling errors. The default value is -1, tries to guess it at startup. - *pg_stat_kcache.track* (enum, default top): controls which statements are tracked by pg_stat_kcache. Specify top to track top-level statements (those issued directly by clients), all to also track nested statements (such as statements invoked within functions), or none to disable statement statistics collection. - *pg_stat_kcache.track_planning* (bool, default off): controls whether planning operations and duration are tracked by pg_stat_kcache (requires PostgreSQL 13 or above). Usage ===== pg_stat_kcache create several objects. pg_stat_kcache view ------------------- +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | Name | Type | Description | +==================+==================+=========================================================================================================================================================+ | datname | name | Name of the database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_user_time | double precision | User CPU time used planning statements in this database, in seconds and milliseconds (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_system_time | double precision | System CPU time used planning statements in this database, in seconds and milliseconds (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_minflts | bigint | Number of page reclaims (soft page faults) planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_majflts | bigint | Number of page faults (hard page faults) planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nswaps | bigint | Number of swaps planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_reads | bigint | Number of bytes read by the filesystem layer planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_reads_blks | bigint | Number of 8K blocks read by the filesystem layer planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_writes | bigint | Number of bytes written by the filesystem layer planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_writes_blks | bigint | Number of 8K blocks written by the filesystem layer planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_msgsnds | bigint | Number of IPC messages sent planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_msgrcvs | bigint | Number of IPC messages received planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nsignals | bigint | Number of signals received planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nvcsws | bigint | Number of voluntary context switches planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nivcsws | bigint | Number of involuntary context switches planning statements in this database (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_user_time | double precision | User CPU time used executing statements in this database, in seconds and milliseconds | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_system_time | double precision | System CPU time used executing statements in this database, in seconds and milliseconds | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_minflts | bigint | Number of page reclaims (soft page faults) executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_majflts | bigint | Number of page faults (hard page faults) executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nswaps | bigint | Number of swaps executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_reads | bigint | Number of bytes read by the filesystem layer executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_reads_blks | bigint | Number of 8K blocks read by the filesystem layer executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_writes | bigint | Number of bytes written by the filesystem layer executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_writes_blks | bigint | Number of 8K blocks written by the filesystem layer executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_msgsnds | bigint | Number of IPC messages sent executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_msgrcvs | bigint | Number of IPC messages received executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nsignals | bigint | Number of signals received executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nvcsws | bigint | Number of voluntary context switches executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nivcsws | bigint | Number of involuntary context switches executing statements in this database | +------------------+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------+ pg_stat_kcache_detail view -------------------------- +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | Name | Type | Description | +==================+==================+==========================================================================================================================================+ | query | text | Query text | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | top | bool | True if the statement is top-level | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | datname | name | Database name | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | rolname | name | Role name | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_user_time | double precision | User CPU time used planning the statement, in seconds and milliseconds (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_system_time | double precision | System CPU time used planning the statement, in seconds and milliseconds (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_minflts | bigint | Number of page reclaims (soft page faults) planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_majflts | bigint | Number of page faults (hard page faults) planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nswaps | bigint | Number of swaps planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_reads | bigint | Number of bytes read by the filesystem layer planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_reads_blks | bigint | Number of 8K blocks read by the filesystem layer planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_writes | bigint | Number of bytes written by the filesystem layer planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_writes_blks | bigint | Number of 8K blocks written by the filesystem layer planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_msgsnds | bigint | Number of IPC messages sent planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_msgrcvs | bigint | Number of IPC messages received planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nsignals | bigint | Number of signals received planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nvcsws | bigint | Number of voluntary context switches planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nivcsws | bigint | Number of involuntary context switches planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_user_time | double precision | User CPU time used executing the statement, in seconds and milliseconds | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_system_time | double precision | System CPU time used executing the statement, in seconds and milliseconds | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_minflts | bigint | Number of page reclaims (soft page faults) executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_majflts | bigint | Number of page faults (hard page faults) executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nswaps | bigint | Number of swaps executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_reads | bigint | Number of bytes read by the filesystem layer executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_reads_blks | bigint | Number of 8K blocks read by the filesystem layer executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_writes | bigint | Number of bytes written by the filesystem layer executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_writes_blks | bigint | Number of 8K blocks written by the filesystem layer executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_msgsnds | bigint | Number of IPC messages sent executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_msgrcvs | bigint | Number of IPC messages received executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nsignals | bigint | Number of signals received executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nvcsws | bigint | Number of voluntary context switches executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nivcsws | bigint | Number of involuntary context switches executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ pg_stat_kcache_reset function ----------------------------- Resets the statistics gathered by pg_stat_kcache. Can be called by superusers:: pg_stat_kcache_reset() pg_stat_kcache function ----------------------- This function is a set-returning functions that dumps the containt of the counters of the shared memory structure. This function is used by the pg_stat_kcache view. The function can be called by any user:: SELECT * FROM pg_stat_kcache(); It provides the following columns: +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | Name | Type | Description | +==================+==================+==========================================================================================================================================+ | queryid | bigint | pg_stat_statements' query identifier | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | top | bool | True if the statement is top-level | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | userid | oid | Database OID | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | dbid | oid | Database OID | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_user_time | double precision | User CPU time used planning the statement, in seconds and milliseconds (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_system_time | double precision | System CPU time used planning the statement, in seconds and milliseconds (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_minflts | bigint | Number of page reclaims (soft page faults) planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_majflts | bigint | Number of page faults (hard page faults) planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nswaps | bigint | Number of swaps planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_reads | bigint | Number of bytes read by the filesystem layer planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_reads_blks | bigint | Number of 8K blocks read by the filesystem layer planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_writes | bigint | Number of bytes written by the filesystem layer planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_writes_blks | bigint | Number of 8K blocks written by the filesystem layer planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_msgsnds | bigint | Number of IPC messages sent planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_msgrcvs | bigint | Number of IPC messages received planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nsignals | bigint | Number of signals received planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nvcsws | bigint | Number of voluntary context switches planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | plan_nivcsws | bigint | Number of involuntary context switches planning the statement (if pg_stat_kcache.track_planning is enabled, otherwise zero) | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_user_time | double precision | User CPU time used executing the statement, in seconds and milliseconds | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_system_time | double precision | System CPU time used executing the statement, in seconds and milliseconds | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_minflts | bigint | Number of page reclaims (soft page faults) executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_majflts | bigint | Number of page faults (hard page faults) executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nswaps | bigint | Number of swaps executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_reads | bigint | Number of bytes read by the filesystem layer executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_reads_blks | bigint | Number of 8K blocks read by the filesystem layer executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_writes | bigint | Number of bytes written by the filesystem layer executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_writes_blks | bigint | Number of 8K blocks written by the filesystem layer executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_msgsnds | bigint | Number of IPC messages sent executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_msgrcvs | bigint | Number of IPC messages received executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nsignals | bigint | Number of signals received executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nvcsws | bigint | Number of voluntary context switches executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ | exec_nivcsws | bigint | Number of involuntary context switches executing the statements | +------------------+------------------+------------------------------------------------------------------------------------------------------------------------------------------+ Bugs and limitations ==================== No known bugs. Tracking planner resources usage requires PostgreSQL 13 or above. We assume that a kernel block is 512 bytes. This is true for Linux, but may not be the case for another Unix implementation. See: http://lkml.indiana.edu/hypermail/linux/kernel/0703.2/0937.html On platforms without a native getrusage(2), all fields except `user_time` and `system_time` will be NULL. On platforms with a native getrusage(2), some of the fields may not be maintained. This is a platform dependent behavior, please refer to your platform getrusage(2) manual page for more details. If *pg_stat_kcache.track* is all, pg_stat_kcache tracks nested statements. The max number of nesting level that will be tracked is is limited to 64, in order to keep implementation simple, but this should be enough for reasonable use cases. Even if *pg_stat_kcache.track* is all, pg_stat_kcache view considers only statistics of top-level statements. So, there is the case which even though user cpu time used planning a nested statement is high, `plan_user_time` of pg_stat_kcache view is small. In such a case, user cpu time used planning a nested statement is counted in `exec_user_time`. Authors ======= pg_stat_kcache is an original development from Thomas Reiss, with large portions of code inspired from pg_stat_plans. Julien Rouhaud also contributed some parts of the extension. Thanks goes to Peter Geoghegan for providing much inspiration with pg_stat_plans so we could write this extension quite straightforward. License ======= pg_stat_kcache is free software distributed under the PostgreSQL license. Copyright (c) 2014-2017, Dalibo Copyright (c) 2018-2020, The PoWA-team pg_stat_kcache-REL2_2_0/debian/000077500000000000000000000000001376431076400164145ustar00rootroot00000000000000pg_stat_kcache-REL2_2_0/debian/changelog000066400000000000000000000016231376431076400202700ustar00rootroot00000000000000pg-stat-kcache (2.2.0-1) unstable; urgency=medium * New upstream version. -- Julien Rouhaud Wed, 09 Dec 2020 22:01:38 +0800 pg-stat-kcache (2.1.3-1) unstable; urgency=medium * New upstream version. -- Julien Rouhaud Thu, 16 Jul 2020 15:12:23 +0000 pg-stat-kcache (2.1.2-1) unstable; urgency=medium * New upstream version. -- Julien Rouhaud Wed, 08 Jul 2020 16:12:51 +0000 pg-stat-kcache (2.1.1-3) unstable; urgency=medium * Team upload for PostgreSQL 12. -- Christoph Berg Tue, 29 Oct 2019 13:48:37 +0100 pg-stat-kcache (2.1.1-2) unstable; urgency=medium * Team upload for PostgreSQL 11. -- Christoph Berg Fri, 12 Oct 2018 13:17:38 +0200 pg-stat-kcache (2.1.1-1) unstable; urgency=low * Initial release. -- Julien Rouhaud Sun, 22 Jul 2018 19:19:36 +0100 pg_stat_kcache-REL2_2_0/debian/compat000066400000000000000000000000021376431076400176120ustar00rootroot000000000000009 pg_stat_kcache-REL2_2_0/debian/control000066400000000000000000000015301376431076400200160ustar00rootroot00000000000000Source: pg-stat-kcache Section: database Priority: optional Maintainer: Julien Rouhaud Standards-Version: 4.1.3 Build-Depends: debhelper (>=9~), postgresql-server-dev-all (>= 141~) Homepage: https://powa.readthedocs.io/ Vcs-Browser: https://github.com/powa-team/pg_stat_kcache Vcs-Git: https://github.com/powa-team/pg_stat_kcache.git Package: postgresql-12-pg-stat-kcache Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, postgresql-12, postgresql-contrib-12 Description: PostgreSQL extension to gather per-query kernel statistics. Statistics gathered are reads and writes done out of the operating system cache, user and system CPU usage, context switches and all the other meaningful metrics returned by getrusage(2). All those counters are aggregated per postgres role, database and normalized query identifier. pg_stat_kcache-REL2_2_0/debian/control.in000066400000000000000000000015551376431076400204320ustar00rootroot00000000000000Source: pg-stat-kcache Section: database Priority: optional Maintainer: Julien Rouhaud Standards-Version: 4.1.3 Build-Depends: debhelper (>=9~), postgresql-server-dev-all (>= 141~) Homepage: https://powa.readthedocs.io/ Vcs-Browser: https://github.com/powa-team/pg_stat_kcache Vcs-Git: https://github.com/powa-team/pg_stat_kcache.git Package: postgresql-PGVERSION-pg-stat-kcache Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, postgresql-PGVERSION, postgresql-contrib-PGVERSION Description: PostgreSQL extension to gather per-query kernel statistics. Statistics gathered are reads and writes done out of the operating system cache, user and system CPU usage, context switches and all the other meaningful metrics returned by getrusage(2). All those counters are aggregated per postgres role, database and normalized query identifier. pg_stat_kcache-REL2_2_0/debian/copyright000066400000000000000000000022541376431076400203520ustar00rootroot00000000000000Portions Copyright (c) 2014-2017, Dalibo Portions Copyright (c) 2018, The PoWA-team Permission to use, copy, modify, and distribute this software and its documentation for any purpose, without fee, and without a written agreement is hereby granted, provided that the above copyright notice and this paragraph and the following two paragraphs appear in all copies. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. Contributors to pg_stat_kcache: * Thomas Reiss * Julien Rouhaud * Guillaume Lelarge * Ronan Dunklau * Maël Rimbault * Alain Delorme * Jean-Sébastien Bacq * edechaux pg_stat_kcache-REL2_2_0/debian/pgversions000066400000000000000000000000051376431076400205310ustar00rootroot000000000000009.4+ pg_stat_kcache-REL2_2_0/debian/rules000077500000000000000000000014111376431076400174710ustar00rootroot00000000000000#!/usr/bin/make -f PKGVER = $(shell dpkg-parsechangelog | awk -F '[:-]' '/^Version:/ { print substr($$2, 2) }') EXCLUDE = --exclude-vcs --exclude=debian include /usr/share/postgresql-common/pgxs_debian_control.mk override_dh_auto_build: # do nothing override_dh_auto_test: # nothing to do here, upstream tests used, see debian/tests/* override_dh_auto_install: # build all supported versions +pg_buildext loop postgresql-%v-pg-stat-kcache override_dh_installdocs: dh_installdocs --all CONTRIBUTORS.md README.rst rm -rvf debian/*/usr/share/doc/postgresql-doc-* override_dh_installchangelogs: dh_installchangelogs CHANGELOG.md upstream orig: debian/control clean cd .. && tar czf pg-stat-kcache_$(PKGVER).orig.tar.gz $(EXCLUDE) pg-stat-kcache-$(PKGVER) %: dh $@ pg_stat_kcache-REL2_2_0/debian/source/000077500000000000000000000000001376431076400177145ustar00rootroot00000000000000pg_stat_kcache-REL2_2_0/debian/source/format000066400000000000000000000000041376431076400211210ustar00rootroot000000000000001.0 pg_stat_kcache-REL2_2_0/debian/tests/000077500000000000000000000000001376431076400175565ustar00rootroot00000000000000pg_stat_kcache-REL2_2_0/debian/tests/control000066400000000000000000000001541376431076400211610ustar00rootroot00000000000000Depends: @, postgresql-contrib-12, postgresql-server-dev-all Tests: installcheck Restrictions: allow-stderr pg_stat_kcache-REL2_2_0/debian/tests/control.in000066400000000000000000000001631376431076400215660ustar00rootroot00000000000000Depends: @, postgresql-contrib-PGVERSION, postgresql-server-dev-all Tests: installcheck Restrictions: allow-stderr pg_stat_kcache-REL2_2_0/debian/tests/installcheck000077500000000000000000000001551376431076400221510ustar00rootroot00000000000000#!/bin/sh set -eu pg_buildext -o "shared_preload_libraries=pg_stat_statements,pg_stat_kcache" installcheck pg_stat_kcache-REL2_2_0/debian/watch000066400000000000000000000001731376431076400174460ustar00rootroot00000000000000version=3 opts="uversionmangle=s/_/./g" \ https://github.com/powa-team/pg_stat_kcache/releases .*/archive/REL(.*).tar.gz pg_stat_kcache-REL2_2_0/expected/000077500000000000000000000000001376431076400167735ustar00rootroot00000000000000pg_stat_kcache-REL2_2_0/expected/pgsk.out000066400000000000000000000034531376431076400204750ustar00rootroot00000000000000CREATE EXTENSION pg_stat_statements; CREATE EXTENSION pg_stat_kcache; -- dummy query SELECT 1 AS dummy; dummy ------- 1 (1 row) SELECT count(*) FROM pg_stat_kcache WHERE datname = current_database(); count ------- 1 (1 row) SELECT count(*) FROM pg_stat_kcache_detail WHERE datname = current_database() AND (query = 'SELECT $1 AS dummy' OR query = 'SELECT ? AS dummy;'); count ------- 1 (1 row) SELECT exec_reads, exec_reads_blks, exec_writes, exec_writes_blks FROM pg_stat_kcache_detail WHERE datname = current_database() AND (query = 'SELECT $1 AS dummy' OR query = 'SELECT ? AS dummy;'); exec_reads | exec_reads_blks | exec_writes | exec_writes_blks ------------+-----------------+-------------+------------------ 0 | 0 | 0 | 0 (1 row) -- dummy table CREATE TABLE test AS SELECT i FROM generate_series(1, 1000) i; -- dummy query again SELECT count(*) FROM test; count ------- 1000 (1 row) SELECT exec_user_time + exec_system_time > 0 AS cpu_time_ok FROM pg_stat_kcache_detail WHERE datname = current_database() AND query LIKE 'SELECT count(*) FROM test%'; cpu_time_ok ------------- t (1 row) -- dummy nested query SET pg_stat_statements.track = 'all'; SET pg_stat_statements.track_planning = TRUE; SET pg_stat_kcache.track = 'all'; SET pg_stat_kcache.track_planning = TRUE; SELECT pg_stat_kcache_reset(); pg_stat_kcache_reset ---------------------- (1 row) CREATE OR REPLACE FUNCTION plpgsql_nested() RETURNS void AS $$ BEGIN PERFORM i::text as str from generate_series(1, 100) as i; PERFORM md5(i::text) as str from generate_series(1, 100) as i; END $$ LANGUAGE plpgsql; SELECT plpgsql_nested(); plpgsql_nested ---------------- (1 row) SELECT COUNT(*) FROM pg_stat_kcache_detail WHERE top IS FALSE; count ------- 2 (1 row) pg_stat_kcache-REL2_2_0/pg_stat_kcache--2.1.0--2.1.1.sql000066400000000000000000000005241376431076400220760ustar00rootroot00000000000000-- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- -- Copyright (c) 2014-2017, Dalibo -- Copyright (c) 2018-2020, The PoWA-team -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "ALTER EXTENSION pg_stat_kcache" to load this file. \quit pg_stat_kcache-REL2_2_0/pg_stat_kcache--2.1.0.sql000066400000000000000000000057161376431076400213740ustar00rootroot00000000000000-- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- -- Copyright (c) 2014-2017, Dalibo -- Copyright (c) 2018-2020, The PoWA-team -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION pg_stat_kcache" to load this file. \quit SET client_encoding = 'UTF8'; CREATE FUNCTION pg_stat_kcache( OUT queryid bigint, OUT userid oid, OUT dbid oid, OUT reads bigint, /* total reads, in bytes */ OUT writes bigint, /* total writes, in bytes */ OUT user_time double precision, /* total user CPU time used */ OUT system_time double precision, /* total system CPU time used */ OUT minflts bigint, /* total page reclaims (soft page faults) */ OUT majflts bigint, /* total page faults (hard page faults) */ OUT nswaps bigint, /* total swaps */ OUT msgsnds bigint, /* total IPC messages sent */ OUT msgrcvs bigint, /* total IPC messages received */ OUT nsignals bigint, /* total signals received */ OUT nvcsws bigint, /* total voluntary context switches */ OUT nivcsws bigint /* total involuntary context switches */ ) RETURNS SETOF record LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_2_1'; GRANT ALL ON FUNCTION pg_stat_kcache() TO public; CREATE FUNCTION pg_stat_kcache_reset() RETURNS void LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_reset'; REVOKE ALL ON FUNCTION pg_stat_kcache_reset() FROM public; CREATE VIEW pg_stat_kcache_detail AS SELECT s.query, d.datname, r.rolname, k.user_time, k.system_time, k.minflts, k.majflts, k.nswaps, k.reads AS reads, k.reads/(current_setting('block_size')::integer) AS reads_blks, k.writes AS writes, k.writes/(current_setting('block_size')::integer) AS writes_blks, k.msgsnds, k.msgrcvs, k.nsignals, k.nvcsws, k.nivcsws FROM pg_stat_kcache() k JOIN pg_stat_statements s ON k.queryid = s.queryid AND k.dbid = s.dbid AND k.userid = s.userid JOIN pg_database d ON d.oid = s.dbid JOIN pg_roles r ON r.oid = s.userid; GRANT SELECT ON pg_stat_kcache_detail TO public; CREATE VIEW pg_stat_kcache AS SELECT datname, SUM(user_time) AS user_time, SUM(system_time) AS system_time, SUM(minflts) AS minflts, SUM(majflts) AS majflts, SUM(nswaps) AS nswaps, SUM(reads) AS reads, SUM(reads_blks) AS reads_blks, SUM(writes) AS writes, SUM(writes_blks) AS writes_blks, SUM(msgsnds) AS msgsnds, SUM(msgrcvs) AS msgrcvs, SUM(nsignals) AS nsignals, SUM(nvcsws) AS nvcsws, SUM(nivcsws) AS nivcsws FROM pg_stat_kcache_detail GROUP BY datname; GRANT SELECT ON pg_stat_kcache TO public; pg_stat_kcache-REL2_2_0/pg_stat_kcache--2.1.1--2.1.2.sql000066400000000000000000000005241376431076400221000ustar00rootroot00000000000000-- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- -- Copyright (c) 2014-2017, Dalibo -- Copyright (c) 2018-2020, The PoWA-team -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "ALTER EXTENSION pg_stat_kcache" to load this file. \quit pg_stat_kcache-REL2_2_0/pg_stat_kcache--2.1.1.sql000066400000000000000000000057161376431076400213750ustar00rootroot00000000000000-- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- -- Copyright (c) 2014-2017, Dalibo -- Copyright (c) 2018-2020, The PoWA-team -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION pg_stat_kcache" to load this file. \quit SET client_encoding = 'UTF8'; CREATE FUNCTION pg_stat_kcache( OUT queryid bigint, OUT userid oid, OUT dbid oid, OUT reads bigint, /* total reads, in bytes */ OUT writes bigint, /* total writes, in bytes */ OUT user_time double precision, /* total user CPU time used */ OUT system_time double precision, /* total system CPU time used */ OUT minflts bigint, /* total page reclaims (soft page faults) */ OUT majflts bigint, /* total page faults (hard page faults) */ OUT nswaps bigint, /* total swaps */ OUT msgsnds bigint, /* total IPC messages sent */ OUT msgrcvs bigint, /* total IPC messages received */ OUT nsignals bigint, /* total signals received */ OUT nvcsws bigint, /* total voluntary context switches */ OUT nivcsws bigint /* total involuntary context switches */ ) RETURNS SETOF record LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_2_1'; GRANT ALL ON FUNCTION pg_stat_kcache() TO public; CREATE FUNCTION pg_stat_kcache_reset() RETURNS void LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_reset'; REVOKE ALL ON FUNCTION pg_stat_kcache_reset() FROM public; CREATE VIEW pg_stat_kcache_detail AS SELECT s.query, d.datname, r.rolname, k.user_time, k.system_time, k.minflts, k.majflts, k.nswaps, k.reads AS reads, k.reads/(current_setting('block_size')::integer) AS reads_blks, k.writes AS writes, k.writes/(current_setting('block_size')::integer) AS writes_blks, k.msgsnds, k.msgrcvs, k.nsignals, k.nvcsws, k.nivcsws FROM pg_stat_kcache() k JOIN pg_stat_statements s ON k.queryid = s.queryid AND k.dbid = s.dbid AND k.userid = s.userid JOIN pg_database d ON d.oid = s.dbid JOIN pg_roles r ON r.oid = s.userid; GRANT SELECT ON pg_stat_kcache_detail TO public; CREATE VIEW pg_stat_kcache AS SELECT datname, SUM(user_time) AS user_time, SUM(system_time) AS system_time, SUM(minflts) AS minflts, SUM(majflts) AS majflts, SUM(nswaps) AS nswaps, SUM(reads) AS reads, SUM(reads_blks) AS reads_blks, SUM(writes) AS writes, SUM(writes_blks) AS writes_blks, SUM(msgsnds) AS msgsnds, SUM(msgrcvs) AS msgrcvs, SUM(nsignals) AS nsignals, SUM(nvcsws) AS nvcsws, SUM(nivcsws) AS nivcsws FROM pg_stat_kcache_detail GROUP BY datname; GRANT SELECT ON pg_stat_kcache TO public; pg_stat_kcache-REL2_2_0/pg_stat_kcache--2.1.2--2.1.3.sql000066400000000000000000000005241376431076400221020ustar00rootroot00000000000000-- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- -- Copyright (c) 2014-2017, Dalibo -- Copyright (c) 2018-2020, The PoWA-team -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "ALTER EXTENSION pg_stat_kcache" to load this file. \quit pg_stat_kcache-REL2_2_0/pg_stat_kcache--2.1.2.sql000066400000000000000000000057161376431076400213760ustar00rootroot00000000000000-- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- -- Copyright (c) 2014-2017, Dalibo -- Copyright (c) 2018-2020, The PoWA-team -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION pg_stat_kcache" to load this file. \quit SET client_encoding = 'UTF8'; CREATE FUNCTION pg_stat_kcache( OUT queryid bigint, OUT userid oid, OUT dbid oid, OUT reads bigint, /* total reads, in bytes */ OUT writes bigint, /* total writes, in bytes */ OUT user_time double precision, /* total user CPU time used */ OUT system_time double precision, /* total system CPU time used */ OUT minflts bigint, /* total page reclaims (soft page faults) */ OUT majflts bigint, /* total page faults (hard page faults) */ OUT nswaps bigint, /* total swaps */ OUT msgsnds bigint, /* total IPC messages sent */ OUT msgrcvs bigint, /* total IPC messages received */ OUT nsignals bigint, /* total signals received */ OUT nvcsws bigint, /* total voluntary context switches */ OUT nivcsws bigint /* total involuntary context switches */ ) RETURNS SETOF record LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_2_1'; GRANT ALL ON FUNCTION pg_stat_kcache() TO public; CREATE FUNCTION pg_stat_kcache_reset() RETURNS void LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_reset'; REVOKE ALL ON FUNCTION pg_stat_kcache_reset() FROM public; CREATE VIEW pg_stat_kcache_detail AS SELECT s.query, d.datname, r.rolname, k.user_time, k.system_time, k.minflts, k.majflts, k.nswaps, k.reads AS reads, k.reads/(current_setting('block_size')::integer) AS reads_blks, k.writes AS writes, k.writes/(current_setting('block_size')::integer) AS writes_blks, k.msgsnds, k.msgrcvs, k.nsignals, k.nvcsws, k.nivcsws FROM pg_stat_kcache() k JOIN pg_stat_statements s ON k.queryid = s.queryid AND k.dbid = s.dbid AND k.userid = s.userid JOIN pg_database d ON d.oid = s.dbid JOIN pg_roles r ON r.oid = s.userid; GRANT SELECT ON pg_stat_kcache_detail TO public; CREATE VIEW pg_stat_kcache AS SELECT datname, SUM(user_time) AS user_time, SUM(system_time) AS system_time, SUM(minflts) AS minflts, SUM(majflts) AS majflts, SUM(nswaps) AS nswaps, SUM(reads) AS reads, SUM(reads_blks) AS reads_blks, SUM(writes) AS writes, SUM(writes_blks) AS writes_blks, SUM(msgsnds) AS msgsnds, SUM(msgrcvs) AS msgrcvs, SUM(nsignals) AS nsignals, SUM(nvcsws) AS nvcsws, SUM(nivcsws) AS nivcsws FROM pg_stat_kcache_detail GROUP BY datname; GRANT SELECT ON pg_stat_kcache TO public; pg_stat_kcache-REL2_2_0/pg_stat_kcache--2.1.3--2.2.0.sql000066400000000000000000000122461376431076400221050ustar00rootroot00000000000000-- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- -- Copyright (c) 2014-2017, Dalibo -- Copyright (c) 2018-2020, The PoWA-team -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "ALTER EXTENSION pg_stat_kcache" to load this file. \quit DROP VIEW pg_stat_kcache; DROP VIEW pg_stat_kcache_detail; DROP FUNCTION pg_stat_kcache(); CREATE FUNCTION pg_stat_kcache( OUT queryid bigint, OUT top bool, OUT userid oid, OUT dbid oid, /* planning time */ OUT plan_reads bigint, /* total reads, in bytes */ OUT plan_writes bigint, /* total writes, in bytes */ OUT plan_user_time double precision, /* total user CPU time used */ OUT plan_system_time double precision, /* total system CPU time used */ OUT plan_minflts bigint, /* total page reclaims (soft page faults) */ OUT plan_majflts bigint, /* total page faults (hard page faults) */ OUT plan_nswaps bigint, /* total swaps */ OUT plan_msgsnds bigint, /* total IPC messages sent */ OUT plan_msgrcvs bigint, /* total IPC messages received */ OUT plan_nsignals bigint, /* total signals received */ OUT plan_nvcsws bigint, /* total voluntary context switches */ OUT plan_nivcsws bigint, /* total involuntary context switches */ /* execution time */ OUT exec_reads bigint, /* total reads, in bytes */ OUT exec_writes bigint, /* total writes, in bytes */ OUT exec_user_time double precision, /* total user CPU time used */ OUT exec_system_time double precision, /* total system CPU time used */ OUT exec_minflts bigint, /* total page reclaims (soft page faults) */ OUT exec_majflts bigint, /* total page faults (hard page faults) */ OUT exec_nswaps bigint, /* total swaps */ OUT exec_msgsnds bigint, /* total IPC messages sent */ OUT exec_msgrcvs bigint, /* total IPC messages received */ OUT exec_nsignals bigint, /* total signals received */ OUT exec_nvcsws bigint, /* total voluntary context switches */ OUT exec_nivcsws bigint /* total involuntary context switches */ ) RETURNS SETOF record LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_2_2'; GRANT ALL ON FUNCTION pg_stat_kcache() TO public; CREATE VIEW pg_stat_kcache_detail AS SELECT s.query, k.top, d.datname, r.rolname, k.plan_user_time, k.plan_system_time, k.plan_minflts, k.plan_majflts, k.plan_nswaps, k.plan_reads AS plan_reads, k.plan_reads/(current_setting('block_size')::integer) AS plan_reads_blks, k.plan_writes AS plan_writes, k.plan_writes/(current_setting('block_size')::integer) AS plan_writes_blks, k.plan_msgsnds, k.plan_msgrcvs, k.plan_nsignals, k.plan_nvcsws, k.plan_nivcsws, k.exec_user_time, k.exec_system_time, k.exec_minflts, k.exec_majflts, k.exec_nswaps, k.exec_reads AS exec_reads, k.exec_reads/(current_setting('block_size')::integer) AS exec_reads_blks, k.exec_writes AS exec_writes, k.exec_writes/(current_setting('block_size')::integer) AS exec_writes_blks, k.exec_msgsnds, k.exec_msgrcvs, k.exec_nsignals, k.exec_nvcsws, k.exec_nivcsws FROM pg_stat_kcache() k JOIN pg_stat_statements s ON k.queryid = s.queryid AND k.dbid = s.dbid AND k.userid = s.userid JOIN pg_database d ON d.oid = s.dbid JOIN pg_roles r ON r.oid = s.userid; GRANT SELECT ON pg_stat_kcache_detail TO public; CREATE VIEW pg_stat_kcache AS SELECT datname, SUM(plan_user_time) AS plan_user_time, SUM(plan_system_time) AS plan_system_time, SUM(plan_minflts) AS plan_minflts, SUM(plan_majflts) AS plan_majflts, SUM(plan_nswaps) AS plan_nswaps, SUM(plan_reads) AS plan_reads, SUM(plan_reads_blks) AS plan_reads_blks, SUM(plan_writes) AS plan_writes, SUM(plan_writes_blks) AS plan_writes_blks, SUM(plan_msgsnds) AS plan_msgsnds, SUM(plan_msgrcvs) AS plan_msgrcvs, SUM(plan_nsignals) AS plan_nsignals, SUM(plan_nvcsws) AS plan_nvcsws, SUM(plan_nivcsws) AS plan_nivcsws, SUM(exec_user_time) AS exec_user_time, SUM(exec_system_time) AS exec_system_time, SUM(exec_minflts) AS exec_minflts, SUM(exec_majflts) AS exec_majflts, SUM(exec_nswaps) AS exec_nswaps, SUM(exec_reads) AS exec_reads, SUM(exec_reads_blks) AS exec_reads_blks, SUM(exec_writes) AS exec_writes, SUM(exec_writes_blks) AS exec_writes_blks, SUM(exec_msgsnds) AS exec_msgsnds, SUM(exec_msgrcvs) AS exec_msgrcvs, SUM(exec_nsignals) AS exec_nsignals, SUM(exec_nvcsws) AS exec_nvcsws, SUM(exec_nivcsws) AS exec_nivcsws FROM pg_stat_kcache_detail WHERE top IS TRUE GROUP BY datname; GRANT SELECT ON pg_stat_kcache TO public; pg_stat_kcache-REL2_2_0/pg_stat_kcache--2.1.3.sql000066400000000000000000000057161376431076400213770ustar00rootroot00000000000000-- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- -- Copyright (c) 2014-2017, Dalibo -- Copyright (c) 2018-2020, The PoWA-team -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION pg_stat_kcache" to load this file. \quit SET client_encoding = 'UTF8'; CREATE FUNCTION pg_stat_kcache( OUT queryid bigint, OUT userid oid, OUT dbid oid, OUT reads bigint, /* total reads, in bytes */ OUT writes bigint, /* total writes, in bytes */ OUT user_time double precision, /* total user CPU time used */ OUT system_time double precision, /* total system CPU time used */ OUT minflts bigint, /* total page reclaims (soft page faults) */ OUT majflts bigint, /* total page faults (hard page faults) */ OUT nswaps bigint, /* total swaps */ OUT msgsnds bigint, /* total IPC messages sent */ OUT msgrcvs bigint, /* total IPC messages received */ OUT nsignals bigint, /* total signals received */ OUT nvcsws bigint, /* total voluntary context switches */ OUT nivcsws bigint /* total involuntary context switches */ ) RETURNS SETOF record LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_2_1'; GRANT ALL ON FUNCTION pg_stat_kcache() TO public; CREATE FUNCTION pg_stat_kcache_reset() RETURNS void LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_reset'; REVOKE ALL ON FUNCTION pg_stat_kcache_reset() FROM public; CREATE VIEW pg_stat_kcache_detail AS SELECT s.query, d.datname, r.rolname, k.user_time, k.system_time, k.minflts, k.majflts, k.nswaps, k.reads AS reads, k.reads/(current_setting('block_size')::integer) AS reads_blks, k.writes AS writes, k.writes/(current_setting('block_size')::integer) AS writes_blks, k.msgsnds, k.msgrcvs, k.nsignals, k.nvcsws, k.nivcsws FROM pg_stat_kcache() k JOIN pg_stat_statements s ON k.queryid = s.queryid AND k.dbid = s.dbid AND k.userid = s.userid JOIN pg_database d ON d.oid = s.dbid JOIN pg_roles r ON r.oid = s.userid; GRANT SELECT ON pg_stat_kcache_detail TO public; CREATE VIEW pg_stat_kcache AS SELECT datname, SUM(user_time) AS user_time, SUM(system_time) AS system_time, SUM(minflts) AS minflts, SUM(majflts) AS majflts, SUM(nswaps) AS nswaps, SUM(reads) AS reads, SUM(reads_blks) AS reads_blks, SUM(writes) AS writes, SUM(writes_blks) AS writes_blks, SUM(msgsnds) AS msgsnds, SUM(msgrcvs) AS msgrcvs, SUM(nsignals) AS nsignals, SUM(nvcsws) AS nvcsws, SUM(nivcsws) AS nivcsws FROM pg_stat_kcache_detail GROUP BY datname; GRANT SELECT ON pg_stat_kcache TO public; pg_stat_kcache-REL2_2_0/pg_stat_kcache--2.2.0.sql000066400000000000000000000124601376431076400213670ustar00rootroot00000000000000-- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- -- Copyright (c) 2014-2017, Dalibo -- Copyright (c) 2018-2020, The PoWA-team -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION pg_stat_kcache" to load this file. \quit SET client_encoding = 'UTF8'; CREATE FUNCTION pg_stat_kcache( OUT queryid bigint, OUT top bool, OUT userid oid, OUT dbid oid, /* planning time */ OUT plan_reads bigint, /* total reads, in bytes */ OUT plan_writes bigint, /* total writes, in bytes */ OUT plan_user_time double precision, /* total user CPU time used */ OUT plan_system_time double precision, /* total system CPU time used */ OUT plan_minflts bigint, /* total page reclaims (soft page faults) */ OUT plan_majflts bigint, /* total page faults (hard page faults) */ OUT plan_nswaps bigint, /* total swaps */ OUT plan_msgsnds bigint, /* total IPC messages sent */ OUT plan_msgrcvs bigint, /* total IPC messages received */ OUT plan_nsignals bigint, /* total signals received */ OUT plan_nvcsws bigint, /* total voluntary context switches */ OUT plan_nivcsws bigint, /* total involuntary context switches */ /* execution time */ OUT exec_reads bigint, /* total reads, in bytes */ OUT exec_writes bigint, /* total writes, in bytes */ OUT exec_user_time double precision, /* total user CPU time used */ OUT exec_system_time double precision, /* total system CPU time used */ OUT exec_minflts bigint, /* total page reclaims (soft page faults) */ OUT exec_majflts bigint, /* total page faults (hard page faults) */ OUT exec_nswaps bigint, /* total swaps */ OUT exec_msgsnds bigint, /* total IPC messages sent */ OUT exec_msgrcvs bigint, /* total IPC messages received */ OUT exec_nsignals bigint, /* total signals received */ OUT exec_nvcsws bigint, /* total voluntary context switches */ OUT exec_nivcsws bigint /* total involuntary context switches */ ) RETURNS SETOF record LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_2_2'; GRANT ALL ON FUNCTION pg_stat_kcache() TO public; CREATE FUNCTION pg_stat_kcache_reset() RETURNS void LANGUAGE c COST 1000 AS '$libdir/pg_stat_kcache', 'pg_stat_kcache_reset'; REVOKE ALL ON FUNCTION pg_stat_kcache_reset() FROM public; CREATE VIEW pg_stat_kcache_detail AS SELECT s.query, k.top, d.datname, r.rolname, k.plan_user_time, k.plan_system_time, k.plan_minflts, k.plan_majflts, k.plan_nswaps, k.plan_reads AS plan_reads, k.plan_reads/(current_setting('block_size')::integer) AS plan_reads_blks, k.plan_writes AS plan_writes, k.plan_writes/(current_setting('block_size')::integer) AS plan_writes_blks, k.plan_msgsnds, k.plan_msgrcvs, k.plan_nsignals, k.plan_nvcsws, k.plan_nivcsws, k.exec_user_time, k.exec_system_time, k.exec_minflts, k.exec_majflts, k.exec_nswaps, k.exec_reads AS exec_reads, k.exec_reads/(current_setting('block_size')::integer) AS exec_reads_blks, k.exec_writes AS exec_writes, k.exec_writes/(current_setting('block_size')::integer) AS exec_writes_blks, k.exec_msgsnds, k.exec_msgrcvs, k.exec_nsignals, k.exec_nvcsws, k.exec_nivcsws FROM pg_stat_kcache() k JOIN pg_stat_statements s ON k.queryid = s.queryid AND k.dbid = s.dbid AND k.userid = s.userid JOIN pg_database d ON d.oid = s.dbid JOIN pg_roles r ON r.oid = s.userid; GRANT SELECT ON pg_stat_kcache_detail TO public; CREATE VIEW pg_stat_kcache AS SELECT datname, SUM(plan_user_time) AS plan_user_time, SUM(plan_system_time) AS plan_system_time, SUM(plan_minflts) AS plan_minflts, SUM(plan_majflts) AS plan_majflts, SUM(plan_nswaps) AS plan_nswaps, SUM(plan_reads) AS plan_reads, SUM(plan_reads_blks) AS plan_reads_blks, SUM(plan_writes) AS plan_writes, SUM(plan_writes_blks) AS plan_writes_blks, SUM(plan_msgsnds) AS plan_msgsnds, SUM(plan_msgrcvs) AS plan_msgrcvs, SUM(plan_nsignals) AS plan_nsignals, SUM(plan_nvcsws) AS plan_nvcsws, SUM(plan_nivcsws) AS plan_nivcsws, SUM(exec_user_time) AS exec_user_time, SUM(exec_system_time) AS exec_system_time, SUM(exec_minflts) AS exec_minflts, SUM(exec_majflts) AS exec_majflts, SUM(exec_nswaps) AS exec_nswaps, SUM(exec_reads) AS exec_reads, SUM(exec_reads_blks) AS exec_reads_blks, SUM(exec_writes) AS exec_writes, SUM(exec_writes_blks) AS exec_writes_blks, SUM(exec_msgsnds) AS exec_msgsnds, SUM(exec_msgrcvs) AS exec_msgrcvs, SUM(exec_nsignals) AS exec_nsignals, SUM(exec_nvcsws) AS exec_nvcsws, SUM(exec_nivcsws) AS exec_nivcsws FROM pg_stat_kcache_detail WHERE top IS TRUE GROUP BY datname; GRANT SELECT ON pg_stat_kcache TO public; pg_stat_kcache-REL2_2_0/pg_stat_kcache.c000066400000000000000000001016401376431076400202770ustar00rootroot00000000000000/*--------------- * pg_stat_kcache * * Provides basic statistics about real I/O done by the filesystem layer. * This way, calculating a real hit-ratio is doable. Also provides basis * statistics about CPU usage. * * Large portions of code freely inspired by pg_stat_plans. Thanks to Peter * Geoghegan for this great extension. * * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * */ #include "postgres.h" #include #ifdef HAVE_SYS_RESOURCE_H #include #include #endif #ifndef HAVE_GETRUSAGE #include "rusagestub.h" #endif #include "access/hash.h" #if PG_VERSION_NUM >= 90600 #include "access/parallel.h" #endif #include "executor/executor.h" #include "funcapi.h" #include "miscadmin.h" #if PG_VERSION_NUM >= 130000 #include "optimizer/planner.h" #endif #include "pgstat.h" #if PG_VERSION_NUM >= 90600 #include "postmaster/autovacuum.h" #endif #include "storage/fd.h" #include "storage/ipc.h" #include "storage/spin.h" #include "utils/builtins.h" #include "utils/guc.h" PG_MODULE_MAGIC; #if PG_VERSION_NUM >= 90300 #define PGSK_DUMP_FILE "pg_stat/pg_stat_kcache.stat" #else #define PGSK_DUMP_FILE "global/pg_stat_kcache.stat" #endif /* In PostgreSQL 11, queryid becomes a uint64 internally. */ #if PG_VERSION_NUM >= 110000 typedef uint64 pgsk_queryid; #else typedef uint32 pgsk_queryid; #endif #define PG_STAT_KCACHE_COLS_V2_0 7 #define PG_STAT_KCACHE_COLS_V2_1 15 #define PG_STAT_KCACHE_COLS_V2_2 28 #define PG_STAT_KCACHE_COLS 28 /* maximum of above */ #define USAGE_INCREASE (1.0) #define USAGE_DECREASE_FACTOR (0.99) /* decreased every pgsk_entry_dealloc */ #define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */ #define USAGE_INIT (1.0) /* including initial planning */ /* ru_inblock block size is 512 bytes with Linux * see http://lkml.indiana.edu/hypermail/linux/kernel/0703.2/0937.html */ #define RUSAGE_BLOCK_SIZE 512 /* Size of a block for getrusage() */ #define TIMEVAL_DIFF(start, end) ((double) end.tv_sec + (double) end.tv_usec / 1000000.0) \ - ((double) start.tv_sec + (double) start.tv_usec / 1000000.0) #if PG_VERSION_NUM < 140000 #define ParallelLeaderBackendId ParallelMasterBackendId #endif #define PGSK_MAX_NESTED_LEVEL 64 /* * Extension version number, for supporting older extension versions' objects */ typedef enum pgskVersion { PGSK_V2_0 = 0, PGSK_V2_1, PGSK_V2_2 } pgskVersion; typedef enum pgskStoreKind { /* * PGSS_PLAN and PGSS_EXEC must be respectively 0 and 1 as they're used to * reference the underlying values in the arrays in the Counters struct, * and this order is required in pg_stat_statements_internal(). */ PGSK_PLAN = 0, PGSK_EXEC, PGSK_NUMKIND /* Must be last value of this enum */ } pgskStoreKind; static const uint32 PGSK_FILE_HEADER = 0x0d756e11; static struct rusage exec_rusage_start[PGSK_MAX_NESTED_LEVEL]; #if PG_VERSION_NUM >= 130000 static struct rusage plan_rusage_start[PGSK_MAX_NESTED_LEVEL]; #endif /* * Current getrusage counters. * * For platform without getrusage support, we rely on postgres implementation * defined in rusagestub.h, which only supports user and system time. * * Note that the following counters are not maintained on GNU/Linux: * - ru_nswap * - ru_msgsnd * - ru_msgrcv * - ru_nsignals */ typedef struct pgskCounters { double usage; /* usage factor */ /* These fields are always used */ float8 utime; /* CPU user time */ float8 stime; /* CPU system time */ #ifdef HAVE_GETRUSAGE /* These fields are only used for platform with HAVE_GETRUSAGE defined */ int64 minflts; /* page reclaims (soft page faults) */ int64 majflts; /* page faults (hard page faults) */ int64 nswaps; /* swaps */ int64 reads; /* Physical block reads */ int64 writes; /* Physical block writes */ int64 msgsnds; /* IPC messages sent */ int64 msgrcvs; /* IPC messages received */ int64 nsignals; /* signals received */ int64 nvcsws; /* voluntary context witches */ int64 nivcsws; /* unvoluntary context witches */ #endif } pgskCounters; static int pgsk_max = 0; /* max #queries to store. pg_stat_statements.max is used */ /* * Hashtable key that defines the identity of a hashtable entry. We use the * same hash as pg_stat_statements */ typedef struct pgskHashKey { Oid userid; /* user OID */ Oid dbid; /* database OID */ pgsk_queryid queryid; /* query identifier */ bool top; /* whether statement is top level */ } pgskHashKey; /* * Statistics per database */ typedef struct pgskEntry { pgskHashKey key; /* hash key of entry - MUST BE FIRST */ pgskCounters counters[PGSK_NUMKIND]; /* statistics for this query */ slock_t mutex; /* protects the counters only */ } pgskEntry; /* * Global shared state */ typedef struct pgskSharedState { LWLock *lock; /* protects hashtable search/modification */ #if PG_VERSION_NUM >= 90600 LWLock *queryids_lock; /* protects queryids array */ pgsk_queryid queryids[FLEXIBLE_ARRAY_MEMBER]; /* queryid info for parallel leaders */ #endif } pgskSharedState; /*---- Local variables ----*/ /* Current nesting depth of ExecutorRun+ProcessUtility calls */ static int exec_nested_level = 0; #if PG_VERSION_NUM >= 130000 /* Current nesting depth of planner calls */ static int plan_nested_level = 0; #endif /* saved hook address in case of unload */ static shmem_startup_hook_type prev_shmem_startup_hook = NULL; #if PG_VERSION_NUM >= 130000 static planner_hook_type prev_planner_hook = NULL; #endif static ExecutorStart_hook_type prev_ExecutorStart = NULL; static ExecutorRun_hook_type prev_ExecutorRun = NULL; static ExecutorFinish_hook_type prev_ExecutorFinish = NULL; static ExecutorEnd_hook_type prev_ExecutorEnd = NULL; /* Links to shared memory state */ static pgskSharedState *pgsk = NULL; static HTAB *pgsk_hash = NULL; /*---- GUC variables ----*/ typedef enum { PGSK_TRACK_NONE, /* track no statements */ PGSK_TRACK_TOP, /* only top level statements */ PGSK_TRACK_ALL /* all statements, including nested ones */ } PGSKTrackLevel; static const struct config_enum_entry pgs_track_options[] = { {"none", PGSK_TRACK_NONE, false}, {"top", PGSK_TRACK_TOP, false}, {"all", PGSK_TRACK_ALL, false}, {NULL, 0, false} }; static int pgsk_track; /* tracking level */ #if PG_VERSION_NUM >= 130000 static bool pgsk_track_planning; /* whether to track planning duration */ #endif #define pgsk_enabled(level) \ ((pgsk_track == PGSK_TRACK_ALL && (level) < PGSK_MAX_NESTED_LEVEL) || \ (pgsk_track == PGSK_TRACK_TOP && (level) == 0)) #define is_top(level) (level) == 0 /*--- Functions --- */ void _PG_init(void); void _PG_fini(void); extern PGDLLEXPORT Datum pg_stat_kcache_reset(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum pg_stat_kcache(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum pg_stat_kcache_2_1(PG_FUNCTION_ARGS); extern PGDLLEXPORT Datum pg_stat_kcache_2_2(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(pg_stat_kcache_reset); PG_FUNCTION_INFO_V1(pg_stat_kcache); PG_FUNCTION_INFO_V1(pg_stat_kcache_2_1); PG_FUNCTION_INFO_V1(pg_stat_kcache_2_2); static void pg_stat_kcache_internal(FunctionCallInfo fcinfo, pgskVersion api_version); static void pgsk_setmax(void); static Size pgsk_memsize(void); static void pgsk_shmem_startup(void); static void pgsk_shmem_shutdown(int code, Datum arg); #if PG_VERSION_NUM >= 130000 static PlannedStmt *pgsk_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams); #endif static void pgsk_ExecutorStart(QueryDesc *queryDesc, int eflags); static void pgsk_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, #if PG_VERSION_NUM >= 90600 uint64 count #else long count #endif #if PG_VERSION_NUM >= 100000 , bool execute_once #endif ); static void pgsk_ExecutorFinish(QueryDesc *queryDesc); static void pgsk_ExecutorEnd(QueryDesc *queryDesc); static pgskEntry *pgsk_entry_alloc(pgskHashKey *key); static void pgsk_entry_dealloc(void); static void pgsk_entry_reset(void); static void pgsk_entry_store(pgsk_queryid queryId, pgskStoreKind kind, int level, pgskCounters counters); static uint32 pgsk_hash_fn(const void *key, Size keysize); static int pgsk_match_fn(const void *key1, const void *key2, Size keysize); static bool pgsk_assign_linux_hz_check_hook(int *newval, void **extra, GucSource source); static void pgsk_compute_counters(pgskCounters *counters, struct rusage *rusage_start, struct rusage *rusage_end, QueryDesc *queryDesc); #if PG_VERSION_NUM >= 90600 static Size pgsk_queryids_array_size(void); static void pgsk_set_queryid(pgsk_queryid queryid); #endif static int pgsk_linux_hz; void _PG_init(void) { if (!process_shared_preload_libraries_in_progress) { elog(ERROR, "This module can only be loaded via shared_preload_libraries"); return; } DefineCustomIntVariable("pg_stat_kcache.linux_hz", "Inform pg_stat_kcache of the linux CONFIG_HZ config option", "This is used by pg_stat_kcache to compensate for sampling errors " "in getrusage due to the kernel adhering to its ticks. The default value, -1, " "tries to guess it at startup. ", &pgsk_linux_hz, -1, -1, INT_MAX, PGC_USERSET, 0, pgsk_assign_linux_hz_check_hook, NULL, NULL); DefineCustomEnumVariable("pg_stat_kcache.track", "Selects which statements are tracked by pg_stat_kcache.", NULL, &pgsk_track, PGSK_TRACK_TOP, pgs_track_options, PGC_SUSET, 0, NULL, NULL, NULL); #if PG_VERSION_NUM >= 130000 DefineCustomBoolVariable("pg_stat_kcache.track_planning", "Selects whether planning duration is tracked by pg_stat_cache.", NULL, &pgsk_track_planning, false, PGC_SUSET, 0, NULL, NULL, NULL); #endif EmitWarningsOnPlaceholders("pg_stat_kcache"); /* set pgsk_max if needed */ pgsk_setmax(); RequestAddinShmemSpace(pgsk_memsize()); #if PG_VERSION_NUM >= 90600 RequestNamedLWLockTranche("pg_stat_kcache", 2); #else RequestAddinLWLocks(1); #endif /* Install hook */ prev_shmem_startup_hook = shmem_startup_hook; shmem_startup_hook = pgsk_shmem_startup; #if PG_VERSION_NUM >= 130000 prev_planner_hook = planner_hook; planner_hook = pgsk_planner; #endif prev_ExecutorStart = ExecutorStart_hook; ExecutorStart_hook = pgsk_ExecutorStart; prev_ExecutorRun = ExecutorRun_hook; ExecutorRun_hook = pgsk_ExecutorRun; prev_ExecutorFinish = ExecutorFinish_hook; ExecutorFinish_hook = pgsk_ExecutorFinish; prev_ExecutorEnd = ExecutorEnd_hook; ExecutorEnd_hook = pgsk_ExecutorEnd; } void _PG_fini(void) { /* uninstall hook */ shmem_startup_hook = prev_shmem_startup_hook; #if PG_VERSION_NUM >= 130000 planner_hook = prev_planner_hook; #endif ExecutorStart_hook = prev_ExecutorStart; ExecutorRun_hook = prev_ExecutorRun; ExecutorFinish_hook = prev_ExecutorFinish; ExecutorEnd_hook = prev_ExecutorEnd; } static bool pgsk_assign_linux_hz_check_hook(int *newval, void **extra, GucSource source) { int val = *newval; struct rusage myrusage; struct timeval previous_value; /* In that case we try to guess it */ if (val == -1) { elog(LOG, "Auto detecting pg_stat_kcache.linux_hz parameter..."); getrusage(RUSAGE_SELF, &myrusage); previous_value = myrusage.ru_utime; while (myrusage.ru_utime.tv_usec == previous_value.tv_usec && myrusage.ru_utime.tv_sec == previous_value.tv_sec) { getrusage(RUSAGE_SELF, &myrusage); } *newval = (int) (1 / ((myrusage.ru_utime.tv_sec - previous_value.tv_sec) + (myrusage.ru_utime.tv_usec - previous_value.tv_usec) / 1000000.)); elog(LOG, "pg_stat_kcache.linux_hz is set to %d", *newval); } return true; } static void pgsk_compute_counters(pgskCounters *counters, struct rusage *rusage_start, struct rusage *rusage_end, QueryDesc *queryDesc) { /* Compute CPU time delta */ counters->utime = TIMEVAL_DIFF(rusage_start->ru_utime, rusage_end->ru_utime); counters->stime = TIMEVAL_DIFF(rusage_start->ru_stime, rusage_end->ru_stime); if (queryDesc && queryDesc->totaltime) { /* Make sure stats accumulation is done */ InstrEndLoop(queryDesc->totaltime); /* * We only consider values greater than 3 * linux tick, otherwise the * bias is too big */ if (queryDesc->totaltime->total < (3. / pgsk_linux_hz)) { counters->stime = 0; counters->utime = queryDesc->totaltime->total; } } #ifdef HAVE_GETRUSAGE /* Compute the rest of the counters */ counters->minflts = rusage_end->ru_minflt - rusage_start->ru_minflt; counters->majflts = rusage_end->ru_majflt - rusage_start->ru_majflt; counters->nswaps = rusage_end->ru_nswap - rusage_start->ru_nswap; counters->reads = rusage_end->ru_inblock - rusage_start->ru_inblock; counters->writes = rusage_end->ru_oublock - rusage_start->ru_oublock; counters->msgsnds = rusage_end->ru_msgsnd - rusage_start->ru_msgsnd; counters->msgrcvs = rusage_end->ru_msgrcv - rusage_start->ru_msgrcv; counters->nsignals = rusage_end->ru_nsignals - rusage_start->ru_nsignals; counters->nvcsws = rusage_end->ru_nvcsw - rusage_start->ru_nvcsw; counters->nivcsws = rusage_end->ru_nivcsw - rusage_start->ru_nivcsw; #endif } #if PG_VERSION_NUM >= 90600 static void pgsk_set_queryid(pgsk_queryid queryid) { /* Only the leader knows the queryid. */ Assert(!IsParallelWorker()); LWLockAcquire(pgsk->queryids_lock, LW_EXCLUSIVE); pgsk->queryids[MyBackendId] = queryid; LWLockRelease(pgsk->queryids_lock); } #endif static void pgsk_shmem_startup(void) { bool found; HASHCTL info; FILE *file; int i; uint32 header; int32 num; pgskEntry *buffer = NULL; if (prev_shmem_startup_hook) prev_shmem_startup_hook(); /* reset in case this is a restart within the postmaster */ pgsk = NULL; /* Create or attach to the shared memory state */ LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); /* global access lock */ pgsk = ShmemInitStruct("pg_stat_kcache", (sizeof(pgskSharedState) #if PG_VERSION_NUM >= 90600 + pgsk_queryids_array_size() #endif ), &found); if (!found) { /* First time through ... */ #if PG_VERSION_NUM >= 90600 LWLockPadded *locks = GetNamedLWLockTranche("pg_stat_kcache"); pgsk->lock = &(locks[0]).lock; pgsk->queryids_lock = &(locks[1]).lock; #else pgsk->lock = LWLockAssign(); #endif } /* set pgsk_max if needed */ pgsk_setmax(); memset(&info, 0, sizeof(info)); info.keysize = sizeof(pgskHashKey); info.entrysize = sizeof(pgskEntry); info.hash = pgsk_hash_fn; info.match = pgsk_match_fn; /* allocate stats shared memory hash */ pgsk_hash = ShmemInitHash("pg_stat_kcache hash", pgsk_max, pgsk_max, &info, HASH_ELEM | HASH_FUNCTION | HASH_COMPARE); LWLockRelease(AddinShmemInitLock); if (!IsUnderPostmaster) on_shmem_exit(pgsk_shmem_shutdown, (Datum) 0); /* * Done if some other process already completed our initialization. */ if (found) return; /* Load stat file, don't care about locking */ file = AllocateFile(PGSK_DUMP_FILE, PG_BINARY_R); if (file == NULL) { if (errno == ENOENT) return; /* ignore not-found error */ goto error; } /* check is header is valid */ if (fread(&header, sizeof(uint32), 1, file) != 1 || header != PGSK_FILE_HEADER) goto error; /* get number of entries */ if (fread(&num, sizeof(int32), 1, file) != 1) goto error; for (i = 0; i < num ; i++) { pgskEntry temp; pgskEntry *entry; if (fread(&temp, sizeof(pgskEntry), 1, file) != 1) goto error; entry = pgsk_entry_alloc(&temp.key); /* copy in the actual stats */ entry->counters[0] = temp.counters[0]; entry->counters[1] = temp.counters[1]; /* don't initialize spinlock, already done */ } FreeFile(file); /* * Remove the file so it's not included in backups/replication slaves, * etc. A new file will be written on next shutdown. */ unlink(PGSK_DUMP_FILE); return; error: ereport(LOG, (errcode_for_file_access(), errmsg("could not read pg_stat_kcache file \"%s\": %m", PGSK_DUMP_FILE))); if (buffer) pfree(buffer); if (file) FreeFile(file); /* delete bogus file, don't care of errors in this case */ unlink(PGSK_DUMP_FILE); } /* * shmem_shutdown hook: dump statistics into file. * */ static void pgsk_shmem_shutdown(int code, Datum arg) { FILE *file; HASH_SEQ_STATUS hash_seq; int32 num_entries; pgskEntry *entry; /* Don't try to dump during a crash. */ if (code) return; if (!pgsk) return; file = AllocateFile(PGSK_DUMP_FILE ".tmp", PG_BINARY_W); if (file == NULL) goto error; if (fwrite(&PGSK_FILE_HEADER, sizeof(uint32), 1, file) != 1) goto error; num_entries = hash_get_num_entries(pgsk_hash); if (fwrite(&num_entries, sizeof(int32), 1, file) != 1) goto error; hash_seq_init(&hash_seq, pgsk_hash); while ((entry = hash_seq_search(&hash_seq)) != NULL) { if (fwrite(entry, sizeof(pgskEntry), 1, file) != 1) { /* note: we assume hash_seq_term won't change errno */ hash_seq_term(&hash_seq); goto error; } } if (FreeFile(file)) { file = NULL; goto error; } /* * Rename file inplace */ if (rename(PGSK_DUMP_FILE ".tmp", PGSK_DUMP_FILE) != 0) ereport(LOG, (errcode_for_file_access(), errmsg("could not rename pg_stat_kcache file \"%s\": %m", PGSK_DUMP_FILE ".tmp"))); return; error: ereport(LOG, (errcode_for_file_access(), errmsg("could not read pg_stat_kcache file \"%s\": %m", PGSK_DUMP_FILE))); if (file) FreeFile(file); unlink(PGSK_DUMP_FILE); } /* * Retrieve pg_stat_statement.max GUC value and store it into pgsk_max, since * we want to store the same number of entries as pg_stat_statements. Don't do * anything if pgsk_max is already set. */ static void pgsk_setmax(void) { const char *pgss_max; const char *name = "pg_stat_statements.max"; if (pgsk_max != 0) return; pgss_max = GetConfigOption(name, true, false); /* * Retrieving pg_stat_statements.max can fail if pgss is loaded after pgsk * in shared_preload_libraries. Hint user in case this happens. */ if (!pgss_max) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("unrecognized configuration parameter \"%s\"", name), errhint("make sure pg_stat_statements is loaded,\n" "and make sure pg_stat_kcache is present after pg_stat_statements" " in the shared_preload_libraries setting"))); pgsk_max = atoi(pgss_max); } static Size pgsk_memsize(void) { Size size; Assert(pgsk_max != 0); size = MAXALIGN(sizeof(pgskSharedState)); size = add_size(size, hash_estimate_size(pgsk_max, sizeof(pgskEntry))); #if PG_VERSION_NUM >= 90600 size = add_size(size, MAXALIGN(pgsk_queryids_array_size())); #endif return size; } #if PG_VERSION_NUM >= 90600 static Size pgsk_queryids_array_size(void) { /* * queryid isn't pushed to parallel workers. We store them in shared mem * for each query, identified by their BackendId. If need room for all * possible backends, plus autovacuum launcher and workers, plus bg workers * and an extra one since BackendId numerotation starts at 1. */ return (sizeof(pgsk_queryid) * (MaxConnections + autovacuum_max_workers + 1 + max_worker_processes + 1)); } #endif /* * support functions */ static void pgsk_entry_store(pgsk_queryid queryId, pgskStoreKind kind, int level, pgskCounters counters) { volatile pgskEntry *e; pgskHashKey key; pgskEntry *entry; /* Safety check... */ if (!pgsk || !pgsk_hash) return; /* Set up key for hashtable search */ key.userid = GetUserId(); key.dbid = MyDatabaseId; key.queryid = queryId; key.top = is_top(level); /* Lookup the hash table entry with shared lock. */ LWLockAcquire(pgsk->lock, LW_SHARED); entry = (pgskEntry *) hash_search(pgsk_hash, &key, HASH_FIND, NULL); /* Create new entry, if not present */ if (!entry) { /* Need exclusive lock to make a new hashtable entry - promote */ LWLockRelease(pgsk->lock); LWLockAcquire(pgsk->lock, LW_EXCLUSIVE); /* OK to create a new hashtable entry */ entry = pgsk_entry_alloc(&key); } /* * Grab the spinlock while updating the counters (see comment about * locking rules at the head of the file) */ e = (volatile pgskEntry *) entry; SpinLockAcquire(&e->mutex); e->counters[0].usage += USAGE_INCREASE; e->counters[kind].utime += counters.utime; e->counters[kind].stime += counters.stime; #ifdef HAVE_GETRUSAGE e->counters[kind].minflts += counters.minflts; e->counters[kind].majflts += counters.majflts; e->counters[kind].nswaps += counters.nswaps; e->counters[kind].reads += counters.reads; e->counters[kind].writes += counters.writes; e->counters[kind].msgsnds += counters.msgsnds; e->counters[kind].msgrcvs += counters.msgrcvs; e->counters[kind].nsignals += counters.nsignals; e->counters[kind].nvcsws += counters.nvcsws; e->counters[kind].nivcsws += counters.nivcsws; #endif SpinLockRelease(&e->mutex); LWLockRelease(pgsk->lock); } /* * Allocate a new hashtable entry. * caller must hold an exclusive lock on pgsk->lock */ static pgskEntry *pgsk_entry_alloc(pgskHashKey *key) { pgskEntry *entry; bool found; /* Make space if needed */ while (hash_get_num_entries(pgsk_hash) >= pgsk_max) pgsk_entry_dealloc(); /* Find or create an entry with desired hash code */ entry = (pgskEntry *) hash_search(pgsk_hash, key, HASH_ENTER, &found); if (!found) { /* New entry, initialize it */ /* reset the statistics */ memset(&entry->counters, 0, sizeof(pgskCounters) * PGSK_NUMKIND); /* set the appropriate initial usage count */ entry->counters[0].usage = USAGE_INIT; /* re-initialize the mutex each time ... we assume no one using it */ SpinLockInit(&entry->mutex); } return entry; } /* * qsort comparator for sorting into increasing usage order */ static int entry_cmp(const void *lhs, const void *rhs) { double l_usage = (*(pgskEntry *const *) lhs)->counters[0].usage; double r_usage = (*(pgskEntry *const *) rhs)->counters[0].usage; if (l_usage < r_usage) return -1; else if (l_usage > r_usage) return +1; else return 0; } /* * Deallocate least used entries. * Caller must hold an exclusive lock on pgsk->lock. */ static void pgsk_entry_dealloc(void) { HASH_SEQ_STATUS hash_seq; pgskEntry **entries; pgskEntry *entry; int nvictims; int i; /* * Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them. * While we're scanning the table, apply the decay factor to the usage * values. */ entries = palloc(hash_get_num_entries(pgsk_hash) * sizeof(pgskEntry *)); i = 0; hash_seq_init(&hash_seq, pgsk_hash); while ((entry = hash_seq_search(&hash_seq)) != NULL) { entries[i++] = entry; entry->counters[0].usage *= USAGE_DECREASE_FACTOR; } qsort(entries, i, sizeof(pgskEntry *), entry_cmp); nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100); nvictims = Min(nvictims, i); for (i = 0; i < nvictims; i++) { hash_search(pgsk_hash, &entries[i]->key, HASH_REMOVE, NULL); } pfree(entries); } static void pgsk_entry_reset(void) { HASH_SEQ_STATUS hash_seq; pgskEntry *entry; LWLockAcquire(pgsk->lock, LW_EXCLUSIVE); hash_seq_init(&hash_seq, pgsk_hash); while ((entry = hash_seq_search(&hash_seq)) != NULL) { hash_search(pgsk_hash, &entry->key, HASH_REMOVE, NULL); } LWLockRelease(pgsk->lock); } /* * Hooks */ #if PG_VERSION_NUM >= 130000 /* * Planner hook: forward to regular planner, but measure planning time * if needed. */ static PlannedStmt * pgsk_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams) { PlannedStmt *result; /* * We can't process the query if no queryid has been computed. * * Note that planner_hook can be called from the planner itself, so we * have a specific nesting level for the planner. However, utility * commands containing optimizable statements can also call the planner, * same for regular DML (for instance for underlying foreign key queries). * So testing the planner nesting level only is not enough to detect real * top level planner call. */ if (pgsk_enabled(plan_nested_level + exec_nested_level) && pgsk_track_planning && parse->queryId != UINT64CONST(0)) { struct rusage *rusage_start = &plan_rusage_start[plan_nested_level]; struct rusage rusage_end; pgskCounters counters; /* capture kernel usage stats in rusage_start */ getrusage(RUSAGE_SELF, rusage_start); plan_nested_level++; PG_TRY(); { if (prev_planner_hook) result = prev_planner_hook(parse, query_string, cursorOptions, boundParams); else result = standard_planner(parse, query_string, cursorOptions, boundParams); plan_nested_level--; } PG_CATCH(); { plan_nested_level--; PG_RE_THROW(); } PG_END_TRY(); /* capture kernel usage stats in rusage_end */ getrusage(RUSAGE_SELF, &rusage_end); pgsk_compute_counters(&counters, rusage_start, &rusage_end, NULL); /* store current number of block reads and writes */ pgsk_entry_store(parse->queryId, PGSK_PLAN, plan_nested_level + exec_nested_level, counters); } else { if (prev_planner_hook) result = prev_planner_hook(parse, query_string, cursorOptions, boundParams); else result = standard_planner(parse, query_string, cursorOptions, boundParams); } return result; } #endif static void pgsk_ExecutorStart (QueryDesc *queryDesc, int eflags) { if (pgsk_enabled(exec_nested_level)) { struct rusage *rusage_start = &exec_rusage_start[exec_nested_level]; /* capture kernel usage stats in rusage_start */ getrusage(RUSAGE_SELF, rusage_start); #if PG_VERSION_NUM >= 90600 /* Save the queryid so parallel worker can retrieve it */ if (!IsParallelWorker()) { pgsk_set_queryid(queryDesc->plannedstmt->queryId); } #endif } /* give control back to PostgreSQL */ if (prev_ExecutorStart) prev_ExecutorStart(queryDesc, eflags); else standard_ExecutorStart(queryDesc, eflags); } /* * ExecutorRun hook: all we need do is track nesting depth */ static void pgsk_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, #if PG_VERSION_NUM >= 90600 uint64 count #else long count #endif #if PG_VERSION_NUM >= 100000 ,bool execute_once #endif ) { exec_nested_level++; PG_TRY(); { if (prev_ExecutorRun) #if PG_VERSION_NUM >= 100000 prev_ExecutorRun(queryDesc, direction, count, execute_once); #else prev_ExecutorRun(queryDesc, direction, count); #endif else #if PG_VERSION_NUM >= 100000 standard_ExecutorRun(queryDesc, direction, count, execute_once); #else standard_ExecutorRun(queryDesc, direction, count); #endif exec_nested_level--; } PG_CATCH(); { exec_nested_level--; PG_RE_THROW(); } PG_END_TRY(); } /* * ExecutorFinish hook: all we need do is track nesting depth */ static void pgsk_ExecutorFinish(QueryDesc *queryDesc) { exec_nested_level++; PG_TRY(); { if (prev_ExecutorFinish) prev_ExecutorFinish(queryDesc); else standard_ExecutorFinish(queryDesc); exec_nested_level--; } PG_CATCH(); { exec_nested_level--; PG_RE_THROW(); } PG_END_TRY(); } static void pgsk_ExecutorEnd (QueryDesc *queryDesc) { pgsk_queryid queryId; struct rusage rusage_end; pgskCounters counters; if (pgsk_enabled(exec_nested_level)) { struct rusage *rusage_start = &exec_rusage_start[exec_nested_level]; /* capture kernel usage stats in rusage_end */ getrusage(RUSAGE_SELF, &rusage_end); #if PG_VERSION_NUM >= 90600 if (IsParallelWorker()) { LWLockAcquire(pgsk->queryids_lock, LW_SHARED); queryId = pgsk->queryids[ParallelLeaderBackendId]; LWLockRelease(pgsk->queryids_lock); } else #endif queryId = queryDesc->plannedstmt->queryId; pgsk_compute_counters(&counters, rusage_start, &rusage_end, queryDesc); /* store current number of block reads and writes */ pgsk_entry_store(queryId, PGSK_EXEC, exec_nested_level, counters); } /* give control back to PostgreSQL */ if (prev_ExecutorEnd) prev_ExecutorEnd(queryDesc); else standard_ExecutorEnd(queryDesc); } /* * Calculate hash value for a key */ static uint32 pgsk_hash_fn(const void *key, Size keysize) { const pgskHashKey *k = (const pgskHashKey *) key; return hash_uint32((uint32) k->userid) ^ hash_uint32((uint32) k->dbid) ^ hash_uint32((uint32) k->queryid) ^ hash_uint32((uint32) k->top); } /* * Compare two keys - zero means match */ static int pgsk_match_fn(const void *key1, const void *key2, Size keysize) { const pgskHashKey *k1 = (const pgskHashKey *) key1; const pgskHashKey *k2 = (const pgskHashKey *) key2; if (k1->userid == k2->userid && k1->dbid == k2->dbid && k1->queryid == k2->queryid && k1->top == k2->top) return 0; else return 1; } /* * Reset statistics. */ PGDLLEXPORT Datum pg_stat_kcache_reset(PG_FUNCTION_ARGS) { if (!pgsk) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("pg_stat_kcache must be loaded via shared_preload_libraries"))); pgsk_entry_reset(); PG_RETURN_VOID(); } PGDLLEXPORT Datum pg_stat_kcache(PG_FUNCTION_ARGS) { pg_stat_kcache_internal(fcinfo, PGSK_V2_0); return (Datum) 0; } PGDLLEXPORT Datum pg_stat_kcache_2_1(PG_FUNCTION_ARGS) { pg_stat_kcache_internal(fcinfo, PGSK_V2_1); return (Datum) 0; } PGDLLEXPORT Datum pg_stat_kcache_2_2(PG_FUNCTION_ARGS) { pg_stat_kcache_internal(fcinfo, PGSK_V2_2); return (Datum) 0; } static void pg_stat_kcache_internal(FunctionCallInfo fcinfo, pgskVersion api_version) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; MemoryContext per_query_ctx; MemoryContext oldcontext; TupleDesc tupdesc; Tuplestorestate *tupstore; HASH_SEQ_STATUS hash_seq; pgskEntry *entry; if (!pgsk) ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("pg_stat_kcache must be loaded via shared_preload_libraries"))); /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not " \ "allowed in this context"))); /* Switch into long-lived context to construct returned data structures */ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); tupstore = tuplestore_begin_heap(true, false, work_mem); rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = tupstore; rsinfo->setDesc = tupdesc; MemoryContextSwitchTo(oldcontext); LWLockAcquire(pgsk->lock, LW_SHARED); hash_seq_init(&hash_seq, pgsk_hash); while ((entry = hash_seq_search(&hash_seq)) != NULL) { Datum values[PG_STAT_KCACHE_COLS]; bool nulls[PG_STAT_KCACHE_COLS]; pgskCounters tmp; int i = 0; int kind, min_kind = 0; #ifdef HAVE_GETRUSAGE int64 reads, writes; #endif memset(values, 0, sizeof(values)); memset(nulls, 0, sizeof(nulls)); values[i++] = Int64GetDatum(entry->key.queryid); if (api_version >= PGSK_V2_2) values[i++] = BoolGetDatum(entry->key.top); values[i++] = ObjectIdGetDatum(entry->key.userid); values[i++] = ObjectIdGetDatum(entry->key.dbid); /* planning time (kind == 0) is added in v2.2 */ if (api_version < PGSK_V2_2) min_kind = 1; for (kind = min_kind; kind < PGSK_NUMKIND; kind++) { /* copy counters to a local variable to keep locking time short */ { volatile pgskEntry *e = (volatile pgskEntry *) entry; SpinLockAcquire(&e->mutex); tmp = e->counters[kind]; SpinLockRelease(&e->mutex); } #ifdef HAVE_GETRUSAGE reads = tmp.reads * RUSAGE_BLOCK_SIZE; writes = tmp.writes * RUSAGE_BLOCK_SIZE; values[i++] = Int64GetDatumFast(reads); values[i++] = Int64GetDatumFast(writes); #else nulls[i++] = true; /* reads */ nulls[i++] = true; /* writes */ #endif values[i++] = Float8GetDatumFast(tmp.utime); values[i++] = Float8GetDatumFast(tmp.stime); if (api_version >= PGSK_V2_1) { #ifdef HAVE_GETRUSAGE values[i++] = Int64GetDatumFast(tmp.minflts); values[i++] = Int64GetDatumFast(tmp.majflts); values[i++] = Int64GetDatumFast(tmp.nswaps); values[i++] = Int64GetDatumFast(tmp.msgsnds); values[i++] = Int64GetDatumFast(tmp.msgrcvs); values[i++] = Int64GetDatumFast(tmp.nsignals); values[i++] = Int64GetDatumFast(tmp.nvcsws); values[i++] = Int64GetDatumFast(tmp.nivcsws); #else nulls[i++] = true; /* minflts */ nulls[i++] = true; /* majflts */ nulls[i++] = true; /* nswaps */ nulls[i++] = true; /* msgsnds */ nulls[i++] = true; /* msgrcvs */ nulls[i++] = true; /* nsignals */ nulls[i++] = true; /* nvcsws */ nulls[i++] = true; /* nivcsws */ #endif } } Assert(i == (api_version == PGSK_V2_0 ? PG_STAT_KCACHE_COLS_V2_0 : api_version == PGSK_V2_1 ? PG_STAT_KCACHE_COLS_V2_1 : api_version == PGSK_V2_2 ? PG_STAT_KCACHE_COLS_V2_2 : -1 /* fail if you forget to update this assert */ )); tuplestore_putvalues(tupstore, tupdesc, values, nulls); } LWLockRelease(pgsk->lock); /* clean up and return the tuplestore */ tuplestore_donestoring(tupstore); } pg_stat_kcache-REL2_2_0/pg_stat_kcache.control000066400000000000000000000002731376431076400215350ustar00rootroot00000000000000# pg_stat_kcache extension comment = 'Kernel statistics gathering' default_version = '2.2.0' requires = 'pg_stat_statements' module_pathname = '$libdir/pg_stat_kcache' relocatable = true pg_stat_kcache-REL2_2_0/test/000077500000000000000000000000001376431076400161515ustar00rootroot00000000000000pg_stat_kcache-REL2_2_0/test/sql/000077500000000000000000000000001376431076400167505ustar00rootroot00000000000000pg_stat_kcache-REL2_2_0/test/sql/pgsk.sql000066400000000000000000000025001376431076400204320ustar00rootroot00000000000000CREATE EXTENSION pg_stat_statements; CREATE EXTENSION pg_stat_kcache; -- dummy query SELECT 1 AS dummy; SELECT count(*) FROM pg_stat_kcache WHERE datname = current_database(); SELECT count(*) FROM pg_stat_kcache_detail WHERE datname = current_database() AND (query = 'SELECT $1 AS dummy' OR query = 'SELECT ? AS dummy;'); SELECT exec_reads, exec_reads_blks, exec_writes, exec_writes_blks FROM pg_stat_kcache_detail WHERE datname = current_database() AND (query = 'SELECT $1 AS dummy' OR query = 'SELECT ? AS dummy;'); -- dummy table CREATE TABLE test AS SELECT i FROM generate_series(1, 1000) i; -- dummy query again SELECT count(*) FROM test; SELECT exec_user_time + exec_system_time > 0 AS cpu_time_ok FROM pg_stat_kcache_detail WHERE datname = current_database() AND query LIKE 'SELECT count(*) FROM test%'; -- dummy nested query SET pg_stat_statements.track = 'all'; SET pg_stat_statements.track_planning = TRUE; SET pg_stat_kcache.track = 'all'; SET pg_stat_kcache.track_planning = TRUE; SELECT pg_stat_kcache_reset(); CREATE OR REPLACE FUNCTION plpgsql_nested() RETURNS void AS $$ BEGIN PERFORM i::text as str from generate_series(1, 100) as i; PERFORM md5(i::text) as str from generate_series(1, 100) as i; END $$ LANGUAGE plpgsql; SELECT plpgsql_nested(); SELECT COUNT(*) FROM pg_stat_kcache_detail WHERE top IS FALSE;