Contiki 3.x
powertrace.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010, Swedish Institute of Computer Science.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * This file is part of the Contiki operating system.
30  *
31  */
32 
33 /**
34  * \file
35  * Powertrace: periodically print out power consumption
36  * \author
37  * Adam Dunkels <adam@sics.se>
38  */
39 
40 #include "contiki.h"
41 #include "contiki-lib.h"
42 #include "sys/compower.h"
43 #include "powertrace.h"
44 #include "net/rime/rime.h"
45 
46 #include <stdio.h>
47 #include <string.h>
48 
49 struct powertrace_sniff_stats {
50  struct powertrace_sniff_stats *next;
51  uint32_t num_input, num_output;
52  uint32_t input_txtime, input_rxtime;
53  uint32_t output_txtime, output_rxtime;
54 #if UIP_CONF_IPV6
55  uint16_t proto; /* includes proto + possibly flags */
56 #endif
57  uint16_t channel;
58  uint32_t last_input_txtime, last_input_rxtime;
59  uint32_t last_output_txtime, last_output_rxtime;
60 };
61 
62 #define INPUT 1
63 #define OUTPUT 0
64 
65 #define MAX_NUM_STATS 16
66 
67 MEMB(stats_memb, struct powertrace_sniff_stats, MAX_NUM_STATS);
68 LIST(stats_list);
69 
70 PROCESS(powertrace_process, "Periodic power output");
71 /*---------------------------------------------------------------------------*/
72 void
73 powertrace_print(char *str)
74 {
75  static uint32_t last_cpu, last_lpm, last_transmit, last_listen;
76  static uint32_t last_idle_transmit, last_idle_listen;
77 
78  uint32_t cpu, lpm, transmit, listen;
79  uint32_t all_cpu, all_lpm, all_transmit, all_listen;
80  uint32_t idle_transmit, idle_listen;
81  uint32_t all_idle_transmit, all_idle_listen;
82 
83  static uint32_t seqno;
84 
85  uint32_t time, all_time, radio, all_radio;
86 
87  struct powertrace_sniff_stats *s;
88 
89  energest_flush();
90 
91  all_cpu = energest_type_time(ENERGEST_TYPE_CPU);
92  all_lpm = energest_type_time(ENERGEST_TYPE_LPM);
93  all_transmit = energest_type_time(ENERGEST_TYPE_TRANSMIT);
94  all_listen = energest_type_time(ENERGEST_TYPE_LISTEN);
95  all_idle_transmit = compower_idle_activity.transmit;
96  all_idle_listen = compower_idle_activity.listen;
97 
98  cpu = all_cpu - last_cpu;
99  lpm = all_lpm - last_lpm;
100  transmit = all_transmit - last_transmit;
101  listen = all_listen - last_listen;
102  idle_transmit = compower_idle_activity.transmit - last_idle_transmit;
103  idle_listen = compower_idle_activity.listen - last_idle_listen;
104 
105  last_cpu = energest_type_time(ENERGEST_TYPE_CPU);
106  last_lpm = energest_type_time(ENERGEST_TYPE_LPM);
107  last_transmit = energest_type_time(ENERGEST_TYPE_TRANSMIT);
108  last_listen = energest_type_time(ENERGEST_TYPE_LISTEN);
109  last_idle_listen = compower_idle_activity.listen;
110  last_idle_transmit = compower_idle_activity.transmit;
111 
112  radio = transmit + listen;
113  time = cpu + lpm;
114  all_time = all_cpu + all_lpm;
115  all_radio = energest_type_time(ENERGEST_TYPE_LISTEN) +
116  energest_type_time(ENERGEST_TYPE_TRANSMIT);
117 
118  printf("%s %lu P %d.%d %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu (radio %d.%02d%% / %d.%02d%% tx %d.%02d%% / %d.%02d%% listen %d.%02d%% / %d.%02d%%)\n",
119  str,
120  clock_time(), linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1], seqno,
121  all_cpu, all_lpm, all_transmit, all_listen, all_idle_transmit, all_idle_listen,
122  cpu, lpm, transmit, listen, idle_transmit, idle_listen,
123  (int)((100L * (all_transmit + all_listen)) / all_time),
124  (int)((10000L * (all_transmit + all_listen) / all_time) - (100L * (all_transmit + all_listen) / all_time) * 100),
125  (int)((100L * (transmit + listen)) / time),
126  (int)((10000L * (transmit + listen) / time) - (100L * (transmit + listen) / time) * 100),
127  (int)((100L * all_transmit) / all_time),
128  (int)((10000L * all_transmit) / all_time - (100L * all_transmit / all_time) * 100),
129  (int)((100L * transmit) / time),
130  (int)((10000L * transmit) / time - (100L * transmit / time) * 100),
131  (int)((100L * all_listen) / all_time),
132  (int)((10000L * all_listen) / all_time - (100L * all_listen / all_time) * 100),
133  (int)((100L * listen) / time),
134  (int)((10000L * listen) / time - (100L * listen / time) * 100));
135 
136  for(s = list_head(stats_list); s != NULL; s = list_item_next(s)) {
137 
138 #if ! UIP_CONF_IPV6
139  printf("%s %lu SP %d.%d %lu %u %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu (channel %d radio %d.%02d%% / %d.%02d%%)\n",
140  str, clock_time(), linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1], seqno,
141  s->channel,
142  s->num_input, s->input_txtime, s->input_rxtime,
143  s->input_txtime - s->last_input_txtime,
144  s->input_rxtime - s->last_input_rxtime,
145  s->num_output, s->output_txtime, s->output_rxtime,
146  s->output_txtime - s->last_output_txtime,
147  s->output_rxtime - s->last_output_rxtime,
148  s->channel,
149  (int)((100L * (s->input_rxtime + s->input_txtime + s->output_rxtime + s->output_txtime)) / all_radio),
150  (int)((10000L * (s->input_rxtime + s->input_txtime + s->output_rxtime + s->output_txtime)) / all_radio),
151  (int)((100L * (s->input_rxtime + s->input_txtime +
152  s->output_rxtime + s->output_txtime -
153  (s->last_input_rxtime + s->last_input_txtime +
154  s->last_output_rxtime + s->last_output_txtime))) /
155  radio),
156  (int)((10000L * (s->input_rxtime + s->input_txtime +
157  s->output_rxtime + s->output_txtime -
158  (s->last_input_rxtime + s->last_input_txtime +
159  s->last_output_rxtime + s->last_output_txtime))) /
160  radio));
161 #else
162  printf("%s %lu SP %d.%d %lu %u %u %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu (proto %u(%u) radio %d.%02d%% / %d.%02d%%)\n",
163  str, clock_time(), linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1], seqno,
164  s->proto, s->channel,
165  s->num_input, s->input_txtime, s->input_rxtime,
166  s->input_txtime - s->last_input_txtime,
167  s->input_rxtime - s->last_input_rxtime,
168  s->num_output, s->output_txtime, s->output_rxtime,
169  s->output_txtime - s->last_output_txtime,
170  s->output_rxtime - s->last_output_rxtime,
171  s->proto, s->channel,
172  (int)((100L * (s->input_rxtime + s->input_txtime + s->output_rxtime + s->output_txtime)) / all_radio),
173  (int)((10000L * (s->input_rxtime + s->input_txtime + s->output_rxtime + s->output_txtime)) / all_radio),
174  (int)((100L * (s->input_rxtime + s->input_txtime +
175  s->output_rxtime + s->output_txtime -
176  (s->last_input_rxtime + s->last_input_txtime +
177  s->last_output_rxtime + s->last_output_txtime))) /
178  radio),
179  (int)((10000L * (s->input_rxtime + s->input_txtime +
180  s->output_rxtime + s->output_txtime -
181  (s->last_input_rxtime + s->last_input_txtime +
182  s->last_output_rxtime + s->last_output_txtime))) /
183  radio));
184 #endif
185  s->last_input_txtime = s->input_txtime;
186  s->last_input_rxtime = s->input_rxtime;
187  s->last_output_txtime = s->output_txtime;
188  s->last_output_rxtime = s->output_rxtime;
189 
190  }
191  seqno++;
192 }
193 /*---------------------------------------------------------------------------*/
194 PROCESS_THREAD(powertrace_process, ev, data)
195 {
196  static struct etimer periodic;
197  clock_time_t *period;
198  PROCESS_BEGIN();
199 
200  period = data;
201 
202  if(period == NULL) {
203  PROCESS_EXIT();
204  }
205  etimer_set(&periodic, *period);
206 
207  while(1) {
209  etimer_reset(&periodic);
210  powertrace_print("");
211  }
212 
213  PROCESS_END();
214 }
215 /*---------------------------------------------------------------------------*/
216 void
217 powertrace_start(clock_time_t period)
218 {
219  process_start(&powertrace_process, (void *)&period);
220 }
221 /*---------------------------------------------------------------------------*/
222 void
223 powertrace_stop(void)
224 {
225  process_exit(&powertrace_process);
226 }
227 /*---------------------------------------------------------------------------*/
228 static void
229 add_stats(struct powertrace_sniff_stats *s, int input_or_output)
230 {
231  if(input_or_output == INPUT) {
232  s->num_input++;
233  s->input_txtime += packetbuf_attr(PACKETBUF_ATTR_TRANSMIT_TIME);
234  s->input_rxtime += packetbuf_attr(PACKETBUF_ATTR_LISTEN_TIME);
235  } else if(input_or_output == OUTPUT) {
236  s->num_output++;
237  s->output_txtime += packetbuf_attr(PACKETBUF_ATTR_TRANSMIT_TIME);
238  s->output_rxtime += packetbuf_attr(PACKETBUF_ATTR_LISTEN_TIME);
239  }
240 }
241 /*---------------------------------------------------------------------------*/
242 static void
243 add_packet_stats(int input_or_output)
244 {
245  struct powertrace_sniff_stats *s;
246 
247  /* Go through the list of stats to find one that matches the channel
248  of the packet. If we don't find one, we allocate a new one and
249  put it on the list. */
250  for(s = list_head(stats_list); s != NULL; s = list_item_next(s)) {
251  if(s->channel == packetbuf_attr(PACKETBUF_ATTR_CHANNEL)
252 #if UIP_CONF_IPV6
253  && s->proto == packetbuf_attr(PACKETBUF_ATTR_NETWORK_ID)
254 #endif
255  ) {
256  add_stats(s, input_or_output);
257  break;
258  }
259  }
260  if(s == NULL) {
261  s = memb_alloc(&stats_memb);
262  if(s != NULL) {
263  memset(s, 0, sizeof(struct powertrace_sniff_stats));
264  s->channel = packetbuf_attr(PACKETBUF_ATTR_CHANNEL);
265 #if UIP_CONF_IPV6
266  s->proto = packetbuf_attr(PACKETBUF_ATTR_NETWORK_ID);
267 #endif
268  list_add(stats_list, s);
269  add_stats(s, input_or_output);
270  }
271  }
272 }
273 /*---------------------------------------------------------------------------*/
274 static void
275 input_sniffer(void)
276 {
277  add_packet_stats(INPUT);
278 }
279 /*---------------------------------------------------------------------------*/
280 static void
281 output_sniffer(int mac_status)
282 {
283  add_packet_stats(OUTPUT);
284 }
285 /*---------------------------------------------------------------------------*/
286 #if ! UIP_CONF_IPV6
287 static void
288 sniffprint(char *prefix, int seqno)
289 {
290  const linkaddr_t *sender, *receiver, *esender, *ereceiver;
291 
292  sender = packetbuf_addr(PACKETBUF_ADDR_SENDER);
293  receiver = packetbuf_addr(PACKETBUF_ADDR_RECEIVER);
294  esender = packetbuf_addr(PACKETBUF_ADDR_ESENDER);
295  ereceiver = packetbuf_addr(PACKETBUF_ADDR_ERECEIVER);
296 
297 
298  printf("%lu %s %d %u %d %d %d.%d %u %u\n",
299  clock_time(),
300  prefix,
301  linkaddr_node_addr.u8[0], seqno,
302  packetbuf_attr(PACKETBUF_ATTR_CHANNEL),
303  packetbuf_attr(PACKETBUF_ATTR_PACKET_TYPE),
304  esender->u8[0], esender->u8[1],
305  packetbuf_attr(PACKETBUF_ATTR_TRANSMIT_TIME),
306  packetbuf_attr(PACKETBUF_ATTR_LISTEN_TIME));
307 }
308 /*---------------------------------------------------------------------------*/
309 static void
310 input_printsniffer(void)
311 {
312  static int seqno = 0;
313  sniffprint("I", seqno++);
314 
315  if(packetbuf_attr(PACKETBUF_ATTR_CHANNEL) == 0) {
316  int i;
317  uint8_t *dataptr;
318 
319  printf("x %d ", packetbuf_totlen());
320  dataptr = packetbuf_hdrptr();
321  printf("%02x ", dataptr[0]);
322  for(i = 1; i < packetbuf_totlen(); ++i) {
323  printf("%02x ", dataptr[i]);
324  }
325  printf("\n");
326  }
327 }
328 /*---------------------------------------------------------------------------*/
329 static void
330 output_printsniffer(int mac_status)
331 {
332  static int seqno = 0;
333  sniffprint("O", seqno++);
334 }
335 /*---------------------------------------------------------------------------*/
336 RIME_SNIFFER(printsniff, input_printsniffer, output_printsniffer);
337 /*---------------------------------------------------------------------------*/
338 void
339 powertrace_printsniff(powertrace_onoff_t onoff)
340 {
341  switch(onoff) {
342  case POWERTRACE_ON:
343  rime_sniffer_add(&printsniff);
344  break;
345  case POWERTRACE_OFF:
346  rime_sniffer_remove(&printsniff);
347  break;
348  }
349 }
350 #endif
351 /*---------------------------------------------------------------------------*/
352 RIME_SNIFFER(powersniff, input_sniffer, output_sniffer);
353 /*---------------------------------------------------------------------------*/
354 void
355 powertrace_sniff(powertrace_onoff_t onoff)
356 {
357  switch(onoff) {
358  case POWERTRACE_ON:
359  rime_sniffer_add(&powersniff);
360  break;
361  case POWERTRACE_OFF:
362  rime_sniffer_remove(&powersniff);
363  break;
364  }
365 }
int etimer_expired(struct etimer *et)
Check if an event timer has expired.
Definition: etimer.c:205
#define PROCESS_WAIT_UNTIL(c)
Wait for a condition to occur.
Definition: process.h:192
linkaddr_t linkaddr_node_addr
The Rime address of the node.
Definition: linkaddr.c:48
Header file for the powertrace application
#define PROCESS_EXIT()
Exit the currently running process.
Definition: process.h:200
#define PROCESS_BEGIN()
Define the beginning of a process.
Definition: process.h:120
void * list_item_next(void *item)
Get the next item following this item.
Definition: list.c:325
void * memb_alloc(struct memb *m)
Allocate a memory block from a block of memory declared with MEMB().
Definition: memb.c:59
#define NULL
The null pointer.
struct compower_activity compower_idle_activity
The default idle communication activity.
Definition: compower.c:50
uint16_t packetbuf_totlen(void)
Get the total length of the header and data in the packetbuf.
Definition: packetbuf.c:260
Header file for the Rime stack
Header file for the communication power accounting module
#define PROCESS_THREAD(name, ev, data)
Define the body of a process.
Definition: process.h:273
#define PROCESS_END()
Define the end of a process.
Definition: process.h:131
CCIF clock_time_t clock_time(void)
Get the current clock time.
Definition: clock.c:41
void * packetbuf_hdrptr(void)
Get a pointer to the header in the packetbuf, for outbound packets.
Definition: packetbuf.c:213
void * list_head(list_t list)
Get a pointer to the first element of a list.
Definition: list.c:83
#define MEMB(name, structure, num)
Declare a memory block.
Definition: memb.h:89
void list_add(list_t list, void *item)
Add an item at the end of a list.
Definition: list.c:143
#define PROCESS(name, strname)
Declare a process.
Definition: process.h:307
#define LIST(name)
Declare a linked list.
Definition: list.h:86
void etimer_reset(struct etimer *et)
Reset an event timer with the same interval as was previously set.
Definition: etimer.c:184
void process_start(struct process *p, process_data_t data)
Start a process.
Definition: process.c:99
void etimer_set(struct etimer *et, clock_time_t interval)
Set an event timer.
Definition: etimer.c:177
A timer.
Definition: etimer.h:76
void process_exit(struct process *p)
Cause a process to exit.
Definition: process.c:202