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