crunchgen(1): Add "linkopts" to specify linker options
[dragonfly.git] / usr.bin / kcollect / gnuplot.c
1 /*
2  * Copyright (c) 2017 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include "kcollect.h"
33
34 void
35 start_gnuplot(int ac __unused, char **av __unused, const char *plotfile)
36 {
37         OutFP = popen("gnuplot", "w");
38         if (OutFP == NULL) {
39                 fprintf(stderr, "can't find gnuplot\n");
40                 exit(1);
41         }
42
43         /*
44          * If plotfile is specified allow .jpg or .JPG or .png or .PNG
45          */
46         if (plotfile) {
47                 const char *ext;
48
49                 if ((ext = strrchr(plotfile, '.')) == NULL) {
50                         ext = "";
51                 } else {
52                         ++ext;
53                 }
54                 if (strcmp(ext, "jpg") == 0 ||
55                     strcmp(ext, "JPG") == 0) {
56                         fprintf(OutFP, "set terminal jpeg size %d,%d\n",
57                                 OutputWidth, OutputHeight);
58                 } else if (strcmp(ext, "png") == 0 ||
59                            strcmp(ext, "PNG") == 0) {
60                         fprintf(OutFP, "set terminal png size %d,%d\n",
61                                 OutputWidth, OutputHeight);
62                 } else {
63                         fprintf(stderr, "plotfile must be .jpg or .png\n");
64                         exit(1);
65                 }
66                 fprintf(OutFP, "set output \"%s\"\n", plotfile);
67         } else {
68                 fprintf(OutFP, "set terminal x11 persist size %d,%d\n",
69                         OutputWidth, OutputHeight);
70         }
71 }
72
73 void
74 dump_gnuplot(kcollect_t *ary, size_t count)
75 {
76         int plot1[] = { KCOLLECT_MEMFRE, KCOLLECT_MEMCAC,
77                         KCOLLECT_MEMINA, KCOLLECT_MEMACT,
78                         KCOLLECT_MEMWIR, KCOLLECT_LOAD };
79         int plot2[] = { KCOLLECT_IDLEPCT, KCOLLECT_INTRPCT,
80                         KCOLLECT_SYSTPCT, KCOLLECT_USERPCT,
81                         KCOLLECT_SWAPPCT,
82                         KCOLLECT_VMFAULT, KCOLLECT_SYSCALLS, KCOLLECT_NLOOKUP };
83         const char *id1[] = {
84                         "free", "cache",
85                         "inact", "active",
86                         "wired", "load" };
87         const char *id2[] = {
88                         "idle", "intr", "system", "user",
89                         "swap",
90                         "faults", "syscalls", "nlookups" };
91         struct tm *tmv;
92         char buf[64];
93         uint64_t value;
94         time_t t;
95         double dv;
96         double smoothed_dv;
97         int i;
98         int j;
99         int jj;
100         int k;
101
102         /*
103          * NOTE: be sure to reset any fields adjusted by the second plot,
104          *       in case we are streaming plots with -f.
105          */
106         fprintf(OutFP, "set xdata time\n");
107         fprintf(OutFP, "set timefmt \"%%d-%%b-%%Y %%H:%%M:%%S\"\n");
108         fprintf(OutFP, "set style fill solid 1.0\n");
109         fprintf(OutFP, "set multiplot layout 2,1\n");
110         fprintf(OutFP, "set key outside\n");
111         fprintf(OutFP, "set lmargin 10\n");
112         fprintf(OutFP, "set rmargin 25\n");
113         fprintf(OutFP, "set xtics rotate\n");
114         fprintf(OutFP, "set format x '%%H:%%M'\n");
115
116         fprintf(OutFP, "set ylabel \"GB\"\n");
117
118         fprintf(OutFP, "set yrange [0:%d]\n",
119                 (int)((KCOLLECT_GETSCALE(ary[0].data[KCOLLECT_MEMFRE]) +
120                        999999) / 1000000000));
121         fprintf(OutFP, "set autoscale y2\n");
122         fprintf(OutFP, "set y2label \"Load\"\n");
123         fprintf(OutFP, "set ytics nomirror\n");
124         fprintf(OutFP, "set y2tics nomirror\n");
125
126         fprintf(OutFP,
127                 "plot "
128                 "\"-\" using 1:3 title \"%s\" with boxes lw 1, "
129                 "\"-\" using 1:3 title \"%s\" with boxes lw 1, "
130                 "\"-\" using 1:3 title \"%s\" with boxes lw 1, "
131                 "\"-\" using 1:3 title \"%s\" with boxes lw 1, "
132                 "\"-\" using 1:3 title \"%s\" with boxes lw 1, "
133                 "\"-\" using 1:3 axes x1y2 title \"%s\" with lines lw 1\n",
134                 id1[0], id1[1], id1[2], id1[3], id1[4], id1[5]);
135
136         for (jj = 0; jj < (int)(sizeof(plot1) / sizeof(plot1[0])); ++jj) {
137                 j = plot1[jj];
138
139                 smoothed_dv = 0.0;
140                 for (i = count - 1; i >= 2; --i) {
141                         /*
142                          * Timestamp
143                          */
144                         t = ary[i].realtime.tv_sec;
145                         if (t < 1000)
146                                 continue;
147                         if (UseGMT)
148                                 tmv = gmtime(&t);
149                         else
150                                 tmv = localtime(&t);
151                         strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", tmv);
152                         value = ary[i].data[j];
153                         if (jj <= 4) {
154                                 for (k = jj + 1; k <= 4; ++k)
155                                         value += ary[i].data[plot1[k]];
156                                 dv = (double)value / 1e9;
157                         } else {
158                                 dv = (double)value / 100.0;
159                         }
160                         if (SmoothOpt) {
161                                 if (i == (int)(count - 1)) {
162                                         smoothed_dv = dv;
163                                 } else if (smoothed_dv < dv) {
164                                         smoothed_dv =
165                                          (smoothed_dv * 5.0 + 5 * dv) /
166                                          10.0;
167                                 } else {
168                                         smoothed_dv =
169                                          (smoothed_dv * 9.0 + 1 * dv) /
170                                          10.0;
171                                 }
172                                 dv = smoothed_dv;
173                         }
174                         fprintf(OutFP, "%s %6.2f\n", buf, dv);
175                 }
176                 fprintf(OutFP, "e\n");
177         }
178
179         fprintf(OutFP, "set ylabel \"Cpu Utilization\"\n");
180         fprintf(OutFP, "set y2label \"MOps/sec (smoothed)\"\n");
181         fprintf(OutFP, "set ytics nomirror\n");
182         fprintf(OutFP, "set y2tics nomirror\n");
183         fprintf(OutFP, "set yrange [0:105]\n");
184         fprintf(OutFP, "set y2range [0:1.0]\n");
185
186         fprintf(OutFP,
187                 "plot "
188                 "\"-\" using 1:3 title \"%s\" with boxes lw 1, "
189                 "\"-\" using 1:3 title \"%s\" with boxes lw 1, "
190                 "\"-\" using 1:3 title \"%s\" with boxes lw 1, "
191                 "\"-\" using 1:3 title \"%s\" with boxes lw 1, "
192                 "\"-\" using 1:3 title \"%s\" with lines lw 1, "
193                 "\"-\" using 1:3 axes x1y2 title \"%s\" with lines lw 1, "
194                 "\"-\" using 1:3 axes x1y2 title \"%s\" with lines lw 1, "
195                 "\"-\" using 1:3 axes x1y2 title \"%s\" with lines lw 1\n",
196                 id2[0], id2[1], id2[2], id2[3], id2[4], id2[5], id2[6], id2[7]);
197
198         for (jj = 0; jj < (int)(sizeof(plot2) / sizeof(plot2[0])); ++jj) {
199                 j = plot2[jj];
200
201                 smoothed_dv = 0.0;
202                 for (i = count - 1; i >= 2; --i) {
203                         /*
204                          * Timestamp
205                          */
206                         t = ary[i].realtime.tv_sec;
207                         if (t < 1000)
208                                 continue;
209                         if (UseGMT)
210                                 tmv = gmtime(&t);
211                         else
212                                 tmv = localtime(&t);
213                         strftime(buf, sizeof(buf), "%d-%b-%Y %H:%M:%S", tmv);
214                         value = ary[i].data[j];
215
216                         if (jj <= 3) {
217                                 /*
218                                  * intr/sys/user/idle percentages
219                                  */
220                                 for (k = jj + 1; k <= 3; ++k)
221                                         value += ary[i].data[plot2[k]];
222                                 dv = (double)value / 100.0;
223                                 if (SmoothOpt) {
224                                         if (i == (int)(count - 1)) {
225                                                 smoothed_dv = dv;
226                                         } else if (smoothed_dv < dv) {
227                                                 smoothed_dv =
228                                                  (smoothed_dv * 5.0 + 5 * dv) /
229                                                  10.0;
230                                         } else {
231                                                 smoothed_dv =
232                                                  (smoothed_dv * 9.0 + 1 * dv) /
233                                                  10.0;
234                                         }
235                                         dv = smoothed_dv;
236                                 }
237                         } else {
238                                 if (jj >= 5) {
239                                         /* fault counters */
240                                         dv = (double)value / KCOLLECT_INTERVAL;
241                                         dv = dv / 1e6;
242                                 } else {
243                                         /* swap percentage (line graph) */
244                                         dv = (double)value / 100.0;
245                                 }
246                                 if (i == (int)(count - 1)) {
247                                         smoothed_dv = dv;
248                                 } else if (smoothed_dv < dv) {
249                                         smoothed_dv =
250                                          (smoothed_dv * 5.0 + 5 * dv) /
251                                          10.0;
252                                 } else {
253                                         smoothed_dv = (smoothed_dv * 9.0 + dv) /
254                                                       10.0;
255                                 }
256                                 dv = smoothed_dv;
257                         }
258                         fprintf(OutFP, "%s %6.2f\n", buf, dv);
259                 }
260                 fprintf(OutFP, "e\n");
261         }
262         fflush(OutFP);
263 }