diff options
author | Mark Wong <markwkm@gmail.com> | 2023-05-21 17:04:31 -0700 |
---|---|---|
committer | Mark Wong <markwkm@gmail.com> | 2023-05-21 18:09:16 -0700 |
commit | 15d2d31ad8d22a836dbb0c1578b0b92a2a7766c3 (patch) | |
tree | 16a6d20a6e162575827d2ba48738bc0e8b8fe6aa | |
parent | b2d63dd8bbf8fd800135b33b74a0be22943c65fe (diff) |
Revert "Revert "monitor the disk I/O of the server""
This reverts commit fa587455496a1aa45cc9ad7ff1280a927e74493b.
-rw-r--r-- | Porting | 11 | ||||
-rw-r--r-- | display.c | 55 | ||||
-rw-r--r-- | display.h | 4 | ||||
-rw-r--r-- | layout.h | 14 | ||||
-rw-r--r-- | machine.h | 34 | ||||
-rw-r--r-- | machine/m_aix43.c | 7 | ||||
-rw-r--r-- | machine/m_aix5.c | 7 | ||||
-rw-r--r-- | machine/m_common.c | 85 | ||||
-rw-r--r-- | machine/m_freebsd.c | 7 | ||||
-rw-r--r-- | machine/m_linux.c | 75 | ||||
-rw-r--r-- | machine/m_netbsd.c | 7 | ||||
-rw-r--r-- | machine/m_openbsd.c | 7 | ||||
-rw-r--r-- | machine/m_sco5.c | 7 | ||||
-rw-r--r-- | machine/m_sunos5.c | 7 | ||||
-rw-r--r-- | machine/m_svr4.c | 7 | ||||
-rw-r--r-- | machine/m_svr5.c | 7 | ||||
-rw-r--r-- | pg_top.c | 24 | ||||
-rw-r--r-- | pg_top.h | 2 |
18 files changed, 362 insertions, 5 deletions
@@ -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. @@ -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. * @@ -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); @@ -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_ */ @@ -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)); +} @@ -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); @@ -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; |