• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *   Copyright © International Business Machines  Corp., 2006, 2008
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  * NAME
20  *	   libstats.c
21  *
22  * DESCRIPTION
23  *	  Some basic statistical analysis convenience tools.
24  *
25  *
26  * USAGE:
27  *	  To be included in test cases
28  *
29  * AUTHOR
30  *		Darren Hart <dvhltc@us.ibm.com>
31  *
32  * HISTORY
33  *	  2006-Oct-17: Initial version by Darren Hart
34  *	  2009-Jul-22: Addition of stats_container_append function by Kiran Prakash
35  *
36  * TODO: the save routine for gnuplot plotting should be more modular...
37  *
38  *****************************************************************************/
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <unistd.h>
45 #include <math.h>
46 #include "libstats.h"
47 #include "librttest.h"
48 
49 int save_stats = 0;
50 
51 /* static helper functions */
stats_record_compare(const void * a,const void * b)52 static int stats_record_compare(const void *a, const void *b)
53 {
54 	int ret = 0;
55 	stats_record_t *rec_a = (stats_record_t *) a;
56 	stats_record_t *rec_b = (stats_record_t *) b;
57 	if (rec_a->y < rec_b->y)
58 		ret = -1;
59 	else if (rec_a->y > rec_b->y)
60 		ret = 1;
61 	return ret;
62 }
63 
64 /* function implementations */
stats_container_init(stats_container_t * data,long size)65 int stats_container_init(stats_container_t * data, long size)
66 {
67 	data->size = size;
68 	data->index = -1;
69 	data->records = calloc(size, sizeof(stats_record_t));
70 	if (!data->records)
71 		return -1;
72 	return 0;
73 }
74 
stats_container_append(stats_container_t * data,stats_record_t rec)75 int stats_container_append(stats_container_t * data, stats_record_t rec)
76 {
77 	int myindex = ++data->index;
78 	if (myindex >= data->size) {
79 		debug(DBG_ERR, "Number of elements cannot be more than %ld\n",
80 		      data->size);
81 		data->index--;
82 		return -1;
83 	}
84 	data->records[myindex] = rec;
85 	return myindex;
86 }
87 
stats_container_resize(stats_container_t * data,long size)88 int stats_container_resize(stats_container_t * data, long size)
89 {
90 	stats_record_t *newrecords =
91 	    realloc(data->records, size * sizeof(stats_record_t));
92 	if (!newrecords)
93 		return -1;
94 	data->records = newrecords;
95 	if (data->size < size)
96 		memset(data->records + data->size, 0, size - data->size);
97 	data->size = size;
98 	return 0;
99 }
100 
stats_container_free(stats_container_t * data)101 int stats_container_free(stats_container_t * data)
102 {
103 	free(data->records);
104 	return 0;
105 }
106 
stats_sort(stats_container_t * data,enum stats_sort_method method)107 int stats_sort(stats_container_t * data, enum stats_sort_method method)
108 {
109 	/* method not implemented, always ascending on y atm */
110 	qsort(data->records, data->index + 1, sizeof(stats_record_t),
111 	      stats_record_compare);
112 	return 0;
113 }
114 
stats_stddev(stats_container_t * data)115 float stats_stddev(stats_container_t * data)
116 {
117 	long i;
118 	float sd, avg, sum, delta;
119 	long n;
120 
121 	sd = 0.0;
122 	n = data->index + 1;
123 	sum = 0.0;
124 
125 	/* calculate the mean */
126 	for (i = 0; i < n; i++) {
127 		sum += data->records[i].y;
128 	}
129 	avg = sum / (float)n;
130 
131 	/* calculate the standard deviation */
132 	sum = 0.0;
133 	for (i = 0; i < n; i++) {
134 		delta = (data->records[i].y - avg);
135 		sum += delta * delta;
136 	}
137 	sum /= n;
138 
139 	sd = sqrt(sum);
140 
141 	return sd;
142 }
143 
stats_avg(stats_container_t * data)144 float stats_avg(stats_container_t * data)
145 {
146 	long i;
147 	float avg, sum;
148 	long n;
149 
150 	n = data->index + 1;
151 	sum = 0.0;
152 
153 	/* calculate the mean */
154 	for (i = 0; i < n; i++) {
155 		sum += data->records[i].y;
156 	}
157 	avg = sum / (float)n;
158 
159 	return avg;
160 }
161 
stats_min(stats_container_t * data)162 long stats_min(stats_container_t * data)
163 {
164 	long i;
165 	long min;
166 	long n;
167 
168 	n = data->index + 1;
169 
170 	/* calculate the mean */
171 	min = data->records[0].y;
172 	for (i = 1; i < n; i++) {
173 		if (data->records[i].y < min) {
174 			min = data->records[i].y;
175 		}
176 	}
177 
178 	return min;
179 }
180 
stats_max(stats_container_t * data)181 long stats_max(stats_container_t * data)
182 {
183 	long i;
184 	long max;
185 	long n;
186 
187 	n = data->index + 1;
188 
189 	/* calculate the mean */
190 	max = data->records[0].y;
191 	for (i = 1; i < n; i++) {
192 		if (data->records[i].y > max) {
193 			max = data->records[i].y;
194 		}
195 	}
196 
197 	return max;
198 }
199 
stats_quantiles_init(stats_quantiles_t * quantiles,int nines)200 int stats_quantiles_init(stats_quantiles_t * quantiles, int nines)
201 {
202 	if (nines < 2) {
203 		return -1;
204 	}
205 	quantiles->nines = nines;
206 	/* allocate space for quantiles, starting with 0.99 (two nines) */
207 	quantiles->quantiles = calloc(sizeof(long), (nines - 1));
208 	if (!quantiles->quantiles) {
209 		return -1;
210 	}
211 	return 0;
212 }
213 
stats_quantiles_free(stats_quantiles_t * quantiles)214 int stats_quantiles_free(stats_quantiles_t * quantiles)
215 {
216 	free(quantiles->quantiles);
217 	return 0;
218 }
219 
stats_quantiles_calc(stats_container_t * data,stats_quantiles_t * quantiles)220 int stats_quantiles_calc(stats_container_t * data,
221 			 stats_quantiles_t * quantiles)
222 {
223 	int i;
224 	int size;
225 	int index;
226 
227 	// check for sufficient data size of accurate calculation
228 	if (data->index < 0 ||
229 	    (data->index + 1) < (long)exp10(quantiles->nines)) {
230 		return -1;
231 	}
232 
233 	size = data->index + 1;
234 	stats_sort(data, ASCENDING_ON_Y);
235 
236 	for (i = 2; i <= quantiles->nines; i++) {
237 		index = size - size / exp10(i);
238 		quantiles->quantiles[i - 2] = data->records[index].y;
239 	}
240 	return 0;
241 }
242 
stats_quantiles_print(stats_quantiles_t * quantiles)243 void stats_quantiles_print(stats_quantiles_t * quantiles)
244 {
245 	int i;
246 	int fraction = 0;
247 	for (i = 0; i <= quantiles->nines - 2; i++) {
248 		if (i > 0)
249 			fraction += 9 * exp10(i - 1);
250 		printf("99.%d%% < %ld\n", fraction, quantiles->quantiles[i]);
251 	}
252 }
253 
stats_hist(stats_container_t * hist,stats_container_t * data)254 int stats_hist(stats_container_t * hist, stats_container_t * data)
255 {
256 	int i;
257 	int ret;
258 	long min, max, width;
259 	long y, b;
260 
261 	ret = 0;
262 
263 	if (hist->size <= 0 || data->index < 0) {
264 		return -1;
265 	}
266 
267 	/* calculate the range of dataset */
268 	min = max = data->records[0].y;
269 	for (i = 0; i <= data->index; i++) {
270 		y = data->records[i].y;
271 		if (y > max)
272 			max = y;
273 		if (y < min)
274 			min = y;
275 	}
276 
277 	/* define the bucket ranges */
278 	width = MAX((max - min) / hist->size, 1);
279 	hist->records[0].x = min;
280 	for (i = 1; i < (hist->size); i++) {
281 		hist->records[i].x = min + i * width;
282 	}
283 
284 	/* fill in the counts */
285 	for (i = 0; i <= data->index; i++) {
286 		y = data->records[i].y;
287 		b = MIN((y - min) / width, hist->size - 1);
288 		hist->records[b].y++;
289 	}
290 
291 	return 0;
292 }
293 
stats_hist_print(stats_container_t * hist)294 void stats_hist_print(stats_container_t * hist)
295 {
296 	long i, x;
297 	for (i = 0; i < hist->size; i++) {
298 		x = hist->records[i].x;
299 		if (i < hist->size - 1)
300 			printf("[%ld,%ld) = %ld\n", x,
301 			       hist->records[i + 1].x, hist->records[i].y);
302 		else
303 			printf("[%ld,-) = %ld\n", x, hist->records[i].y);
304 	}
305 }
306 
stats_container_save(char * filename,char * title,char * xlabel,char * ylabel,stats_container_t * data,char * mode)307 int stats_container_save(char *filename, char *title, char *xlabel,
308 			 char *ylabel, stats_container_t * data, char *mode)
309 {
310 	int i;
311 	int minx = 0, maxx = 0, miny = 0, maxy = 0;
312 	FILE *dat_fd;
313 	FILE *plt_fd;
314 	char *datfile;
315 	char *pltfile;
316 	stats_record_t *rec;
317 
318 	if (!save_stats)
319 		return 0;
320 
321 	/* generate the filenames */
322 	if (asprintf(&datfile, "%s.dat", filename) == -1) {
323 		fprintf(stderr,
324 			"Failed to allocate string for data filename\n");
325 		return -1;
326 	}
327 	if (asprintf(&pltfile, "%s.plt", filename) == -1) {
328 		fprintf(stderr,
329 			"Failed to allocate string for plot filename\n");
330 		return -1;
331 	}
332 
333 	/* generate the data file */
334 	if ((dat_fd = fopen(datfile, "w")) == NULL) {
335 		perror("Failed to open dat file");
336 		return -1;
337 	} else {
338 		minx = maxx = data->records[0].x;
339 		miny = maxy = data->records[0].y;
340 		for (i = 0; i <= data->index; i++) {
341 			rec = &data->records[i];
342 			minx = MIN(minx, rec->x);
343 			maxx = MAX(maxx, rec->x);
344 			miny = MIN(miny, rec->y);
345 			maxy = MAX(maxy, rec->y);
346 			fprintf(dat_fd, "%ld %ld\n", rec->x, rec->y);
347 		}
348 		fclose(dat_fd);
349 	}
350 
351 	/* generate the plt file */
352 	if (!(plt_fd = fopen(pltfile, "w"))) {
353 		perror("Failed to open plt file");
354 		return -1;
355 	} else {
356 		fprintf(plt_fd, "set terminal png\n");
357 		fprintf(plt_fd, "set output \"%s.png\"\n", pltfile);
358 		fprintf(plt_fd, "set title \"%s\"\n", title);
359 		fprintf(plt_fd, "set xlabel \"%s\"\n", xlabel);
360 		fprintf(plt_fd, "set ylabel \"%s\"\n", ylabel);
361 		fprintf(plt_fd, "plot [0:%d] [0:%d] \"%s\" with %s\n",
362 			maxx + 1, maxy + 1, datfile, mode);
363 		fclose(plt_fd);
364 	}
365 
366 	return 0;
367 }
368