pmm  1.0.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
pmm_load.c
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008-2010 Robert Higgins
3  Author: Robert Higgins <robert.higgins@ucd.ie>
4 
5  This file is part of PMM.
6 
7  PMM is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  PMM is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with PMM. If not, see <http://www.gnu.org/licenses/>.
19 */
20 /*!
21  * @file pmm_load.c
22  * @brief Code for handling load structure
23  *
24  * Contains functions for dealing with the load data structures.
25  */
26 #if HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29 
30 #include <stdlib.h> // for malloc/free
31 #include <time.h> // for time_t
32 
33 #include "pmm_load.h"
34 #include "pmm_log.h"
35 
36 /*!
37  * Allocates and initialises memory for a new load history structure. This is
38  * a circular array arrangement with pointers to the beginning and end.
39  * Iteration over the array is done using the modulus operator to wrap the
40  * physically beginning and end addresses.
41  *
42  * note for a given size we must keep size+1 elements in the array. Thus we
43  * store two different sizes. 'size' refers to the number of accessible elements
44  * in the circular array. 'size_mod' refers to actual allocated elements in the
45  * array and is only to be used when iterating through the accessible elements
46  * using i+1%size_mod. 'size_mod' will always be the accessible size 'size' + 1
47  *
48  * @return pointer to a new loadhistory structure or NULL on failure
49  */
51 {
52  struct pmm_loadhistory *h;
53 
54  h = malloc(sizeof *h);
55  if(h == NULL) {
56  ERRPRINTF("Error allocating load history structure.\n");
57  return NULL;
58  }
59 
60  h->load_path = LOCALSTATEDIR"/loadhistory";
61 
62  h->write_period = 10;
63 
64  h->size = 0;
65  h->size_mod = 1;
66  h->history = NULL;
67 
68 
69  h->start = NULL;
70  h->end = NULL;
71 
72  h->start_i = -1;
73  h->end_i = -1;
74 
75  return h;
76 }
77 
78 /*!
79  * Function initialises the array and indexes that are used to store the load
80  * history (in a circular type array)
81  *
82  * @param h pointer to a load history structure
83  * @param size size of the circular array
84  *
85  * @return 0 on success, -1 on failure
86  *
87  * TODO check that history is not already allocated, free in this case first
88  */
89 int
91 {
92  h->size = size;
93  h->size_mod = size+1;
94 
95  h->history = malloc(h->size_mod * sizeof *(h->history));
96  if(h->history == NULL) {
97  ERRPRINTF("Error allocating load history memory.\n");
98  return -1;
99  }
100 
101  h->start = &h->history[0];
102  h->end = &h->history[0];
103 
104  h->start_i = 0;
105  h->end_i = 0;
106 
107  return 0;
108 }
109 
110 /*!
111  * This function _copies_ the structure l into the load history structure which
112  * is a circular array.
113  *
114  * @param h pointer to the load history structure
115  * @param l pointer to the load to be copied into the next free/expired
116  * element of the circular array
117  *
118  *
119  */
120 void add_load(struct pmm_loadhistory *h, struct pmm_load *l)
121 {
122 #ifdef ENABLE_DEBUG
123  print_load(PMM_DBG, l);
124  DBGPRINTF("h:%p\n", h);
125  DBGPRINTF("h->end_i: %d\n", h->end_i);
126 #endif
127 
128  // end_i always points to a vacant element
129  h->history[h->end_i].time = l->time;
130  h->history[h->end_i].load[0] = l->load[0];
131  h->history[h->end_i].load[1] = l->load[1];
132  h->history[h->end_i].load[2] = l->load[2];
133 
134  //TODO decide whether to use indexes or pointers
135 
136  /* Increment the end index and set it to zero if it reaches h->size_mod */
137  h->end_i = (h->end_i + 1) % h->size_mod;
138 
139  /* if end index and start index are the same rotate the start index by 1 */
140  if(h->end_i == h->start_i) {
141  h->start_i = (h->start_i + 1) % h->size_mod;
142  }
143 
144  /* obliterate the history element that end_i points to inorder to avoid
145  * confusion with the elements that are part of the rotating array */
146  h->history[h->end_i].time = (time_t)0;
147  h->history[h->end_i].load[0] = 0.0;
148  h->history[h->end_i].load[1] = 0.0;
149  h->history[h->end_i].load[2] = 0.0;
150 
151 }
152 
153 /*!
154  * Do some sanity checking on the load history structure
155  *
156  * @param h pointer to load history
157  *
158  * @returns 1 if load history passes check, 0 if it fails
159  */
161 
162  if(h->size < 1) {
163  LOGPRINTF("Error, loadhistory size is less than 1.\n");
164  return 0;
165  }
166  else if(h->size_mod != h->size+1) {
167  LOGPRINTF("Error, loadhistory internal variable is corrupted.\n");
168  return 0;
169  }
170  else if(h->history == NULL) {
171  LOGPRINTF("Error, load history array is not allocated\n.");
172  return 0;
173  }
174  else if(h->write_period < 0) {
175  LOGPRINTF("Error, load history write to disk period is negative.\n");
176  return 0;
177  }
178  else if(h->load_path == NULL) {
179  LOGPRINTF("Error, no history file specified.\n");
180  return 0;
181  }
182 
183  return 1;
184 }
185 
186 /*!
187  * initialized a new load observation structure
188  *
189  * @returns pointer to an allocated and intialized load structure
190  */
191 struct pmm_load* new_load() {
192  struct pmm_load *l;
193 
194  l = malloc(sizeof *l);
195  //TODO NULL check
196 
197  l->time = (time_t)0;
198  l->load[0] = 0.0;
199  l->load[1] = 0.0;
200  l->load[2] = 0.0;
201 
202  return l;
203 }
204 
205 /*!
206  * prints a load history sequence
207  *
208  * @param output output stream to print to
209  * @param h pointer to the load history
210  */
211 void print_loadhistory(const char *output, struct pmm_loadhistory *h) {
212  int i;
213 
214  SWITCHPRINTF(output, "history:%p size: %d start_i:%d end_i:%d\n",
215  h->history, h->size, h->start_i, h->end_i);
216  SWITCHPRINTF(output, "load_path: %s\n", h->load_path);
217 
218  i = h->start_i;
219  while(i != h->end_i) {
220  print_load(output, &h->history[i]);
221  i = (i + 1) % h->size_mod;
222  }
223  //print_load(&h->history[c]);
224 
225 }
226 
227 /*!
228  * prints a single load observation
229  *
230  * @param output output stream to print to
231  * @param l pointer to load structure to print
232  */
233 void print_load(const char *output, struct pmm_load *l) {
234  SWITCHPRINTF(output, "time:%d loads:%.2f %.2f %.2f\n", (int)l->time,
235  l->load[0], l->load[1], l->load[2]);
236 }
237 
238 /*!
239  * frees a load history structure and all of its members
240  *
241  * @param h pointer to address of the load history structure
242  */
244  free((*h)->load_path);
245  (*h)->load_path = NULL;
246 
247  free((*h)->history);
248  (*h)->history = NULL;
249 
250  free(*h);
251  *h = NULL;
252 }
253