Factored out the time table keeping code from the profiling code and placed it in a separate 'timetable' module, that may be uesd on its own.

This commit is contained in:
adamdunkels 2008-01-17 12:19:25 +00:00
parent f2599b38e7
commit 7b71f23abe
7 changed files with 738 additions and 203 deletions

View File

@ -50,7 +50,7 @@ ifdef CHAMELEON
include $(CONTIKI)/core/net/chameleon/Makefile.chameleon include $(CONTIKI)/core/net/chameleon/Makefile.chameleon
endif endif
include $(CONTIKI)/core/net/mac/Makefile.mac include $(CONTIKI)/core/net/mac/Makefile.mac
SYSTEM = process.c procinit.c autostart.c elfloader.c profile.c profile-aggregates.c SYSTEM = process.c procinit.c autostart.c elfloader.c profile.c timetable.c timetable-aggregate.c
THREADS = mt.c THREADS = mt.c
LIBS = memb.c timer.c list.c etimer.c energest.c rtimer.c print-stats.c LIBS = memb.c timer.c list.c etimer.c energest.c rtimer.c print-stats.c
UIP = uip.c uiplib.c resolv.c tcpip.c psock.c hc.c uip-split.c uip-fw.c \ UIP = uip.c uiplib.c resolv.c tcpip.c psock.c hc.c uip-split.c uip-fw.c \

View File

@ -28,7 +28,7 @@
* *
* This file is part of the Contiki operating system. * This file is part of the Contiki operating system.
* *
* $Id: profile.c,v 1.3 2007/11/18 19:16:49 oliverschmidt Exp $ * $Id: profile.c,v 1.4 2008/01/17 12:19:26 adamdunkels Exp $
*/ */
/** /**
@ -39,144 +39,159 @@
*/ */
#include "sys/profile.h" #include "sys/profile.h"
#include "sys/clock.h"
#include <stddef.h> /* For NULL */ #include <stdio.h>
unsigned int profile_timestamp_ptr; /* XXX: the profiling code is under development and may not work at
struct profile_timestamp profile_timestamps[PROFILE_LIST_LENGTH]; present. */
rtimer_clock_t profile_timestamp_time;
int profile_invalid_episode_overflow, profile_invalid_episode_toolong;
int profile_max_queuelen = 0; TIMETABLE_NONSTATIC(profile_timetable);
TIMETABLE_NONSTATIC(profile_begin_timetable);
TIMETABLE_NONSTATIC(profile_end_timetable);
TIMETABLE_AGGREGATE(profile_aggregate, PROFILE_AGGREGATE_SIZE);
static rtimer_clock_t episode_start_time; static rtimer_clock_t episode_start_time;
static unsigned int invalid_episode_overflow, invalid_episode_toolong,
max_queuelen;
/* The number of fine grained ticks per coarse grained ticks. We /* The number of fine grained ticks per coarse grained ticks. We
currently (MSP430) have 2457600 ticks per second for the fine currently (MSP430) have 2457600 ticks per second for the fine
grained timer, and 32678 / 8 ticks per second for the coarse. */ grained timer, and 32678 / 8 ticks per second for the coarse. */
#define FINE_TICKS_PER_COARSE_TICK (2457600/(32678/8)) #define XXX_HACK_FINE_TICKS_PER_COARSE_TICK (2457600/(32678/8))
/* XXX hack: we use a function called clock_counter() that is not part
of the clock API and currently is only implemented for the
MSP430. We therefore declare this function here instead of in
dev/clock.h. */
rtimer_clock_t clock_counter(void);
/*---------------------------------------------------------------------------*/
rtimer_clock_t
profile_timediff(const char *ptr1, const char *ptr2)
{
int i;
int t1, t2;
int timestamp_ptr = PROFILE_TIMESTAMP_PTR;
/* printf("profile_timestamp_ptr %d max %d\n", profile_timestamp_ptr, profile_max_queuelen);*/
t1 = t2 = PROFILE_LIST_LENGTH;
for(i = timestamp_ptr - 1; i >= 0; --i) {
/* printf("Checking 1 %s %u == %s i %d\n",
profile_timestamps[i].ptr,
profile_timestamps[i].time,
ptr1, i);*/
if(profile_timestamps[i].ptr == ptr1) {
t1 = i;
break;
}
}
for(i = i - 1; i >= 0; --i) {
/* printf("Checking 2 %s %u == %s i %d\n",
profile_timestamps[i].ptr,
profile_timestamps[i].time,
ptr1, i);*/
if(profile_timestamps[i].ptr == ptr2) {
t2 = i;
break;
}
}
/* printf("t1 %d t2 %d\n", t1, t2);*/
if(t1 != PROFILE_LIST_LENGTH && t2 != PROFILE_LIST_LENGTH) {
return profile_timestamps[t1].time - profile_timestamps[t2].time;
}
return 0;
}
/*---------------------------------------------------------------------------*/
void
profile_clear_timestamps(void)
{
/* int i;
for(i = 0; i < PROFILE_LIST_LENGTH; ++i) {
profile_timestamps[i].str = "NULL";
profile_timestamps[i].time = 0;
}*/
profile_timestamp_ptr = 0;
}
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
profile_init(void) profile_init(void)
{ {
profile_clear_timestamps(); timetable_init();
timetable_clear(&profile_begin_timetable);
/* Measure the time for taking a timestamp. */ timetable_clear(&profile_end_timetable);
PROFILE_TIMESTAMP(NULL);
PROFILE_TIMESTAMP(NULL);
profile_timestamp_time = profile_timestamps[1].time - profile_timestamps[0].time;
profile_clear_timestamps();
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
profile_episode_start(void) profile_episode_start(void)
{ {
profile_timestamp_ptr = 0; struct timetable_timestamp *e;
timetable_clear(&profile_begin_timetable);
timetable_clear(&profile_end_timetable);
episode_start_time = clock_time();
episode_start_time = clock_counter(); e = timetable_entry(&profile_begin_timetable,
PROFILE_TIMETABLE_SIZE - 1);
profile_timestamps[PROFILE_LIST_LENGTH - 1].ptr = NULL; if(e != NULL) {
e->id = NULL;
}
e = timetable_entry(&profile_end_timetable,
PROFILE_TIMETABLE_SIZE - 1);
if(e != NULL) {
e->id = NULL;
}
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
profile_episode_end(void) profile_episode_end(void)
{ {
rtimer_clock_t episode_end_time = clock_counter(); struct timetable_timestamp *e;
rtimer_clock_t episode_end_time = clock_time();
PROFILE_TIMESTAMP("profile_episode_end"); /* printf("timetable_episode_end start %u, end %u, max time %u\n", episode_start_time, episode_end_time, 65536/FINE_TICKS_PER_COARSE_TICK); */
e = timetable_entry(&profile_begin_timetable,
/* printf("profile_episode_end start %u, end %u, max time %u\n", episode_start_time, episode_end_time, 65536/FINE_TICKS_PER_COARSE_TICK); */ PROFILE_TIMETABLE_SIZE - 1);
if(profile_timestamps[PROFILE_LIST_LENGTH - 1].ptr != NULL) { if(e != NULL && e->id != NULL) {
/* Invalid episode because of list overflow. */ /* Invalid episode because of list overflow. */
profile_invalid_episode_overflow++; invalid_episode_overflow++;
profile_max_queuelen = PROFILE_LIST_LENGTH; max_queuelen = PROFILE_TIMETABLE_SIZE;
} else if(episode_end_time - episode_start_time > 65536/FINE_TICKS_PER_COARSE_TICK) { } else if(episode_end_time - episode_start_time >
65536/XXX_HACK_FINE_TICKS_PER_COARSE_TICK) {
/* Invalid episode because of timer overflow. */ /* Invalid episode because of timer overflow. */
profile_invalid_episode_toolong++; invalid_episode_toolong++;
} else { } else {
/* Compute aggregates. */ /* Compute aggregates. */
if(PROFILE_TIMESTAMP_PTR > profile_max_queuelen) { if(timetable_ptr(&profile_begin_timetable) > max_queuelen) {
profile_max_queuelen = PROFILE_TIMESTAMP_PTR; max_queuelen = timetable_ptr(&profile_begin_timetable);
} }
profile_aggregates_compute(); /* timetable_aggregates_compute();*/
/* printf("Episode length %d\n", profile_timestamp_ptr);*/ }
}
/*---------------------------------------------------------------------------*/
/*
*
* Find a specific aggregate ID in the list of aggregates.
*
*/
static struct timetable_aggregate_entry *
find_aggregate(struct timetable_aggregate *a,
const char *id)
{
int i;
for(i = 0; i < a->ptr; ++i) {
if(a->entries[i].id == id) {
return &a->entries[i];
}
}
if(i == a->size) {
return NULL;
}
a->entries[a->ptr].id = NULL;
return &a->entries[a->ptr++];
}
/*---------------------------------------------------------------------------*/
void
profile_aggregate_print_detailed(void)
{
int i;
struct timetable_aggregate *a = &profile_aggregate;
/* printf("timetable_aggregate_print_detailed: a ptr %d\n", a->ptr);*/
for(i = 0; i < a->ptr; ++i) {
printf("-- %s: %lu / %u = %lu\n", a->entries[i].id,
a->entries[i].time,
a->entries[i].episodes,
a->entries[i].time / a->entries[i].episodes);
} }
/* profile_aggregates_print(); */ printf("Memory for entries: %d * %d = %d\n",
/* profile_print_stats(); */ (int)sizeof(struct timetable_aggregate), a->ptr,
(int)sizeof(struct timetable_aggregate) * a->ptr);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#if 0
#include <stdio.h>
void void
profile_print_stats(void) profile_aggregate_compute_detailed(void)
{ {
printf("Memory for profiling: %d * %d = %d\n", int i;
sizeof(struct profile_timestamp), profile_max_queuelen, int last;
sizeof(struct profile_timestamp) * profile_max_queuelen); rtimer_clock_t t;
printf("Invalid episodes overflow %d time %d\n", struct timetable_aggregate *a = &profile_aggregate;
profile_invalid_episode_overflow, struct timetable *timetable = &profile_timetable;
profile_invalid_episode_toolong); struct timetable_aggregate_entry *entry;
last = timetable_ptr(&profile_begin_timetable);
t = profile_begin_timetable.timestamps[0].time;
for(i = 0; i < last; ++i) {
entry = find_aggregate(a, profile_begin_timetable.timestamps[i].id);
if(entry == NULL) {
/* The list is full, skip this entry */
/* printf("detailed_timetable_aggregate_compute: list full\n");*/
} else if(entry->id == NULL) {
/* The id was found in the list, so we add it. */
entry->id = timetable->timestamps[i - 1].id;
entry->time = (unsigned long)(timetable->timestamps[i].time - t -
timetable_timestamp_time);
entry->episodes = 1;
/* printf("New entry %s %lu\n", entry->id, entry->time);*/
} else {
entry->time += (unsigned long)(timetable->timestamps[i].time - t -
timetable_timestamp_time);
entry->episodes++;
}
t = timetable->timestamps[i].time;
/* printf("a ptr %d\n", a->ptr);*/
}
} }
#endif /* 0 */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/

View File

@ -28,7 +28,7 @@
* *
* This file is part of the Contiki operating system. * This file is part of the Contiki operating system.
* *
* $Id: profile.h,v 1.2 2007/11/17 10:14:19 adamdunkels Exp $ * $Id: profile.h,v 1.3 2008/01/17 12:19:26 adamdunkels Exp $
*/ */
/** /**
@ -41,116 +41,48 @@
#ifndef __PROFILE_H__ #ifndef __PROFILE_H__
#define __PROFILE_H__ #define __PROFILE_H__
#include "sys/rtimer.h" /* XXX: the profiling code is under development and may not work at
present. */
#ifdef EXPERIMENT_SETUP #define TIMETABLE_WITH_TYPE 1
#include "experiment-setup.h" #include "sys/timetable.h"
#endif
#include "contiki-conf.h" #ifdef PROFILE_CONF_TIMETABLE_SIZE
#define PROFILE_TIMETABLE_SIZE PROFILE_CONF_TIMETABLE_SIZE
#ifdef PROFILE_CONF_LIST_LENGTH
#define PROFILE_LIST_LENGTH PROFILE_CONF_LIST_LENGTH
#else #else
#define PROFILE_LIST_LENGTH 128 #define PROFILE_TIMETABLE_SIZE 128
#endif #endif
struct profile_timestamp { #ifdef PROFILE_CONF_AGGREGATE_SIZE
const char *ptr; #define PROFILE_AGGREGATE_SIZE PROFILE_CONF_AGGREGATE_SIZE
rtimer_clock_t time; #else
}; #define PROFILE_AGGREGATE_SIZE 128
#endif
extern struct profile_timestamp profile_timestamps[PROFILE_LIST_LENGTH]; #define PROFILE_BEGIN(id) TIMETABLE_TIMESTAMP_TYPE(profile_timetable, id, 1)
extern unsigned int profile_timestamp_ptr; #define PROFILE_END(id) TIMETABLE_TIMESTAMP_TYPE(profile_timetable, id, 2)
extern rtimer_clock_t profile_timestamp_time;
#define PROFILE_TIMESTAMP_PTR (profile_timestamp_ptr / sizeof(struct profile_timestamp)) /*#define PROFILE_COND_BEGIN(cond, id) TIMETABLE_COND_TIMESTAMP(profile_begin_timetable, \
cond, id)
#define PROFILE_COND_END(cond, id) TIMETABLE_COND_TIMESTAMP(profile_end_timetable, \
cond, id)
*/
#if PROFILE_CONF_ON #define profile_begin_timetable_size PROFILE_TIMETABLE_SIZE
#define PROFILE_TIMESTAMP(str) \ TIMETABLE_DECLARE(profile_begin_timetable);
do { \ #define profile_end_timetable_size PROFILE_TIMETABLE_SIZE
profile_timestamps[profile_timestamp_ptr / sizeof(struct profile_timestamp)].ptr = str; \ TIMETABLE_DECLARE(profile_end_timetable);
profile_timestamps[profile_timestamp_ptr / sizeof(struct profile_timestamp)].time = RTIMER_NOW(); \
profile_timestamp_ptr = (profile_timestamp_ptr + sizeof(struct profile_timestamp)) % (PROFILE_LIST_LENGTH * sizeof(struct profile_timestamp)); \
} while(0)
#define PROFILE_RESUME(num) PROFILE_TIMESTAMP(profile_timestamps[num].ptr)
#define PROFILE_COND_TIMESTAMP(cond, ptr) do { if(cond) {PROFILE_TIMESTAMP(ptr);} } while(0) #define profile_timetable_size PROFILE_TIMETABLE_SIZE
#define PROFILE_COND_RESUME(cond, num) PROFILE_COND_TIMESTAMP(cond, profile_timestamps[num].ptr) TIMETABLE_DECLARE(profile_timetable);
#else /* PROFILE_CONF_ON */
#define PROFILE_TIMESTAMP(id)
#define PROFILE_RESUME(num)
#define PROFILE_COND_TIMESTAMP(cond, id)
#define PROFILE_COND_RESUME(cond, num)
#endif /* PROFILE_CONF_ON */
rtimer_clock_t profile_timediff(const char *ptr1, const char *ptr2);
#define PROFILE_GETPTR() (PROFILE_TIMESTAMP_PTR)
void profile_clear_timestamps(void);
void profile_init(void); void profile_init(void);
void profile_episode_start(void); void profile_episode_start(void);
void profile_episode_end(void); void profile_episode_end(void);
void profile_aggregates_print(void); void profile_aggregate_print_detailed(void);
void profile_aggregates_compute(void); void profile_aggregate_compute_detailed(void);
void profile_print_stats(void);
enum {
PROFILE_TYPE_STACK,
PROFILE_TYPE_HW,
PROFILE_TYPE_RADIO,
PROFILE_TYPE_SYSTEM,
PROFILE_TYPE_APP,
};
#endif /* __PROFILE_H__ */ #endif /* __PROFILE_H__ */
/* profile_timestamp_ptr code:
2e: 1f 42 00 00 mov &0x0000,r15 ;0x0000
32: 0e 4f mov r15, r14 ;
34: 0e 5e rla r14 ;
36: 0e 5e rla r14 ;
38: 3e 50 00 00 add #0, r14 ;#0x0000
3c: be 40 00 00 mov #0, 0(r14) ;#0x0000
40: 00 00
42: 9e 42 90 01 mov &0x0190,2(r14) ;0x0190
46: 02 00
48: 1f 53 inc r15 ;
4a: 3f f0 3f 00 and #63, r15 ;#0x003f
4e: 82 4f 00 00 mov r15, &0x0000 ;
msp430-specific profile_timetstamp_2ptr code:
2e: 1f 42 00 00 mov &0x0000,r15 ;0x0000
32: 0e 4f mov r15, r14 ;
34: 3e 50 00 00 add #0, r14 ;#0x0000
38: be 40 00 00 mov #0, 0(r14) ;#0x0000
3c: 00 00
3e: 9e 42 90 01 mov &0x0190,2(r14) ;0x0190
42: 02 00
44: 2f 53 incd r15 ;
46: 3f f0 7f 00 and #127, r15 ;#0x007f
4a: 82 4f 00 00 mov r15, &0x0000 ;
generic timestamp_2ptr code:
2e: 1f 42 00 00 mov &0x0000,r15 ;0x0000
32: 0e 4f mov r15, r14 ;
34: 1e c3 bic #1, r14 ;r3 As==01
36: 0e 5e rla r14 ;
38: 3e 50 00 00 add #0, r14 ;#0x0000
3c: be 40 00 00 mov #0, 0(r14) ;#0x0000
40: 00 00
42: 9e 42 90 01 mov &0x0190,2(r14) ;0x0190
46: 02 00
48: 2f 53 incd r15 ;
4a: 3f f0 7f 00 and #127, r15 ;#0x007f
4e: 82 4f 00 00 mov r15, &0x0000 ;
*/

View File

@ -0,0 +1,229 @@
/*
* Copyright (c) 2008, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
* $Id: timetable-aggregate.c,v 1.1 2008/01/17 12:19:26 adamdunkels Exp $
*/
/**
* \file
* A brief description of what this file is.
* \author
* Adam Dunkels <adam@sics.se>
*/
#include "sys/timetable-aggregate.h"
#define XXX_HACK_MAX_CATEGORIES 32
#include <stdio.h>
/*---------------------------------------------------------------------------*/
/*
*
* Find an aggregation category in the list of aggregates. If the
* category could not be found, the function returns a pointer to an
* empty entry. If the list is full, the function returns NULL.
*
*/
static struct timetable_aggregate_entry *
find_aggregate_category(struct timetable_aggregate *a,
const uint16_t cat)
{
int i;
uint16_t acat;
for(i = 0; i < a->ptr; ++i) {
acat = (a->entries[i].id[0] << 8) + a->entries[i].id[1];
if(acat == cat) {
return &a->entries[i];
}
}
if(i == a->size) {
return NULL;
}
a->entries[a->ptr].id = NULL;
return &a->entries[a->ptr++];
}
/*---------------------------------------------------------------------------*/
/*
*
* Find a specific aggregate ID in the list of aggregates.
*
*/
static struct timetable_aggregate_entry *
find_aggregate(struct timetable_aggregate *a,
const char *id)
{
int i;
for(i = 0; i < a->ptr; ++i) {
if(a->entries[i].id == id) {
return &a->entries[i];
}
}
if(i == a->size) {
return NULL;
}
a->entries[a->ptr].id = NULL;
return &a->entries[a->ptr++];
}
/*---------------------------------------------------------------------------*/
void
timetable_aggregate_print_detailed(struct timetable_aggregate *a)
{
int i;
/* printf("timetable_aggregate_print_detailed: a ptr %d\n", a->ptr);*/
for(i = 0; i < a->ptr; ++i) {
printf("-- %s: %lu / %u = %lu\n", a->entries[i].id,
a->entries[i].time,
a->entries[i].episodes,
a->entries[i].time / a->entries[i].episodes);
}
printf("Memory for entries: %d * %d = %d\n",
(int)sizeof(struct timetable_aggregate), a->ptr,
(int)sizeof(struct timetable_aggregate) * a->ptr);
}
/*---------------------------------------------------------------------------*/
void
timetable_aggregate_print_categories(struct timetable_aggregate *a)
{
int i;
/* printf("timetable_aggregate_print_categories: a ptr %d\n", a->ptr);*/
for(i = 0; i < a->ptr; ++i) {
printf("-- %c%c: %lu / %u = %lu\n",
a->entries[i].id[0], a->entries[i].id[1],
a->entries[i].time,
a->entries[i].episodes,
a->entries[i].time / a->entries[i].episodes);
}
printf("Memory for entries: %d * %d = %d\n",
(int)sizeof(struct timetable_aggregate), a->ptr,
(int)sizeof(struct timetable_aggregate) * a->ptr);
}
/*---------------------------------------------------------------------------*/
void
timetable_aggregate_compute_detailed(struct timetable_aggregate *a,
struct timetable *timetable)
{
int i;
rtimer_clock_t t;
t = timetable->timestamps[0].time;
for(i = 1; i < *timetable->ptr; ++i) {
struct timetable_aggregate_entry *entry;
entry = find_aggregate(a, timetable->timestamps[i - 1].id);
if(entry == NULL) {
/* The list is full, skip this entry */
/* printf("detailed_timetable_aggregate_compute: list full\n");*/
} else if(entry->id == NULL) {
/* The id was found in the list, so we add it. */
entry->id = timetable->timestamps[i - 1].id;
entry->time = (unsigned long)(timetable->timestamps[i].time - t -
timetable_timestamp_time);
entry->episodes = 1;
/* printf("New entry %s %lu\n", entry->id, entry->time);*/
} else {
entry->time += (unsigned long)(timetable->timestamps[i].time - t -
timetable_timestamp_time);
entry->episodes++;
}
t = timetable->timestamps[i].time;
/* printf("a ptr %d\n", a->ptr);*/
}
}
/*---------------------------------------------------------------------------*/
void
timetable_aggregate_compute_categories(struct timetable_aggregate *a,
struct timetable *timetable)
{
int i,j;
rtimer_clock_t t;
uint16_t categories[XXX_HACK_MAX_CATEGORIES];
int categories_ptr = 0;
t = timetable->timestamps[0].time;
for(i = 1; i < *timetable->ptr; ++i) {
struct timetable_aggregate_entry *entry;
uint16_t cat;
/* printf("category_timetable_aggregate_compute %s %d\n",
timetable->timestamps[i - 1].id, i);*/
cat = (timetable->timestamps[i - 1].id[0] << 8) +
(timetable->timestamps[i - 1].id[1] & 0xff);
entry = find_aggregate_category(a, cat);
if(entry == NULL) {
/* The list is full, skip this entry */
/* printf("category_timetable_aggregate_compute: list full\n");*/
} else if(entry->id == NULL) {
/* The category was not found in the list, so we add it. */
entry->id = timetable->timestamps[i - 1].id;
entry->time = (unsigned long)(timetable->timestamps[i].time - t -
timetable_timestamp_time);
entry->episodes = 1;
/* printf("New category %c%c time %lu\n",
timetable->timestamps[i - 1].id[0],
timetable->timestamps[i - 1].id[1], entry->time);*/
} else {
entry->time += (unsigned long)(timetable->timestamps[i].time - t -
timetable_timestamp_time);
/* printf("Adding time to %c%c time %lu\n",
timetable->timestamps[i - 1].id[0],
timetable->timestamps[i - 1].id[1], entry->time);*/
/* Make sure that we only update the episodes of each category
once per run. We keep track of all updated categories in the
"categories" array. If the category is already present in the
array, we do not update it. Otherwise, we insert the category
in the array and update the episodes counter of the
category. */
for(j = 0; j < categories_ptr; ++j) {
if(categories[j] == cat) {
break;
}
}
if(j == categories_ptr) {
categories[j] = cat;
categories_ptr++;
entry->episodes++;
}
}
t = timetable->timestamps[i].time;
}
}
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2008, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
* $Id: timetable-aggregate.h,v 1.1 2008/01/17 12:19:26 adamdunkels Exp $
*/
/**
* \file
* A brief description of what this file is.
* \author
* Adam Dunkels <adam@sics.se>
*/
#ifndef __TIMETABLE_AGGREGATE_H__
#define __TIMETABLE_AGGREGATE_H__
#include "sys/timetable.h"
#include "sys/cc.h"
struct timetable_aggregate_entry {
const char *id;
unsigned short episodes;
unsigned long time;
};
struct timetable_aggregate {
struct timetable_aggregate_entry *entries;
int ptr;
const int size;
};
#define TIMETABLE_AGGREGATE_DECLARE(name) \
struct timetable_aggregate name
#define TIMETABLE_AGGREGATE(name, size) \
static struct timetable_aggregate_entry CC_CONCAT(name,_entries)[size]; \
static struct timetable_aggregate name = { \
CC_CONCAT(name,_entries), \
0, \
size \
}
#define TIMETABLE_AGGREGATE_NONSTATIC(name, size) \
static struct timetable_aggregate_entry CC_CONCAT(name,_entries)[size]; \
struct timetable_aggregate name = { \
CC_CONCAT(name,_entries), \
0, \
size \
}
void timetable_aggregate_print_detailed(struct timetable_aggregate *a);
void timetable_aggregate_print_categories(struct timetable_aggregate *a);
void timetable_aggregate_compute_detailed(struct timetable_aggregate *a,
struct timetable *timetable);
void timetable_aggregate_compute_categories(struct timetable_aggregate *a,
struct timetable *timetable);
#endif /* __TIMETABLE_AGGREGATE_H__ */

128
core/sys/timetable.c Normal file
View File

@ -0,0 +1,128 @@
/*
* Copyright (c) 2008, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
* $Id: timetable.c,v 1.1 2008/01/17 12:19:26 adamdunkels Exp $
*/
/**
* \file
* A brief description of what this file is.
* \author
* Adam Dunkels <adam@sics.se>
*/
#include "sys/timetable.h"
#include <stdio.h>
rtimer_clock_t timetable_timestamp_time;
/*---------------------------------------------------------------------------*/
struct timetable_timestamp *
timetable_entry(struct timetable *t, int num)
{
if(t == NULL) {
return NULL;
}
return &(t->timestamps[num]);
}
/*---------------------------------------------------------------------------*/
int
timetable_ptr(struct timetable *t)
{
return *t->ptr;
}
/*---------------------------------------------------------------------------*/
void
timetable_clear(struct timetable *t)
{
*t->ptr = 0;
}
/*---------------------------------------------------------------------------*/
rtimer_clock_t
timetable_timediff(struct timetable *t,
const char *id1, const char *id2)
{
int i;
int t1, t2;
t1 = t2 = t->size;
for(i = *t->ptr - 1; i >= 0; --i) {
if(t->timestamps[i].id == id1) {
t1 = i;
break;
}
}
for(i = i - 1; i >= 0; --i) {
if(t->timestamps[i].id == id2) {
t2 = i;
break;
}
}
if(t1 != t->size && t2 != t->size) {
return t->timestamps[t1].time - t->timestamps[t2].time;
}
return 0;
}
/*---------------------------------------------------------------------------*/
void
timetable_init(void)
{
char dummy1, dummy2;
#define temp_size 4
TIMETABLE_NONSTATIC(temp);
timetable_clear(&temp);
/* Measure the time for taking a timestamp. */
TIMETABLE_TIMESTAMP(temp, &dummy1);
TIMETABLE_TIMESTAMP(temp, &dummy2);
timetable_timestamp_time = timetable_timediff(&temp, &dummy1, &dummy2);
}
/*---------------------------------------------------------------------------*/
void
timetable_print(struct timetable *t)
{
int i;
int time;
time = t->timestamps[0].time;
printf("---\n");
for(i = 1; i < *t->ptr; ++i) {
printf("%s: %u\n", t->timestamps[i - 1].id, t->timestamps[i].time - time);
time = t->timestamps[i].time;
}
}
/*---------------------------------------------------------------------------*/

140
core/sys/timetable.h Normal file
View File

@ -0,0 +1,140 @@
/*
* Copyright (c) 2008, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* This file is part of the Contiki operating system.
*
* $Id: timetable.h,v 1.1 2008/01/17 12:19:26 adamdunkels Exp $
*/
/**
* \file
* A brief description of what this file is.
* \author
* Adam Dunkels <adam@sics.se>
*/
#ifndef __TIMETABLE_H__
#define __TIMETABLE_H__
#include "sys/cc.h"
#include "sys/rtimer.h"
struct timetable_timestamp {
const char *id;
rtimer_clock_t time;
#if TIMETABLE_WITH_TYPE
uint8_t type;
#endif /* TIMETABLE_WITH_TYPE */
};
struct timetable {
struct timetable_timestamp *timestamps;
const int size;
unsigned int * const ptr;
};
#define TIMETABLE_NONSTATIC(name) \
struct timetable_timestamp CC_CONCAT(name,_timestamps)[CC_CONCAT(name,_size)]; \
unsigned int CC_CONCAT(name,_ptr); \
struct timetable name = { \
CC_CONCAT(name,_timestamps), \
CC_CONCAT(name,_size), \
&CC_CONCAT(name,_ptr)}
#define TIMETABLE_STATIC(name) \
static struct timetable_timestamp CC_CONCAT(name,_timestamps)[CC_CONCAT(name,_size)]; \
static unsigned int CC_CONCAT(name,_ptr); \
static struct timetable name = { \
CC_CONCAT(name,_timestamps), \
CC_CONCAT(name,_size), \
&CC_CONCAT(name,_ptr)}
#define TIMETABLE_DECLARE(name) \
extern unsigned int CC_CONCAT(name,_ptr); \
extern struct timetable_timestamp CC_CONCAT(name, _timestamps)[CC_CONCAT(name,_size)]; \
extern struct timetable name
#define TIMETABLE(name) TIMETABLE_STATIC(name)
#define TIMETABLE_TIMESTAMP(name, str) \
do { \
CC_CONCAT(name,_timestamps)[CC_CONCAT(name,_ptr)].id = str; \
CC_CONCAT(name,_timestamps)[CC_CONCAT(name,_ptr)].time = RTIMER_NOW(); \
CC_CONCAT(name,_ptr) = (CC_CONCAT(name,_ptr) + 1) % \
CC_CONCAT(name,_size); \
} while(0)
#if TIMETABLE_WITH_TYPE
#define TIMETABLE_TIMESTAMP_TYPE(name, str, t) \
do { \
CC_CONCAT(name,_timestamps)[CC_CONCAT(name,_ptr)].id = str; \
CC_CONCAT(name,_timestamps)[CC_CONCAT(name,_ptr)].type = t; \
CC_CONCAT(name,_timestamps)[CC_CONCAT(name,_ptr)].time = RTIMER_NOW(); \
CC_CONCAT(name,_ptr) = (CC_CONCAT(name,_ptr) + 1) % \
CC_CONCAT(name,_size); \
} while(0)
#else /* TIMETABLE_WITH_TYPE */
#define TIMETABLE_TIMESTAMP_TYPE(name, str, t) TIMETABLE_TIMESTAMP(name, str)
#endif /* TIMETABLE_WITH_TYPE */
#define TIMETABLE_RESUME(name,num) \
TIMETABLE_TIMESTAMP(CC_CONCAT(name,_timestamps[num].id))
#define TIMETABLE_COND_TIMESTAMP(cond,name,id) \
do { if(cond) { \
TIMETABLE_TIMESTAMP(id); \
} while(0)
#define TIMETABLE_COND_RESUME(cond,name,num) \
TIMETABLE_COND_TIMESTAMP(cond,name, \
CC_CONCAT(name,_timestamps[num].id))
#define TIMETABLE_ENTRY(name, num) CC_CONCAT(name,_timestamps)[num]
#define TIMETABLE_PTR(name) CC_CONCAT(name,_ptr)
/**
* The time for taking a timestamp.
*/
extern rtimer_clock_t timetable_timestamp_time;
struct timetable_timestamp *timetable_entry(struct timetable *t,
int num);
int timetable_ptr(struct timetable *t);
void timetable_clear(struct timetable *t);
rtimer_clock_t timetable_timediff(struct timetable *t,
const char *id1, const char *id2);
void timetable_init(void);
void timetable_print(struct timetable *t);
#include "sys/timetable-aggregate.h"
#endif /* __TIMETABLE_H__ */