capture: Add support for variable length records.

This commit is contained in:
Jennifer Averett
2014-08-05 15:48:01 -05:00
parent 133962bf2f
commit 2a86615b98
10 changed files with 480 additions and 77 deletions

View File

@@ -149,6 +149,7 @@ include_rtems_HEADERS += libmisc/bspcmdline/bspcmdline.h
## capture
include_rtems_HEADERS += libmisc/capture/capture.h
include_rtems_HEADERS += libmisc/capture/capture-cli.h
include_rtems_HEADERS += libmisc/capture/captureimpl.h
## cpuuse
include_rtems_HEADERS += libmisc/cpuuse/cpuuse.h

View File

@@ -18,8 +18,9 @@ EXTRA_DIST += capture/README
noinst_LIBRARIES += libcapture.a
libcapture_a_SOURCES = capture/capture.c capture/capture-cli.c \
capture/capture_user_extension.c \
capture/capture.h capture/captureimpl.h capture/capture-cli.h
capture/capture_user_extension.c capture/capture_buffer.c \
capture/capture.h capture/captureimpl.h capture/capture-cli.h \
capture/capture_buffer.h
## cpuuse
EXTRA_DIST += cpuuse/README

View File

@@ -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;

View File

@@ -30,6 +30,7 @@
#include <rtems/rtems/tasksimpl.h>
#include "captureimpl.h"
#include "capture_buffer.h"
#include <rtems/score/statesimpl.h>
#include <rtems/score/todimpl.h>
@@ -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;
rtems_interrupt_lock_acquire (&capture_lock, &lock_context);
if (capture_count < capture_size)
{
capture_count++;
capture_in->task = task;
capture_in->events = (events |
(task->tcb->real_priority) |
(task->tcb->current_priority << 8));
if ((events & RTEMS_CAPTURE_RECORD_EVENTS) == 0)
task->flags |= RTEMS_CAPTURE_TRACED;
rtems_capture_get_time (&capture_in->time);
if (capture_in == &capture_records[capture_size - 1])
capture_in = capture_records;
else
capture_in++;
rtems_capture_refcount_up (task);
}
else
capture_flags |= RTEMS_CAPTURE_OVERFLOW;
rtems_interrupt_lock_release (&capture_lock, &lock_context);
return false;
}
}
return true;
}
/*
* 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;
rtems_interrupt_lock_acquire (&capture_lock, lock_context);
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 ((events & RTEMS_CAPTURE_RECORD_EVENTS) == 0)
task->flags |= RTEMS_CAPTURE_TRACED;
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;
*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);
*recs = &capture_records[capture_out];
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;
}

View File

@@ -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;
/**

View File

@@ -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 <rtems.h>
#include <rtems/score/assert.h>
#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;
}

View File

@@ -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 <stdlib.h>
/**@{*/
#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

View File

@@ -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;

View File

@@ -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
}

View File

@@ -330,6 +330,10 @@ $(PROJECT_INCLUDE)/rtems/capture-cli.h: libmisc/capture/capture-cli.h $(PROJECT_
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/capture-cli.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/capture-cli.h
$(PROJECT_INCLUDE)/rtems/captureimpl.h: libmisc/capture/captureimpl.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/captureimpl.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/captureimpl.h
$(PROJECT_INCLUDE)/rtems/cpuuse.h: libmisc/cpuuse/cpuuse.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/cpuuse.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/cpuuse.h