Typo in debug output.
[exim.git] / src / exim_monitor / em_strip.c
1 /*************************************************
2 * Exim Monitor *
3 *************************************************/
4
5 /* Copyright (c) University of Cambridge 1995 - 2009 */
6 /* See the file NOTICE for conditions of use and distribution. */
7
8
9 #include "em_hdr.h"
10
11 /* This module contains functions for handling stripcharts */
12
13
14 /*************************************************
15 * Static variables *
16 *************************************************/
17
18 static int queue_first_time = 1; /* flag for resetting time */
19 static int size_first_time = 1; /* and another */
20
21 static int stripchart_count = 0; /* count stripcharts created */
22 static int *stripchart_delay; /* vector of delay counts */
23 static Widget *stripchart_label; /* vector of label widgets */
24 static int *stripchart_last_total; /* vector of prevous values */
25 static int *stripchart_max; /* vector of maxima */
26 static int *stripchart_middelay; /* vector of */
27 static int *stripchart_midmax; /* vector of */
28 static uschar **stripchart_name; /* vector of name strings */
29 static Widget stripchart_prev_chart = NULL; /* previously created chart */
30 static Widget stripchart_prev_label = NULL; /* previously created label */
31
32
33
34 /*************************************************
35 * Initialize *
36 *************************************************/
37
38 void stripchart_init(void)
39 {
40 stripchart_delay = (int *)store_malloc(stripchart_number * sizeof(int));
41 stripchart_label = (Widget *)store_malloc(stripchart_number * sizeof(Widget));
42 stripchart_last_total = (int *)store_malloc(stripchart_number * sizeof(int));
43 stripchart_max = (int *)store_malloc(stripchart_number * sizeof(int));
44 stripchart_middelay = (int *)store_malloc(stripchart_number * sizeof(int));
45 stripchart_midmax = (int *)store_malloc(stripchart_number * sizeof(int));
46 stripchart_name = (uschar **)store_malloc(stripchart_number * sizeof(uschar *));
47 stripchart_total = (int *)store_malloc(stripchart_number * sizeof(int));
48 }
49
50
51
52 /*************************************************
53 * Stripchart callback function *
54 *************************************************/
55
56 /* The client data is the index of the stripchart. We have to play
57 a little game in order to ensure that the double value is correctly
58 passed back via the value pointer without the compiler doing an
59 unwanted cast. */
60
61 static void stripchartAction(Widget w, XtPointer client_data, XtPointer value)
62 {
63 double *ptr = (double *)value;
64 static int thresholds[] =
65 {10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 0};
66 int num = (int)client_data;
67 int oldmax = 0;
68 int newmax = 0;
69 int newvalue = 0;
70 int i = 0;
71
72 /* For the queue stripchart, the value is the current vector value.
73 We reset the initial delay of 1 second to the normal value. */
74
75 if (num == 0)
76 {
77 newvalue = stripchart_total[0];
78 if (queue_first_time)
79 {
80 xs_SetValues(w, 1, "update", stripchart_update);
81 queue_first_time = 0;
82 }
83 }
84
85 /* For the size monitoring stripchart, the value is the percentage
86 fullness of the partition. A similar fudge to the above is implemented
87 for the first time. Not all OS have statvfs(); for those that don't this
88 code is omitted. In fact it should never be obeyed, as we don't allow
89 size_stripchart to get set in that case. For some OS the old function
90 and struct name statfs is used; that is handled by a macro. */
91
92 else if (size_stripchart != NULL && num == 1)
93 {
94 #ifdef HAVE_STATFS
95 struct statvfs statbuf;
96 if (statvfs(CS size_stripchart, &statbuf) == 0)
97 {
98 int used = statbuf.f_blocks - statbuf.f_bfree;
99 int max = used + statbuf.f_bavail;
100 double fraction = ((double)used) / ((double)max);
101 newvalue = (int)((fraction + 0.005) * 100.0);
102 }
103 #endif
104 if (size_first_time)
105 {
106 xs_SetValues(w, 1, "update", stripchart_update);
107 size_first_time = 0;
108 }
109 }
110
111 /* For the configured stripcharts, the value to be set is
112 the difference from last time; save the current total for
113 next time. */
114
115 else
116 {
117 newvalue = stripchart_total[num] - stripchart_last_total[num];
118 stripchart_last_total[num] = stripchart_total[num];
119 }
120
121 /* Adjust the scale of the stripchart according to the value;
122 we delay enlarging the scale for a while after the values
123 reduce. Keep the maximum value while delaying, and reset
124 down to that. For the size stripchart, the threshold is always
125 forced to be at least 100. */
126
127 while (thresholds[i] > 0)
128 {
129 int thresh = (size_stripchart != NULL && num == 1)? 100 : thresholds[i++];
130 if (newvalue < (double)thresh)
131 {
132 /* If the current maximum is less than required, or if it is
133 greater and we have delayed long enough, adjust the scale. */
134
135 if (stripchart_max[num] < thresh ||
136 (stripchart_max[num] > thresh && stripchart_delay[num]++ > 20))
137 {
138 uschar buffer[128];
139 newmax = (thresh > stripchart_midmax[num])?
140 thresh : stripchart_midmax[num];
141 if (newmax == 10) sprintf(CS buffer, "%s", stripchart_name[num]);
142 else sprintf(CS buffer, "%s x%d", stripchart_name[num], newmax/10);
143 if (size_stripchart != NULL && num == 1) Ustrcat(buffer, "%");
144 xs_SetValues(stripchart_label[num], 1, "label", buffer);
145 oldmax = stripchart_max[num];
146 stripchart_max[num] = newmax;
147 stripchart_midmax[num] = 0;
148 stripchart_delay[num] -= stripchart_middelay[num];
149 }
150
151 /* Otherwise, if the current maximum is greater than required,
152 keep the highest value encountered during the delay, and its
153 position so we can adjust the delay when re-scaling. */
154
155 else if (stripchart_max[num] > thresh)
156 {
157 if (thresh > stripchart_midmax[num])
158 {
159 stripchart_midmax[num] = thresh;
160 stripchart_middelay[num] = stripchart_delay[num];
161 }
162 }
163
164 /* If the maximum is exactly what we need, reset the delay. */
165
166 if (stripchart_max[num] == thresh) stripchart_delay[num] = 0;
167 break;
168 }
169 }
170
171 /* The vanilla Athena stripchart widget does not support change of
172 scale - it just draws scale lines closer and closer together, which
173 doesn't work when the number gets very large. However, we can cause
174 it to change scale quite simply by recomputing all the values and
175 then calling its repaint routine. I had to nobble the repaint routine
176 too, to stop it changing scale to anything other than 10. There's
177 probably a better way to do this, like adding some new resource, but
178 I'm not a widget programmer and want to get on with the rest of
179 eximon... */
180
181 if (oldmax > 0)
182 {
183 int i;
184 StripChartWidget ww = (StripChartWidget)w;
185 ww->strip_chart.max_value = 0;
186 for (i = 0; i < (int)ww->strip_chart.interval; i++)
187 {
188 ww->strip_chart.valuedata[i] =
189 (ww->strip_chart.valuedata[i] * oldmax)/newmax;
190 if (ww->strip_chart.valuedata[i] > ww->strip_chart.max_value)
191 ww->strip_chart.max_value = ww->strip_chart.valuedata[i];
192 }
193 XClearWindow( XtDisplay(w), XtWindow(w));
194 ww->strip_chart.interval = repaint_window(ww, 0, (int)w->core.width);
195 }
196
197 /* Pass back the new value at the new scale */
198
199 *ptr = ((double)newvalue * 10.0)/(double)(stripchart_max[num]);
200 }
201
202
203
204 /*************************************************
205 * Create one stripchart *
206 *************************************************/
207
208 /* This function creates two widgets, one being the title and the other being
209 the stripchart. The client_data values for each stripchart are index into the
210 stripchart_values vector; each new stripchart just gets the next number. There
211 is a fudge for the very first stripchart, which is the queue length display,
212 and for the second if it is a partition size display; its update time is
213 initially set to 1 second so that it gives an immediate display of the queue.
214 The first time its callback function is obeyed, the update time gets reset. */
215
216 void create_stripchart(Widget parent, uschar *title)
217 {
218 Widget chart;
219
220 Widget label = XtCreateManagedWidget("label",
221 labelWidgetClass, parent, NULL, 0);
222
223 xs_SetValues(label, 10,
224 "label", title,
225 "width", stripchart_width + 2,
226 "borderWidth", 0,
227 "internalHeight", 0,
228 "internalWidth", 0,
229 "left", XawChainLeft,
230 "right", XawChainLeft,
231 "top", XawChainTop,
232 "bottom", XawChainTop,
233 XtNfromHoriz, stripchart_prev_label);
234
235 chart = XtCreateManagedWidget("stripchart",
236 mystripChartWidgetClass, parent, NULL, 0);
237
238 xs_SetValues(chart, 11,
239 "jumpScroll", 1,
240 "update", (stripchart_count < stripchart_varstart)? 1:stripchart_update,
241 "minScale", 10,
242 "width", stripchart_width,
243 "height", stripchart_height,
244 "left", XawChainLeft,
245 "right", XawChainLeft,
246 "top", XawChainTop,
247 "bottom", XawChainTop,
248 XtNfromHoriz, stripchart_prev_chart,
249 XtNfromVert, label);
250
251 XtAddCallback(chart, "getValue", stripchartAction,
252 (XtPointer)stripchart_count);
253
254 stripchart_last_total[stripchart_count] = 0;
255 stripchart_max[stripchart_count] = 10;
256 stripchart_midmax[stripchart_count] = 0;
257 stripchart_name[stripchart_count] = title;
258 stripchart_prev_label = stripchart_label[stripchart_count] = label;
259 stripchart_prev_chart = chart;
260 stripchart_total[stripchart_count] = 0;
261 stripchart_count++;
262 }
263
264 /* End of em_strip.c */