Imported Upstream version 20091031
[ltp-debian.git] / testcases / realtime / lib / libstats.c
blob3144643bc958d93166f5b4de6b6a9470903b42c0
1 /******************************************************************************
3 * Copyright © International Business Machines Corp., 2006, 2008
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * NAME
20 * libstats.c
22 * DESCRIPTION
23 * Some basic statistical analysis convenience tools.
26 * USAGE:
27 * To be included in test cases
29 * AUTHOR
30 * Darren Hart <dvhltc@us.ibm.com>
32 * HISTORY
33 * 2006-Oct-17: Initial version by Darren Hart
34 * 2009-Jul-22: Addition of stats_container_append function by Kiran Prakash
36 * TODO: the save routine for gnuplot plotting should be more modular...
38 *****************************************************************************/
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>
49 int save_stats = 0;
51 /* static helper functions */
52 static int stats_record_compare(const void * a, const void * b) {
53 int ret = 0;
54 stats_record_t * rec_a = (stats_record_t *)a;
55 stats_record_t * rec_b = (stats_record_t *)b;
56 if (rec_a->y < rec_b->y)
57 ret = -1;
58 else if (rec_a->y > rec_b->y)
59 ret = 1;
60 return ret;
63 /* function implementations */
64 int stats_container_init(stats_container_t *data, long size)
66 data->size = size;
67 data->index = -1;
68 data->records = calloc(size, sizeof(stats_record_t));
69 if (!data->records)
70 return -1;
71 return 0;
74 int stats_container_append(stats_container_t *data, stats_record_t rec)
76 int myindex = ++data->index;
77 if (myindex >= data->size) {
78 debug(DBG_ERR, "Number of elements cannot be more than %ld\n",
79 data->size);
80 data->index--;
81 return -1;
83 data->records[myindex] = rec;
84 return myindex;
87 int stats_container_resize(stats_container_t *data, long size)
89 stats_record_t *newrecords = realloc(data->records, size*sizeof(stats_record_t));
90 if (!newrecords)
91 return -1;
92 data->records = newrecords;
93 if (data->size < size)
94 memset(data->records + data->size, 0, size - data->size);
95 data->size = size;
96 return 0;
99 int stats_container_free(stats_container_t *data)
101 free(data->records);
102 return 0;
105 int stats_sort(stats_container_t *data, enum stats_sort_method method)
107 // method not implemented, always ascending on y atm
108 qsort(data->records, data->index + 1, sizeof(stats_record_t),
109 stats_record_compare);
110 return 0;
113 float stats_stddev(stats_container_t *data)
115 long i;
116 float sd, avg, sum, delta;
117 long n;
119 sd = 0.0;
120 n = data->index + 1;
121 sum = 0.0;
123 /* calculate the mean */
124 for (i = 0; i < n; i++) {
125 sum += data->records[i].y;
127 avg = sum / (float)n;
129 /* calculate the standard deviation */
130 sum = 0.0;
131 for (i = 0; i < n; i++) {
132 delta = (data->records[i].y - avg);
133 sum += delta*delta;
135 sum /= n;
137 sd = sqrt(sum);
139 return sd;
142 float stats_avg(stats_container_t *data)
144 long i;
145 float avg, sum;
146 long n;
148 n = data->index + 1;
149 sum = 0.0;
151 /* calculate the mean */
152 for (i = 0; i < n; i++) {
153 sum += data->records[i].y;
155 avg = sum / (float)n;
157 return avg;
160 long stats_min(stats_container_t *data)
162 long i;
163 long min;
164 long n;
166 n = data->index + 1;
168 /* calculate the mean */
169 min = data->records[0].y;
170 for (i = 1; i < n; i++) {
171 if (data->records[i].y < min) {
172 min = data->records[i].y;
176 return min;
179 long stats_max(stats_container_t *data)
181 long i;
182 long max;
183 long n;
185 n = data->index + 1;
187 /* calculate the mean */
188 max = data->records[0].y;
189 for (i = 1; i < n; i++) {
190 if (data->records[i].y > max) {
191 max = data->records[i].y;
195 return max;
198 int stats_quantiles_init(stats_quantiles_t *quantiles, int nines)
200 if (nines < 2) {
201 return -1;
203 quantiles->nines = nines;
204 // allocate space for quantiles, starting with 0.99 (two nines)
205 quantiles->quantiles = malloc(sizeof(long) * (nines-1));
206 if (!quantiles->quantiles) {
207 return -1;
209 memset(quantiles->quantiles, 0, (nines-1) * sizeof(long));
210 return 0;
213 int stats_quantiles_free(stats_quantiles_t *quantiles)
215 free(quantiles->quantiles);
216 return 0;
219 int stats_quantiles_calc(stats_container_t *data, stats_quantiles_t *quantiles)
221 int i;
222 int size;
223 int index;
225 // check for sufficient data size of accurate calculation
226 if (data->index < 0 || (data->index + 1) \
227 < (long)exp10(quantiles->nines)) {
228 //printf("ERROR: insufficient data size for %d nines\n", data->size);
229 return -1;
232 size = data->index + 1;
233 stats_sort(data, ASCENDING_ON_Y);
235 for (i = 2; i <= quantiles->nines; i++) {
236 index = size - size / exp10(i);
237 quantiles->quantiles[i-2] = data->records[index].y;
239 return 0;
242 void stats_quantiles_print(stats_quantiles_t *quantiles)
244 int i;
245 int fraction = 0;
246 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]);
254 int stats_hist(stats_container_t *hist, stats_container_t *data)
256 int i;
257 int ret;
258 long min, max, width;
259 long y, b;
261 ret = 0;
263 if (hist->size <= 0 || data->index < 0) {
264 return -1;
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) max = y;
272 if (y < min) min = y;
274 //printf("min = %d\n", min);
275 //printf("max = %d\n", max);
277 /* define the bucket ranges */
278 width = MAX((max-min)/hist->size, 1);
279 //printf("width = %d\n", width);
280 hist->records[0].x = min;
281 //printf("hist[0].x = %d\n", min);
282 for (i = 1; i < (hist->size); i++) {
283 hist->records[i].x = min + i*width;
284 //printf("hist[%d].x = %d\n", i, hist->records[i].x);
287 /* fill in the counts */
288 for (i = 0; i <= data->index; i++) {
289 y = data->records[i].y;
290 b = MIN((y-min)/width, hist->size-1);
291 //printf("%d will go in bucket %d\n", y, b);
292 hist->records[b].y++;
295 return 0;
298 void stats_hist_print(stats_container_t *hist)
300 long i, x;
301 for (i = 0; i < hist->size; i++) {
302 x = hist->records[i].x;
303 if (i < hist->size-1)
304 printf("[%ld,%ld) = %ld\n", x,
305 hist->records[i+1].x, hist->records[i].y);
306 else
307 printf("[%ld,-) = %ld\n", x, hist->records[i].y);
311 int stats_container_save(char *filename, char *title, char *xlabel, char *ylabel, stats_container_t *data, char *mode)
313 int i;
314 int minx = 0, maxx = 0, miny = 0, maxy = 0;
315 FILE *dat_fd;
316 FILE *plt_fd;
317 char *datfile;
318 char *pltfile;
319 stats_record_t *rec;
321 if (!save_stats)
322 return 0;
324 /* generate the filenames */
325 if (asprintf(&datfile, "%s.dat", filename) == -1) {
326 fprintf(stderr, "Failed to allocate string for data filename\n");
327 return -1;
329 if (asprintf(&pltfile, "%s.plt", filename) == -1) {
330 fprintf(stderr, "Failed to allocate string for plot filename\n");
331 return -1;
334 /* generate the data file */
335 if (!(dat_fd = fopen(datfile, "w"))) {
336 perror("Failed to open dat file");
337 return -1;
338 } else {
339 minx = maxx = data->records[0].x;
340 miny = maxy = data->records[0].y;
341 for (i = 0; i <= data->index; i++) {
342 rec = &data->records[i];
343 minx = MIN(minx, rec->x);
344 maxx = MAX(maxx, rec->x);
345 miny = MIN(miny, rec->y);
346 maxy = MAX(maxy, rec->y);
347 fprintf(dat_fd, "%ld %ld\n", rec->x, rec->y);
349 fclose(dat_fd);
352 /* generate the plt file */
353 if (!(plt_fd = fopen(pltfile, "w"))) {
354 perror("Failed to open plt file");
355 return -1;
356 } else {
357 fprintf(plt_fd, "set terminal png\n");
358 fprintf(plt_fd, "set output \"%s.png\"\n", pltfile);
359 fprintf(plt_fd, "set title \"%s\"\n", title);
360 fprintf(plt_fd, "set xlabel \"%s\"\n", xlabel);
361 fprintf(plt_fd, "set ylabel \"%s\"\n", ylabel);
363 // exact range mode
364 //fprintf(plt_fd, "plot [%d:%d] [%d:%d] \"%s\" with %s\n",
365 // minx, maxx, miny, maxy, datfile, mode);
367 // expanded range mode - slightly more intuitive I think...
368 fprintf(plt_fd, "plot [0:%d] [0:%d] \"%s\" with %s\n",
369 maxx+1, maxy+1, datfile, mode);
370 fclose(plt_fd);
373 return 0;