当前位置: 首页 > news >正文

【OS zephyr】子系统logging

1、概述

        logging子系统特点:运行模式可配,分级管理,多格式打印可选,支持同步异步打印,支持多后端,支持实例日志。底层都是vprintk()接口,vprintk()接口可能有多种实现实方式。

运行模式打印格式接口说明
mini模式str

z_log_minimal_printk()

hex

z_log_minimal_hexdump_print()

fall模式str

Z_LOG_MSG_CREATE()

支持立即模式(),线程模式(

CONFIG_LOG_PROCESS_THREAD

)可选
hex

Z_LOG_MSG_CREATE()

由于日志需要用到外设初始化,初始化的定义与执行控制如下:

/* Init level ordinals 宏定时引用*/
#define Z_INIT_ORD_EARLY    0
#define Z_INIT_ORD_PRE_KERNEL_1 1
#define Z_INIT_ORD_PRE_KERNEL_2 2
#define Z_INIT_ORD_POST_KERNEL  3
#define Z_INIT_ORD_APPLICATION  4
#define Z_INIT_ORD_SMP      5//levels[]中包含不同等级初始化段的段起始。static const struct init_entry *levels[] = {__init_EARLY_start,__init_PRE_KERNEL_1_start,__init_PRE_KERNEL_2_start,__init_POST_KERNEL_start,__init_APPLICATION_start,
#ifdef CONFIG_SMP__init_SMP_start,
#endif /* CONFIG_SMP *//* End marker */__init_end,};
//初始化时确定顺序时引用。与levels[]配置使用。
enum init_level {INIT_LEVEL_EARLY = 0,INIT_LEVEL_PRE_KERNEL_1,INIT_LEVEL_PRE_KERNEL_2,INIT_LEVEL_POST_KERNEL,INIT_LEVEL_APPLICATION,
#ifdef CONFIG_SMPINIT_LEVEL_SMP,
#endif /* CONFIG_SMP */
};

2、子系统依赖

2.1..\zephyr\drivers\serial\

        文件件夹下管理着众多平台的串口驱动。 static const struct uart_driver_api uart_acts_driver_api 结构体的定义,同时通过宏将串口添加为设备树的节点。

        ..\hal\actions\subsys\log\ 炬芯平台也有自己的打印子系统。

        ..\hal\actions\drivers\serial\uart_acts.c 炬芯平台串口文件。UART设备入口段的定义如下:

/* uart acts device init */
#define UART_ACTS_DEVICE_INIT(idx)						\PINCTRL_DT_DEFINE(UARTNODE(idx));					       \UART_ACTS_DEFINE_CONFIG(idx);					\static struct acts_uart_data uart_acts_dev_data_##idx ;\DEVICE_DT_DEFINE(UARTNODE(idx),					       \&uart_acts_init,				       \NULL,			       \&uart_acts_dev_data_##idx,				       \&uart_acts_config_##idx,				       \PRE_KERNEL_1,					       \CONFIG_SERIAL_INIT_PRIORITY,			       \&uart_acts_driver_api);
2.2..\zephyr\lib\os\printk.c

        系统层打印接口。如果使用DMA方式接口需要再加一层__vprintk()内部接口。printk_dma.c会定义一个vprintk()接口。#ifdef CONFIG_ACTIONS_PRINTK_DMA        void __vprintk(const char *fmt, va_list ap)        #else        void vprintk(const char *fmt, va_list ap)        #endif

#ifdef CONFIG_ACTIONS_PRINTK_DMA
void __vprintk(const char *fmt, va_list ap)
#else
void vprintk(const char *fmt, va_list ap)
#endif
{//如果使用zephyr的loging模块执行if (IS_ENABLED(CONFIG_LOG_PRINTK)) {z_log_vprintk(fmt, ap);return;}//不使用zephyr的loging模块执行if (k_is_user_context()) {struct buf_out_context ctx = {
#ifdef CONFIG_PICOLIBC.file = FDEV_SETUP_STREAM((int(*)(char, FILE *))buf_char_out,NULL, NULL, _FDEV_SETUP_WRITE),
#else0
#endif};#ifdef CONFIG_PICOLIBC(void) vfprintf(&ctx.file, fmt, ap);
#elsecbvprintf(buf_char_out, &ctx, fmt, ap);
#endifif (ctx.buf_count) {buf_flush(&ctx);}} else {
#ifdef CONFIG_PRINTK_SYNCk_spinlock_key_t key = k_spin_lock(&lock);
#endif#ifdef CONFIG_PICOLIBCFILE console = FDEV_SETUP_STREAM((int(*)(char, FILE *))char_out,NULL, NULL, _FDEV_SETUP_WRITE);(void) vfprintf(&console, fmt, ap);
#elsecbvprintf(char_out, NULL, fmt, ap);
#endif#ifdef CONFIG_PRINTK_SYNCk_spin_unlock(&lock, key);
#endif}
}

开启了CONFIG_LOG_PRINTK子系统后使用 z_log_vprintk()->z_log_msg_runtime_vcreate()(由于启动了DMA这个接口是没有执行)。

2.3..\hal\actions\subsys\trace\printk_dma.c

        SYS_INIT(printk_dma_init, APPLICATION, 1);//UART DMA设备入口段的定义,完成对static printk_ctx_t g_pr_ctx;结构体的变量。

        printk_dma.c会定义一个vprintk()接口。如果使用DMA方式则引用该接口。当DMA方式开启时通过{cbvprintf(buf_char_out, &ctx_buf, fmt, args);ctx_buf_flush(&ctx_buf);dma_start_tx(pctx);}接口完成数据发送。

void vprintk(const char *fmt, va_list args)
{printk_ctx_t *pctx = &g_pr_ctx;struct buf_out_ctx ctx_buf;if(!pctx->init){__vprintk(fmt, args);return ;}if(pctx->panic){dma_send_sync(pctx);k_busy_wait(100000); //wait fifo send finsheduart_dma_switch(pctx, 0); // CPUpctx->init = FALSE;__vprintk(fmt, args);return;}#ifdef CONFIG_PRINTK_TIME_FREFIXif ((pctx->isprint_time) && (pctx->last_char == '\0' ||pctx->last_char == '\n')) {ctx_buf.count = get_time_prefix(ctx_buf.buf);} else {ctx_buf.count = 0;}#elsectx_buf.count = 0;#endifcbvprintf(buf_char_out, &ctx_buf, fmt, args);ctx_buf_flush(&ctx_buf);dma_start_tx(pctx);
}

        uart_dma_send_buf()//shell打印引用

        uart_dma_send_buf_ex()//HCI打印专用接口。

        int uart_dma_send_buf_prepare(); void uart_dma_send_buf_prepare_over();//dsp打印引用

3、logging主要文件

..\zephyr\subsys\logging\log_frontend_dict_uart.c

        logging模块前端API,结合printk相关文件。

..\zephyr\subsys\logging\log_minimal.c

        mini模式的核心接口。

..\zephyr\subsys\logging\log_msg.c

        fall模式的核心接口。

..\zephyr\subsys\logging\log_core.c

         logger模块有线程处理方式(异步模式)与同步模式。

        logging子系统的入口段的定义如下:

static int enable_logger(void)
{if (IS_ENABLED(CONFIG_LOG_PROCESS_THREAD)) {k_timer_init(&log_process_thread_timer,log_process_thread_timer_expiry_fn, NULL);/* start logging thread */k_thread_create(&logging_thread, logging_stack,K_KERNEL_STACK_SIZEOF(logging_stack),log_process_thread_func, NULL, NULL, NULL,LOG_PROCESS_THREAD_PRIORITY, 0,COND_CODE_1(CONFIG_LOG_PROCESS_THREAD,K_MSEC(CONFIG_LOG_PROCESS_THREAD_STARTUP_DELAY_MS),K_NO_WAIT));k_thread_name_set(&logging_thread, "logging");} else {(void)z_log_init(false, false);}return 0;
}SYS_INIT(enable_logger, POST_KERNEL, CONFIG_LOG_CORE_INIT_PRIORITY);

        CONFIG_LOG_MODE_MINIMAL为真则为最小模式否则为完整模式。一般小型嵌入式系统只管理打印选择最小模式是完全够用了。

        16制打印入口Z_LOG_HEXDUMP2():最小模式调用z_log_minimal_hexdump_print(),完整模式调用Z_LOG_MSG_CREATE()接口。

        普通字符串打印入口Z_LOG2():最小模式调用z_log_minimal_printk(),完整模式调用Z_LOG_MSG_CREATE()接口。

#define Z_LOG2(_level, _inst, _source, _dsource, ...) do { \if (!Z_LOG_CONST_LEVEL_CHECK(_level)) { \break; \} \if (IS_ENABLED(CONFIG_LOG_MODE_MINIMAL)) { \Z_LOG_TO_PRINTK(_level, __VA_ARGS__); \break; \} \/* For instance logging check instance specific static level */ \if (_inst != 0 && !IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) { \if (_level > ((struct log_source_const_data *)_source)->level) { \break; \} \} \\bool is_user_context = k_is_user_context(); \if (IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) && \!is_user_context && _level > Z_LOG_RUNTIME_FILTER((_dsource)->filters)) { \break; \} \int _mode; \void *_src = IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING) ? \(void *)(_dsource) : (void *)(_source); \bool string_ok; \LOG_POINTERS_VALIDATE(string_ok, __VA_ARGS__); \if (!string_ok) { \LOG_STRING_WARNING(_mode, _src, __VA_ARGS__); \break; \} \Z_LOG_MSG_CREATE(UTIL_NOT(IS_ENABLED(CONFIG_USERSPACE)), _mode, \Z_LOG_LOCAL_DOMAIN_ID, _src, _level, NULL,\0, __VA_ARGS__); \(void)_mode; \if (false) { \/* Arguments checker present but never evaluated.*/ \/* Placed here to ensure that __VA_ARGS__ are*/ \/* evaluated once when log is enabled.*/ \z_log_printf_arg_checker(__VA_ARGS__); \} \
} while (false)

4、分级管理

        系统定义了4个等级[DBG, INF, WRN, EERR],但除了这4种等级还有两个比较特殊的接口

WRN_ONC():警告等级只执行一次的模块。

Z_LOG_PRINTK(_is_raw, ...):无等级打印接口。​​is_raw = 1原始字符串模式,换行[\n]时不自动加[\r],is_raw 这个参数在Minimal Mode下是不起作用的。

5、多格式打印可选

        Z_LOG(_level, ...):字符模式

        Z_LOG_HEXDUMP(_level, _data, _length, ...)16进制输出方式。与字符串明显区别是有length参数,遇到0也不会结束。

6、运行模式

最小模式 (Minimal Mode)

完整模式 (Full Mode):包含所有高级功能:过滤、缓冲、多后端等

如果只用DMA会被DMA发送接口接管,不开DMA则最底层都是走z_log_msg_runtime_vcreate()接口。接下内容如下:

void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source,uint8_t level, const void *data, size_t dlen,uint32_t package_flags, const char *fmt, va_list ap)
{int plen;if (fmt) {va_list ap2;va_copy(ap2, ap);plen = cbvprintf_package(NULL, Z_LOG_MSG_ALIGN_OFFSET,package_flags, fmt, ap2);__ASSERT_NO_MSG(plen >= 0);va_end(ap2);} else {plen = 0;}if (plen > Z_LOG_MSG_MAX_PACKAGE) {LOG_WRN("Message dropped because it exceeds size limitation (%u)",(uint32_t)Z_LOG_MSG_MAX_PACKAGE);return;}size_t msg_wlen = Z_LOG_MSG_ALIGNED_WLEN(plen, dlen);struct log_msg *msg;uint8_t *pkg;struct log_msg_desc desc =Z_LOG_MSG_DESC_INITIALIZER(domain_id, level, plen, dlen);if (IS_ENABLED(CONFIG_LOG_MODE_DEFERRED) && BACKENDS_IN_USE()) {msg = z_log_msg_alloc(msg_wlen);if (IS_ENABLED(CONFIG_LOG_FRONTEND) && msg == NULL) {pkg = alloca(plen);} else {pkg = msg ? msg->data : NULL;}} else {msg = alloca(msg_wlen * sizeof(int));pkg = msg->data;}if (pkg && fmt) {plen = cbvprintf_package(pkg, (size_t)plen, package_flags, fmt, ap);__ASSERT_NO_MSG(plen >= 0);}if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, desc.level)) {log_frontend_msg(source, desc, pkg, data);//}if (BACKENDS_IN_USE()) {z_log_msg_finalize(msg, source, desc, data);//多后端处理}
}

log_frontend_init()功能:完成回调函数配置;MPSC(Multi producer single consumer) 包坏缓冲结构体初始化,static struct mpsc_pbuf_buffer buf,这个buf在Full Mode时才有使用。

//
void log_frontend_init(void)
{int err;if (IS_ENABLED(CONFIG_UART_ASYNC_API)) {err = uart_callback_set(uart_dev, uart_callback, NULL);//异步(完成)回调处理} else if (IS_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN)) {uart_irq_callback_user_data_set(uart_dev, uart_isr_callback, NULL);//中断回调处理err = 0;}__ASSERT(err == 0, "Failed to set callback");if (err < 0) {return;}mpsc_pbuf_init(&buf, &config);//MPSC(Multi producer single consumer) packet buffer 初始化
}

7、过滤

9、同步异步打印

ats3239_dvb_ext_nor_defconfig:

CONFIG_LOG_MODE_MINIMAL//最小模式

CONFIG_LOG_MODE_IMMEDIATE//立即模式

enum z_log_msg_mode {

    /* Runtime mode is least efficient but supports all cases thus it is treated as a fallback method when others cannot be used.*/

    Z_LOG_MSG_MODE_RUNTIME,

    /* Mode creates statically a string package on stack and calls a function for creating a message. It takes code size than Z_LOG_MSG_MODE_ZERO_COPY but is a bit slower.*/

    Z_LOG_MSG_MODE_FROM_STACK,

    /* Mode calculates size of the message and allocates it and writes directly to the message space. It is the fastest method but requires more code size.*/

    Z_LOG_MSG_MODE_ZERO_COPY,

    /* Mode optimized for simple messages with 0 to 2 32 bit word arguments.*/

    Z_LOG_MSG_MODE_SIMPLE,

};

依赖线程的模式:

Z_LOG_MSG_MODE_RUNTIME- 唯一的线程依赖模式

不依赖线程的模式:

Z_LOG_MSG_MODE_FROM_STACK- 栈上处理,同步立即

Z_LOG_MSG_MODE_ZERO_COPY- 零拷贝优化,高性能同步

Z_LOG_MSG_MODE_SIMPLE- 简单消息特化,轻量同步

9、多后端

void z_log_msg_finalize(struct log_msg *msg, const void *source,const struct log_msg_desc desc, const void *data)
{if (!msg) {z_log_dropped(false);return;}if (data) {uint8_t *d = msg->data + desc.package_len;memcpy(d, data, desc.data_len);}msg->hdr.desc = desc;msg->hdr.source = source;
#if CONFIG_LOG_THREAD_ID_PREFIXmsg->hdr.tid = k_is_in_isr() ? NULL : k_current_get();
#endifz_log_msg_commit(msg);
}

10、实例日志

实例打印接口

#define Z_LOG_INSTANCE(_level, _inst, ...) do { \(void)_inst; \Z_LOG2(_level, 1, \COND_CODE_1(CONFIG_LOG_RUNTIME_FILTERING, (NULL), (Z_LOG_INST(_inst))), \(struct log_source_dynamic_data *)COND_CODE_1( \CONFIG_LOG_RUNTIME_FILTERING, \(Z_LOG_INST(_inst)), (NULL)), \__VA_ARGS__); \
} while (0)

11、紧急状态(panic模式)

核心作用

  • 标识系统处于崩溃状态,需要特殊的日志处理策略

  • 确保关键日志在系统崩溃时能够输出

  • 避免在崩溃状态下使用复杂的日志机制

void log_frontend_panic(void){in_panic = true;/* Flush all data */while (atomic_get(&active_cnt) > 0) {tx();/* empty */}
}

12、其打印模块

虽然zephyr系统有自己的底层vprintk()接口,宏定义层LOG_XXX()->Z_LOG()接口,但在一个平台的SDK经常会定义一套自己的printf与log接口。如炬芯的:SYS_LOG_XXX(),os_printk() ,ACT_LOG()。

12.1 ..\framework\porting\include\os_common_api.h

        定义了SYS_LOG_XXX()打印 SYS_LOG_ERR() /SYS_LOG_WRN() /SYS_LOG_INF() /SYS_LOG_DBG()

#ifndef CONFIG_ACTLOG
#ifdef CONFIG_LOG
#define SYS_LOG_INF(...)	\do {	\if (LOG_PRINT_FUNC_NAME) {  \if (Z_LOG_CONST_LEVEL_CHECK(LOG_LEVEL_INF)) {  \Z_LOG_WITH_FUNC_NAME(LOG_LEVEL_INF, __VA_ARGS__);  \}  \} else {  \Z_LOG_ACTS(LOG_LEVEL_INF, __VA_ARGS__);  \}  \} while (0)
#else
#define SYS_LOG_INF(...)
#endif
#else
#define SYS_LOG_INF(...) ACT_LOG(LOG_LEVEL_INF,__VA_ARGS__)
#endif

        定义了 os_printk() -> vprintk()

12.2..\hal\actions\subsys\log\act_log.c  ..\hal\actions\include\logging\act_log.h

        如果CONFIG_ACTLOG被定义则SYS_LOG_XXX()使用actions下的log模块接口。

12.3..\hal\actions\subsys\trace\printk_acts.c

        如果CONFIG_ACTLOG没有定义SYS_LOG_XXX()使用zephyr的vprintk()接口。

http://www.dtcms.com/a/577491.html

相关文章:

  • 哪里有免费建设网站企业解决方案ppt
  • Android内核进阶之获取PCM状态snd_pcm_status:用法实例(八十三)
  • 建设银行网站用户登录网页类界面图片
  • 【产品调研】MATB-II 软件用户指南总结
  • 程序开发的步骤东莞关键词排名seo
  • 重装系统后,恢复mysql的方法
  • 年化波动率匹配原则在ETF网格区间选择中的应用
  • 智慧公厕系统单机版与联网版有哪些区别
  • 华为技术有限公司 C语言编程规范
  • 新买的硬盘格式化后容量为啥缩水啦?
  • 【Ros2学习】服务-客户端模式
  • 网站建设的新闻重庆建网
  • 数字货币时代网络域名的价值评估
  • 帆软报表本地设计器中连接远程服务器后SAP数据集不显示问题
  • 第174期 TIMM:让迁移学习变得异常简单的PyTorch“隐藏”库
  • git cherry-pick
  • AR 眼镜之-普通电话-实现方案
  • 下厨房网站学做蒸包视频可以上传自己做的视频的网站吗
  • IO卡常见问题处理
  • 11_FastMCP 2.x 中文文档之FastMCP高级功能:用户引导详解
  • 门户网站 移动端黄石专业网站建设推广
  • 类的嵌套 、封装
  • (128页PPT)麦肯锡金字塔原理培训思考写作和解决问题的逻辑(附下载方式)
  • Python 类实战:从“函数堆函数”到“客户端对象”,看类如何让 API 请求代码脱胎换骨
  • springboot的单元测试功能有什么用
  • 5昌平区网站建设免费模板网站哪个好
  • 济南网站制作设计公司网站建设属于什么科目
  • 深入解析Kafka的消息模型:如何确保消息不丢失且高效传递
  • 微服务之Nacos(注册中心、配置中心)
  • 导致Resources文件夹的资源在Android打包后丢失的原因