aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mstat_plot.c168
1 files changed, 16 insertions, 152 deletions
diff --git a/mstat_plot.c b/mstat_plot.c
index 3ccf888..fd32582 100644
--- a/mstat_plot.c
+++ b/mstat_plot.c
@@ -1,147 +1,14 @@
-//
-// Created by jhunk on 8/24/22.
-//
-
-#include <string.h>
-#include <stdarg.h>
#include "common.h"
+#include "gnuplot.h"
extern char *mstat_field_names[];
-struct GNUPLOT_PLOT {
- char *title;
- char *xlabel;
- char *ylabel;
- char *line_type;
- double line_width;
- unsigned int line_color;
- unsigned char grid_toggle;
- unsigned char autoscale_toggle;
- unsigned char legend_toggle;
- unsigned char legend_enhanced;
- char *legend_title;
-};
-
-struct Option {
+static struct Option {
unsigned char verbose;
char *fields[0xffff];
char filename[PATH_MAX];
} option;
-
-/**
- * Open a new gnuplot handle
- * @return stream on success, or NULL on error
- */
-FILE *gnuplot_open() {
- // -p = persistent window after exit
- return popen("gnuplot -p", "w");
-}
-
-/**
- * Close a gnuplot handle
- * @param fp pointer to gnuplot stream
- * @return 0 on success, or <0 on error
- */
-int gnuplot_close(FILE *fp) {
- return pclose(fp);
-}
-
-/**
- * Send shell command to gnuplot instance
- * @param fp pointer to gnuplot stream
- * @param fmt command to execute (requires caller to end string with a LF "\n")
- * @param ... formatter arguments
- * @return value of `vfprintf()`. <0 on error
- */
-int gnuplot_sh(FILE *fp, char *fmt, ...) {
- int status;
-
- va_list args;
- va_start(args, fmt);
- status = vfprintf(fp, fmt, args);
- va_end(args);
-
- return status;
-}
-
-/**
- * Generate a plot
- * Each GNUPLOT_PLOT pointer in the `gp` array corresponds to a line.
- * @param fp pointer to gnuplot stream
- * @param gp pointer to an array of GNUPLOT_PLOT structures
- * @param x an array representing the x axis
- * @param y an array of double-precision arrays representing the y axes
- * @param x_count total length of array x
- * @param y_count total number of arrays in y
- */
-void gnuplot_plot(FILE *fp, struct GNUPLOT_PLOT **gp, double x[], double *y[], size_t x_count, size_t y_count) {
- // Configure plot
- gnuplot_sh(fp, "set title '%s'\n", gp[0]->title);
- gnuplot_sh(fp, "set xlabel '%s'\n", gp[0]->xlabel);
- gnuplot_sh(fp, "set ylabel '%s'\n", gp[0]->ylabel);
- if (gp[0]->grid_toggle)
- gnuplot_sh(fp, "set grid\n");
- if (gp[0]->autoscale_toggle)
- gnuplot_sh(fp, "set autoscale\n");
- if (gp[0]->legend_toggle) {
- gnuplot_sh(fp, "set key nobox\n");
- //gnuplot_sh(fp, "set key bmargin\n");
- gnuplot_sh(fp, "set key font ',5'\n");
- gnuplot_sh(fp, "set key outside\n");
- }
- if (gp[0]->legend_enhanced) {
- gnuplot_sh(fp, "set key enhanced\n");
- } else {
- gnuplot_sh(fp, "set key noenhanced\n");
- }
-
- // Begin plotting
- gnuplot_sh(fp, "plot ");
- for (size_t i = 0; i < y_count; i++) {
- char pltbuf[1024] = {0};
- sprintf(pltbuf, "'-' ");
- if (gp[0]->legend_toggle) {
- sprintf(pltbuf + strlen(pltbuf), "title '%s' ", gp[i]->legend_title);
- sprintf(pltbuf + strlen(pltbuf), "with lines ");
- if (gp[i]->line_width) {
- sprintf(pltbuf + strlen(pltbuf), "lw %0.1f ", gp[i]->line_width);
- }
- if (gp[i]->line_type) {
- sprintf(pltbuf + strlen(pltbuf), "lt %s ", gp[i]->line_type);
- }
- if (gp[i]->line_color) {
- sprintf(pltbuf + strlen(pltbuf), "lc rgb '#%06x' ", gp[i]->line_color);
- }
- gnuplot_sh(fp, "%s ", pltbuf);
- } else {
- gnuplot_sh(fp, "with lines ");
- }
- if (i < y_count - 1) {
- gnuplot_sh(fp, ", ");
- }
- }
- gnuplot_sh(fp, "\n");
-
- // Emit MSTAT data
- for (size_t arr = 0; arr < y_count; arr++) {
- for (size_t i = 0; i < x_count; i++) {
- gnuplot_sh(fp, "%lf %lf\n", x[i], y[arr][i]);
- }
- // Commit plot and execute
- gnuplot_sh(fp, "e\n");
- }
- fflush(fp);
-}
-
-unsigned int rgb(unsigned char r, unsigned char g, unsigned char b) {
- unsigned int result = r;
- result = result << 8 | g;
- result = result << 8 | b;
- return result;
-}
-
-
static void show_fields(char **fields) {
size_t total;
for (total = 0; fields[total] != NULL; total++);
@@ -174,7 +41,7 @@ static void usage(char *prog) {
"", name);
}
-void parse_options(int argc, char *argv[]) {
+static void parse_options(int argc, char *argv[]) {
if (argc < 2) {
usage(argv[0]);
exit(1);
@@ -187,7 +54,7 @@ void parse_options(int argc, char *argv[]) {
for (int x = 0, i = 1; i < argc; i++) {
char *arg = argv[i];
- if (strlen(argv[i]) > 1 && !strncmp(argv[i], "-", 1)) {
+ if (strlen(arg) > 1 && !strncmp(arg, "-", 1)) {
arg = argv[i] + 1;
if (!strcmp(arg, "h")) {
usage(argv[0]);
@@ -201,6 +68,7 @@ void parse_options(int argc, char *argv[]) {
option.verbose = 1;
}
if (!strcmp(arg, "f")) {
+ mstat_check_argument_str(argv, arg, i);
char *val = argv[i+1];
char *token = NULL;
if (!val) {
@@ -230,7 +98,7 @@ int main(int argc, char *argv[]) {
struct mstat_record_t p;
char **stored_fields;
char **field;
- int data_total;
+ size_t data_total;
double **axis_y;
double *axis_x;
double mem_min, mem_max;
@@ -242,7 +110,6 @@ int main(int argc, char *argv[]) {
parse_options(argc, argv);
rec = 0;
- data_total = 0;
mem_min = 0.0;
mem_max = 0.0;
field = option.fields;
@@ -298,13 +165,13 @@ int main(int argc, char *argv[]) {
}
mstat_rewind(fp);
- printf("Reading: %s\n", argv[1]);
+ printf("Reading: %s\n", option.filename);
// Assign requested MSTAT data to y-axis. x-axis will always be time elapsed.
rec = 0;
while (!mstat_iter(fp, &p)) {
axis_x[rec] = mstat_get_field_by_name(&p, "timestamp").d64 / 3600;
- for (int i = 0; i < data_total; i++) {
+ for (size_t i = 0; i < data_total; i++) {
axis_y[i][rec] = (double) mstat_get_field_by_name(&p, field[i]).u64 / 1024;
}
rec++;
@@ -328,7 +195,7 @@ int main(int argc, char *argv[]) {
exit(1);
}
- struct GNUPLOT_PLOT **gp = calloc(data_total, sizeof(**gp));
+ struct GNUPLOT_PLOT **gp = calloc(data_total + 1, sizeof(*gp[0]));
if (!gp) {
perror("Unable to allocate memory for gnuplot configuration array");
exit(1);
@@ -342,27 +209,22 @@ int main(int argc, char *argv[]) {
}
}
- unsigned char r, g, b;
char title[255] = {0};
- r = 0x10;
- g = 0x20;
- b = 0x30;
snprintf(title, sizeof(title) - 1, "Memory Usage (PID %d)", p.pid);
gp[0]->xlabel = strdup("Time (HR)");
gp[0]->ylabel = strdup("MB");
gp[0]->title = strdup(title);
gp[0]->grid_toggle = 1;
+ gp[0]->grid_mytics = 5;
+ gp[0]->grid_mxtics = 5;
gp[0]->autoscale_toggle = 1;
gp[0]->legend_toggle = 1;
for (size_t i = 0; i < data_total; i++) {
gp[i]->legend_title = strdup(field[i]);
- gp[i]->line_color = rgb(r, g, b);
- gp[i]->line_width = 0.50;
- r -= 0x30;
- b += 0x20;
- g *= 3;
+ gp[i]->line_width = 1.0;
+ gp[i]->line_color = 0;
}
printf("Generating plot... ");
@@ -375,6 +237,7 @@ int main(int argc, char *argv[]) {
exit(1);
}
gnuplot_plot(plt, gp, axis_x, axis_y, rec, data_total);
+ gnuplot_wait(plt);
gnuplot_close(plt);
printf("done!\n");
@@ -383,6 +246,7 @@ int main(int argc, char *argv[]) {
free(axis_y[i]);
free(gp[i]);
}
-
+ free(axis_y);
+ free(gp);
return 0;
}