pax_global_header00006660000000000000000000000064145541546600014524gustar00rootroot0000000000000052 comment=44f0c7e079b7056a3174ef9515fdfc594fd196e4 pg_stat_kcache-REL2_2_3/000077500000000000000000000000001455415466000151745ustar00rootroot00000000000000pg_stat_kcache-REL2_2_3/.github/000077500000000000000000000000001455415466000165345ustar00rootroot00000000000000pg_stat_kcache-REL2_2_3/.github/workflows/000077500000000000000000000000001455415466000205715ustar00rootroot00000000000000pg_stat_kcache-REL2_2_3/.github/workflows/regression.yml000066400000000000000000000017641455415466000235040ustar00rootroot00000000000000name: Build on: [push, pull_request] jobs: build: runs-on: ubuntu-latest defaults: run: shell: sh strategy: matrix: pgversion: - 9.4 - 9.5 - 9.6 - 10 - 11 - 12 - 13 - 14 - 15 - 16 env: PGVERSION: ${{ matrix.pgversion }} steps: - name: checkout uses: actions/checkout@v2 - name: install pg run: | sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh -v $PGVERSION -p -i sudo -u postgres createuser -s "$USER" - name: build run: | make PROFILE="-Werror" sudo -E make install - name: test run: | sudo pg_conftool $PGVERSION main set shared_preload_libraries pg_stat_statements,pg_stat_kcache sudo service postgresql restart make installcheck - name: show regression diffs if: ${{ failure() }} run: | cat regression.diffs pg_stat_kcache-REL2_2_3/.gitignore000066400000000000000000000000631455415466000171630ustar00rootroot00000000000000*.o *.a *.so *.pc *~ pg_stat_kcache-*.zip results/ pg_stat_kcache-REL2_2_3/CHANGELOG.md000066400000000000000000000074121455415466000170110ustar00rootroot00000000000000## 2.2.3 (2024-01-24) **Miscellaneous**: - Improve performance for workloads with a high number of clients (Julien Rouhaud, thanks to Vitaliy Kukharik for the report) ## 2.2.2 (2023-08-01) **Miscellaneous**: - Add postgres 16 compatibility (Julien Rouhaud, Christoph Berg, Japin Li) - Add CI (Christoph Berg) - Recommend installation from PGDG repository rather than compiling the extension (Julien Rouhaud) ## 2.2.1 (2022-05-16) **Bugfix**: - Fix memory allocation on postgres 12 and above (Julien Rouhaud) **New features**: - Expose some structures and add a counters hook so other extensions can extend this extension's metrics (Sviatoslav Ermilin) **Miscellaneous**: - Various improvements to the debian packaging (Christoph Berg) - Add compatibility with postgres 15 (Julien Rouhaud) - Improve extension update documentation (Julien Rouhaud) ## 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_3/CONTRIBUTORS.md000066400000000000000000000004721455415466000174560ustar00rootroot00000000000000 * 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 * github user munakoiso * Christoph Berg * Sviatoslav Ermilin * Vitaliy Kukharik pg_stat_kcache-REL2_2_3/LICENSE000066400000000000000000000017461455415466000162110ustar00rootroot00000000000000Copyright (c) 2014-2017, Dalibo Copyright (c) 2018-2023, 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_3/META.json000066400000000000000000000021331455415466000166140ustar00rootroot00000000000000{ "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_3/Makefile000066400000000000000000000016231455415466000166360ustar00rootroot00000000000000EXTENSION = 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_3/README.rst000066400000000000000000001212341455415466000166660ustar00rootroot00000000000000pg_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 ============ From PGDG repositories ---------------------- If you installed PostgreSQL from the PGDG repositories (either `APT on Debian/Ubuntu ` or `YUM on RHEL/Rocky Wed, 24 Jan 2024 17:29:41 +0800 pg-stat-kcache (2.2.2-2) unstable; urgency=medium * Team upload. * Upload for PostgreSQL 16. * Use ${postgresql:Depends}. -- Christoph Berg Sun, 17 Sep 2023 21:02:35 +0200 pg-stat-kcache (2.2.2-1) unstable; urgency=medium * Team upload. * New upstream version with PG16 support. -- Christoph Berg Wed, 02 Aug 2023 16:10:59 +0200 pg-stat-kcache (2.2.1-2) unstable; urgency=medium * Team upload for PostgreSQL 15. * debian/watch: Look at GitHub tags instead of releases. -- Christoph Berg Fri, 21 Oct 2022 11:03:01 +0200 pg-stat-kcache (2.2.1-1) unstable; urgency=medium * New upstream version. -- Julien Rouhaud Mon, 16 May 2022 14:03:03 +0800 pg-stat-kcache (2.2.0-2) unstable; urgency=medium * Upload for PostgreSQL 14. -- Christoph Berg Fri, 15 Oct 2021 15:44:51 +0200 pg-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-2) unstable; urgency=medium * Team upload for PostgreSQL 13. * Source format 3.0 (quilt). * Use dh --with pgxs_loop. * R³: no. * DH 13. * debian/tests: Use 'make' instead of postgresql-server-dev-all. -- Christoph Berg Mon, 19 Oct 2020 11:49:40 +0200 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_3/debian/control000066400000000000000000000015641455415466000200270ustar00rootroot00000000000000Source: pg-stat-kcache Section: database Priority: optional Maintainer: Julien Rouhaud Standards-Version: 4.6.2 Rules-Requires-Root: no Build-Depends: debhelper-compat (= 13), postgresql-all (>= 217~) 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-16-pg-stat-kcache Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, ${postgresql:Depends}, postgresql-contrib-16 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_3/debian/control.in000066400000000000000000000016021455415466000204250ustar00rootroot00000000000000Source: pg-stat-kcache Section: database Priority: optional Maintainer: Julien Rouhaud Standards-Version: 4.6.2 Rules-Requires-Root: no Build-Depends: debhelper-compat (= 13), postgresql-all (>= 217~) 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:Depends}, 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_3/debian/copyright000066400000000000000000000024151455415466000203530ustar00rootroot00000000000000Portions Copyright (c) 2014-2017, Dalibo Portions Copyright (c) 2018-2023, 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 * Felix Geisendörfer * github user atorik * github user tbe * github user mikecaat pg_stat_kcache-REL2_2_3/debian/pgversions000066400000000000000000000000051455415466000205330ustar00rootroot000000000000009.4+ pg_stat_kcache-REL2_2_3/debian/rules000077500000000000000000000004761455415466000175050ustar00rootroot00000000000000#!/usr/bin/make -f override_dh_pgxs_test: pg_buildext -o "shared_preload_libraries=pg_stat_statements,pg_stat_kcache" installcheck . . postgresql-%v-pg-stat-kcache override_dh_installdocs: dh_installdocs --all CONTRIBUTORS.md README.rst rm -rvf debian/*/usr/share/doc/postgresql-doc-* %: dh $@ --with pgxs_loop pg_stat_kcache-REL2_2_3/debian/source/000077500000000000000000000000001455415466000177165ustar00rootroot00000000000000pg_stat_kcache-REL2_2_3/debian/source/format000066400000000000000000000000141455415466000211240ustar00rootroot000000000000003.0 (quilt) pg_stat_kcache-REL2_2_3/debian/tests/000077500000000000000000000000001455415466000175605ustar00rootroot00000000000000pg_stat_kcache-REL2_2_3/debian/tests/control000066400000000000000000000001271455415466000211630ustar00rootroot00000000000000Depends: @, postgresql-contrib-16, make Tests: installcheck Restrictions: allow-stderr pg_stat_kcache-REL2_2_3/debian/tests/control.in000066400000000000000000000001361455415466000215700ustar00rootroot00000000000000Depends: @, postgresql-contrib-PGVERSION, make Tests: installcheck Restrictions: allow-stderr pg_stat_kcache-REL2_2_3/debian/tests/installcheck000077500000000000000000000001551455415466000221530ustar00rootroot00000000000000#!/bin/sh set -eu pg_buildext -o "shared_preload_libraries=pg_stat_statements,pg_stat_kcache" installcheck pg_stat_kcache-REL2_2_3/debian/watch000066400000000000000000000001571455415466000174520ustar00rootroot00000000000000version=4 opts="uversionmangle=s/_/./g" \ https://github.com/powa-team/pg_stat_kcache/tags .*/REL(.*).tar.gz pg_stat_kcache-REL2_2_3/expected/000077500000000000000000000000001455415466000167755ustar00rootroot00000000000000pg_stat_kcache-REL2_2_3/expected/pgsk.out000066400000000000000000000040221455415466000204700ustar00rootroot00000000000000CREATE EXTENSION pg_stat_statements; CREATE EXTENSION pg_stat_kcache; -- first make sure that catcache is loaded to avoid physical reads SELECT count(*) >= 0 FROM pg_stat_kcache; ?column? ---------- t (1 row) SELECT pg_stat_kcache_reset(); pg_stat_kcache_reset ---------------------- (1 row) -- 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_3/pg_stat_kcache--2.1.0--2.1.1.sql000066400000000000000000000005241455415466000221000ustar00rootroot00000000000000-- 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-2024, 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_3/pg_stat_kcache--2.1.0.sql000066400000000000000000000057161455415466000213760ustar00rootroot00000000000000-- 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-2024, 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_3/pg_stat_kcache--2.1.1--2.1.2.sql000066400000000000000000000005241455415466000221020ustar00rootroot00000000000000-- 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-2022, 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_3/pg_stat_kcache--2.1.1.sql000066400000000000000000000057161455415466000213770ustar00rootroot00000000000000-- 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-2024, 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_3/pg_stat_kcache--2.1.2--2.1.3.sql000066400000000000000000000005241455415466000221040ustar00rootroot00000000000000-- 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-2022, 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_3/pg_stat_kcache--2.1.2.sql000066400000000000000000000057161455415466000214000ustar00rootroot00000000000000-- 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-2024, 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_3/pg_stat_kcache--2.1.3--2.2.0.sql000066400000000000000000000122461455415466000221070ustar00rootroot00000000000000-- 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-2022, 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_3/pg_stat_kcache--2.1.3.sql000066400000000000000000000057161455415466000214010ustar00rootroot00000000000000-- 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-2024, 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_3/pg_stat_kcache--2.2.0--2.2.1.sql000066400000000000000000000005241455415466000221020ustar00rootroot00000000000000-- 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-2022, 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_3/pg_stat_kcache--2.2.0.sql000066400000000000000000000124601455415466000213710ustar00rootroot00000000000000-- 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-2022, 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_3/pg_stat_kcache--2.2.1--2.2.2.sql000066400000000000000000000005241455415466000221040ustar00rootroot00000000000000-- 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-2024, 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_3/pg_stat_kcache--2.2.1.sql000066400000000000000000000124601455415466000213720ustar00rootroot00000000000000-- 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-2024, 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_3/pg_stat_kcache--2.2.2--2.2.3.sql000066400000000000000000000005241455415466000221060ustar00rootroot00000000000000-- 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-2024, 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_3/pg_stat_kcache--2.2.2.sql000066400000000000000000000124601455415466000213730ustar00rootroot00000000000000-- 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-2024, 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_3/pg_stat_kcache--2.2.3.sql000066400000000000000000000124601455415466000213740ustar00rootroot00000000000000-- 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-2024, 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_3/pg_stat_kcache.c000066400000000000000000001007411455415466000203020ustar00rootroot00000000000000/*--------------- * 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 /* * pg16 removed the configure probe for getrusage. Simply define it for all * platforms except Windows to keep existing code backward compatible. */ #if PG_VERSION_NUM >= 160000 #ifndef WIN32 #define HAVE_GETRUSAGE #endif /* HAVE_GETRUSAGE */ #endif /* pg16+ */ #if PG_VERSION_NUM < 160000 #ifdef HAVE_SYS_RESOURCE_H #include #include #endif /* HAVE_SYS_RESOURCE_H */ #ifndef HAVE_GETRUSAGE #include "rusagestub.h" #endif /* !HAVE_GETRUSAGE */ #endif /* pg16- */ #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 #if PG_VERSION_NUM >= 120000 #include "replication/walsender.h" #endif #include "storage/fd.h" #include "storage/ipc.h" #include "storage/spin.h" #include "utils/builtins.h" #include "utils/guc.h" #if PG_VERSION_NUM >= 160000 #include "utils/pg_rusage.h" #endif #include "pg_stat_kcache.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 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 */ #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; 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 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 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 */ #if PG_VERSION_NUM >= 150000 static shmem_request_hook_type prev_shmem_request_hook = NULL; #endif 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 = PGSK_TRACK_TOP; /* tracking level */ #if PG_VERSION_NUM >= 130000 static bool pgsk_track_planning = false; /* 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); 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); #if PG_VERSION_NUM >= 150000 static void pgsk_shmem_request(void); #endif 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 = 0; 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(); /* * If you change code here, don't forget to also report the modifications * in pgsk_shmem_request() for pg15 and later. */ #if PG_VERSION_NUM < 150000 RequestAddinShmemSpace(pgsk_memsize()); #if PG_VERSION_NUM >= 90600 RequestNamedLWLockTranche("pg_stat_kcache", 1); #else RequestAddinLWLocks(1); #endif /* pg 9.6+ */ #endif /* pg 15- */ /* Install hook */ #if PG_VERSION_NUM >= 150000 prev_shmem_request_hook = shmem_request_hook; shmem_request_hook = pgsk_shmem_request; #endif 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; } 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()); pgsk->queryids[MyBackendId] = queryid; } #endif #if PG_VERSION_NUM >= 150000 /* * Request additional shared memory resources. * * If you change code here, don't forget to also report the modifications in * _PG_init() for pg14 and below. */ static void pgsk_shmem_request(void) { if (prev_shmem_request_hook) prev_shmem_request_hook(); RequestAddinShmemSpace(pgsk_memsize()); RequestNamedLWLockTranche("pg_stat_kcache", 1); } #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 pgsk->lock = &(GetNamedLWLockTranche("pg_stat_kcache"))->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. It therefore needs room * for all possible backends, plus autovacuum launcher and workers, plus bg * workers and an extra one since BackendId numerotation starts at 1. * Starting with pg12, wal senders aren't part of MaxConnections anymore, * so they need to be accounted for. */ #if PG_VERSION_NUM >= 150000 Assert (MaxBackends > 0); return (sizeof(pgsk_queryid) * (MaxBackends + 1)); #else return (sizeof(pgsk_queryid) * (MaxConnections + autovacuum_max_workers + 1 + max_worker_processes #if PG_VERSION_NUM >= 120000 + max_wal_senders #endif /* pg12+ */ + 1)); #endif /* pg15- */ } #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); if (pgsk_counters_hook) pgsk_counters_hook(&counters, query_string, plan_nested_level + exec_nested_level, PGSK_PLAN); } 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()) queryId = pgsk->queryids[ParallelLeaderBackendId]; 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); if (pgsk_counters_hook) pgsk_counters_hook(&counters, (const char *)queryDesc->sourceText, exec_nested_level, PGSK_EXEC); } /* 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); } pg_stat_kcache-REL2_2_3/pg_stat_kcache.control000066400000000000000000000002731455415466000215370ustar00rootroot00000000000000# pg_stat_kcache extension comment = 'Kernel statistics gathering' default_version = '2.2.3' requires = 'pg_stat_statements' module_pathname = '$libdir/pg_stat_kcache' relocatable = true pg_stat_kcache-REL2_2_3/pg_stat_kcache.h000066400000000000000000000041061455415466000203050ustar00rootroot00000000000000#ifndef PGSK_H_ #define PGSK_H_ #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 */ /* 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() */ /* * 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; 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; /* Hook for extensions to use pgskCounters right after calculation. */ typedef void (*pgsk_counters_hook_type) ( pgskCounters *counters, const char *query_string, int level, pgskStoreKind kind); pgsk_counters_hook_type pgsk_counters_hook = NULL; #endif pg_stat_kcache-REL2_2_3/test/000077500000000000000000000000001455415466000161535ustar00rootroot00000000000000pg_stat_kcache-REL2_2_3/test/sql/000077500000000000000000000000001455415466000167525ustar00rootroot00000000000000pg_stat_kcache-REL2_2_3/test/sql/pgsk.sql000066400000000000000000000027151455415466000204440ustar00rootroot00000000000000CREATE EXTENSION pg_stat_statements; CREATE EXTENSION pg_stat_kcache; -- first make sure that catcache is loaded to avoid physical reads SELECT count(*) >= 0 FROM pg_stat_kcache; SELECT pg_stat_kcache_reset(); -- 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;