summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Wong <markwkm@gmail.com>2023-05-21 17:04:31 -0700
committerMark Wong <markwkm@gmail.com>2023-05-21 18:09:16 -0700
commit15d2d31ad8d22a836dbb0c1578b0b92a2a7766c3 (patch)
tree16a6d20a6e162575827d2ba48738bc0e8b8fe6aa
parentb2d63dd8bbf8fd800135b33b74a0be22943c65fe (diff)
Revert "Revert "monitor the disk I/O of the server""
-rw-r--r--Porting11
-rw-r--r--display.c55
-rw-r--r--display.h4
-rw-r--r--layout.h14
-rw-r--r--machine.h34
-rw-r--r--machine/m_aix43.c7
-rw-r--r--machine/m_aix5.c7
-rw-r--r--machine/m_common.c85
-rw-r--r--machine/m_freebsd.c7
-rw-r--r--machine/m_linux.c75
-rw-r--r--machine/m_netbsd.c7
-rw-r--r--machine/m_openbsd.c7
-rw-r--r--machine/m_sco5.c7
-rw-r--r--machine/m_sunos5.c7
-rw-r--r--machine/m_svr4.c7
-rw-r--r--machine/m_svr5.c7
-rw-r--r--pg_top.c24
-rw-r--r--pg_top.h2
18 files changed, 362 insertions, 5 deletions
diff --git a/Porting b/Porting
index a1bf0e9..2570b3b 100644
--- a/Porting
+++ b/Porting
@@ -74,6 +74,15 @@ struct system_info
int *memory; /* memory information */
};
+The io_info struct is filled in by get_io_info.
+struct io_info {
+ int64_t reads;
+ int64_t readsectors;
+ int64_t writes;
+ int64_t writesectors;
+};
+
+
The last three pointers each point to an array of integers. The
length of the array is determined by the length of the corresponding
_names array in the statics structure. Furthermore, if an entry in a
@@ -116,6 +125,8 @@ int proc_compare(caddr_t, caddr_t)
qsort comparison function
+void get_io_info(struct io_info *)
+
get_process_info is called immediately after get_system_info. In
fact, the two functions could be rolled in to one. The reason they
are not is mostly historical.
diff --git a/display.c b/display.c
index 5091587..2d785c2 100644
--- a/display.c
+++ b/display.c
@@ -72,6 +72,10 @@ static int y_mem = Y_MEM;
static int x_swap = -1;
static int y_swap = -1;
static int y_message = Y_MESSAGE;
+static int x_db = X_DB;
+static int y_db = Y_DB;
+static int x_io = X_IO;
+static int y_io = Y_IO;
static int x_header = X_HEADER;
static int y_header = Y_HEADER;
static int x_idlecursor = X_IDLECURSOR;
@@ -1196,6 +1200,57 @@ u_swap(long *stats)
}
/*
+ * *_db(db_info) - print "DB activity: " followed by database activity
+ */
+void
+i_db(struct db_info *db_info)
+{
+ u_db(db_info);
+}
+
+void
+u_db(struct db_info *db_info)
+{
+ char buf[128];
+
+ display_write(x_db, y_db, 0, 0, "DB activity: ");
+ snprintf(buf, sizeof(buf),
+ "%3ld tps, %2ld rollbs/s, %3ld buffer r/s, %2ld hit%%, %6ld row r/s, %4ld row w/s ",
+ db_info->numXact, db_info->numRollback,
+ db_info->numBlockRead,
+ db_info->numBlockRead + db_info->numBlockHit > 0 ?
+ ((int64_t)(db_info->numBlockHit * 100 /
+ (db_info->numBlockRead + db_info->numBlockHit))) : 0,
+ db_info->numTupleFetched,
+ db_info->numTupleAltered);
+ display_write(-1, -1, 0, 0, buf);
+}
+
+/*
+ * *_io(io_info) - print "DB I/O: " followed by IO summary
+ */
+void
+i_io(struct io_info *io_info)
+{
+ char buf[128];
+ display_write(x_io, y_io, 0, 0, "DB I/O: ");
+
+ snprintf(buf, sizeof(buf),
+ "%5ld reads/s, %5ld KB/s, %5ld writes/s, %5ld KB/s ",
+ io_info->reads,
+ io_info->readsectors / 2,
+ io_info->writes,
+ io_info->writesectors / 2);
+ display_write(-1, -1, 0, 0, buf);
+}
+
+void
+u_io(struct io_info *io_info)
+{
+ i_io(io_info);
+}
+
+/*
* *_message() - print the next pending message line, or erase the one
* that is there.
*
diff --git a/display.h b/display.h
index f5b8c2a..4cc15d0 100644
--- a/display.h
+++ b/display.h
@@ -28,6 +28,10 @@ void i_memory(long *stats);
void u_memory(long *stats);
void i_swap(long *stats);
void u_swap(long *stats);
+void i_db(struct db_info *db_info);
+void u_db(struct db_info *db_info);
+void i_io(struct io_info *io_info);
+void u_io(struct io_info *io_info);
void i_message();
void u_message();
void i_header(char *text);
diff --git a/layout.h b/layout.h
index c64f2d0..cda9db4 100644
--- a/layout.h
+++ b/layout.h
@@ -27,13 +27,17 @@
#define Y_CPUSTATES 2
#define X_MEM 8
#define Y_MEM 3
+#define X_DB 0
+#define Y_DB 4
+#define X_IO 0
+#define Y_IO 5
#define X_SWAP 6
-#define Y_SWAP 4
-#define Y_MESSAGE 4
+#define Y_SWAP 6
+#define Y_MESSAGE 6
#define X_HEADER 0
-#define Y_HEADER 5
+#define Y_HEADER 7
#define X_IDLECURSOR 0
-#define Y_IDLECURSOR 4
-#define Y_PROCS 6
+#define Y_IDLECURSOR 6
+#define Y_PROCS 8
#endif /* _LAYOUT_H_ */
diff --git a/machine.h b/machine.h
index 4604a5a..dbee31d 100644
--- a/machine.h
+++ b/machine.h
@@ -97,6 +97,31 @@ struct system_info
*/
/*
+ * Database activity information
+ */
+struct db_info {
+ int numDb;
+ int64_t numXact;
+ int64_t numRollback;
+ int64_t numBlockRead;
+ int64_t numBlockHit;
+ int64_t numTupleFetched;
+ int64_t numTupleAltered;
+ int64_t numConflict;
+};
+
+/*
+ * Info on reads/writes happening on disk.
+ * On Linux, this can be obtained from /proc/diskstats.
+ */
+struct io_info {
+ int64_t reads;
+ int64_t readsectors;
+ int64_t writes;
+ int64_t writesectors;
+};
+
+/*
* the process_select struct tells get_process_info what processes we
* are interested in seeing
*/
@@ -114,6 +139,15 @@ int machine_init(struct statics *);
void get_system_info(struct system_info *);
caddr_t get_process_info(struct system_info *, struct process_select *, int,
struct pg_conninfo_ctx *, int);
+#ifdef __linux__
+caddr_t get_process_info(struct system_info *, struct process_select *, int,
+ struct pg_conninfo_ctx *, int);
+#else
+caddr_t get_process_info(struct system_info *, struct process_select *, int,
+ char *);
+#endif /* __linux__ */
+void get_database_info(struct db_info *, struct pg_conninfo_ctx *);
+void get_io_info(struct io_info *);
char *format_header(char *);
#if defined(__linux__) || defined (__FreeBSD__)
char *format_next_io(caddr_t);
diff --git a/machine/m_aix43.c b/machine/m_aix43.c
index 52cf39a..72a0f43 100644
--- a/machine/m_aix43.c
+++ b/machine/m_aix43.c
@@ -741,3 +741,10 @@ proc_owner(int pid)
return (-1);
}
+
+void
+get_io_info(struct io_info *io_info)
+{
+ /* Not supported yet */
+ memset(io_info, 0, sizeof(*io_info));
+}
diff --git a/machine/m_aix5.c b/machine/m_aix5.c
index 0656b57..c07ba26 100644
--- a/machine/m_aix5.c
+++ b/machine/m_aix5.c
@@ -828,3 +828,10 @@ int pid;
return (-1);
}
+
+void
+get_io_info(struct io_info *io_info)
+{
+ /* Not supported yet */
+ memset(io_info, 0, sizeof(*io_info));
+}
diff --git a/machine/m_common.c b/machine/m_common.c
index fb9c6a6..fb7833a 100644
--- a/machine/m_common.c
+++ b/machine/m_common.c
@@ -13,6 +13,13 @@
#include "machine.h"
+/* Query to fetch information about database activity */
+#define QUERY_STAT_DB \
+ "SELECT datid, datname, numbackends, xact_commit, xact_rollback, \n" \
+ " blks_read, blks_hit, tup_returned, tup_fetched, \n" \
+ " tup_inserted, tup_updated, tup_deleted, conflicts \n" \
+ "FROM pg_stat_database;"
+
char *backendstatenames[] =
{
"", "idle", "active", "idltxn", "fast", "abort", "disabl", NULL
@@ -26,6 +33,84 @@ char *procstatenames[] =
char fmt_header_replication[] =
" PID USERNAME APPLICATION CLIENT STATE PRIMARY SENT WRITE FLUSH REPLAY SLAG WLAG FLAG RLAG";
+/*
+ * Get database info via the above QUERY_STAT_DB info.
+ * Returns rate info on the various statistics by comparing current
+ * values with previous values.
+ */
+void
+get_database_info(struct db_info *db_info, struct pg_conninfo_ctx *conninfo)
+{
+ struct timeval thistime;
+ double timediff;
+ int i;
+ int rows;
+ PGresult *pgresult = NULL;
+ struct db_info cur_info;
+ static struct timeval lasttime;
+ static struct db_info last_db_info;
+
+ /* 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;
+
+ rows = 0;
+ connect_to_db(conninfo);
+ if (conninfo->connection != NULL)
+ {
+ pgresult = PQexec(conninfo->connection, QUERY_STAT_DB);
+ if (PQresultStatus(pgresult) == PGRES_TUPLES_OK)
+ rows = PQntuples(pgresult);
+
+ }
+ if (rows == 0)
+ {
+ /* Database probably stopped, clear current and last */
+ memset(&last_db_info, 0, sizeof(last_db_info));
+ }
+ memset(&cur_info, 0, sizeof(cur_info));
+ for (i = 0; i < rows; i++)
+ {
+ PQgetvalue(pgresult, i, 2);
+ /* Count all databases, even with no active backends */
+ cur_info.numDb++;
+ cur_info.numXact += atoi(PQgetvalue(pgresult, i, 3));
+ cur_info.numRollback += atoi(PQgetvalue(pgresult, i, 4));
+ cur_info.numBlockRead += atoi(PQgetvalue(pgresult, i, 5));
+ cur_info.numBlockHit += atoi(PQgetvalue(pgresult, i, 6));
+ cur_info.numTupleFetched += atoi(PQgetvalue(pgresult, i, 8));
+ cur_info.numTupleAltered += atoi(PQgetvalue(pgresult, i, 9)) +
+ atoi(PQgetvalue(pgresult, i, 10)) +
+ atoi(PQgetvalue(pgresult, i, 11));
+ cur_info.numConflict += atoi(PQgetvalue(pgresult, i, 12));
+ }
+ if (pgresult != NULL)
+ PQclear(pgresult);
+ disconnect_from_db(conninfo);
+ if (timediff <= 0)
+ {
+ last_db_info = cur_info;
+ memset(db_info, 0, sizeof(*db_info));
+ return;
+ }
+
+ /* Compute the rate information */
+ db_info->numDb = cur_info.numDb;
+ db_info->numXact = (double)(cur_info.numXact - last_db_info.numXact) / timediff;
+ db_info->numRollback = (double)(cur_info.numRollback - last_db_info.numRollback) / timediff;
+ db_info->numBlockRead = (double)(cur_info.numBlockRead - last_db_info.numBlockRead) / timediff;
+ db_info->numBlockHit = (double)(cur_info.numBlockHit - last_db_info.numBlockHit) / timediff;
+ db_info->numTupleFetched = (double)(cur_info.numTupleFetched - last_db_info.numTupleFetched) / timediff;
+ db_info->numTupleAltered = (double)(cur_info.numTupleAltered - last_db_info.numTupleAltered) / timediff;
+ db_info->numConflict = (double)(cur_info.numConflict - last_db_info.numConflict) / timediff;
+ last_db_info = cur_info;
+}
void
update_state(int *pgstate, char *state)
diff --git a/machine/m_freebsd.c b/machine/m_freebsd.c
index 4f78043..8e20b6a 100644
--- a/machine/m_freebsd.c
+++ b/machine/m_freebsd.c
@@ -1208,3 +1208,10 @@ topproccmp(struct pg_proc *e1, struct pg_proc *e2)
{
return (e1->pid < e2->pid ? -1 : e1->pid > e2->pid);
}
+void
+
+get_io_info(struct io_info *io_info)
+{
+ /* Not supported yet */
+ memset(io_info, 0, sizeof(*io_info));
+}
diff --git a/machine/m_linux.c b/machine/m_linux.c
index 50a09cb..79b2825 100644
--- a/machine/m_linux.c
+++ b/machine/m_linux.c
@@ -15,6 +15,8 @@
* AUTHOR: Richard Henderson <rth@tamu.edu>
* Order support added by Alexey Klimkin <kad@klon.tme.mcst.ru>
* Ported to 2.4 by William LeFebvre
+ *
+ * Portions Copyright (c) 2013 VMware, Inc. All Rights Reserved.
*/
#define _GNU_SOURCE
@@ -1370,3 +1372,76 @@ compare_writes(const void *v1, const void *v2)
return (result);
}
+
+/*
+ * Get IO information for the SCSI devices in the system. Returns
+ * read/write IOs per second and bandwidth by comparing current values
+ * with previous values.
+ */
+void
+get_io_info(struct io_info *io_info)
+{
+ struct timeval thistime;
+ double timediff;
+ static struct timeval lasttime;
+ struct io_info cur_info;
+ static struct io_info last_io_info;
+ FILE *fp;
+ char line[256];
+ int major, minor;
+ char dev_name[32];
+ int64_t reads, readsectors, skip, writes, writesectors;
+ int i;
+
+ /* 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;
+
+ fp = fopen("/proc/diskstats", "r");
+ if (fp == NULL)
+ {
+ memset(io_info, 0, sizeof(*io_info));
+ return;
+ }
+
+ memset(&cur_info, 0, sizeof(cur_info));
+ while (fgets(line, 256, fp) != NULL)
+ {
+ i = sscanf(line, "%d %d %31s %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld %ld",
+ &major, &minor, dev_name,
+ &reads, &skip, &readsectors, &skip,
+ &writes, &skip, &writesectors, &skip,
+ &skip, &skip, &skip);
+ if (i != 14)
+ continue;
+
+ /* Total up full scsi devices (not partitions) */
+ if (major == 8 && (minor % 16) == 0)
+ {
+ cur_info.reads += reads;
+ cur_info.readsectors += readsectors;
+ cur_info.writes += writes;
+ cur_info.writesectors += writesectors;
+ }
+ }
+ fclose(fp);
+ if (timediff == 0)
+ {
+ last_io_info = cur_info;
+ memset(io_info, 0, sizeof(*io_info));
+ return;
+ }
+
+ /* Compute the rate information */
+ io_info->reads = (double)(cur_info.reads - last_io_info.reads) / timediff;
+ io_info->readsectors = (double)(cur_info.readsectors - last_io_info.readsectors) / timediff;
+ io_info->writes = (double)(cur_info.writes - last_io_info.writes) / timediff;
+ io_info->writesectors = (double)(cur_info.writesectors - last_io_info.writesectors) / timediff;
+ last_io_info = cur_info;
+}
diff --git a/machine/m_netbsd.c b/machine/m_netbsd.c
index 6f9f566..6265817 100644
--- a/machine/m_netbsd.c
+++ b/machine/m_netbsd.c
@@ -903,3 +903,10 @@ u_int64_t *diffs;
for (i = 0; i < cnt; i++)
*out++ = (int) ((*diffs++ * 1000 + half_total) / total_change);
}
+
+void
+get_io_info(struct io_info *io_info)
+{
+ /* Not supported yet */
+ memset(io_info, 0, sizeof(*io_info));
+}
diff --git a/machine/m_openbsd.c b/machine/m_openbsd.c
index 6508106..27461e3 100644
--- a/machine/m_openbsd.c
+++ b/machine/m_openbsd.c
@@ -866,3 +866,10 @@ topproccmp(struct pg_proc *e1, struct pg_proc *e2)
{
return (e1->pid < e2->pid ? -1 : e1->pid > e2->pid);
}
+
+void
+get_io_info(struct io_info *io_info)
+{
+ /* Not supported yet */
+ memset(io_info, 0, sizeof(*io_info));
+}
diff --git a/machine/m_sco5.c b/machine/m_sco5.c
index 6a4b2e3..6c62c27 100644
--- a/machine/m_sco5.c
+++ b/machine/m_sco5.c
@@ -864,3 +864,10 @@ compare_time(struct proc **pp1, struct proc **pp2)
return (result);
}
+
+void
+get_io_info(struct io_info *io_info)
+{
+ /* Not supported yet */
+ memset(io_info, 0, sizeof(*io_info));
+}
diff --git a/machine/m_sunos5.c b/machine/m_sunos5.c
index 02a0a58..22cb4d4 100644
--- a/machine/m_sunos5.c
+++ b/machine/m_sunos5.c
@@ -1799,3 +1799,10 @@ reallocproc(int n)
op->oldpid = -1;
}
}
+
+void
+get_io_info(struct io_info *io_info)
+{
+ /* Not supported yet */
+ memset(io_info, 0, sizeof(*io_info));
+}
diff --git a/machine/m_svr4.c b/machine/m_svr4.c
index fbdf7da..f4f9ed3 100644
--- a/machine/m_svr4.c
+++ b/machine/m_svr4.c
@@ -749,3 +749,10 @@ struct sysinfo *percpu_si;
percpu_p++;
}
}
+
+void
+get_io_info(struct io_info *io_info)
+{
+ /* Not supported yet */
+ memset(io_info, 0, sizeof(*io_info));
+}
diff --git a/machine/m_svr5.c b/machine/m_svr5.c
index 7014013..2b9cbc5 100644
--- a/machine/m_svr5.c
+++ b/machine/m_svr5.c
@@ -1437,3 +1437,10 @@ kmet_verify(
}
return;
}
+
+void
+get_io_info(struct io_info *io_info)
+{
+ /* Not supported yet */
+ memset(io_info, 0, sizeof(*io_info));
+}
diff --git a/pg_top.c b/pg_top.c
index 2bb78b2..fee2c18 100644
--- a/pg_top.c
+++ b/pg_top.c
@@ -124,6 +124,8 @@ void (*d_procstates) (int, int *) = i_procstates;
void (*d_cpustates) (int64_t *) = i_cpustates;
void (*d_memory) (long *) = i_memory;
void (*d_swap) (long *) = i_swap;
+void (*d_db) (struct db_info *) = i_db;
+void (*d_io) (struct io_info *) = i_io;
void (*d_message) () = i_message;
void (*d_process) (int, char *) = i_process;
@@ -196,6 +198,12 @@ do_display(struct pg_top_context *pgtctx)
pgtctx->order_index, &pgtctx->conninfo, pgtctx->mode);
}
+ /* Get database activity information */
+ get_database_info(&pgtctx->db_info, &pgtctx->conninfo);
+
+ /* Get database I/O information */
+ get_io_info(&pgtctx->io_info);
+
/* display the load averages */
(*d_loadave) (pgtctx->system_info.last_pid, pgtctx->system_info.load_avg);
@@ -236,6 +244,12 @@ do_display(struct pg_top_context *pgtctx)
/* display memory stats */
(*d_memory) (pgtctx->system_info.memory);
+ /* display database activity */
+ (*d_db) (&pgtctx->db_info);
+
+ /* display database I/O */
+ (*d_io) (&pgtctx->io_info);
+
/* display swap stats */
(*d_swap) (pgtctx->system_info.swap);
@@ -332,6 +346,8 @@ do_display(struct pg_top_context *pgtctx)
d_procstates = u_procstates;
d_cpustates = u_cpustates;
d_memory = u_memory;
+ d_db = u_db;
+ d_io = u_io;
d_swap = u_swap;
d_message = u_message;
pgtctx->d_header = u_header;
@@ -538,6 +554,8 @@ reset_display(struct pg_top_context *pgtctx)
d_cpustates = i_cpustates;
d_memory = i_memory;
d_swap = i_swap;
+ d_db = i_db;
+ d_io = i_io;
d_message = i_message;
pgtctx->d_header = i_header;
d_process = i_process;
@@ -1001,6 +1019,12 @@ main(int argc, char *argv[])
&pgtctx.conninfo, -1);
}
+ /* Get database activity information */
+ get_database_info(&pgtctx.db_info, &pgtctx.conninfo);
+
+ /* Get database I/O information */
+ get_io_info(&pgtctx.io_info);
+
pgtctx.timeout.tv_sec = 1;
pgtctx.timeout.tv_usec = 0;
select(0, NULL, NULL, NULL, &pgtctx.timeout);
diff --git a/pg_top.h b/pg_top.h
index b3af7ec..4156754 100644
--- a/pg_top.h
+++ b/pg_top.h
@@ -101,6 +101,8 @@ struct pg_top_context
* system. */
int order_index;
char *order_name;
+ struct db_info db_info;
+ struct io_info io_info;
struct process_select ps;
char show_tags;
struct statics statics;