From 2a86615b98ee22eb2cb664011f97ae3a4d07e294 Mon Sep 17 00:00:00 2001 From: Jennifer Averett Date: Tue, 5 Aug 2014 15:48:01 -0500 Subject: capture: Add support for variable length records. --- cpukit/libmisc/capture/capture-cli.c | 7 +- cpukit/libmisc/capture/capture.c | 174 +++++++++++++++--------- cpukit/libmisc/capture/capture.h | 1 + cpukit/libmisc/capture/capture_buffer.c | 117 ++++++++++++++++ cpukit/libmisc/capture/capture_buffer.h | 105 ++++++++++++++ cpukit/libmisc/capture/capture_user_extension.c | 17 +++ cpukit/libmisc/capture/captureimpl.h | 116 ++++++++++++++++ 7 files changed, 467 insertions(+), 70 deletions(-) create mode 100644 cpukit/libmisc/capture/capture_buffer.c create mode 100644 cpukit/libmisc/capture/capture_buffer.h (limited to 'cpukit/libmisc/capture') diff --git a/cpukit/libmisc/capture/capture-cli.c b/cpukit/libmisc/capture/capture-cli.c index 9c978d28d9..2aa7c9c229 100644 --- a/cpukit/libmisc/capture/capture-cli.c +++ b/cpukit/libmisc/capture/capture-cli.c @@ -1353,6 +1353,7 @@ rtems_capture_cli_trace_records (int argc, int count; uint32_t read; rtems_capture_record_t* rec; + uint8_t* ptr; int arg; rtems_capture_time_t last_t = 0; @@ -1408,9 +1409,11 @@ rtems_capture_cli_trace_records (int argc, } count = total < read ? total : read; - + ptr = (uint8_t *) rec; while (count--) { + rec = (rtems_capture_record_t*) ptr; + if (csv) fprintf (stdout, "%08" PRIxPTR ",%03" PRIu32 ",%03" PRIu32 ",%04" PRIx32 ",%" PRId64 "\n", @@ -1450,7 +1453,7 @@ rtems_capture_cli_trace_records (int argc, event >>= 1; } } - rec++; + ptr += rec->size; } count = total < read ? total : read; diff --git a/cpukit/libmisc/capture/capture.c b/cpukit/libmisc/capture/capture.c index 54b289439b..64d2699f88 100644 --- a/cpukit/libmisc/capture/capture.c +++ b/cpukit/libmisc/capture/capture.c @@ -30,6 +30,7 @@ #include #include "captureimpl.h" +#include "capture_buffer.h" #include #include @@ -52,7 +53,9 @@ RTEMS_CAPTURE_DELETED_EVENT | \ RTEMS_CAPTURE_BEGIN_EVENT | \ RTEMS_CAPTURE_EXITTED_EVENT | \ - RTEMS_CAPTURE_TERMINATED_EVENT) + RTEMS_CAPTURE_TERMINATED_EVENT | \ + RTEMS_CAPTURE_AUTOGEN_ENTRY_EVENT | \ + RTEMS_CAPTURE_AUTOGEN_EXIT_EVENT) #else #define RTEMS_CAPTURE_RECORD_EVENTS (0) #endif @@ -61,11 +64,8 @@ /* * RTEMS Capture Data. */ -static rtems_capture_record_t* capture_records; -static uint32_t capture_size; +static rtems_capture_buffer_t capture_records = {NULL, 0, 0, 0, 0, 0}; static uint32_t capture_count; -static rtems_capture_record_t* capture_in; -static uint32_t capture_out; static uint32_t capture_flags; static rtems_capture_task_t* capture_tasks; static rtems_capture_control_t* capture_controls; @@ -464,16 +464,12 @@ rtems_capture_destroy_capture_task (rtems_capture_task_t* task) } /* - * This function records a capture record into the capture buffer. + * This function indicates if data should be filtered from the + * log. */ -void -rtems_capture_record (rtems_capture_task_t* task, - uint32_t events) +bool rtems_capture_filter( rtems_capture_task_t* task, + uint32_t events) { - /* - * Check the watch state if we have a task control, and - * the task's real priority is lower or equal to the ceiling. - */ if (task && ((capture_flags & (RTEMS_CAPTURE_TRIGGERED | RTEMS_CAPTURE_ONLY_MONITOR)) == @@ -494,35 +490,55 @@ rtems_capture_record (rtems_capture_task_t* task, ((capture_flags & RTEMS_CAPTURE_GLOBAL_WATCH) || (control && (control->flags & RTEMS_CAPTURE_WATCH))))) { - rtems_interrupt_lock_context lock_context; + return false; + } + } - rtems_interrupt_lock_acquire (&capture_lock, &lock_context); + return true; +} - if (capture_count < capture_size) - { - capture_count++; - capture_in->task = task; - capture_in->events = (events | - (task->tcb->real_priority) | - (task->tcb->current_priority << 8)); +/* + * This function records a capture record into the capture buffer. + */ +void * +rtems_capture_record_open (rtems_capture_task_t* task, + uint32_t events, + size_t size, + rtems_interrupt_lock_context* lock_context) +{ + uint8_t* ptr; + rtems_capture_record_t* capture_in; - if ((events & RTEMS_CAPTURE_RECORD_EVENTS) == 0) - task->flags |= RTEMS_CAPTURE_TRACED; + rtems_interrupt_lock_acquire (&capture_lock, lock_context); - rtems_capture_get_time (&capture_in->time); + ptr = rtems_capture_buffer_allocate(&capture_records, size); + capture_in = (rtems_capture_record_t *) ptr; + if ( capture_in ) + { + capture_count++; + capture_in->size = size; + capture_in->task = task; + capture_in->events = (events | + (task->tcb->real_priority) | + (task->tcb->current_priority << 8)); - if (capture_in == &capture_records[capture_size - 1]) - capture_in = capture_records; - else - capture_in++; + if ((events & RTEMS_CAPTURE_RECORD_EVENTS) == 0) + task->flags |= RTEMS_CAPTURE_TRACED; - rtems_capture_refcount_up (task); - } - else - capture_flags |= RTEMS_CAPTURE_OVERFLOW; - rtems_interrupt_lock_release (&capture_lock, &lock_context); - } + rtems_capture_get_time (&capture_in->time); + + rtems_capture_refcount_up (task); + ptr = ptr + sizeof(*capture_in); } + else + capture_flags |= RTEMS_CAPTURE_OVERFLOW; + + return ptr; +} + +void rtems_capture_record_close( void *rec, rtems_interrupt_lock_context* lock_context) +{ + rtems_interrupt_lock_release (&capture_lock, lock_context); } /* @@ -607,18 +623,15 @@ rtems_capture_open (uint32_t size, rtems_capture_timestamp timestamp __attribu * See if the capture engine is already open. */ - if (capture_records) + if (capture_records.buffer) return RTEMS_RESOURCE_IN_USE; - capture_records = malloc (size * sizeof (rtems_capture_record_t)); + rtems_capture_buffer_create( &capture_records, size ); - if (capture_records == NULL) + if (capture_records.buffer == NULL) return RTEMS_NO_MEMORY; - capture_size = size; capture_count = 0; - capture_in = capture_records; - capture_out = 0; capture_flags = 0; capture_tasks = NULL; capture_ceiling = 0; @@ -628,8 +641,7 @@ rtems_capture_open (uint32_t size, rtems_capture_timestamp timestamp __attribu if (sc != RTEMS_SUCCESSFUL) { - free (capture_records); - capture_records = NULL; + rtems_capture_buffer_destroy( &capture_records); } /* @@ -653,7 +665,7 @@ rtems_capture_close (void) rtems_interrupt_lock_acquire (&capture_lock, &lock_context); - if (!capture_records) + if (!capture_records.buffer) { rtems_interrupt_lock_release (&capture_lock, &lock_context); return RTEMS_SUCCESSFUL; @@ -661,8 +673,6 @@ rtems_capture_close (void) capture_flags &= ~(RTEMS_CAPTURE_ON | RTEMS_CAPTURE_ONLY_MONITOR); - capture_records = NULL; - rtems_interrupt_lock_release (&capture_lock, &lock_context); /* @@ -697,10 +707,9 @@ rtems_capture_close (void) capture_controls = NULL; - if (capture_records) + if (capture_records.buffer) { - free (capture_records); - capture_records = NULL; + rtems_capture_buffer_destroy( &capture_records); } return RTEMS_SUCCESSFUL; @@ -722,7 +731,7 @@ rtems_capture_control (bool enable) rtems_interrupt_lock_acquire (&capture_lock, &lock_context); - if (!capture_records) + if (!capture_records.buffer) { rtems_interrupt_lock_release (&capture_lock, &lock_context); return RTEMS_UNSATISFIED; @@ -752,7 +761,7 @@ rtems_capture_monitor (bool enable) rtems_interrupt_lock_acquire (&capture_lock, &lock_context); - if (!capture_records) + if (!capture_records.buffer) { rtems_interrupt_lock_release (&capture_lock, &lock_context); return RTEMS_UNSATISFIED; @@ -791,9 +800,8 @@ rtems_capture_flush (bool prime) else capture_flags &= ~RTEMS_CAPTURE_OVERFLOW; + rtems_capture_buffer_flush( &capture_records ); capture_count = 0; - capture_in = capture_records; - capture_out = 0; rtems_interrupt_lock_release (&capture_lock, &lock_context); @@ -1195,6 +1203,26 @@ rtems_capture_clear_trigger (rtems_name from_name, return RTEMS_SUCCESSFUL; } +static inline uint32_t rtems_capture_count_records( void* recs, size_t size ) +{ + rtems_capture_record_t* rec; + uint8_t* ptr = recs; + uint32_t rec_count = 0; + size_t byte_count = 0; + + + while (byte_count < size) { + rec = (rtems_capture_record_t*) ptr; + rec_count++; + _Assert( rec->size >= sizeof(*rec) ); + ptr += rec->size; + byte_count += rec->size; + _Assert( rec_count <= capture_count ); + }; + + return rec_count; +} + /* * This function reads a number of records from the capture buffer. * The user can optionally block and wait until the buffer as a @@ -1229,7 +1257,8 @@ rtems_capture_read (uint32_t threshold, { rtems_interrupt_lock_context lock_context; rtems_status_code sc = RTEMS_SUCCESSFUL; - uint32_t count; + size_t recs_size = 0; + bool wrapped; *read = 0; *recs = NULL; @@ -1247,25 +1276,24 @@ rtems_capture_read (uint32_t threshold, } capture_flags |= RTEMS_CAPTURE_READER_ACTIVE; - *read = count = capture_count; - rtems_interrupt_lock_release (&capture_lock, &lock_context); + *recs = rtems_capture_buffer_peek( &capture_records, &recs_size ); + *read = rtems_capture_count_records( *recs, recs_size ); - *recs = &capture_records[capture_out]; + rtems_interrupt_lock_release (&capture_lock, &lock_context); for (;;) { /* - * See if the count wraps the end of the record buffer. + * See if the data wraps the end of the record buffer. */ - if (count && ((capture_out + count) >= capture_size)) - *read = capture_size - capture_out; + wrapped = rtems_capture_buffer_has_wrapped( &capture_records); /* - * Do we have a threshold and the current count has not wrapped + * Do we have a threshold and have not wrapped * around the end of the capture record buffer ? */ - if ((*read == count) && threshold) + if ((!wrapped) && threshold) { /* * Do we have enough records ? @@ -1297,7 +1325,8 @@ rtems_capture_read (uint32_t threshold, rtems_interrupt_lock_acquire (&capture_lock, &lock_context); - *read = count = capture_count; + *recs = rtems_capture_buffer_peek( &capture_records, &recs_size ); + *read = rtems_capture_count_records( *recs, recs_size ); rtems_interrupt_lock_release (&capture_lock, &lock_context); @@ -1322,8 +1351,10 @@ rtems_status_code rtems_capture_release (uint32_t count) { rtems_interrupt_lock_context lock_context; + uint8_t* ptr; rtems_capture_record_t* rec; uint32_t counted; + size_t ptr_size = 0; rtems_interrupt_lock_acquire (&capture_lock, &lock_context); @@ -1333,21 +1364,26 @@ rtems_capture_release (uint32_t count) rtems_interrupt_lock_release (&capture_lock, &lock_context); counted = count; + + ptr = rtems_capture_buffer_peek( &capture_records, &ptr_size ); + _Assert(ptr_size >= (count * sizeof(*rec) )); - rec = &capture_records[capture_out]; - + ptr_size = 0; while (counted--) - { + { + rec = (rtems_capture_record_t*) ptr; + ptr_size += rec->size; rtems_capture_refcount_down (rec->task); rtems_capture_destroy_capture_task (rec->task); - rec++; + ptr += rec->size; } rtems_interrupt_lock_acquire (&capture_lock, &lock_context); capture_count -= count; - capture_out = (capture_out + count) % capture_size; + if (count) + rtems_capture_buffer_free( &capture_records, ptr_size ); capture_flags &= ~RTEMS_CAPTURE_READER_ACTIVE; @@ -1430,3 +1466,5 @@ rtems_capture_get_control_list (void) { return capture_controls; } + + diff --git a/cpukit/libmisc/capture/capture.h b/cpukit/libmisc/capture/capture.h index 737c73f754..8bc2fc3f3b 100644 --- a/cpukit/libmisc/capture/capture.h +++ b/cpukit/libmisc/capture/capture.h @@ -191,6 +191,7 @@ typedef struct rtems_capture_record_s rtems_capture_task_t* task; uint32_t events; rtems_capture_time_t time; + size_t size; } rtems_capture_record_t; /** diff --git a/cpukit/libmisc/capture/capture_buffer.c b/cpukit/libmisc/capture/capture_buffer.c new file mode 100644 index 0000000000..9557f70ba8 --- /dev/null +++ b/cpukit/libmisc/capture/capture_buffer.c @@ -0,0 +1,117 @@ +/* + ------------------------------------------------------------------------ + + COPYRIGHT (c) 2014. + On-Line Applications Research Corporation (OAR). + + The license and distribution terms for this file may be + found in the file LICENSE in this distribution. + + This software with is provided ``as is'' and with NO WARRANTY. + + ------------------------------------------------------------------------ + + RTEMS Performance Monitoring and Measurement Framework. + + This is the Target Interface Command Line Interface. You need + start the RTEMS monitor. + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "capture_buffer.h" + +void * rtems_capture_buffer_allocate( rtems_capture_buffer_t* buffer, size_t size ) +{ + static uint32_t end; + static void *ptr; + + if ( rtems_capture_buffer_is_full( buffer ) ) + return NULL; + + if ( (buffer->count + size) > buffer->end ) + return NULL; + + /* + * Determine if the end of free space is marked with + * the end of buffer space, or the head of allocated + * space. + * + * |...|head| freespace |tail| ...| end + * + * tail|.....|head| freespace| end + * + */ + if (buffer->tail > buffer->head) { + end = buffer->tail; + } else { + end = buffer->end; + } + + /* + * Can we allocate it easily? + */ + if ((buffer->head + size) <= end) { + ptr = &buffer->buffer[ buffer->head ]; + buffer->head += size; + buffer->count = buffer->count + size; + return ptr; + } + + /* + * We have to consider wrapping around to the front of the buffer + */ + + /* If there is not room at the end of the buffer */ + /* and we have we already wrapped then we can't allocate */ + if ( end == buffer->tail ) + return NULL; + + /* Is there no room at the front of the buffer */ + if ( (buffer->tail < size )) + return NULL; + + /* change the end pointer to the last used byte, so a read will wrap when out of data */ + buffer->end = buffer->head; + + /* now return the buffer */ + ptr = buffer->buffer; + buffer->head = size; + buffer->count = buffer->count + size; + + return ptr; +} + +void *rtems_capture_buffer_free( rtems_capture_buffer_t* buffer, size_t size ) +{ + static void *ptr; + static uint32_t next; + size_t buff_size; + + if (size == 0) + return NULL; + + ptr = rtems_capture_buffer_peek(buffer, &buff_size); + next = buffer->tail + size; + + /* Check if we are freeing space past the end of the buffer */ + _Assert( ! rtems_capture_buffer_is_empty( buffer ) ); + _Assert( !((buffer->tail > buffer->head) && (next > buffer->end)) ); + _Assert( !((buffer->tail < buffer->head) && (next > buffer->head)) ); + + buffer->count = buffer->count - size; + + if (next == buffer->end) { + buffer->end = buffer->size; + buffer->tail = 0; + } else { + buffer->tail = next; + } + + return ptr; +} diff --git a/cpukit/libmisc/capture/capture_buffer.h b/cpukit/libmisc/capture/capture_buffer.h new file mode 100644 index 0000000000..a01ca29654 --- /dev/null +++ b/cpukit/libmisc/capture/capture_buffer.h @@ -0,0 +1,105 @@ +/** + * @file capture_buffer.h + * + * @brief Capture buffer + * + * This is a set of functions to control a variable length capture record buffer. + */ + +/* + ------------------------------------------------------------------------ + + COPYRIGHT (c) 2014. + On-Line Applications Research Corporation (OAR). + + The license and distribution terms for this file may be + found in the file LICENSE in this distribution. + + This software with is provided ``as is'' and with NO WARRANTY. + + ------------------------------------------------------------------------ +*/ + +#ifndef __CAPTUREBUFFER_H_ +#define __CAPTUREBUFFER_H_ + +#include + + +/**@{*/ +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint8_t *buffer; + size_t size; + volatile uint32_t count; + volatile uint32_t head; + volatile uint32_t tail; + volatile uint32_t end; +} rtems_capture_buffer_t; + +static inline void rtems_capture_buffer_flush( rtems_capture_buffer_t* buffer ) +{ + buffer->end = buffer->size; + buffer->head = buffer->tail = 0; + buffer->count = 0; +} + +static inline void rtems_capture_buffer_create( rtems_capture_buffer_t* buffer, size_t size ) +{ + buffer->buffer = malloc(size); + buffer->size = size; + rtems_capture_buffer_flush( buffer ); +} + +static inline void rtems_capture_buffer_destroy( rtems_capture_buffer_t* buffer ) +{ + rtems_capture_buffer_flush( buffer ); + free( buffer->buffer); + buffer->buffer = NULL; +} + +static inline bool rtems_capture_buffer_is_empty( rtems_capture_buffer_t* buffer ) +{ + return( buffer->count == 0 ); +} + +static inline bool rtems_capture_buffer_is_full( rtems_capture_buffer_t* buffer ) +{ + return (buffer->count == buffer->size); +} + +static inline bool rtems_capture_buffer_has_wrapped( rtems_capture_buffer_t* buffer ) +{ + if ( buffer->tail > buffer->head) + return true; + + return false; +} + +static inline void *rtems_capture_buffer_peek( rtems_capture_buffer_t* buffer, size_t *size ) +{ + if (rtems_capture_buffer_is_empty(buffer)) { + *size = 0; + return NULL; + } + + if ( buffer->tail > buffer->head) + *size = buffer->end - buffer->tail; + else + *size = buffer->head - buffer->tail; + + return &buffer->buffer[ buffer->tail ]; +} + +void *rtems_capture_buffer_allocate( rtems_capture_buffer_t* buffer, size_t size ); + +void *rtems_capture_buffer_free( rtems_capture_buffer_t* buffer, size_t size ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/cpukit/libmisc/capture/capture_user_extension.c b/cpukit/libmisc/capture/capture_user_extension.c index f3bebc829a..4236d8caeb 100644 --- a/cpukit/libmisc/capture/capture_user_extension.c +++ b/cpukit/libmisc/capture/capture_user_extension.c @@ -84,6 +84,23 @@ static const rtems_extensions_table capture_extensions = { .thread_terminate = rtems_capture_terminated_task }; + +static inline void rtems_capture_record ( + rtems_capture_task_t* task, + uint32_t events +) +{ + rtems_capture_record_t* rec; + + if (rtems_capture_filter( task, events) ) + return; + + rtems_capture_begin_add_record (task, events, sizeof(*rec), &rec); + + rtems_capture_end_add_record ( rec ); +} + + rtems_status_code rtems_capture_user_extension_open(void) { rtems_status_code sc; diff --git a/cpukit/libmisc/capture/captureimpl.h b/cpukit/libmisc/capture/captureimpl.h index ee18d827ad..fa366889b7 100644 --- a/cpukit/libmisc/capture/captureimpl.h +++ b/cpukit/libmisc/capture/captureimpl.h @@ -154,6 +154,89 @@ rtems_capture_task_t* rtems_capture_create_capture_task (rtems_tcb* new_task); bool rtems_capture_trigger (rtems_capture_task_t* ft, rtems_capture_task_t* tt, uint32_t events); + +/** + * @brief Capture append to record + * + * This function Capture appends data to a capture record. It should + * be called between rtems_capture_begin_add_record and + * rtems_capture_end_add_record. + * + * @param[in] rec specifies the next location to write in the record + * @param[in] data specifies the data to write + * @param[in] size specifies specifies the size of the data + * + * @retval This method returns a pointer which is used as a marker + * for the next location in the capture record. it should only be + * used as input into rtems_capture_append_to_record or + * rtems_capture_end_add_record. + */ +static void *rtems_capture_append_to_record(void* rec, + void* data, + size_t size ); + +/** + * @brief Capture filter + * + * This function this function specifies if the given task + * and events should be logged. + * + * @param[in] task specifies the capture task control block + * @param[in] events specifies the events + * + * @retval This method returns true if this data should be + * filtered from the log. It returns false if this data + * should be logged. + */ +bool rtems_capture_filter( rtems_capture_task_t* task, + uint32_t events); +/** + * @brief Capture begin add record. + * + * This function opens a record for writing and inserts + * the header information + * + * @param[in] _task specifies the capture task block + * @param[in] _events specifies the events + * @param[in] _size specifies the expected size of the capture record + * @param[out] _rec specifies the next write point in the capture record + */ +#define rtems_capture_begin_add_record( _task, _events, _size, _rec) \ + do { \ + rtems_interrupt_lock_context _lock_context; \ + *_rec = rtems_capture_record_open( _task, _events, _size, &_lock_context ); + +/** + * @brief Capture append to record. + * + * This function appends data of a specifed size into a capture record. + * + * @param[in] rec specifies the next write point in the capture record + * @param[in] data specifies the data to write + * @param[in] size specifies the size of the data + * + * @retval This method returns the next write point in the capture record. + */ +static inline void *rtems_capture_append_to_record(void* rec, + void* data, + size_t size ) +{ + uint8_t *ptr = rec; + memcpy( ptr, data, size ); + return (ptr + size); +} + +/** + * @brief Capture end add record. + * + * This function completes the add capture record process + * + * @param[in] _rec specifies the end of the capture record + */ +#define rtems_capture_end_add_record( _rec ) \ + rtems_capture_record_close( _rec, &_lock_context ); \ + } while (0) + /** * @brief Capture initialize stack usage * @@ -187,6 +270,39 @@ void rtems_capture_destroy_capture_task (rtems_capture_task_t* task); */ void rtems_capture_get_time (rtems_capture_time_t* time); +/** + * @brief Capture record open. + * + * This function allocates a record and fills in the + * header information. It does a lock acquire + * which will remain in effect until + * rtems_capture_record_close is called. This method + * should only be used by rtems_capture_begin_add_record. + * + * @param[in] task specifies the caputre task block + * @param[in] events specifies the events + * @param[in] size specifies capture record size + * @param[out] lock_context specifies the lock context + * + * @retval This method returns a pointer to the next location in + * the capture record to store data. + */ +void* rtems_capture_record_open (rtems_capture_task_t* task, + uint32_t events, + size_t size, + rtems_interrupt_lock_context* lock_context); +/** + * @brief Capture record close. + * + * This function closes writing to capure record and + * releases the lock that was held on the record. This + * method should only be used by rtems_capture_end_add_record. + * + * @param[in] rec specifies the record + * @param[out] lock_context specifies the lock context + */ +void rtems_capture_record_close( void *rec, rtems_interrupt_lock_context* lock_context); + #ifdef __cplusplus } -- cgit v1.2.3