Contiki 2.5
statistics.c
Go to the documentation of this file.
1  /**
2  * \addtogroup statistics Statistics module
3  *
4  * @{
5  */
6 
7 /**
8  * \file
9  * \brief uDTN Statistics Module implementation
10  * \author Wolf-Bastian Poettner <poettner@ibr.cs.tu-bs.de>
11  */
12 
13 #include <string.h> // for memcpy
14 
15 #include "agent.h"
16 #include "contiki.h"
17 #include "bundle.h"
18 #include "logging.h"
19 
20 #include "statistics.h"
21 
22 process_event_t dtn_statistics_overrun;
23 
24 unsigned long statistics_timestamp = 0;
25 struct statistics_element_t statistics_array[STATISTICS_ELEMENTS];
26 struct contact_element_t statistics_contacts[STATISTICS_CONTACTS];
27 struct process * statistics_event_process = NULL;
28 uint8_t contacts_pointer = 0;
29 unsigned long contacts_timestamp = 0;
30 
31 /**
32  * \brief Internal function to find out, into which array slot the information is written
33  */
35 {
36 #if STATISTICS_PERIOD > 0
37  // Calculate since when we are recording statistics
38  unsigned long elapsed = clock_seconds() - statistics_timestamp;
39 
40  // Find out in which "slot" of the array we are currently writing
41  uint8_t ptr = elapsed / STATISTICS_PERIOD;
42 
43  if( ptr >= STATISTICS_ELEMENTS ) {
44  ptr = STATISTICS_ELEMENTS - 1;
45  }
46 
47  return ptr;
48 #else
49  return 0;
50 #endif
51 }
52 
53 /**
54  * \brief Init function to be called by application
55  * \return Seconds after which the statistics have to be sent off
56  */
57 uint16_t statistics_setup(struct process * process)
58 {
59  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "setup()");
60 
61  // Reset the results (just to be sure)
63 
64  // Store to which process we have to send the events
65  statistics_event_process = process;
66 
67  // Allocate our event
68  dtn_statistics_overrun = process_alloc_event();
69 
70  return STATISTICS_PERIOD * STATISTICS_ELEMENTS;
71 }
72 
73 /**
74  * \brief Copy the statistics bundle into the provided buffer
75  * \return Length of the payload
76  */
77 uint8_t statistics_get_bundle(uint8_t * buffer, uint8_t maximum_length)
78 {
79  int offset = 0;
80 
81  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "get_bundle(%p, %u)", buffer, maximum_length);
82 
83  // Store the timestamp of this period
84  memcpy(buffer + offset, &statistics_timestamp, sizeof(statistics_timestamp));
85  offset += sizeof(statistics_timestamp);
86 
87  // Store how long each step is
88  buffer[offset++] = (STATISTICS_PERIOD & 0x00FF) >> 0;
89  buffer[offset++] = (STATISTICS_PERIOD & 0xFF00) >> 8;
90 
91  // Store how many periods are recorded
92  buffer[offset++] = STATISTICS_ELEMENTS;
93 
94  // And now copy over the struct
95  memcpy(buffer + offset, &statistics_array, sizeof(struct statistics_element_t) * STATISTICS_ELEMENTS);
96  offset += sizeof(struct statistics_element_t) * STATISTICS_ELEMENTS;
97 
98  return offset;
99 }
100 
101 /**
102  * \brief Copy the contacts bundle into the provided buffer
103  * \return Length of the payload
104  */
105 uint8_t statistics_get_contacts_bundle(uint8_t * buffer, uint8_t maximum_length)
106 {
107  int offset = 0;
108 
109  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "get_contacts_bundle(%p, %u)", buffer, maximum_length);
110 
111  // This should never happen
112  if( contacts_pointer > STATISTICS_CONTACTS ) {
113  contacts_pointer = STATISTICS_CONTACTS;
114  }
115 
116  // Store how many entries are following
117  buffer[offset++] = contacts_pointer;
118 
119  buffer[offset++] = (contacts_timestamp & 0x000000FF) >> 0;
120  buffer[offset++] = (contacts_timestamp & 0x0000FF00) >> 8;
121  buffer[offset++] = (contacts_timestamp & 0x00FF0000) >> 16;
122  buffer[offset++] = (contacts_timestamp & 0xFF000000) >> 24;
123 
124  // And now copy over the struct
125  memcpy(buffer + offset, &statistics_contacts, sizeof(struct contact_element_t) * contacts_pointer);
126  offset += sizeof(struct contact_element_t) * contacts_pointer;
127 
128  return offset;
129 }
130 
131 /**
132  * \brief Resets the contact information, to be called by application after contacts bundle has been retrieved
133  */
135 {
136  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "reset_contacts()");
137 
138  memset(statistics_contacts, 0, sizeof(struct contact_element_t) * STATISTICS_CONTACTS);
139  contacts_pointer = 0;
140  contacts_timestamp = 0;
141 }
142 
143 /**
144  * \brief Resets the statistics, to be called by application after bundle has been retrieved
145  */
147 {
148  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "reset()");
149 
150  // Nullify the whole array
151  memset(statistics_array, 0, sizeof(struct statistics_element_t) * STATISTICS_ELEMENTS);
152 
153  // Record the current timestamp
154  statistics_timestamp = clock_seconds();
155 }
156 
157 /**
158  * \brief new bundle has been received
159  */
160 void statistics_bundle_incoming(uint8_t count)
161 {
162 #if STATISTICS_ELEMENTS > 0
163  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "bundle_incoming(%u)", count);
164 
165  statistics_array[statistics_get_pointer()].bundles_incoming += count;
166 #endif
167 }
168 
169 /**
170  * \brief Bundle has been sent out
171  */
172 void statistics_bundle_outgoing(uint8_t count)
173 {
174 #if STATISTICS_ELEMENTS > 0
175  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "bundle_outgoing(%u)", count);
176 
177  statistics_array[statistics_get_pointer()].bundles_outgoing += count;
178 #endif
179 }
180 
181 /**
182  * \brief Bundle was generated locally
183  */
184 void statistics_bundle_generated(uint8_t count)
185 {
186 #if STATISTICS_ELEMENTS > 0
187  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "bundle_generated(%u)", count);
188 
189  statistics_array[statistics_get_pointer()].bundles_generated += count;
190 #endif
191 }
192 
193 /**
194  * \brief Bundle was delivered locally
195  */
196 void statistics_bundle_delivered(uint8_t count)
197 {
198 #if STATISTICS_ELEMENTS > 0
199  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "statistics_bundle_delivered(%u)", count);
200 
201  statistics_array[statistics_get_pointer()].bundles_delivered += count;
202 #endif
203 }
204 
205 /**
206  * \brief Provide the number of bundles currently in storage
207  */
208 void statistics_storage_bundles(uint8_t bundles)
209 {
210 #if STATISTICS_ELEMENTS > 0
211  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "storage_bundles(%u)", bundles);
212 
213  statistics_array[statistics_get_pointer()].storage_bundles = bundles;
214 #endif
215 }
216 
217 /**
218  * \brief Provide the amount of memory that is free
219  */
220 void statistics_storage_memory(uint16_t free)
221 {
222 #if STATISTICS_ELEMENTS > 0
223  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "storage_memory(%u)", free);
224 
225  statistics_array[statistics_get_pointer()].storage_memory = free;
226 #endif
227 }
228 
229 /**
230  * \brief A new neighbour has been found
231  */
232 void statistics_contacts_up(rimeaddr_t * peer)
233 {
234 #if STATISTICS_ELEMENTS > 0
235  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "contacts_up(%u.%u)", peer->u8[0], peer->u8[1]);
236 #endif
237 }
238 
239 /**
240  * \brief Neighbour disappeared
241  */
242 void statistics_contacts_down(rimeaddr_t * peer, uint16_t duration)
243 {
244 #if STATISTICS_ELEMENTS > 0
245  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "contacts_down(%u.%u, %u)", peer->u8[0], peer->u8[1], duration);
246 
247  statistics_array[statistics_get_pointer()].contacts_count ++;
248  statistics_array[statistics_get_pointer()].contacts_duration += duration;
249 #endif
250 
251 #if STATISTICS_CONTACTS > 0
252  uint32_t id = convert_rime_to_eid(peer);
253 
254  // We record only contacts with nodes that have a lower id than ourselves to avoid recording contacts twice (on both sides)
255  if( duration == 0 || id > dtn_node_id ) {
256  return;
257  }
258 
259  if( contacts_pointer >= STATISTICS_CONTACTS ) {
260  // This can only happen, when nobody picks up the data (or if somebody forgot to reset)
261  contacts_pointer = STATISTICS_CONTACTS - 1;
262  }
263 
264  // Record the contact
265  unsigned long timestamp = clock_seconds() - duration;
266 
267  if( contacts_timestamp == 0 && contacts_pointer == 0 ) {
268  contacts_timestamp = timestamp;
269  }
270 
271  statistics_contacts[contacts_pointer].time_difference = (uint16_t) (timestamp - contacts_timestamp);
272  statistics_contacts[contacts_pointer].peer = (uint8_t) id;
273  statistics_contacts[contacts_pointer].duration = duration;
274  contacts_pointer ++;
275 
276  // Avoid overrunning the array
277  if( contacts_pointer >= STATISTICS_CONTACTS && statistics_event_process != NULL ) {
278  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "contacts full, sending event");
279  process_post(statistics_event_process, dtn_statistics_overrun, NULL);
280  } else if( statistics_event_process == NULL ) {
281  // Nobody is interested in our data anyway, start from the beginning
282  LOG(LOGD_DTN, LOG_AGENT, LOGL_DBG, "contacts full, clearing array");
284  }
285 #endif
286 }
287 /** @} */