tracing: add infrastructure for collection of tracing data
First, this commit adds user interface in tracing_format.h which can trace both string format and data format packet. Second, it adds method both for asynchronous and synchronous way. For asynchronous method, tracing packet will be buffered in tracing buffer first, tracing thread will output the stream data with the help of tracing backend when tracing thread get scheduled. Third, it adds UART and USB tracing backend for asynchronous tracing method, and adds POSIX tracing backend for synchronous tracing way. Also it can receive command from host to dynamically enable and disable tracing to have host capture tracing data conveniently. Signed-off-by: Wentong Wu <wentong.wu@intel.com>
This commit is contained in:
parent
6c218ac2c6
commit
8ccc04de6a
16 changed files with 1410 additions and 10 deletions
79
include/debug/tracing_format.h
Normal file
79
include/debug/tracing_format.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_TRACE_FORMAT_H
|
||||||
|
#define ZEPHYR_INCLUDE_TRACE_FORMAT_H
|
||||||
|
|
||||||
|
#include <toolchain/common.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A structure to represent tracing data format.
|
||||||
|
*/
|
||||||
|
typedef struct tracing_data {
|
||||||
|
u8_t *data;
|
||||||
|
u32_t length;
|
||||||
|
} __packed tracing_data_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Macro to trace a message in string format.
|
||||||
|
*/
|
||||||
|
#define TRACING_STRING(fmt, ...) \
|
||||||
|
do { \
|
||||||
|
tracing_format_string(fmt, ##__VA_ARGS__); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Macro to format data to tracing data format.
|
||||||
|
*/
|
||||||
|
#define TRACING_FORMAT_DATA(x) \
|
||||||
|
((struct tracing_data){.data = (u8_t *)&(x), .length = sizeof((x))})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Macro to trace a message in tracing data format.
|
||||||
|
*
|
||||||
|
* All the parameters should be struct tracing_data.
|
||||||
|
*/
|
||||||
|
#define TRACING_DATA(...) \
|
||||||
|
do { \
|
||||||
|
struct tracing_data arg[] = {__VA_ARGS__}; \
|
||||||
|
\
|
||||||
|
tracing_format_data(arg, sizeof(arg) / \
|
||||||
|
sizeof(struct tracing_data)); \
|
||||||
|
} while (false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tracing a message in string format.
|
||||||
|
*
|
||||||
|
* @param str String to format.
|
||||||
|
* @param ... Variable length arguments.
|
||||||
|
*/
|
||||||
|
void tracing_format_string(const char *str, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tracing a message in raw data format.
|
||||||
|
*
|
||||||
|
* @param data Raw data to be traced.
|
||||||
|
* @param length Raw data length.
|
||||||
|
*/
|
||||||
|
void tracing_format_raw_data(u8_t *data, u32_t length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tracing a message in tracing data format.
|
||||||
|
*
|
||||||
|
* @param tracing_data_array Tracing_data format data array to be traced.
|
||||||
|
* @param count Tracing_data array data count.
|
||||||
|
*/
|
||||||
|
void tracing_format_data(tracing_data_t *tracing_data_array, u32_t count);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -160,3 +160,10 @@
|
||||||
KEEP(*(SORT_BY_NAME("._cfb_font.*")))
|
KEEP(*(SORT_BY_NAME("._cfb_font.*")))
|
||||||
__font_entry_end = .;
|
__font_entry_end = .;
|
||||||
} GROUP_LINK_IN(ROMABLE_REGION)
|
} GROUP_LINK_IN(ROMABLE_REGION)
|
||||||
|
|
||||||
|
SECTION_DATA_PROLOGUE(tracing_backends_sections,,)
|
||||||
|
{
|
||||||
|
_tracing_backend_list_start = .;
|
||||||
|
KEEP(*("._tracing_backend.*"));
|
||||||
|
_tracing_backend_list_end = .;
|
||||||
|
} GROUP_LINK_IN(ROMABLE_REGION)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
# Copyright (c) 2015 Wind River Systems, Inc.
|
# Copyright (c) 2015 Wind River Systems, Inc.
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
DT_CHOSEN_Z_CONSOLE := zephyr,console
|
||||||
|
|
||||||
menu "System Monitoring Options"
|
menu "System Monitoring Options"
|
||||||
|
|
||||||
config BOOT_TIME_MEASUREMENT
|
config BOOT_TIME_MEASUREMENT
|
||||||
|
@ -43,6 +45,121 @@ config TRACING
|
||||||
Enable system tracing. This requires a backend such as SEGGER
|
Enable system tracing. This requires a backend such as SEGGER
|
||||||
Systemview to be enabled as well.
|
Systemview to be enabled as well.
|
||||||
|
|
||||||
|
if TRACING
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Tracing Method"
|
||||||
|
default TRACING_ASYNC
|
||||||
|
|
||||||
|
config TRACING_SYNC
|
||||||
|
bool "Synchronous Tracing"
|
||||||
|
select RING_BUFFER
|
||||||
|
help
|
||||||
|
Enable synchronous tracing. This requires the backend to be
|
||||||
|
very low-latency.
|
||||||
|
|
||||||
|
config TRACING_ASYNC
|
||||||
|
bool "Asynchronous Tracing"
|
||||||
|
select RING_BUFFER
|
||||||
|
help
|
||||||
|
Enable asynchronous tracing. This will buffer all the tracing
|
||||||
|
packets to the ring buffer first, tracing thread will try to
|
||||||
|
output as much data in ring buffer as possible when tracing
|
||||||
|
thread get scheduled.
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config TRACING_THREAD_STACK_SIZE
|
||||||
|
int "Stack size of tracing thread"
|
||||||
|
default 1024
|
||||||
|
depends on TRACING_ASYNC
|
||||||
|
help
|
||||||
|
Stack size of tracing thread.
|
||||||
|
|
||||||
|
config TRACING_THREAD_WAIT_THRESHOLD
|
||||||
|
int "Tracing thread waiting threshold"
|
||||||
|
default 100
|
||||||
|
depends on TRACING_ASYNC
|
||||||
|
help
|
||||||
|
Tracing thread waiting period given in milliseconds after
|
||||||
|
every first packet put to tracing buffer.
|
||||||
|
|
||||||
|
config TRACING_BUFFER_SIZE
|
||||||
|
int "Size of tracing buffer"
|
||||||
|
default 2048 if TRACING_ASYNC
|
||||||
|
default TRACING_PACKET_MAX_SIZE if TRACING_SYNC
|
||||||
|
range 32 65536
|
||||||
|
help
|
||||||
|
Size of tracing buffer. If TRACING_ASYNC is enabled, tracing buffer
|
||||||
|
is used as ring_buffer to buffer data packet and string packet. If
|
||||||
|
TRACING_SYNC is enabled, it's used to hold the formated data.
|
||||||
|
|
||||||
|
config TRACING_PACKET_MAX_SIZE
|
||||||
|
int "Max size of one tracing packet"
|
||||||
|
default 32
|
||||||
|
help
|
||||||
|
Max size of one tracing packet.
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Tracing Backend"
|
||||||
|
default TRACING_BACKEND_UART
|
||||||
|
|
||||||
|
config TRACING_BACKEND_UART
|
||||||
|
bool "Enable UART backend"
|
||||||
|
depends on UART_CONSOLE
|
||||||
|
depends on TRACING_ASYNC
|
||||||
|
help
|
||||||
|
When enabled backend is using UART to output tracing data.
|
||||||
|
|
||||||
|
config TRACING_BACKEND_USB
|
||||||
|
bool "Enable USB backend"
|
||||||
|
depends on TRACING_ASYNC
|
||||||
|
help
|
||||||
|
When enabled backend is using USB to output tracing data.
|
||||||
|
|
||||||
|
config TRACING_BACKEND_POSIX
|
||||||
|
bool "Enable POSIX backend"
|
||||||
|
depends on TRACING_SYNC
|
||||||
|
depends on ARCH_POSIX
|
||||||
|
help
|
||||||
|
When enabled backend is using posix API to output tracing
|
||||||
|
data to file system.
|
||||||
|
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config TRACING_BACKEND_UART_NAME
|
||||||
|
string "Device Name of UART Device for UART backend"
|
||||||
|
default "$(dt_chosen_label,$(DT_CHOSEN_Z_CONSOLE))" if HAS_DTS
|
||||||
|
default "UART_0"
|
||||||
|
depends on TRACING_BACKEND_UART
|
||||||
|
help
|
||||||
|
This option specifies the name of UART device to be used for
|
||||||
|
tracing backend.
|
||||||
|
|
||||||
|
config TRACING_USB_MPS
|
||||||
|
int "USB backend max packet size"
|
||||||
|
default 64
|
||||||
|
depends on TRACING_BACKEND_USB
|
||||||
|
help
|
||||||
|
USB tracing backend max packet size(endpoint MPS).
|
||||||
|
|
||||||
|
config TRACING_HANDLE_HOST_CMD
|
||||||
|
bool "Enable host cmd handle"
|
||||||
|
select UART_INTERRUPT_DRIVEN if TRACING_BACKEND_UART
|
||||||
|
help
|
||||||
|
When enabled tracing will handle cmd from host to dynamically
|
||||||
|
enable and disable tracing to have host capture tracing stream
|
||||||
|
data conveniently.
|
||||||
|
|
||||||
|
config TRACING_CMD_BUFFER_SIZE
|
||||||
|
int "Size of tracing cmd buffer"
|
||||||
|
default 32
|
||||||
|
range 32 128
|
||||||
|
help
|
||||||
|
Size of tracing command buffer.
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
config ASAN
|
config ASAN
|
||||||
bool "Build with address sanitizer"
|
bool "Build with address sanitizer"
|
||||||
depends on ARCH_POSIX
|
depends on ARCH_POSIX
|
||||||
|
|
|
@ -1,27 +1,57 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
if(CONFIG_SEGGER_SYSTEMVIEW OR CONFIG_TRACING_CPU_STATS)
|
if(CONFIG_SEGGER_SYSTEMVIEW OR CONFIG_TRACING_CPU_STATS)
|
||||||
zephyr_library()
|
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(
|
zephyr_sources_ifdef(
|
||||||
CONFIG_SEGGER_SYSTEMVIEW
|
CONFIG_SEGGER_SYSTEMVIEW
|
||||||
sysview_config.c
|
sysview_config.c
|
||||||
sysview.c
|
sysview.c
|
||||||
)
|
)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(
|
zephyr_sources_ifdef(
|
||||||
CONFIG_TRACING_CPU_STATS
|
CONFIG_TRACING_CPU_STATS
|
||||||
cpu_stats.c
|
cpu_stats.c
|
||||||
)
|
)
|
||||||
|
|
||||||
if(CONFIG_TRACING)
|
|
||||||
zephyr_library_include_directories(
|
|
||||||
${ZEPHYR_BASE}/kernel/include
|
|
||||||
${ZEPHYR_BASE}/arch/${ARCH}/include
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
zephyr_sources_ifdef(
|
||||||
|
CONFIG_TRACING
|
||||||
|
tracing_buffer.c
|
||||||
|
tracing_core.c
|
||||||
|
tracing_format_common.c
|
||||||
|
)
|
||||||
|
|
||||||
|
zephyr_sources_ifdef(
|
||||||
|
CONFIG_TRACING_SYNC
|
||||||
|
tracing_format_sync.c
|
||||||
|
)
|
||||||
|
|
||||||
|
zephyr_sources_ifdef(
|
||||||
|
CONFIG_TRACING_ASYNC
|
||||||
|
tracing_format_async.c
|
||||||
|
)
|
||||||
|
|
||||||
|
zephyr_sources_ifdef(
|
||||||
|
CONFIG_TRACING_BACKEND_USB
|
||||||
|
tracing_backend_usb.c
|
||||||
|
)
|
||||||
|
|
||||||
|
zephyr_sources_ifdef(
|
||||||
|
CONFIG_TRACING_BACKEND_UART
|
||||||
|
tracing_backend_uart.c
|
||||||
|
)
|
||||||
|
|
||||||
|
zephyr_sources_ifdef(
|
||||||
|
CONFIG_TRACING_BACKEND_POSIX
|
||||||
|
tracing_backend_posix.c
|
||||||
|
)
|
||||||
|
|
||||||
|
zephyr_include_directories_ifdef(
|
||||||
|
CONFIG_TRACING
|
||||||
|
${ZEPHYR_BASE}/kernel/include
|
||||||
|
${ZEPHYR_BASE}/arch/${ARCH}/include
|
||||||
|
)
|
||||||
|
|
||||||
zephyr_include_directories_ifdef(CONFIG_TRACING include)
|
zephyr_include_directories_ifdef(CONFIG_TRACING include)
|
||||||
|
|
||||||
add_subdirectory_ifdef(CONFIG_TRACING_CTF ctf)
|
add_subdirectory_ifdef(CONFIG_TRACING_CTF ctf)
|
||||||
|
|
108
subsys/debug/tracing/include/tracing_backend.h
Normal file
108
subsys/debug/tracing/include/tracing_backend.h
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TRACE_BACKEND_H
|
||||||
|
#define _TRACE_BACKEND_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/util.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tracing backend
|
||||||
|
* @defgroup Tracing_backend Tracing backend
|
||||||
|
* @{
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct tracing_backend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tracing backend API.
|
||||||
|
*/
|
||||||
|
struct tracing_backend_api {
|
||||||
|
void (*init)(void);
|
||||||
|
void (*output)(const struct tracing_backend *backend,
|
||||||
|
u8_t *data, u32_t length);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tracing backend structure.
|
||||||
|
*/
|
||||||
|
struct tracing_backend {
|
||||||
|
const char *name;
|
||||||
|
const struct tracing_backend_api *api;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create tracing_backend instance.
|
||||||
|
*
|
||||||
|
* @param _name Instance name.
|
||||||
|
* @param _api Tracing backend API.
|
||||||
|
*/
|
||||||
|
#define TRACING_BACKEND_DEFINE(_name, _api) \
|
||||||
|
static const Z_STRUCT_SECTION_ITERABLE(tracing_backend, _name) = \
|
||||||
|
{ \
|
||||||
|
.name = STRINGIFY(_name), \
|
||||||
|
.api = &_api \
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize tracing backend.
|
||||||
|
*
|
||||||
|
* @param backend Pointer to tracing_backend instance.
|
||||||
|
*/
|
||||||
|
static inline void tracing_backend_init(
|
||||||
|
const struct tracing_backend *backend)
|
||||||
|
{
|
||||||
|
if (backend && backend->api) {
|
||||||
|
backend->api->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Output tracing packet with tracing backend.
|
||||||
|
*
|
||||||
|
* @param backend Pointer to tracing_backend instance.
|
||||||
|
* @param data Address of outputing buffer.
|
||||||
|
* @param length Length of outputing buffer.
|
||||||
|
*/
|
||||||
|
static inline void tracing_backend_output(
|
||||||
|
const struct tracing_backend *backend,
|
||||||
|
u8_t *data, u32_t length)
|
||||||
|
{
|
||||||
|
if (backend && backend->api) {
|
||||||
|
backend->api->output(backend, data, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get tracing backend based on the name of
|
||||||
|
* tracing backend in tracing backend section.
|
||||||
|
*
|
||||||
|
* @param name Name of wanted tracing backend.
|
||||||
|
*
|
||||||
|
* @return Pointer of the wanted backend or NULL.
|
||||||
|
*/
|
||||||
|
static inline struct tracing_backend *tracing_backend_get(char *name)
|
||||||
|
{
|
||||||
|
Z_STRUCT_SECTION_FOREACH(tracing_backend, backend) {
|
||||||
|
if (strcmp(backend->name, name) == 0) {
|
||||||
|
return backend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
120
subsys/debug/tracing/include/tracing_buffer.h
Normal file
120
subsys/debug/tracing/include/tracing_buffer.h
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TRACE_BUFFER_H
|
||||||
|
#define _TRACE_BUFFER_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize tracing buffer.
|
||||||
|
*/
|
||||||
|
void tracing_buffer_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Tracing buffer is empty or not.
|
||||||
|
*
|
||||||
|
* @return true if the ring buffer is empty, or false if not.
|
||||||
|
*/
|
||||||
|
bool tracing_buffer_is_empty(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get free space in the tracing buffer.
|
||||||
|
*
|
||||||
|
* @return Tracing buffer free space (in bytes).
|
||||||
|
*/
|
||||||
|
u32_t tracing_buffer_space_get(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get tracing buffer capacity (max size).
|
||||||
|
*
|
||||||
|
* @return Tracing buffer capacity (in bytes).
|
||||||
|
*/
|
||||||
|
u32_t tracing_buffer_capacity_get(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Try to allocate buffer in the tracing buffer.
|
||||||
|
*
|
||||||
|
* @param data Pointer to the address. It's set to a location
|
||||||
|
* within the tracing buffer.
|
||||||
|
* @param size Requested buffer size (in bytes).
|
||||||
|
*
|
||||||
|
* @return Size of allocated buffer which can be smaller than
|
||||||
|
* requested if there isn't enough free space or buffer wraps.
|
||||||
|
*/
|
||||||
|
u32_t tracing_buffer_put_claim(u8_t **data, u32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indicate number of bytes written to the allocated buffer.
|
||||||
|
*
|
||||||
|
* @param size Number of bytes written to the allocated buffer.
|
||||||
|
*
|
||||||
|
* @retval 0 Successful operation.
|
||||||
|
* @retval -EINVAL Given @a size exceeds free space of tracing buffer.
|
||||||
|
*/
|
||||||
|
int tracing_buffer_put_finish(u32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write data to tracing buffer.
|
||||||
|
*
|
||||||
|
* @param data Address of data.
|
||||||
|
* @param size Data size (in bytes).
|
||||||
|
*
|
||||||
|
* @retval Number of bytes written to tracing buffer.
|
||||||
|
*/
|
||||||
|
u32_t tracing_buffer_put(u8_t *data, u32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get address of the first valid data in tracing buffer.
|
||||||
|
*
|
||||||
|
* @param data Pointer to the address. It's set to a location pointing to
|
||||||
|
* the first valid data within the tracing buffer.
|
||||||
|
* @param size Requested buffer size (in bytes).
|
||||||
|
*
|
||||||
|
* @return Size of valid buffer which can be smaller than requested
|
||||||
|
* if there isn't enough valid data or buffer wraps.
|
||||||
|
*/
|
||||||
|
u32_t tracing_buffer_get_claim(u8_t **data, u32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indicate number of bytes read from claimed buffer.
|
||||||
|
*
|
||||||
|
* @param size Number of bytes read from claimed buffer.
|
||||||
|
*
|
||||||
|
* @retval 0 Successful operation.
|
||||||
|
* @retval -EINVAL Given @a size exceeds available data of tracing buffer.
|
||||||
|
*/
|
||||||
|
int tracing_buffer_get_finish(u32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read data from tracing buffer to output buffer.
|
||||||
|
*
|
||||||
|
* @param data Address of the output buffer.
|
||||||
|
* @param size Data size (in bytes).
|
||||||
|
*
|
||||||
|
* @retval Number of bytes written to the output buffer.
|
||||||
|
*/
|
||||||
|
u32_t tracing_buffer_get(u8_t *data, u32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get buffer from tracing command buffer.
|
||||||
|
*
|
||||||
|
* @param data Pointer to tracing command buffer start address.
|
||||||
|
*
|
||||||
|
* @return Tracing command buffer size (in bytes).
|
||||||
|
*/
|
||||||
|
u32_t tracing_cmd_buffer_alloc(u8_t **data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
67
subsys/debug/tracing/include/tracing_core.h
Normal file
67
subsys/debug/tracing/include/tracing_core.h
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TRACE_CORE_H
|
||||||
|
#define _TRACE_CORE_H
|
||||||
|
|
||||||
|
#include <irq.h>
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TRACING_LOCK() { int key; key = irq_lock()
|
||||||
|
|
||||||
|
#define TRACING_UNLOCK() { irq_unlock(key); } }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check tracing enabled or not.
|
||||||
|
*
|
||||||
|
* @return True if tracing enabled; False if tracing disabled.
|
||||||
|
*/
|
||||||
|
bool is_tracing_enabled(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Give tracing buffer to backend.
|
||||||
|
*
|
||||||
|
* @param data Tracing buffer address.
|
||||||
|
* @param length Tracing buffer length.
|
||||||
|
*/
|
||||||
|
void tracing_buffer_handle(u8_t *data, u32_t length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle tracing packet drop.
|
||||||
|
*/
|
||||||
|
void tracing_packet_drop_handle(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handle tracing command.
|
||||||
|
*
|
||||||
|
* @param buf Tracing command buffer address.
|
||||||
|
* @param length Tracing command buffer length.
|
||||||
|
*/
|
||||||
|
void tracing_cmd_handle(u8_t *buf, u32_t length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trigger tracing thread to run after every first put.
|
||||||
|
*
|
||||||
|
* @param before_put_is_empty If tracing buffer is empty before this put.
|
||||||
|
*/
|
||||||
|
void tracing_trigger_output(bool before_put_is_empty);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check if we are in tracing thread context.
|
||||||
|
*
|
||||||
|
* @return True if in tracing thread context; False if not.
|
||||||
|
*/
|
||||||
|
bool is_tracing_thread(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
68
subsys/debug/tracing/include/tracing_format_common.h
Normal file
68
subsys/debug/tracing/include/tracing_format_common.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TRACE_FORMAT_COMMON_H
|
||||||
|
#define _TRACE_FORMAT_COMMON_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <sys/printk.h>
|
||||||
|
#include <debug/tracing_format.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A structure to represent tracing format context.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int status;
|
||||||
|
u32_t length;
|
||||||
|
} tracing_ctx_t;
|
||||||
|
|
||||||
|
#ifdef CONFIG_NEWLIB_LIBC
|
||||||
|
typedef int (*str_put_func_t)(int c, void *ctx);
|
||||||
|
extern void z_vprintk(str_put_func_t out, void *ctx,
|
||||||
|
const char *fmt, va_list ap);
|
||||||
|
#else
|
||||||
|
extern int z_prf(int (*func)(), void *dest, char *format, va_list vargs);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put string format tracing message to tracing buffer.
|
||||||
|
*
|
||||||
|
* @param str String to format.
|
||||||
|
* @param args Variable parameters.
|
||||||
|
*
|
||||||
|
* @return true if put tracing message to tracing buffer successfully.
|
||||||
|
*/
|
||||||
|
bool tracing_format_string_put(const char *str, va_list args);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put raw data format tracing message to tracing buffer.
|
||||||
|
*
|
||||||
|
* @param data Raw data to be traced.
|
||||||
|
* @param length Raw data length.
|
||||||
|
*
|
||||||
|
* @return true if put tracing message to tracing buffer successfully.
|
||||||
|
*/
|
||||||
|
bool tracing_format_raw_data_put(u8_t *data, u32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Put tracing_data format message to tracing buffer.
|
||||||
|
*
|
||||||
|
* @param tracing_data_array Tracing_data format data array to be traced.
|
||||||
|
* @param count Tracing_data array data count.
|
||||||
|
*
|
||||||
|
* @return true if put tracing message to tracing buffer successfully.
|
||||||
|
*/
|
||||||
|
bool tracing_format_data_put(tracing_data_t *tracing_data_array, u32_t count);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
66
subsys/debug/tracing/tracing_backend_posix.c
Normal file
66
subsys/debug/tracing/tracing_backend_posix.c
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Oticon A/S
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <soc.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <cmdline.h>
|
||||||
|
#include <sys/__assert.h>
|
||||||
|
#include <tracing_backend.h>
|
||||||
|
|
||||||
|
static void *out_stream;
|
||||||
|
static const char *file_name;
|
||||||
|
|
||||||
|
static void tracing_backend_posix_init(void)
|
||||||
|
{
|
||||||
|
if (file_name == NULL) {
|
||||||
|
file_name = "channel0_0";
|
||||||
|
}
|
||||||
|
|
||||||
|
out_stream = (void *)fopen(file_name, "wb");
|
||||||
|
|
||||||
|
__ASSERT(out_stream != NULL, "posix backend init failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tracing_backend_posix_output(
|
||||||
|
const struct tracing_backend *backend,
|
||||||
|
u8_t *data, u32_t length)
|
||||||
|
{
|
||||||
|
fwrite(data, length, 1, (FILE *)out_stream);
|
||||||
|
|
||||||
|
if (!k_is_in_isr()) {
|
||||||
|
fflush((FILE *)out_stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tracing_backend_api tracing_backend_posix_api = {
|
||||||
|
.init = tracing_backend_posix_init,
|
||||||
|
.output = tracing_backend_posix_output
|
||||||
|
};
|
||||||
|
|
||||||
|
TRACING_BACKEND_DEFINE(tracing_backend_posix, tracing_backend_posix_api);
|
||||||
|
|
||||||
|
void tracing_backend_posix_option(void)
|
||||||
|
{
|
||||||
|
static struct args_struct_t tracing_backend_option[] = {
|
||||||
|
{
|
||||||
|
.manual = false,
|
||||||
|
.is_mandatory = false,
|
||||||
|
.is_switch = false,
|
||||||
|
.option = "trace-file",
|
||||||
|
.name = "file_name",
|
||||||
|
.type = 's',
|
||||||
|
.dest = (void *)&file_name,
|
||||||
|
.call_when_found = NULL,
|
||||||
|
.descript = "File name for tracing output.",
|
||||||
|
},
|
||||||
|
ARG_TABLE_ENDMARKER
|
||||||
|
};
|
||||||
|
|
||||||
|
native_add_command_line_opts(tracing_backend_option);
|
||||||
|
}
|
||||||
|
|
||||||
|
NATIVE_TASK(tracing_backend_posix_option, PRE_BOOT_1, 1);
|
95
subsys/debug/tracing/tracing_backend_uart.c
Normal file
95
subsys/debug/tracing/tracing_backend_uart.c
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <device.h>
|
||||||
|
#include <drivers/uart.h>
|
||||||
|
#include <sys/__assert.h>
|
||||||
|
#include <tracing_core.h>
|
||||||
|
#include <tracing_buffer.h>
|
||||||
|
#include <tracing_backend.h>
|
||||||
|
|
||||||
|
static struct device *dev;
|
||||||
|
|
||||||
|
#ifdef CONFIG_TRACING_HANDLE_HOST_CMD
|
||||||
|
static void uart_isr(struct device *dev)
|
||||||
|
{
|
||||||
|
int rx;
|
||||||
|
u8_t byte;
|
||||||
|
static u8_t *cmd;
|
||||||
|
static u32_t length, cur;
|
||||||
|
|
||||||
|
while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
|
||||||
|
if (!uart_irq_rx_ready(dev)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rx = uart_fifo_read(dev, &byte, 1);
|
||||||
|
if (rx < 0) {
|
||||||
|
uart_irq_rx_disable(dev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cmd) {
|
||||||
|
length = tracing_cmd_buffer_alloc(&cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isprint(byte)) {
|
||||||
|
if (byte == '\r') {
|
||||||
|
cmd[cur] = '\0';
|
||||||
|
tracing_cmd_handle(cmd, cur);
|
||||||
|
cmd = NULL;
|
||||||
|
cur = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur < length - 1) {
|
||||||
|
cmd[cur++] = byte;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void tracing_backend_uart_output(
|
||||||
|
const struct tracing_backend *backend,
|
||||||
|
u8_t *data, u32_t length)
|
||||||
|
{
|
||||||
|
for (u32_t i = 0; i < length; i++) {
|
||||||
|
uart_poll_out(dev, data[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tracing_backend_uart_init(void)
|
||||||
|
{
|
||||||
|
dev = device_get_binding(CONFIG_TRACING_BACKEND_UART_NAME);
|
||||||
|
__ASSERT(dev, "uart backend binding failed");
|
||||||
|
|
||||||
|
#ifdef CONFIG_TRACING_HANDLE_HOST_CMD
|
||||||
|
uart_irq_rx_disable(dev);
|
||||||
|
uart_irq_tx_disable(dev);
|
||||||
|
|
||||||
|
uart_irq_callback_set(dev, uart_isr);
|
||||||
|
|
||||||
|
while (uart_irq_rx_ready(dev)) {
|
||||||
|
u8_t c;
|
||||||
|
|
||||||
|
uart_fifo_read(dev, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_irq_rx_enable(dev);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tracing_backend_api tracing_backend_uart_api = {
|
||||||
|
.init = tracing_backend_uart_init,
|
||||||
|
.output = tracing_backend_uart_output
|
||||||
|
};
|
||||||
|
|
||||||
|
TRACING_BACKEND_DEFINE(tracing_backend_uart, tracing_backend_uart_api);
|
184
subsys/debug/tracing/tracing_backend_usb.c
Normal file
184
subsys/debug/tracing/tracing_backend_usb.c
Normal file
|
@ -0,0 +1,184 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/util.h>
|
||||||
|
#include <sys/atomic.h>
|
||||||
|
#include <sys/__assert.h>
|
||||||
|
#include <sys/byteorder.h>
|
||||||
|
#include <usb/usb_device.h>
|
||||||
|
#include <usb/usb_common.h>
|
||||||
|
#include <usb_descriptor.h>
|
||||||
|
#include <tracing_core.h>
|
||||||
|
#include <tracing_buffer.h>
|
||||||
|
#include <tracing_backend.h>
|
||||||
|
|
||||||
|
#define USB_TRANSFER_ONGOING 1
|
||||||
|
#define USB_TRANSFER_FREE 0
|
||||||
|
|
||||||
|
#define TRACING_IF_IN_EP_ADDR 0x81
|
||||||
|
#define TRACING_IF_OUT_EP_ADDR 0x01
|
||||||
|
|
||||||
|
struct usb_device_desc {
|
||||||
|
struct usb_if_descriptor if0;
|
||||||
|
struct usb_ep_descriptor if0_in_ep;
|
||||||
|
struct usb_ep_descriptor if0_out_ep;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
static volatile int transfer_state;
|
||||||
|
static enum usb_dc_status_code usb_device_status = USB_DC_UNKNOWN;
|
||||||
|
|
||||||
|
USBD_CLASS_DESCR_DEFINE(primary, 0) struct usb_device_desc dev_desc = {
|
||||||
|
/*
|
||||||
|
* Interface descriptor 0
|
||||||
|
*/
|
||||||
|
.if0 = {
|
||||||
|
.bLength = sizeof(struct usb_if_descriptor),
|
||||||
|
.bDescriptorType = USB_INTERFACE_DESC,
|
||||||
|
.bInterfaceNumber = 0,
|
||||||
|
.bAlternateSetting = 0,
|
||||||
|
.bNumEndpoints = 2,
|
||||||
|
.bInterfaceClass = CUSTOM_CLASS,
|
||||||
|
.bInterfaceSubClass = 0,
|
||||||
|
.bInterfaceProtocol = 0,
|
||||||
|
.iInterface = 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data Endpoint IN
|
||||||
|
*/
|
||||||
|
.if0_in_ep = {
|
||||||
|
.bLength = sizeof(struct usb_ep_descriptor),
|
||||||
|
.bDescriptorType = USB_ENDPOINT_DESC,
|
||||||
|
.bEndpointAddress = TRACING_IF_IN_EP_ADDR,
|
||||||
|
.bmAttributes = USB_DC_EP_BULK,
|
||||||
|
.wMaxPacketSize = sys_cpu_to_le16(CONFIG_TRACING_USB_MPS),
|
||||||
|
.bInterval = 0x00,
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data Endpoint OUT
|
||||||
|
*/
|
||||||
|
.if0_out_ep = {
|
||||||
|
.bLength = sizeof(struct usb_ep_descriptor),
|
||||||
|
.bDescriptorType = USB_ENDPOINT_DESC,
|
||||||
|
.bEndpointAddress = TRACING_IF_OUT_EP_ADDR,
|
||||||
|
.bmAttributes = USB_DC_EP_BULK,
|
||||||
|
.wMaxPacketSize = sys_cpu_to_le16(CONFIG_TRACING_USB_MPS),
|
||||||
|
.bInterval = 0x00,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void dev_status_cb(struct usb_cfg_data *cfg,
|
||||||
|
enum usb_dc_status_code status,
|
||||||
|
const u8_t *param)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(cfg);
|
||||||
|
ARG_UNUSED(param);
|
||||||
|
|
||||||
|
usb_device_status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tracing_ep_out_cb(u8_t ep, enum usb_dc_ep_cb_status_code ep_status)
|
||||||
|
{
|
||||||
|
u8_t *cmd = NULL;
|
||||||
|
u32_t bytes_to_read, length;
|
||||||
|
|
||||||
|
usb_read(ep, NULL, 0, &bytes_to_read);
|
||||||
|
|
||||||
|
while (bytes_to_read) {
|
||||||
|
length = tracing_cmd_buffer_alloc(&cmd);
|
||||||
|
if (cmd) {
|
||||||
|
length = MIN(length, bytes_to_read);
|
||||||
|
usb_read(ep, cmd, length, NULL);
|
||||||
|
tracing_cmd_handle(cmd, length);
|
||||||
|
|
||||||
|
bytes_to_read -= length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* send ZLP to sync with host receive thread
|
||||||
|
*/
|
||||||
|
usb_write(TRACING_IF_IN_EP_ADDR, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tracing_ep_in_cb(u8_t ep, enum usb_dc_ep_cb_status_code ep_status)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(ep);
|
||||||
|
ARG_UNUSED(ep_status);
|
||||||
|
|
||||||
|
transfer_state = USB_TRANSFER_FREE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct usb_ep_cfg_data ep_cfg[] = {
|
||||||
|
{
|
||||||
|
.ep_cb = tracing_ep_out_cb,
|
||||||
|
.ep_addr = TRACING_IF_OUT_EP_ADDR,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ep_cb = tracing_ep_in_cb,
|
||||||
|
.ep_addr = TRACING_IF_IN_EP_ADDR,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
USBD_CFG_DATA_DEFINE(primary, tracing_backend_usb)
|
||||||
|
struct usb_cfg_data tracing_backend_usb_config = {
|
||||||
|
.usb_device_description = NULL,
|
||||||
|
.interface_descriptor = &dev_desc.if0,
|
||||||
|
.cb_usb_status = dev_status_cb,
|
||||||
|
.interface = {
|
||||||
|
.class_handler = NULL,
|
||||||
|
.custom_handler = NULL,
|
||||||
|
.vendor_handler = NULL,
|
||||||
|
},
|
||||||
|
.num_endpoints = ARRAY_SIZE(ep_cfg),
|
||||||
|
.endpoint = ep_cfg,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void tracing_backend_usb_output(const struct tracing_backend *backend,
|
||||||
|
u8_t *data, u32_t length)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
u32_t bytes;
|
||||||
|
|
||||||
|
while (length > 0) {
|
||||||
|
transfer_state = USB_TRANSFER_ONGOING;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* make sure every USB tansfer no need ZLP at all
|
||||||
|
* because we are in lowest priority thread content
|
||||||
|
* there are no deterministic time between real USB
|
||||||
|
* packet and ZLP
|
||||||
|
*/
|
||||||
|
ret = usb_write(TRACING_IF_IN_EP_ADDR, data,
|
||||||
|
length >= CONFIG_TRACING_USB_MPS ?
|
||||||
|
CONFIG_TRACING_USB_MPS - 1 : length, &bytes);
|
||||||
|
if (ret) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
data += bytes;
|
||||||
|
length -= bytes;
|
||||||
|
|
||||||
|
while (transfer_state == USB_TRANSFER_ONGOING) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tracing_backend_usb_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = usb_enable(NULL);
|
||||||
|
__ASSERT(ret == 0, "usb backend enable failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct tracing_backend_api tracing_backend_usb_api = {
|
||||||
|
.init = tracing_backend_usb_init,
|
||||||
|
.output = tracing_backend_usb_output
|
||||||
|
};
|
||||||
|
|
||||||
|
TRACING_BACKEND_DEFINE(tracing_backend_usb, tracing_backend_usb_api);
|
69
subsys/debug/tracing/tracing_buffer.c
Normal file
69
subsys/debug/tracing/tracing_buffer.c
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/ring_buffer.h>
|
||||||
|
|
||||||
|
static struct ring_buf tracing_ring_buf;
|
||||||
|
static u8_t tracing_buffer[CONFIG_TRACING_BUFFER_SIZE + 1];
|
||||||
|
static u8_t tracing_cmd_buffer[CONFIG_TRACING_CMD_BUFFER_SIZE];
|
||||||
|
|
||||||
|
u32_t tracing_cmd_buffer_alloc(u8_t **data)
|
||||||
|
{
|
||||||
|
*data = &tracing_cmd_buffer[0];
|
||||||
|
|
||||||
|
return sizeof(tracing_cmd_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t tracing_buffer_put_claim(u8_t **data, u32_t size)
|
||||||
|
{
|
||||||
|
return ring_buf_put_claim(&tracing_ring_buf, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tracing_buffer_put_finish(u32_t size)
|
||||||
|
{
|
||||||
|
return ring_buf_put_finish(&tracing_ring_buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t tracing_buffer_put(u8_t *data, u32_t size)
|
||||||
|
{
|
||||||
|
return ring_buf_put(&tracing_ring_buf, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t tracing_buffer_get_claim(u8_t **data, u32_t size)
|
||||||
|
{
|
||||||
|
return ring_buf_get_claim(&tracing_ring_buf, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tracing_buffer_get_finish(u32_t size)
|
||||||
|
{
|
||||||
|
return ring_buf_get_finish(&tracing_ring_buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t tracing_buffer_get(u8_t *data, u32_t size)
|
||||||
|
{
|
||||||
|
return ring_buf_get(&tracing_ring_buf, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tracing_buffer_init(void)
|
||||||
|
{
|
||||||
|
ring_buf_init(&tracing_ring_buf,
|
||||||
|
sizeof(tracing_buffer), tracing_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tracing_buffer_is_empty(void)
|
||||||
|
{
|
||||||
|
return ring_buf_is_empty(&tracing_ring_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t tracing_buffer_capacity_get(void)
|
||||||
|
{
|
||||||
|
return ring_buf_capacity_get(&tracing_ring_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
u32_t tracing_buffer_space_get(void)
|
||||||
|
{
|
||||||
|
return ring_buf_space_get(&tracing_ring_buf);
|
||||||
|
}
|
153
subsys/debug/tracing/tracing_core.c
Normal file
153
subsys/debug/tracing/tracing_core.c
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <init.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <sys/util.h>
|
||||||
|
#include <sys/atomic.h>
|
||||||
|
#include <tracing_core.h>
|
||||||
|
#include <tracing_buffer.h>
|
||||||
|
#include <tracing_backend.h>
|
||||||
|
|
||||||
|
#define TRACING_CMD_ENABLE "enable"
|
||||||
|
#define TRACING_CMD_DISABLE "disable"
|
||||||
|
|
||||||
|
#ifdef CONFIG_TRACING_BACKEND_UART
|
||||||
|
#define TRACING_BACKEND_NAME "tracing_backend_uart"
|
||||||
|
#elif defined CONFIG_TRACING_BACKEND_USB
|
||||||
|
#define TRACING_BACKEND_NAME "tracing_backend_usb"
|
||||||
|
#elif defined CONFIG_TRACING_BACKEND_POSIX
|
||||||
|
#define TRACING_BACKEND_NAME "tracing_backend_posix"
|
||||||
|
#else
|
||||||
|
#define TRACING_BACKEND_NAME ""
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum tracing_state {
|
||||||
|
TRACING_DISABLE = 0,
|
||||||
|
TRACING_ENABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
static atomic_t tracing_state;
|
||||||
|
static atomic_t tracing_packet_drop_num;
|
||||||
|
static struct tracing_backend *working_backend;
|
||||||
|
|
||||||
|
#ifdef CONFIG_TRACING_ASYNC
|
||||||
|
#define TRACING_THREAD_NAME "tracing_thread"
|
||||||
|
|
||||||
|
static k_tid_t tracing_thread_tid;
|
||||||
|
static struct k_thread tracing_thread;
|
||||||
|
static struct k_timer tracing_thread_timer;
|
||||||
|
static K_SEM_DEFINE(tracing_thread_sem, 0, 1);
|
||||||
|
static K_THREAD_STACK_DEFINE(tracing_thread_stack,
|
||||||
|
CONFIG_TRACING_THREAD_STACK_SIZE);
|
||||||
|
|
||||||
|
static void tracing_thread_func(void *dummy1, void *dummy2, void *dummy3)
|
||||||
|
{
|
||||||
|
u8_t *transferring_buf;
|
||||||
|
u32_t transferring_length, tracing_buffer_max_length;
|
||||||
|
|
||||||
|
tracing_thread_tid = k_current_get();
|
||||||
|
|
||||||
|
tracing_buffer_max_length = tracing_buffer_capacity_get();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (tracing_buffer_is_empty()) {
|
||||||
|
k_sem_take(&tracing_thread_sem, K_FOREVER);
|
||||||
|
} else {
|
||||||
|
transferring_length =
|
||||||
|
tracing_buffer_get_claim(
|
||||||
|
&transferring_buf,
|
||||||
|
tracing_buffer_max_length);
|
||||||
|
tracing_buffer_handle(transferring_buf,
|
||||||
|
transferring_length);
|
||||||
|
tracing_buffer_get_finish(transferring_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tracing_thread_timer_expiry_fn(struct k_timer *timer)
|
||||||
|
{
|
||||||
|
k_sem_give(&tracing_thread_sem);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void tracing_set_state(enum tracing_state state)
|
||||||
|
{
|
||||||
|
atomic_set(&tracing_state, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tracing_init(struct device *arg)
|
||||||
|
{
|
||||||
|
ARG_UNUSED(arg);
|
||||||
|
|
||||||
|
tracing_buffer_init();
|
||||||
|
|
||||||
|
working_backend = tracing_backend_get(TRACING_BACKEND_NAME);
|
||||||
|
tracing_backend_init(working_backend);
|
||||||
|
|
||||||
|
atomic_set(&tracing_packet_drop_num, 0);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_TRACING_HANDLE_HOST_CMD)) {
|
||||||
|
tracing_set_state(TRACING_DISABLE);
|
||||||
|
} else {
|
||||||
|
tracing_set_state(TRACING_ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_TRACING_ASYNC
|
||||||
|
k_timer_init(&tracing_thread_timer,
|
||||||
|
tracing_thread_timer_expiry_fn, NULL);
|
||||||
|
|
||||||
|
k_thread_create(&tracing_thread, tracing_thread_stack,
|
||||||
|
K_THREAD_STACK_SIZEOF(tracing_thread_stack),
|
||||||
|
tracing_thread_func, NULL, NULL, NULL,
|
||||||
|
K_LOWEST_APPLICATION_THREAD_PRIO, 0, K_NO_WAIT);
|
||||||
|
k_thread_name_set(&tracing_thread, TRACING_THREAD_NAME);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(tracing_init, APPLICATION, 0);
|
||||||
|
|
||||||
|
#ifdef CONFIG_TRACING_ASYNC
|
||||||
|
void tracing_trigger_output(bool before_put_is_empty)
|
||||||
|
{
|
||||||
|
if (before_put_is_empty) {
|
||||||
|
k_timer_start(&tracing_thread_timer,
|
||||||
|
CONFIG_TRACING_THREAD_WAIT_THRESHOLD, K_NO_WAIT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_tracing_thread(void)
|
||||||
|
{
|
||||||
|
return (!k_is_in_isr() && (k_current_get() == tracing_thread_tid));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool is_tracing_enabled(void)
|
||||||
|
{
|
||||||
|
return atomic_get(&tracing_state) == TRACING_ENABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tracing_cmd_handle(u8_t *buf, u32_t length)
|
||||||
|
{
|
||||||
|
if (strncmp(buf, TRACING_CMD_ENABLE, length) == 0) {
|
||||||
|
tracing_set_state(TRACING_ENABLE);
|
||||||
|
} else if (strncmp(buf, TRACING_CMD_DISABLE, length) == 0) {
|
||||||
|
tracing_set_state(TRACING_DISABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tracing_buffer_handle(u8_t *data, u32_t length)
|
||||||
|
{
|
||||||
|
tracing_backend_output(working_backend, data, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tracing_packet_drop_handle(void)
|
||||||
|
{
|
||||||
|
atomic_inc(&tracing_packet_drop_num);
|
||||||
|
}
|
74
subsys/debug/tracing/tracing_format_async.c
Normal file
74
subsys/debug/tracing/tracing_format_async.c
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <tracing_core.h>
|
||||||
|
#include <tracing_buffer.h>
|
||||||
|
#include <tracing_format_common.h>
|
||||||
|
|
||||||
|
void tracing_format_string(const char *str, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
bool put_success, before_put_is_empty;
|
||||||
|
|
||||||
|
if (!is_tracing_enabled() || is_tracing_thread()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(args, str);
|
||||||
|
|
||||||
|
TRACING_LOCK();
|
||||||
|
before_put_is_empty = tracing_buffer_is_empty();
|
||||||
|
put_success = tracing_format_string_put(str, args);
|
||||||
|
TRACING_UNLOCK();
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (put_success) {
|
||||||
|
tracing_trigger_output(before_put_is_empty);
|
||||||
|
} else {
|
||||||
|
tracing_packet_drop_handle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tracing_format_raw_data(u8_t *data, u32_t length)
|
||||||
|
{
|
||||||
|
bool put_success, before_put_is_empty;
|
||||||
|
|
||||||
|
if (!is_tracing_enabled() || is_tracing_thread()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACING_LOCK();
|
||||||
|
before_put_is_empty = tracing_buffer_is_empty();
|
||||||
|
put_success = tracing_format_raw_data_put(data, length);
|
||||||
|
TRACING_UNLOCK();
|
||||||
|
|
||||||
|
if (put_success) {
|
||||||
|
tracing_trigger_output(before_put_is_empty);
|
||||||
|
} else {
|
||||||
|
tracing_packet_drop_handle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void tracing_format_data(tracing_data_t *tracing_data_array, u32_t count)
|
||||||
|
{
|
||||||
|
bool put_success, before_put_is_empty;
|
||||||
|
|
||||||
|
if (!is_tracing_enabled() || is_tracing_thread()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACING_LOCK();
|
||||||
|
before_put_is_empty = tracing_buffer_is_empty();
|
||||||
|
put_success = tracing_format_data_put(tracing_data_array, count);
|
||||||
|
TRACING_UNLOCK();
|
||||||
|
|
||||||
|
if (put_success) {
|
||||||
|
tracing_trigger_output(before_put_is_empty);
|
||||||
|
} else {
|
||||||
|
tracing_packet_drop_handle();
|
||||||
|
}
|
||||||
|
}
|
88
subsys/debug/tracing/tracing_format_common.c
Normal file
88
subsys/debug/tracing/tracing_format_common.c
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <tracing_buffer.h>
|
||||||
|
#include <tracing_format_common.h>
|
||||||
|
|
||||||
|
static int str_put(int c, void *ctx)
|
||||||
|
{
|
||||||
|
tracing_ctx_t *str_ctx = (tracing_ctx_t *)ctx;
|
||||||
|
|
||||||
|
if (str_ctx->status == 0) {
|
||||||
|
u8_t *buf;
|
||||||
|
u32_t claimed_size;
|
||||||
|
|
||||||
|
claimed_size = tracing_buffer_put_claim(&buf, 1);
|
||||||
|
if (claimed_size) {
|
||||||
|
*buf = (u8_t)c;
|
||||||
|
str_ctx->length++;
|
||||||
|
} else {
|
||||||
|
str_ctx->status = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tracing_format_string_put(const char *str, va_list args)
|
||||||
|
{
|
||||||
|
tracing_ctx_t str_ctx = {0};
|
||||||
|
|
||||||
|
#if !defined(CONFIG_NEWLIB_LIBC) && !defined(CONFIG_ARCH_POSIX)
|
||||||
|
(void)z_prf(str_put, (void *)&str_ctx, (char *)str, args);
|
||||||
|
#else
|
||||||
|
z_vprintk(str_put, (void *)&str_ctx, str, args);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (str_ctx.status == 0) {
|
||||||
|
tracing_buffer_put_finish(str_ctx.length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing_buffer_put_finish(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tracing_format_raw_data_put(u8_t *data, u32_t size)
|
||||||
|
{
|
||||||
|
u32_t space = tracing_buffer_space_get();
|
||||||
|
|
||||||
|
if (space >= size) {
|
||||||
|
tracing_buffer_put(data, size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool tracing_format_data_put(tracing_data_t *tracing_data_array, u32_t count)
|
||||||
|
{
|
||||||
|
u32_t total_size = 0U;
|
||||||
|
|
||||||
|
for (u32_t i = 0; i < count; i++) {
|
||||||
|
tracing_data_t *tracing_data =
|
||||||
|
tracing_data_array + i;
|
||||||
|
u8_t *data = tracing_data->data, *buf;
|
||||||
|
u32_t length = tracing_data->length, claimed_size;
|
||||||
|
|
||||||
|
do {
|
||||||
|
claimed_size = tracing_buffer_put_claim(&buf, length);
|
||||||
|
memcpy(buf, data, claimed_size);
|
||||||
|
total_size += claimed_size;
|
||||||
|
length -= claimed_size;
|
||||||
|
data += claimed_size;
|
||||||
|
} while (length && claimed_size);
|
||||||
|
|
||||||
|
if (length && claimed_size == 0) {
|
||||||
|
tracing_buffer_put_finish(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing_buffer_put_finish(total_size);
|
||||||
|
return true;
|
||||||
|
}
|
75
subsys/debug/tracing/tracing_format_sync.c
Normal file
75
subsys/debug/tracing/tracing_format_sync.c
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <tracing_core.h>
|
||||||
|
#include <tracing_buffer.h>
|
||||||
|
#include <tracing_format_common.h>
|
||||||
|
|
||||||
|
void tracing_format_string(const char *str, ...)
|
||||||
|
{
|
||||||
|
u8_t *data;
|
||||||
|
va_list args;
|
||||||
|
bool put_success;
|
||||||
|
u32_t length, tracing_buffer_size;
|
||||||
|
|
||||||
|
if (!is_tracing_enabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing_buffer_size = tracing_buffer_capacity_get();
|
||||||
|
|
||||||
|
va_start(args, str);
|
||||||
|
|
||||||
|
TRACING_LOCK();
|
||||||
|
put_success = tracing_format_string_put(str, args);
|
||||||
|
|
||||||
|
if (put_success) {
|
||||||
|
length = tracing_buffer_get_claim(&data, tracing_buffer_size);
|
||||||
|
tracing_buffer_handle(data, length);
|
||||||
|
tracing_buffer_get_finish(length);
|
||||||
|
} else {
|
||||||
|
tracing_packet_drop_handle();
|
||||||
|
}
|
||||||
|
TRACING_UNLOCK();
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tracing_format_raw_data(u8_t *data, u32_t length)
|
||||||
|
{
|
||||||
|
if (!is_tracing_enabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACING_LOCK();
|
||||||
|
tracing_buffer_handle(data, length);
|
||||||
|
TRACING_UNLOCK();
|
||||||
|
}
|
||||||
|
|
||||||
|
void tracing_format_data(tracing_data_t *tracing_data_array, u32_t count)
|
||||||
|
{
|
||||||
|
u8_t *data;
|
||||||
|
bool put_success;
|
||||||
|
u32_t length, tracing_buffer_size;
|
||||||
|
|
||||||
|
if (!is_tracing_enabled()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracing_buffer_size = tracing_buffer_capacity_get();
|
||||||
|
|
||||||
|
TRACING_LOCK();
|
||||||
|
put_success = tracing_format_data_put(tracing_data_array, count);
|
||||||
|
|
||||||
|
if (put_success) {
|
||||||
|
length = tracing_buffer_get_claim(&data, tracing_buffer_size);
|
||||||
|
tracing_buffer_handle(data, length);
|
||||||
|
tracing_buffer_get_finish(length);
|
||||||
|
} else {
|
||||||
|
tracing_packet_drop_handle();
|
||||||
|
}
|
||||||
|
TRACING_UNLOCK();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue