/* * Copyright (c) 2008-2009, Mark Wong */ #ifdef __linux__ #define _GNU_SOURCE #endif /* __linux__ */ #include #if defined(__FreeBSD__) || defined(__OpenBSD__) #include #endif /* __FreeBSD__*/ #ifdef __linux__ #include #include #endif /* __linux__ */ #include #include #include #include #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(&head_proc_r); RB_PROTOTYPE(pgprocr, top_proc_r, entry, topprocrcmp) RB_GENERATE(pgprocr, top_proc_r, entry, topprocrcmp) static char *cpustatenames[NCPUSTATES + 1] = { "user", "nice", "system", "idle", "iowait", NULL }; static char *memorynames[NMEMSTATS + 1] = { "K used, ", "K free, ", "K shared, ", "K buffers, ", "K cached", NULL }; /* 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", "locks", "command", "flag", "rlag", "slag", "wlag", NULL }; static char *swapnames[NSWAPSTATS + 1] = { "K used, ", "K free, ", "K cached", NULL }; static char fmt_header[] = " PID X SIZE RES STATE XTIME QTIME %CPU LOCKS COMMAND"; char fmt_header_io_r[] = " PID RCHAR WCHAR SYSCR SYSCW READS WRITES CWRITES COMMAND"; char fmt_header_replication_r[] = " PID USERNAME APPLICATION CLIENT STATE PRIMARY SENT WRITE FLUSH REPLAY SLAG WLAG FLAG RLAG"; /* Now the array that maps process state to a weight. */ unsigned char sort_state_r[] = { 0, /* empty */ 6, /* run */ 3, /* sleep */ 5, /* disk wait */ 1, /* zombie */ 2, /* stop */ 4 /* swap */ }; static int64_t cpu_states[NCPUSTATES]; static long memory_stats[NMEMSTATS]; static int process_states[NPROCSTATES]; static long swap_stats[NSWAPSTATS]; static struct timeval lasttime; static int64_t cp_time[NCPUSTATES]; static int64_t cp_old[NCPUSTATES]; static int64_t cp_diff[NCPUSTATES]; #define ORDERKEY_PCTCPU if ((result = (int)(p2->pcpu - p1->pcpu)) == 0) #define ORDERKEY_STATE if ((result = p1->pgstate < p2->pgstate)) #define ORDERKEY_RSSIZE if ((result = p2->rss - p1->rss) == 0) #define ORDERKEY_LAG_FLUSH if ((result = p2->flush_lag - p1->flush_lag) == 0) #define ORDERKEY_LAG_REPLAY if ((result = p2->replay_lag - \ p1->replay_lag) == 0) #define ORDERKEY_LAG_SENT if ((result = p2->sent_lag - p1->sent_lag) == 0) #define ORDERKEY_LAG_WRITE if ((result = p2->write_lag - p1->write_lag) == 0) #define ORDERKEY_MEM if ((result = p2->size - p1->size) == 0) #define ORDERKEY_NAME if ((result = strcmp(p1->name, p2->name)) == 0) #define ORDERKEY_RCHAR if ((result = p1->rchar - p2->rchar) == 0) #define ORDERKEY_WCHAR if ((result = p1->wchar - p2->wchar) == 0) #define ORDERKEY_SYSCR if ((result = p1->syscr - p2->syscr) == 0) #define ORDERKEY_SYSCW if ((result = p1->syscw - p2->syscw) == 0) #define ORDERKEY_READS if ((result = p1->read_bytes - p2->read_bytes) == 0) #define ORDERKEY_WRITES if ((result = p1->write_bytes - p2->write_bytes) == 0) #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_lag_flush(const void *, const void *); static int compare_lag_replay(const void *, const void *); static int compare_lag_sent(const void *, const void *); static int compare_lag_write(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 *); static int compare_res_r(const void *, const void *); static int compare_size_r(const void *, const void *); static int compare_syscr_r(const void *, const void *); static int compare_syscw_r(const void *, const void *); static int compare_wchar_r(const void *, const void *); static int compare_writes_r(const void *, const void *); static int compare_xtime_r(const void *, const void *); int check_for_function(PGconn *pgconn, char *procname) { PGresult *pgresult = NULL; int rows = 0; int count; char sql[128]; sprintf(sql, QUERY_PG_PROC, procname); pgresult = PQexec(pgconn, sql); rows = PQntuples(pgresult); /* Don't need to clean up on error, the program will exit shortly after. */ if (rows == 0) { fprintf(stderr, "Error executing '%s'.\n", sql); return -1; } count = atoi(PQgetvalue(pgresult, 0, 0)); if (count == 0) { fprintf(stderr, "Stored function '%s' is missing.\n", procname); return -1; } if (pgresult != NULL) PQclear(pgresult); return 0; } int (*proc_compares_r[]) () = { compare_cpu_r, compare_size_r, compare_res_r, compare_xtime_r, compare_qtime_r, compare_rchar_r, compare_wchar_r, compare_syscr_r, compare_syscw_r, compare_reads_r, compare_writes_r, compare_cwrites_r, compare_locks_r, compare_cmd_r, compare_lag_flush, compare_lag_replay, compare_lag_sent, compare_lag_write, NULL }; /* The comparison function for sorting by command name. */ static int compare_cmd_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_NAME ORDERKEY_PCTCPU ORDERKEY_STATE ORDERKEY_RSSIZE ORDERKEY_MEM ; return (result); } /* compare_cpu_r - the comparison function for sorting by cpu percentage */ static int compare_cpu_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_PCTCPU ORDERKEY_STATE ORDERKEY_RSSIZE ORDERKEY_MEM ; return (result); } static int compare_cwrites_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_CWRITES ORDERKEY_RCHAR ORDERKEY_WCHAR ORDERKEY_SYSCR ORDERKEY_SYSCW ORDERKEY_READS ORDERKEY_WRITES ORDERKEY_NAME ; return (result); } static int compare_lag_flush(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_LAG_FLUSH ORDERKEY_PCTCPU ORDERKEY_STATE ORDERKEY_MEM ORDERKEY_RSSIZE ; return (result); } static int compare_lag_replay(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_LAG_REPLAY ORDERKEY_PCTCPU ORDERKEY_STATE ORDERKEY_MEM ORDERKEY_RSSIZE ; return (result); } static int compare_lag_sent(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_LAG_SENT ORDERKEY_PCTCPU ORDERKEY_STATE ORDERKEY_MEM ORDERKEY_RSSIZE ; return (result); } static int compare_lag_write(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_LAG_WRITE ORDERKEY_PCTCPU ORDERKEY_STATE ORDERKEY_MEM ORDERKEY_RSSIZE ; 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 compare_qtime_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_QTIME ORDERKEY_PCTCPU ORDERKEY_STATE ORDERKEY_MEM ORDERKEY_RSSIZE ; return (result); } /* The comparison function for sorting by resident set size. */ static int compare_res_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_RSSIZE ORDERKEY_MEM ORDERKEY_PCTCPU ORDERKEY_STATE ; return (result); } /* The comparison function for sorting by total memory usage. */ static int compare_rchar_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_RCHAR ORDERKEY_WCHAR ORDERKEY_SYSCR ORDERKEY_SYSCW ORDERKEY_READS ORDERKEY_WRITES ORDERKEY_CWRITES ORDERKEY_NAME ; return (result); } static int compare_reads_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_READS ORDERKEY_RCHAR ORDERKEY_WCHAR ORDERKEY_SYSCR ORDERKEY_SYSCW ORDERKEY_WRITES ORDERKEY_CWRITES ORDERKEY_NAME ; return (result); } static int compare_size_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_MEM ORDERKEY_RSSIZE ORDERKEY_PCTCPU ORDERKEY_STATE ; return (result); } static int compare_syscr_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_SYSCR ORDERKEY_RCHAR ORDERKEY_WCHAR ORDERKEY_SYSCW ORDERKEY_READS ORDERKEY_WRITES ORDERKEY_CWRITES ORDERKEY_NAME ; return (result); } static int compare_syscw_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_SYSCW ORDERKEY_RCHAR ORDERKEY_WCHAR ORDERKEY_SYSCR ORDERKEY_READS ORDERKEY_WRITES ORDERKEY_CWRITES ORDERKEY_NAME ; return (result); } /* compare_xtime_r - the comparison function for sorting by total cpu xtime */ static int compare_xtime_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_XTIME ORDERKEY_PCTCPU ORDERKEY_STATE ORDERKEY_MEM ORDERKEY_RSSIZE ; return (result); } static int compare_wchar_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_WCHAR ORDERKEY_RCHAR ORDERKEY_SYSCR ORDERKEY_SYSCW ORDERKEY_READS ORDERKEY_WRITES ORDERKEY_CWRITES ORDERKEY_NAME ; return (result); } static int compare_writes_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_WRITES ORDERKEY_RCHAR ORDERKEY_WCHAR ORDERKEY_SYSCR ORDERKEY_SYSCW ORDERKEY_READS ORDERKEY_CWRITES ORDERKEY_NAME ; return (result); } char * format_header_r(char *uname_field) { int uname_len = strlen(uname_field); if (uname_len > 8) uname_len = 8; memcpy(strchr(fmt_header, 'X'), uname_field, uname_len); return fmt_header; } char * format_next_io_r(caddr_t handler) { static char fmt[MAX_COLS]; /* static area where result is built */ struct top_proc_r *p = &pgrtable[proc_r_index++]; snprintf(fmt, sizeof(fmt), "%7d %5s %5s %7lld %7lld %5s %6s %7s %s", (int) p->pid, format_b(p->rchar_diff), format_b(p->wchar_diff), p->syscr_diff, p->syscw_diff, format_b(p->read_bytes_diff), format_b(p->write_bytes_diff), format_b(p->cancelled_write_bytes_diff), p->name); return (fmt); } char * format_next_process_r(caddr_t handler) { static char fmt[MAX_COLS]; /* static area where result is built */ struct top_proc_r *p = &pgrtable[proc_r_index++]; snprintf(fmt, sizeof(fmt), "%7d %-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), format_k(p->rss), backendstatenames[p->pgstate], format_time(p->xtime), format_time(p->qtime), p->pcpu * 100.0, p->locks, p->name); return (fmt); } char * format_next_replication_r(caddr_t handle) { static char fmt[MAX_COLS]; /* static area where result is built */ struct top_proc_r *p = &pgrtable[proc_r_index++]; snprintf(fmt, sizeof(fmt), "%7d %-8.8s %-11.11s %15s %-9.9s %9s %9s %9s %9s %9s %5s %5s %5s %5s", p->pid, p->usename, p->application_name, p->client_addr, p->repstate, p->primary, p->sent, p->write, p->flush, p->replay, format_b(p->sent_lag), format_b(p->write_lag), format_b(p->flush_lag), format_b(p->replay_lag)); /* return the result */ return (fmt); } void get_system_info_r(struct system_info *info, struct pg_conninfo_ctx *conninfo) { PGresult *pgresult = NULL; int rows = 0; connect_to_db(conninfo); if (conninfo->connection != NULL) { pgresult = PQexec(conninfo->connection, QUERY_LOADAVG); rows = PQntuples(pgresult); } /* Get load averages. */ if (rows > 0) { info->load_avg[0] = atof(PQgetvalue(pgresult, 0, c_load1)); info->load_avg[1] = atof(PQgetvalue(pgresult, 0, c_load5)); info->load_avg[2] = atof(PQgetvalue(pgresult, 0, c_load15)); info->last_pid = atoi(PQgetvalue(pgresult, 0, c_last_pid)); } else { info->load_avg[0] = 0; info->load_avg[1] = 0; info->load_avg[2] = 0; info->last_pid = 0; } /* Get processor time info. */ if (conninfo->connection != NULL) { pgresult = PQexec(conninfo->connection, QUERY_CPUTIME); rows = PQntuples(pgresult); } if (rows > 0) { cp_time[0] = atol(PQgetvalue(pgresult, 0, c_cpu_user)); cp_time[1] = atol(PQgetvalue(pgresult, 0, c_cpu_nice)); cp_time[2] = atol(PQgetvalue(pgresult, 0, c_cpu_system)); cp_time[3] = atol(PQgetvalue(pgresult, 0, c_cpu_idle)); cp_time[4] = atol(PQgetvalue(pgresult, 0, c_cpu_iowait)); /* convert cp_time counts to percentages */ percentages(NCPUSTATES, cpu_states, cp_time, cp_old, cp_diff); } else { cpu_states[0] = 0; cpu_states[1] = 0; cpu_states[2] = 0; cpu_states[3] = 0; cpu_states[4] = 0; } /* Get system wide memory usage. */ if (conninfo->connection != NULL) { pgresult = PQexec(conninfo->connection, QUERY_MEMUSAGE); rows = PQntuples(pgresult); } if (rows > 0) { memory_stats[MEMUSED] = atol(PQgetvalue(pgresult, 0, c_memused)); memory_stats[MEMFREE] = atol(PQgetvalue(pgresult, 0, c_memfree)); memory_stats[MEMSHARED] = atol(PQgetvalue(pgresult, 0, c_memshared)); memory_stats[MEMBUFFERS] = atol(PQgetvalue(pgresult, 0, c_membuffers)); memory_stats[MEMCACHED] = atol(PQgetvalue(pgresult, 0, c_memcached)); swap_stats[SWAPUSED] = atol(PQgetvalue(pgresult, 0, c_swapused)); swap_stats[SWAPFREE] = atol(PQgetvalue(pgresult, 0, c_swapfree)); swap_stats[SWAPCACHED] = atol(PQgetvalue(pgresult, 0, c_swapcached)); } else { memory_stats[MEMUSED] = 0; memory_stats[MEMFREE] = 0; memory_stats[MEMSHARED] = 0; memory_stats[MEMBUFFERS] = 0; memory_stats[MEMCACHED] = 0; swap_stats[SWAPUSED] = 0; swap_stats[SWAPFREE] = 0; swap_stats[SWAPCACHED] = 0; } info->cpustates = cpu_states; info->memory = memory_stats; info->swap = swap_stats; if (pgresult != NULL) PQclear(pgresult); disconnect_from_db(conninfo); } caddr_t get_process_info_r(struct system_info *si, struct process_select *sel, int compare_index, struct pg_conninfo_ctx *conninfo, int mode) { int i; PGresult *pgresult = NULL; int rows; struct timeval thistime; double timediff; int active_procs = 0; int total_procs = 0; int show_idle = sel->idle; struct top_proc_r *n, *p; memset(process_states, 0, sizeof(process_states)); /* Calculate the time difference since our last check. */ gettimeofday(&thistime, 0); if (lasttime.tv_sec) { timediff = ((thistime.tv_sec - lasttime.tv_sec) + (thistime.tv_usec - lasttime.tv_usec) * 1e-6); } else { timediff = 0; } lasttime = thistime; timediff *= HZ; /* Convert to ticks. */ connect_to_db(conninfo); if (conninfo->connection != NULL) { switch (mode) { case MODE_REPLICATION: pgresult = pg_replication(conninfo->connection); break; default: if (sel->fullcmd == 2) { pgresult = PQexec(conninfo->connection, QUERY_PROCTAB_QUERY); } else { pgresult = PQexec(conninfo->connection, QUERY_PROCTAB); } } rows = PQntuples(pgresult); } else { rows = 0; } if (rows > 0) { p = realloc(pgrtable, sizeof(struct top_proc_r) * rows); if (p == NULL) { fprintf(stderr, "realloc error\n"); if (pgresult != NULL) PQclear(pgresult); disconnect_from_db(conninfo); exit(1); } pgrtable = p; } for (i = 0; i < rows; i++) { unsigned long otime; long long value; n = malloc(sizeof(struct top_proc_r)); if (n == NULL) { fprintf(stderr, "malloc error\n"); if (pgresult != NULL) PQclear(pgresult); disconnect_from_db(conninfo); exit(1); } memset(n, 0, sizeof(struct top_proc_r)); n->pid = atoi(PQgetvalue(pgresult, i, c_pid)); p = RB_INSERT(pgprocr, &head_proc_r, n); if (p != NULL) { free(n); n = p; } else { n->time = 0; } otime = n->time; switch (mode) { case MODE_REPLICATION: update_str(&n->usename, PQgetvalue(pgresult, i, 1)); update_str(&n->application_name, PQgetvalue(pgresult, i, 2)); update_str(&n->client_addr, PQgetvalue(pgresult, i, 3)); update_str(&n->repstate, PQgetvalue(pgresult, i, 4)); update_str(&n->primary, PQgetvalue(pgresult, i, 5)); update_str(&n->sent, PQgetvalue(pgresult, i, 6)); update_str(&n->write, PQgetvalue(pgresult, i, 7)); update_str(&n->flush, PQgetvalue(pgresult, i, 8)); update_str(&n->replay, PQgetvalue(pgresult, i, 9)); n->sent_lag = atol(PQgetvalue(pgresult, i, 10)); n->write_lag = atol(PQgetvalue(pgresult, i, 11)); n->flush_lag = atol(PQgetvalue(pgresult, i, 12)); n->replay_lag = atol(PQgetvalue(pgresult, i, 13)); memcpy(&pgrtable[active_procs++], n, sizeof(struct top_proc_r)); break; default: if (sel->fullcmd && PQgetvalue(pgresult, i, c_fullcomm)) update_str(&n->name, PQgetvalue(pgresult, i, c_fullcomm)); else update_str(&n->name, PQgetvalue(pgresult, i, c_comm)); switch (PQgetvalue(pgresult, i, c_state)[0]) { case 'R': n->state = 1; break; case 'S': n->state = 2; break; case 'D': n->state = 3; break; case 'Z': n->state = 4; break; case 'T': n->state = 5; break; case 'W': n->state = 6; break; case '\0': continue; } update_state(&n->pgstate, PQgetvalue(pgresult, i, c_pgstate)); n->time = (unsigned long) atol(PQgetvalue(pgresult, i, c_utime)); n->time += (unsigned long) atol(PQgetvalue(pgresult, i, c_stime)); n->start_time = (unsigned long) atol(PQgetvalue(pgresult, i, c_starttime)); n->size = bytetok((unsigned long) atol(PQgetvalue(pgresult, i, c_vsize))); n->rss = bytetok((unsigned long) atol(PQgetvalue(pgresult, i, c_rss))); update_str(&n->usename, PQgetvalue(pgresult, i, c_username)); 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; value = atoll(PQgetvalue(pgresult, i, c_wchar)); n->wchar_diff = value - n->wchar; n->wchar = value; value = atoll(PQgetvalue(pgresult, i, c_syscr)); n->syscr_diff = value - n->syscr; n->syscr = value; value = atoll(PQgetvalue(pgresult, i, c_syscw)); n->syscw_diff = value - n->syscw; n->syscw = value; value = atoll(PQgetvalue(pgresult, i, c_reads)); n->read_bytes_diff = value - n->read_bytes; n->read_bytes = value; value = atoll(PQgetvalue(pgresult, i, c_writes)); n->write_bytes_diff = value - n->write_bytes; n->write_bytes = value; value = atoll(PQgetvalue(pgresult, i, c_cwrites)); n->cancelled_write_bytes_diff = value - n->cancelled_write_bytes; n->cancelled_write_bytes = value; ++total_procs; ++process_states[n->pgstate]; if (timediff > 0.0) { if ((n->pcpu = (n->time - otime) / timediff) < 0.0001) n->pcpu = 0; } if ((show_idle || n->pgstate != STATE_IDLE) && (sel->usename[0] == '\0' || strcmp(n->usename, sel->usename) == 0)) memcpy(&pgrtable[active_procs++], n, sizeof(struct top_proc_r)); } } if (pgresult != NULL) PQclear(pgresult); disconnect_from_db(conninfo); si->p_active = active_procs; si->p_total = total_procs; si->procstates = process_states; /* Sort the "active" procs if specified. */ if (compare_index >= 0 && si->p_active) qsort(pgrtable, si->p_active, sizeof(struct top_proc_r), proc_compares_r[compare_index]); /* don't even pretend that the return value thing here isn't bogus */ proc_r_index = 0; return 0; } int machine_init_r(struct statics *statics, struct pg_conninfo_ctx *conninfo) { /* Make sure the remote system has the stored function installed. */ connect_to_db(conninfo); if (conninfo->connection == NULL) { fprintf(stderr, "Cannot connect to database.\n"); return -1; } if (check_for_function(conninfo->connection, "pg_cputime") != 0) return -1; if (check_for_function(conninfo->connection, "pg_loadavg") != 0) return -1; if (check_for_function(conninfo->connection, "pg_memusage") != 0) return -1; if (check_for_function(conninfo->connection, "pg_proctab") != 0) return -1; disconnect_from_db(conninfo); /* fill in the statics information */ statics->procstate_names = procstatenames; statics->cpustate_names = cpustatenames; statics->memory_names = memorynames; statics->swap_names = swapnames; statics->order_names = ordernames; statics->boottime = boottime; statics->flags.fullcmds = 1; statics->flags.warmup = 1; return 0; } int topprocrcmp(struct top_proc_r *e1, struct top_proc_r *e2) { return (e1->pid < e2->pid ? -1 : e1->pid > e2->pid); }