/*
* Copyright (c) 2008-2009, Mark Wong
*/
#include <stdlib.h>
#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <sys/tree.h>
#endif /* __FreeBSD__*/
#ifdef __linux__
#include <bsd/stdlib.h>
#include <bsd/sys/tree.h>
#endif /* __linux__ */
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
#include <libpq-fe.h>
#include "pg.h"
#include "remote.h"
#include "utils.h"
#define QUERY_CPUTIME \
"SELECT user, nice, system, idle, iowait\n" \
"FROM pg_cputime()"
#define QUERY_LOADAVG \
"SELECT load1, load5, load15, last_pid\n" \
"FROM pg_loadavg()"
#define QUERY_MEMUSAGE \
"SELECT memused, memfree, memshared, membuffers, memcached,\n" \
" swapused, swapfree, swapcached\n" \
"FROM pg_memusage()"
#define QUERY_PROCTAB \
"WITH lock_activity AS\n" \
"(\n" \
" SELECT pid, count(*) AS lock_count\n" \
" FROM pg_locks\n" \
" WHERE relation IS NOT NULL\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" \
" 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\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" \
" 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\n" \
" LEFT OUTER JOIN lock_activity c\n" \
" ON a.pid = c.pid;"
#define QUERY_PG_PROC \
"SELECT COUNT(*)\n" \
"FROM pg_catalog.pg_proc\n" \
"WHERE proname = '%s'"
enum column_cputime
{
c_cpu_user, c_cpu_nice, c_cpu_system, c_cpu_idle,
c_cpu_iowait
};
enum column_loadavg
{
c_load1, c_load5, c_load15, c_last_pid
};
enum column_memusage
{
c_memused, c_memfree, c_memshared, c_membuffers,
c_memcached, c_swapused, c_swapfree, c_swapcached
};
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_locks
};
#define bytetok(x) (((x) + 512) >> 10)
#define INITIAL_ACTIVE_SIZE (256)
#define PROCBLOCK_SIZE (32)
#define NCPUSTATES 5
#define NMEMSTATS 5
#define NSWAPSTATS 3
#define MEMUSED 0
#define MEMFREE 1
#define MEMSHARED 2
#define MEMBUFFERS 3
#define MEMCACHED 4
#define NMEMSTATS 5
#define SWAPUSED 0
#define SWAPFREE 1
#define SWAPCACHED 2
struct top_proc_r
{
RB_ENTRY(top_proc_r) entry;
pid_t pid;
char *name;
char *usename;
unsigned long size;
unsigned long rss; /* in k */
int state;
int pgstate;
unsigned long time;
unsigned long start_time;
unsigned long xtime;
unsigned long qtime;
unsigned int locks;
double pcpu;
/* The change in the previous values and current values. */
long long rchar_diff;
long long wchar_diff;
long long syscr_diff;
long long syscw_diff;
long long read_bytes_diff;
long long write_bytes_diff;
long long cancelled_write_bytes_diff;
/* The absolute values. */
long long rchar;
long long wchar;
long long syscr;
long long syscw;
long long read_bytes;
long long write_bytes;
long long cancelled_write_bytes;
/* Replication data */
char *application_name;
char *client_addr;
char *repstate;
char *primary;
char *sent;
char *write;
char *flush;
char *replay;
long long sent_lag;
long long write_lag;
long long flush_lag;
long long replay_lag;
};
static time_t boottime = -1;
static struct top_proc_r *pgrtable;
static int proc_r_index;
int topprocrcmp(struct top_proc_r *, struct top_proc_r *);
RB_HEAD(pgprocr, top_proc_r) head_proc_r = RB_INITIALIZER(&