diff --git a/core/sys/profile-aggregates.c b/core/sys/profile-aggregates.c new file mode 100644 index 000000000..1ad3e3a3b --- /dev/null +++ b/core/sys/profile-aggregates.c @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2007, 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: profile-aggregates.c,v 1.1 2007/10/23 20:39:07 adamdunkels Exp $ + */ + +/** + * \file + * Compuation of aggregates for the Contiki profiling system + * \author + * Adam Dunkels + */ + +#include "sys/profile.h" + +#include +#include + +struct aggregate { + const unsigned char *ptr; + unsigned short episodes; + unsigned long cycles; +}; + +#define DETAILED_AGGREGATES 0 + +#define MAX_CATEGORIES 32 +#define LIST_LEN 100 + +static struct aggregate aggregates[LIST_LEN]; + +static int aggregates_list_ptr = 0; + +/*---------------------------------------------------------------------------*/ +static struct aggregate * +find_aggregate_category(const uint16_t cat) +{ + int i; + uint16_t acat; + +/* printf("find_aggregate_category 0x%04x %c%c\n", */ +/* cat, cat >> 8, cat & 0xff); */ + + for(i = 0; i < aggregates_list_ptr; ++i) { + acat = (aggregates[i].ptr[0] << 8) + aggregates[i].ptr[1]; + +/* printf("acat 0x%04x %c%c\n", */ +/* acat, acat >> 8, acat & 0xff); */ + + if(acat == cat) { + return &aggregates[i]; + } + } + + if(i == LIST_LEN) { + return NULL; + } + + aggregates[aggregates_list_ptr].ptr = NULL; + return &aggregates[aggregates_list_ptr++]; +} +/*---------------------------------------------------------------------------*/ +static struct aggregate * +find_aggregate(const unsigned char *ptr) +{ + int i; + for(i = 0; i < aggregates_list_ptr; ++i) { + if(aggregates[i].ptr == ptr) { + return &aggregates[i]; + } + } + if(i == LIST_LEN) { + return NULL; + } + + return &aggregates[aggregates_list_ptr++]; +} +/*---------------------------------------------------------------------------*/ +void +profile_aggregates_print(void) +{ + int i; + +#if DETAILED_AGGREGATES + for(i = 0; i < aggregates_list_ptr; ++i) { + printf("-- %s: %lu / %u = %lu\n", aggregates[i].ptr, + aggregates[i].cycles, + aggregates[i].episodes, + aggregates[i].cycles / aggregates[i].episodes); + } +#else + for(i = 0; i < aggregates_list_ptr; ++i) { + printf("-- %c%c: %lu / %u = %lu\n", + aggregates[i].ptr[0], aggregates[i].ptr[1], + aggregates[i].cycles, + aggregates[i].episodes, + aggregates[i].cycles / aggregates[i].episodes); + } +#endif + + printf("Memory for aggregates: %d * %d = %d\n", + sizeof(struct aggregate), aggregates_list_ptr, + sizeof(struct aggregate) * aggregates_list_ptr); +} +/*---------------------------------------------------------------------------*/ +static void +detailed_profile_aggregates_compute(void) +{ + int i; + rtimer_clock_t t; + /* const char *str = "profile_aggregates_compute"; + + PROFILE_TIMESTAMP(str);*/ + + t = profile_timestamps[0].time; + + for(i = 1; i < PROFILE_TIMESTAMP_PTR; ++i) { + struct aggregate *a; + a = find_aggregate(profile_timestamps[i - 1].ptr); + if(a == NULL) { + /* The list is full, skip this entry */ + printf("profile_aggregates_compute: list full\n"); + } else if(a->ptr == NULL) { + a->ptr = profile_timestamps[i - 1].ptr; + a->cycles = (unsigned long)(profile_timestamps[i].time - t); + a->episodes = 1; + } else { + a->cycles += (unsigned long)(profile_timestamps[i].time - t); + a->episodes++; + } + t = profile_timestamps[i].time; + } + + /* PROFILE_TIMESTAMP(str);*/ + + /*printf("Aggregating time %u, len %d, list len %d, overhead %d\n", + profile_timediff(str, str), PROFILE_TIMESTAMP_PTR, + aggregates_list_ptr, profile_timestamp_time);*/ + + + /* print_aggregates();*/ +} +/*---------------------------------------------------------------------------*/ +static void +category_profile_aggregates_compute(void) +{ + int i,j; + rtimer_clock_t t; + uint16_t categories[MAX_CATEGORIES]; + int categories_ptr = 0; + /* const char *str = "profile_aggregates_compute"; + + PROFILE_TIMESTAMP(str);*/ + + t = profile_timestamps[0].time; + + for(i = 1; i < PROFILE_TIMESTAMP_PTR; ++i) { + struct aggregate *a; + uint16_t cat; + +/* printf("category_profile_aggregates_compute %s\n", */ +/* profile_timestamps[i - 1].ptr); */ + cat = (profile_timestamps[i - 1].ptr[0] << 8) + + (profile_timestamps[i - 1].ptr[1] & 0xff); + a = find_aggregate_category(cat); + if(a == NULL) { + /* The list is full, skip this entry */ + printf("profile_aggregates_compute: list full\n"); + } else if(a->ptr == NULL) { + a->ptr = profile_timestamps[i - 1].ptr; + a->cycles = (unsigned long)(profile_timestamps[i].time - t - profile_timestamp_time); + a->episodes = 1; + } else { + + a->cycles += (unsigned long)(profile_timestamps[i].time - t - profile_timestamp_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++; + a->episodes++; + } + } + t = profile_timestamps[i].time; + } + + /* PROFILE_TIMESTAMP(str);*/ + + /*printf("Aggregating time %u, len %d, list len %d, overhead %d\n", + profile_timediff(str, str), PROFILE_TIMESTAMP_PTR, + aggregates_list_ptr, profile_timestamp_time);*/ + + + /* print_aggregates();*/ +} +/*---------------------------------------------------------------------------*/ +void +profile_aggregates_compute(void) +{ +#if DETAILED_AGGREGATES + detailed_profile_aggregates_compute(); +#else + category_profile_aggregates_compute(); +#endif +} +/*---------------------------------------------------------------------------*/ diff --git a/core/sys/profile.c b/core/sys/profile.c new file mode 100644 index 000000000..df97ef09d --- /dev/null +++ b/core/sys/profile.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2007, 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: profile.c,v 1.1 2007/10/23 20:39:07 adamdunkels Exp $ + */ + +/** + * \file + * Implementation of the Contiki profiling system + * \author + * Adam Dunkels + */ + +#include "sys/profile.h" + +#include /* For NULL */ + +unsigned int profile_timestamp_ptr; +struct profile_timestamp profile_timestamps[PROFILE_LIST_LENGTH]; +rtimer_clock_t profile_timestamp_time; + +int profile_invalid_episode_overflow, profile_invalid_episode_toolong; + +int profile_max_queuelen = 0; + +static rtimer_clock_t episode_start_time; + +/* 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)) + +/*---------------------------------------------------------------------------*/ +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(); +} +/*---------------------------------------------------------------------------*/ +void +profile_episode_start(void) +{ + profile_timestamp_ptr = 0; + + episode_start_time = clock_counter(); + + profile_timestamps[PROFILE_LIST_LENGTH - 1].ptr = NULL; +} +/*---------------------------------------------------------------------------*/ +void +profile_episode_end(void) +{ + rtimer_clock_t episode_end_time = clock_counter(); + + 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) { + /* 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 because of timer overflow. */ + profile_invalid_episode_toolong++; + } else { + /* Compute aggregates. */ + if(PROFILE_TIMESTAMP_PTR > profile_max_queuelen) { + profile_max_queuelen = PROFILE_TIMESTAMP_PTR; + } + profile_aggregates_compute(); + /* printf("Episode length %d\n", profile_timestamp_ptr);*/ + } + +/* profile_aggregates_print(); */ +/* profile_print_stats(); */ +} +/*---------------------------------------------------------------------------*/ +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); +} +/*---------------------------------------------------------------------------*/ diff --git a/core/sys/profile.h b/core/sys/profile.h new file mode 100644 index 000000000..d8f70b378 --- /dev/null +++ b/core/sys/profile.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2007, 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: profile.h,v 1.1 2007/10/23 20:39:07 adamdunkels Exp $ + */ + +/** + * \file + * Header file for the Contiki profiling system + * \author + * Adam Dunkels + */ + +#ifndef __PROFILE_H__ +#define __PROFILE_H__ + +#include "sys/rtimer.h" + +#ifdef EXPERIMENT_SETUP +#include "experiment-setup.h" +#endif + +#include "contiki-conf.h" + +#ifdef PROFILE_CONF_LIST_LENGTH +#define PROFILE_LIST_LENGTH PROFILE_CONF_LIST_LENGTH +#else +#define PROFILE_LIST_LENGTH 128 +#endif + +struct profile_timestamp { + const unsigned char *ptr; + rtimer_clock_t time; +}; + +extern struct profile_timestamp profile_timestamps[PROFILE_LIST_LENGTH]; +extern unsigned int profile_timestamp_ptr; +extern rtimer_clock_t profile_timestamp_time; + +#define PROFILE_TIMESTAMP_PTR (profile_timestamp_ptr / sizeof(struct profile_timestamp)) + +#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_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 */ + +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_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 ; + +*/