summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Wong <mark@2ndQuadrant.com>2019-06-14 20:26:30 +0000
committerMark Wong <mark@2ndQuadrant.com>2019-07-08 12:07:56 -0700
commita1ae03b7b681fef428a009ed3c159d69f0603dab (patch)
tree64a1b0257068ce87f73486b707c5445a496ac7d8
parent1d9377c1c6ed915c9be5ef3a93e9e0ccf207e27e (diff)
Add LOCKS column
The locks column displays a count of database locks per process.
-rw-r--r--machine/m_linux.c34
-rw-r--r--machine/m_remote.c64
-rw-r--r--pg.c14
-rw-r--r--pg_top.1.in3
4 files changed, 101 insertions, 14 deletions
diff --git a/machine/m_linux.c b/machine/m_linux.c
index 98cfd15..f6db76d 100644
--- a/machine/m_linux.c
+++ b/machine/m_linux.c
@@ -84,6 +84,7 @@ struct top_proc
unsigned long start_time;
unsigned long xtime;
unsigned long qtime;
+ unsigned int locks;
double pcpu;
/* Data from /proc/<pid>/io. */
@@ -144,19 +145,20 @@ static char *swapnames[NSWAPSTATS + 1] =
};
static char fmt_header[] =
-" PID X SIZE RES STATE XTIME QTIME %CPU COMMAND";
+" PID X SIZE RES STATE XTIME QTIME %CPU LOCKS COMMAND";
/* these are names given to allowed sorting orders -- first is default */
static char *ordernames[] =
{
"cpu", "size", "res", "xtime", "qtime", "rchar", "wchar", "syscr",
- "syscw", "reads", "writes", "cwrites", "command", NULL
+ "syscw", "reads", "writes", "cwrites", "locks", "command", NULL
};
/* forward definitions for comparison functions */
static int compare_cmd(const void *, const void *);
static int compare_cpu(const void *, const void *);
static int compare_cwrites(const void *, const void *);
+static int compare_locks(const void *, const void *);
static int compare_qtime(const void *, const void *);
static int compare_rchar(const void *, const void *);
static int compare_reads(const void *, const void *);
@@ -182,6 +184,7 @@ int (*proc_compares[]) () =
compare_reads,
compare_writes,
compare_cwrites,
+ compare_locks,
compare_cmd,
NULL
};
@@ -809,6 +812,7 @@ get_process_info(struct system_info * si,
update_str(&n->usename, PQgetvalue(pgresult, i, 3));
n->xtime = atol(PQgetvalue(pgresult, i, 4));
n->qtime = atol(PQgetvalue(pgresult, i, 5));
+ n->locks = atoi(PQgetvalue(pgresult, i, 6));
total_procs++;
process_states[n->pgstate]++;
@@ -908,7 +912,7 @@ format_next_process(caddr_t handle)
struct top_proc *p = &pgtable[proc_index++];
snprintf(fmt, sizeof(fmt),
- "%5d %-8.8s %5s %5s %-6s %5s %5s %5.1f %s",
+ "%5d %-8.8s %5s %5s %-6s %5s %5s %5.1f %5d %s",
p->pid,
p->usename,
format_k(p->size),
@@ -917,6 +921,7 @@ format_next_process(caddr_t handle)
format_time(p->xtime),
format_time(p->qtime),
p->pcpu * 100.0,
+ p->locks,
p->name);
/* return the result */
@@ -944,6 +949,7 @@ format_next_process(caddr_t handle)
#define ORDERKEY_CWRITES if ((result = p1->cancelled_write_bytes - \
p2->cancelled_write_bytes) == 0)
+#define ORDERKEY_LOCKS if ((result = p2->locks - p1->locks) == 0)
#define ORDERKEY_MEM if ((result = p2->size - p1->size) == 0)
#define ORDERKEY_NAME if ((result = strcmp(p1->name, p2->name)) == 0)
#define ORDERKEY_PCTCPU if ((result = (int)(p2->pcpu - p1->pcpu)) == 0)
@@ -1015,6 +1021,28 @@ compare_cwrites(const void *v1, const void *v2)
return (result);
}
+/*
+ * compare_locks - the comparison function for sorting by total locks ancquired
+ */
+
+static int
+compare_locks(const void *v1, const void *v2)
+{
+ struct top_proc *p1 = (struct top_proc *) v1;
+ struct top_proc *p2 = (struct top_proc *) v2;
+ int result;
+
+ ORDERKEY_LOCKS
+ ORDERKEY_QTIME
+ ORDERKEY_PCTCPU
+ ORDERKEY_STATE
+ ORDERKEY_MEM
+ ORDERKEY_RSSIZE
+ ;
+
+ return (result);
+}
+
/* compare_qtime - the comparison function for sorting by total cpu qtime */
static int
diff --git a/machine/m_remote.c b/machine/m_remote.c
index b2a2dfe..7c274bc 100644
--- a/machine/m_remote.c
+++ b/machine/m_remote.c
@@ -31,26 +31,44 @@
"FROM pg_memusage()"
#define QUERY_PROCTAB \
+ "WITH lock_activity AS\n" \
+ "(\n" \
+ " SELECT pid, count(*) AS lock_count\n" \
+ " FROM pg_locks\n" \
+ " GROUP BY pid\n" \
+ ")\n" \
"SELECT a.pid, comm, fullcomm, a.state, utime, stime,\n" \
" starttime, vsize, rss, usename, rchar, wchar,\n" \
" syscr, syscw, reads, writes, cwrites, b.state,\n" \
" extract(EPOCH FROM age(clock_timestamp(),\n" \
" xact_start))::BIGINT,\n" \
" extract(EPOCH FROM age(clock_timestamp(),\n" \
- " query_start))::BIGINT\n" \
+ " query_start))::BIGINT,\n" \
+ " coalesce(lock_count, 0) AS lock_count\n" \
"FROM pg_proctab() a LEFT OUTER JOIN pg_stat_activity b\n" \
- " ON a.pid = b.pid"
+ " ON a.pid = b.pid\n" \
+ " LEFT OUTER JOIN lock_activity c\n" \
+ " ON a.pid = c.pid;"
#define QUERY_PROCTAB_QUERY \
+ "WITH lock_activity AS\n" \
+ "(\n" \
+ " SELECT pid, count(*) AS lock_count\n" \
+ " FROM pg_locks\n" \
+ " GROUP BY pid\n" \
+ ")\n" \
"SELECT a.pid, comm, query, a.state, utime, stime,\n" \
" starttime, vsize, rss, usename, rchar, wchar,\n" \
" syscr, syscw, reads, writes, cwrites, b.state,\n" \
" extract(EPOCH FROM age(clock_timestamp(),\n" \
" xact_start))::BIGINT,\n" \
" extract(EPOCH FROM age(clock_timestamp(),\n" \
- " query_start))::BIGINT\n" \
+ " query_start))::BIGINT,\n" \
+ " coalesce(lock_count, 0) AS lock_count\n" \
"FROM pg_proctab() a LEFT OUTER JOIN pg_stat_activity b\n" \
- " ON a.pid = b.pid"
+ " ON a.pid = b.pid\n" \
+ " LEFT OUTER JOIN lock_activity c\n" \
+ " ON a.pid = c.pid;"
#define QUERY_PG_PROC \
"SELECT COUNT(*)\n" \
@@ -65,7 +83,7 @@ enum column_memusage { c_memused, c_memfree, c_memshared, c_membuffers,
enum column_proctab { c_pid, c_comm, c_fullcomm, c_state, c_utime, c_stime,
c_starttime, c_vsize, c_rss, c_username,
c_rchar, c_wchar, c_syscr, c_syscw, c_reads, c_writes, c_cwrites,
- c_pgstate, c_xtime, c_qtime};
+ c_pgstate, c_xtime, c_qtime, c_locks};
#define bytetok(x) (((x) + 512) >> 10)
@@ -101,6 +119,7 @@ struct top_proc_r
unsigned long start_time;
unsigned long xtime;
unsigned long qtime;
+ unsigned int locks;
double pcpu;
/* The change in the previous values and current values. */
@@ -146,7 +165,7 @@ static char *memorynames[NMEMSTATS + 1] =
static char *ordernames[] =
{
"cpu", "size", "res", "xtime", "qtime", "rchar", "wchar", "syscr",
- "syscw", "reads", "writes", "cwrites", "command", NULL
+ "syscw", "reads", "writes", "cwrites", "locks", "command", NULL
};
static char *swapnames[NSWAPSTATS + 1] =
@@ -155,7 +174,7 @@ static char *swapnames[NSWAPSTATS + 1] =
};
static char fmt_header[] =
- " PID X SIZE RES STATE XTIME QTIME %CPU COMMAND";
+ " PID X SIZE RES STATE XTIME QTIME %CPU LOCKS COMMAND";
/* Now the array that maps process state to a weight. */
@@ -195,11 +214,13 @@ static int64_t cp_diff[NCPUSTATES];
#define ORDERKEY_CWRITES if ((result = p1->cancelled_write_bytes - p2->cancelled_write_bytes) == 0)
#define ORDERKEY_XTIME if ((result = p2->xtime - p1->xtime) == 0)
#define ORDERKEY_QTIME if ((result = p2->qtime - p1->qtime) == 0)
+#define ORDERKEY_LOCKS if ((result = p2->locks - p1->locks) == 0)
int check_for_function(PGconn *, char *);
static int compare_cmd_r(const void *, const void *);
static int compare_cpu_r(const void *, const void *);
static int compare_cwrites_r(const void *, const void *);
+static int compare_locks_r(const void *, const void *);
static int compare_qtime_r(const void *, const void *);
static int compare_rchar_r(const void *, const void *);
static int compare_reads_r(const void *, const void *);
@@ -252,6 +273,7 @@ int (*proc_compares_r[])() =
compare_reads_r,
compare_writes_r,
compare_cwrites_r,
+ compare_locks_r,
compare_cmd_r,
NULL
};
@@ -313,6 +335,29 @@ compare_cwrites_r(const void *v1, const void *v2)
return (result);
}
+/*
+ * compare_locks_r - the comparison function for sorting by total locks
+ * acquired
+ */
+
+int
+compare_locks_r(const void *v1, const void *v2)
+{
+ struct top_proc_r *p1 = (struct top_proc_r *) v1;
+ struct top_proc_r *p2 = (struct top_proc_r *) v2;
+ int result;
+
+ ORDERKEY_LOCKS
+ ORDERKEY_QTIME
+ ORDERKEY_PCTCPU
+ ORDERKEY_STATE
+ ORDERKEY_MEM
+ ORDERKEY_RSSIZE
+ ;
+
+ return (result);
+}
+
/* compare_qtime_r - the comparison function for sorting by total cpu qtime */
static int
@@ -559,7 +604,7 @@ format_next_process_r(caddr_t handler)
struct top_proc_r *p = &pgrtable[proc_r_index++];
snprintf(fmt, sizeof(fmt),
- "%5d %-8.8s %5s %5s %-6s %5s %5s %5.1f %s",
+ "%5d %-8.8s %5s %5s %-6s %5s %5s %5.1f %5d %s",
(int) p->pid, /* Some OS's need to cast pid_t to int. */
p->usename,
format_k(p->size),
@@ -568,6 +613,7 @@ format_next_process_r(caddr_t handler)
format_time(p->xtime),
format_time(p->qtime),
p->pcpu * 100.0,
+ p->locks,
p->name);
return (fmt);
@@ -804,6 +850,8 @@ get_process_info_r(struct system_info *si, struct process_select *sel,
n->xtime = atol(PQgetvalue(pgresult, i, c_xtime));
n->qtime = atol(PQgetvalue(pgresult, i, c_qtime));
+ n->locks = atol(PQgetvalue(pgresult, i, c_locks));
+
value = atoll(PQgetvalue(pgresult, i, c_rchar));
n->rchar_diff = value - n->rchar;
n->rchar = value;
diff --git a/pg.c b/pg.c
index 878dcc1..aa8c1bc 100644
--- a/pg.c
+++ b/pg.c
@@ -9,12 +9,20 @@
#include "pg_top.h"
#define QUERY_PROCESSES \
- "SELECT pid, query, state, usename,\n" \
+ "WITH lock_activity AS\n" \
+ "(\n" \
+ " SELECT pid, count(*) AS lock_count\n" \
+ " FROM pg_locks\n" \
+ " GROUP BY pid\n" \
+ ")\n" \
+ "SELECT a.pid, query, state, usename,\n" \
" extract(EPOCH FROM age(clock_timestamp(),\n" \
" xact_start))::BIGINT,\n" \
" extract(EPOCH FROM age(clock_timestamp(),\n" \
- " query_start))::BIGINT\n" \
- "FROM pg_stat_activity;"
+ " query_start))::BIGINT,\n" \
+ " coalesce(lock_count, 0) AS lock_count\n" \
+ "FROM pg_stat_activity a LEFT OUTER JOIN lock_activity b\n" \
+ " ON a.pid = b.pid;"
#define QUERY_PROCESSES_9_1 \
"SELECT procpid, current_query\n" \
diff --git a/pg_top.1.in b/pg_top.1.in
index 16d949c..ea2fc06 100644
--- a/pg_top.1.in
+++ b/pg_top.1.in
@@ -327,6 +327,9 @@ Elapsed time since the current query started.
.B %CPU
Percentage of available cpu time used by this process.
.TP
+.B LOCKS
+Number of locks granted to this process.
+.TP
.B COMMAND
Name of the command that the process is currently running.
.SH COLOR