From 7b71f23abe2fca8c1ac5b1952b114d53b6f1f84e Mon Sep 17 00:00:00 2001 From: adamdunkels Date: Thu, 17 Jan 2008 12:19:25 +0000 Subject: [PATCH] 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. --- Makefile.include | 2 +- core/sys/profile.c | 227 +++++++++++++++++--------------- core/sys/profile.h | 124 ++++-------------- core/sys/timetable-aggregate.c | 229 +++++++++++++++++++++++++++++++++ core/sys/timetable-aggregate.h | 91 +++++++++++++ core/sys/timetable.c | 128 ++++++++++++++++++ core/sys/timetable.h | 140 ++++++++++++++++++++ 7 files changed, 738 insertions(+), 203 deletions(-) create mode 100644 core/sys/timetable-aggregate.c create mode 100644 core/sys/timetable-aggregate.h create mode 100644 core/sys/timetable.c create mode 100644 core/sys/timetable.h diff --git a/Makefile.include b/Makefile.include index b92cf92fd..129bbd733 100644 --- a/Makefile.include +++ b/Makefile.include @@ -50,7 +50,7 @@ ifdef CHAMELEON include $(CONTIKI)/core/net/chameleon/Makefile.chameleon endif 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 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 \ diff --git a/core/sys/profile.c b/core/sys/profile.c index d6e7d7988..9f16c0b31 100644 --- a/core/sys/profile.c +++ b/core/sys/profile.c @@ -28,7 +28,7 @@ * * 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/clock.h" -#include /* For NULL */ +#include -unsigned int profile_timestamp_ptr; -struct profile_timestamp profile_timestamps[PROFILE_LIST_LENGTH]; -rtimer_clock_t profile_timestamp_time; +/* XXX: the profiling code is under development and may not work at + present. */ -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 unsigned int invalid_episode_overflow, invalid_episode_toolong, + max_queuelen; /* The number of fine grained ticks per coarse grained ticks. We currently (MSP430) have 2457600 ticks per second for the fine 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 profile_init(void) { - profile_clear_timestamps(); - - /* Measure the time for taking a timestamp. */ - PROFILE_TIMESTAMP(NULL); - PROFILE_TIMESTAMP(NULL); - profile_timestamp_time = profile_timestamps[1].time - profile_timestamps[0].time; - - profile_clear_timestamps(); + timetable_init(); + timetable_clear(&profile_begin_timetable); + timetable_clear(&profile_end_timetable); } /*---------------------------------------------------------------------------*/ 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(); - - profile_timestamps[PROFILE_LIST_LENGTH - 1].ptr = NULL; + e = timetable_entry(&profile_begin_timetable, + PROFILE_TIMETABLE_SIZE - 1); + if(e != NULL) { + e->id = NULL; + } + e = timetable_entry(&profile_end_timetable, + PROFILE_TIMETABLE_SIZE - 1); + if(e != NULL) { + e->id = NULL; + } } /*---------------------------------------------------------------------------*/ 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("profile_episode_end start %u, end %u, max time %u\n", episode_start_time, episode_end_time, 65536/FINE_TICKS_PER_COARSE_TICK); */ - if(profile_timestamps[PROFILE_LIST_LENGTH - 1].ptr != NULL) { +/* 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, + PROFILE_TIMETABLE_SIZE - 1); + if(e != NULL && e->id != NULL) { /* Invalid episode because of list overflow. */ - profile_invalid_episode_overflow++; - profile_max_queuelen = PROFILE_LIST_LENGTH; - } else if(episode_end_time - episode_start_time > 65536/FINE_TICKS_PER_COARSE_TICK) { + invalid_episode_overflow++; + max_queuelen = PROFILE_TIMETABLE_SIZE; + } else if(episode_end_time - episode_start_time > + 65536/XXX_HACK_FINE_TICKS_PER_COARSE_TICK) { /* Invalid episode because of timer overflow. */ - profile_invalid_episode_toolong++; + invalid_episode_toolong++; } else { /* Compute aggregates. */ - if(PROFILE_TIMESTAMP_PTR > profile_max_queuelen) { - profile_max_queuelen = PROFILE_TIMESTAMP_PTR; + if(timetable_ptr(&profile_begin_timetable) > max_queuelen) { + max_queuelen = timetable_ptr(&profile_begin_timetable); } - profile_aggregates_compute(); - /* printf("Episode length %d\n", profile_timestamp_ptr);*/ + /* timetable_aggregates_compute();*/ + } +} +/*---------------------------------------------------------------------------*/ +/* + * + * 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); + } + + printf("Memory for entries: %d * %d = %d\n", + (int)sizeof(struct timetable_aggregate), a->ptr, + (int)sizeof(struct timetable_aggregate) * a->ptr); +} +/*---------------------------------------------------------------------------*/ +void +profile_aggregate_compute_detailed(void) +{ + int i; + int last; + rtimer_clock_t t; + struct timetable_aggregate *a = &profile_aggregate; + struct timetable *timetable = &profile_timetable; + 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);*/ + } -/* profile_aggregates_print(); */ -/* profile_print_stats(); */ } /*---------------------------------------------------------------------------*/ -#if 0 -#include -void -profile_print_stats(void) -{ - printf("Memory for profiling: %d * %d = %d\n", - sizeof(struct profile_timestamp), profile_max_queuelen, - sizeof(struct profile_timestamp) * profile_max_queuelen); - printf("Invalid episodes overflow %d time %d\n", - profile_invalid_episode_overflow, - profile_invalid_episode_toolong); -} -#endif /* 0 */ -/*---------------------------------------------------------------------------*/ diff --git a/core/sys/profile.h b/core/sys/profile.h index 28d5c13ec..bd9c3226e 100644 --- a/core/sys/profile.h +++ b/core/sys/profile.h @@ -28,7 +28,7 @@ * * 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__ #define __PROFILE_H__ -#include "sys/rtimer.h" +/* XXX: the profiling code is under development and may not work at + present. */ -#ifdef EXPERIMENT_SETUP -#include "experiment-setup.h" -#endif +#define TIMETABLE_WITH_TYPE 1 +#include "sys/timetable.h" -#include "contiki-conf.h" - -#ifdef PROFILE_CONF_LIST_LENGTH -#define PROFILE_LIST_LENGTH PROFILE_CONF_LIST_LENGTH +#ifdef PROFILE_CONF_TIMETABLE_SIZE +#define PROFILE_TIMETABLE_SIZE PROFILE_CONF_TIMETABLE_SIZE #else -#define PROFILE_LIST_LENGTH 128 +#define PROFILE_TIMETABLE_SIZE 128 #endif -struct profile_timestamp { - const char *ptr; - rtimer_clock_t time; -}; +#ifdef PROFILE_CONF_AGGREGATE_SIZE +#define PROFILE_AGGREGATE_SIZE PROFILE_CONF_AGGREGATE_SIZE +#else +#define PROFILE_AGGREGATE_SIZE 128 +#endif -extern struct profile_timestamp profile_timestamps[PROFILE_LIST_LENGTH]; -extern unsigned int profile_timestamp_ptr; -extern rtimer_clock_t profile_timestamp_time; +#define PROFILE_BEGIN(id) TIMETABLE_TIMESTAMP_TYPE(profile_timetable, id, 1) +#define PROFILE_END(id) TIMETABLE_TIMESTAMP_TYPE(profile_timetable, id, 2) -#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_TIMESTAMP(str) \ - do { \ - profile_timestamps[profile_timestamp_ptr / sizeof(struct profile_timestamp)].ptr = str; \ - 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_begin_timetable_size PROFILE_TIMETABLE_SIZE +TIMETABLE_DECLARE(profile_begin_timetable); +#define profile_end_timetable_size PROFILE_TIMETABLE_SIZE +TIMETABLE_DECLARE(profile_end_timetable); -#define PROFILE_COND_TIMESTAMP(cond, ptr) do { if(cond) {PROFILE_TIMESTAMP(ptr);} } while(0) -#define PROFILE_COND_RESUME(cond, num) PROFILE_COND_TIMESTAMP(cond, profile_timestamps[num].ptr) -#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 */ +#define profile_timetable_size PROFILE_TIMETABLE_SIZE +TIMETABLE_DECLARE(profile_timetable); -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_episode_start(void); void profile_episode_end(void); -void profile_aggregates_print(void); -void profile_aggregates_compute(void); +void profile_aggregate_print_detailed(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__ */ - -/* 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 ; - -*/ diff --git a/core/sys/timetable-aggregate.c b/core/sys/timetable-aggregate.c new file mode 100644 index 000000000..dabe4189e --- /dev/null +++ b/core/sys/timetable-aggregate.c @@ -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 + */ + +#include "sys/timetable-aggregate.h" + +#define XXX_HACK_MAX_CATEGORIES 32 + +#include + +/*---------------------------------------------------------------------------*/ +/* + * + * 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; + } +} +/*---------------------------------------------------------------------------*/ diff --git a/core/sys/timetable-aggregate.h b/core/sys/timetable-aggregate.h new file mode 100644 index 000000000..d7bc72b6e --- /dev/null +++ b/core/sys/timetable-aggregate.h @@ -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 + */ + +#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__ */ diff --git a/core/sys/timetable.c b/core/sys/timetable.c new file mode 100644 index 000000000..ce226acf4 --- /dev/null +++ b/core/sys/timetable.c @@ -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 + */ + +#include "sys/timetable.h" + +#include + +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; + } +} +/*---------------------------------------------------------------------------*/ diff --git a/core/sys/timetable.h b/core/sys/timetable.h new file mode 100644 index 000000000..46aced967 --- /dev/null +++ b/core/sys/timetable.h @@ -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 + */ + +#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__ */