1 前言

刚接触Zephyr,两眼一抹黑,光是阅读代码对系统没什么概念。还需要通过一些日志了解系统的运行机制,以及各种内核行为。

这就需要借助系统的Logging,大体分为两部分System LoggingKernel Event Logger

下面就分别介绍System Logging和Kernel Event Logger。

2 Kernel Event Logger

Logger记录内核特定性为,比如Interrupts、Context Switching、Sleep等。这些Log有助于优化应用,无论是进行debug还是性能调优。

2.1 Kernel Event Logger Configuration

Logger有很多内核相关配置选项,可以通过这些选项进行细化。

配置 解释

CONFIG_KERNEL_EVENT_LOGGER

Logger总开关。

CONFIG_KERNEL_EVENT_LOGGER_CONTEXT_SWITCH

进程切换事件。

CONFIG_KERNEL_EVENT_LOGGER_INTERRUPT

中断事件。

CONFIG_KERNEL_EVENT_LOGGER_SLEEP

睡眠事件。

CONFIG_KERNEL_EVENT_LOGGER_BUFFER_SIZE

RingBuffer大小。

CONFIG_KERNEL_EVENT_LOGGER_DYNAMIC

将logging控制权交给应用自身。

CONFIG_KERNEL_EVENT_LOGGER_CUSTOM_TIMESTAMP

允许自定义时间戳函数。

2.2 Event定义

目前内核已经支持如下四中预定义Event,分别是进程切换、中断、睡眠、和线程。

这些事件被记录在内核的Ring Buffer中,应用可以读取然后分析内核行为。这些记录在Ring Buffer满之后,会被覆盖,因此必须及时读取。

默认情况下,内核打开所有事件记录。但是应用自身可以根据需要开关特定类型事件,或者选择特定时间段开关。

#define KERNEL_EVENT_LOGGER_CONTEXT_SWITCH_EVENT_ID             0x0001
#define KERNEL_EVENT_LOGGER_INTERRUPT_EVENT_ID 0x0002
#define KERNEL_EVENT_LOGGER_SLEEP_EVENT_ID 0x0003
#define KERNEL_EVENT_LOGGER_THREAD_EVENT_ID 0x0004

2.2.1 时间戳

默认情况下,时间戳从Hardware clock取,这是一个32为的时钟计数,很容易溢出,需要将溢出计数进行记录。

同时,Logger的时间戳还可以通过sys_k_event_logger_set_timer()进行自定义。

2.2.2 事件读取

事件的读取可以通过如下函数进行,具体用法可以查看链接。

如下是代码示例:

u16_t event_id;
u8_t dropped_count;
u32_t data[];
u8_t data_size; while() {
/* retrieve an event */
data_size = SIZE32_OF(data);
res = sys_k_event_logger_get_wait(&event_id, &dropped_count, data,
&data_size); if (dropped_count > ) {
/* ... Process the dropped events count ... */
} if (res > ) {
/* process the event */
switch (event_id) {
case KERNEL_EVENT_LOGGER_CONTEXT_SWITCH_EVENT_ID:
/* ... Process the context switch event ... */
break;
case KERNEL_EVENT_LOGGER_INTERRUPT_EVENT_ID:
/* ... Process the interrupt event ... */
break;
case KERNEL_EVENT_LOGGER_SLEEP_EVENT_ID:
/* ... Process the sleep event ... */
break;
default:
printf("unrecognized event id %d\n", event_id);
}
} else if (res == -EMSGSIZE) {
/* ... Data array is too small to hold the event! ... */
}
}

2.2.3 增加自定义事件

首先需要在kernel_event_logger.h定义一个Event ID,ID总会不超过32.

自定义事件通过如下API写入到Logger中:

自定义事件接口函数内容如下:

#define MY_CUSTOM_EVENT_ID 8

/* record custom event only if recording is currently wanted */
if (sys_k_must_log_event(MY_CUSTOM_EVENT_ID)) {
u32_t data[]; data[] = custom_data_1;
data[] = custom_data_2; sys_k_event_logger_put(MY_CUSTOM_EVENT_ID, data, ARRAY_SIZE(data));
}

应用调用此事件示例如下:

#define MY_CUSTOM_TIME_ONLY_EVENT_ID 9

if (sys_k_must_log_event(MY_CUSTOM_TIME_ONLY_EVENT_ID)) {
sys_k_event_logger_put_timed(MY_CUSTOM_TIME_ONLY_EVENT_ID);
}

2.3 系统预定义事件

KERNEL_EVENT_LOGGER_CONTEXT_SWITCH_EVENT_ID

在__pendsv(swap.S)中进行线程上下文切换,然后在这里记录事件。

SECTION_FUNC(TEXT, __pendsv)

#ifdef CONFIG_KERNEL_EVENT_LOGGER_CONTEXT_SWITCH
/* Register the context switch */
push {lr}
bl _sys_k_event_logger_context_switch
... void _sys_k_event_logger_context_switch(void)
{
extern struct _kernel _kernel;
u32_t data[];
... data[] = _sys_k_get_time();----------------------------记录当前Hardware Cycles
data[] = (u32_t)_kernel.current;-----------------------记录切换出去的线程ID
...
_sys_event_logger_put_non_preemptible(&sys_k_event_logger,
KERNEL_EVENT_LOGGER_CONTEXT_SWITCH_EVENT_ID, data,
ARRAY_SIZE(data));
}

KERNEL_EVENT_LOGGER_INTERRUPT_EVENT_ID

中断事件记录入口在中断处理函数中:

_timer_int_handler(cortex_x_systick.c)-->
_isr_wrapper(isr_wrapper.S)-->
_arch_isr_direct_header(irq_manage.c)-->
_sys_k_event_logger_interrupt

void _sys_k_event_logger_interrupt(void)
{
u32_t data[]; if (!sys_k_must_log_event(KERNEL_EVENT_LOGGER_INTERRUPT_EVENT_ID)) {
return;
} /* if the kernel event logger has not been initialized, we do nothing */
if (sys_k_event_logger.ring_buf.buf == NULL) {
return;
} data[] = _sys_k_get_time();-----------------记录Hardware cycles
data[] = _sys_current_irq_key_get();--------中断号 sys_k_event_logger_put(KERNEL_EVENT_LOGGER_INTERRUPT_EVENT_ID, data,
ARRAY_SIZE(data));
}

KERNEL_EVENT_LOGGER_SLEEP_EVENT_ID

由于睡眠需要记录睡眠和唤醒点,以及导致唤醒的中断,所以参数有三个。

k_cpu_idle(cpu_idle.S)-->
_sys_k_event_logger_enter_sleep void _sys_k_event_logger_enter_sleep(void)
{
if (!sys_k_must_log_event(KERNEL_EVENT_LOGGER_SLEEP_EVENT_ID)) {
return;
} _sys_k_event_logger_sleep_start_time = k_cycle_get_32();---------------------记录睡眠开始时间
} _isr_wrapper(isr_wrapper.S)-->
_arch_isr_direct_header(irq_manage.c)-->
_sys_k_event_logger_exit_sleep void _sys_k_event_logger_exit_sleep(void)
{
u32_t data[]; if (!sys_k_must_log_event(KERNEL_EVENT_LOGGER_SLEEP_EVENT_ID)) {
return;
} if (_sys_k_event_logger_sleep_start_time != ) {
data[] = _sys_k_get_time();-------------------------------------------------------------唤醒时间
data[] = (k_cycle_get_32() - _sys_k_event_logger_sleep_start_time)----------------------记录睡眠持续时间
/ sys_clock_hw_cycles_per_tick;
/* register the cause of exiting sleep mode */
data[] = _sys_current_irq_key_get();----------------------------------------------------唤醒中断号
...
_sys_k_event_logger_sleep_start_time = ; sys_k_event_logger_put(KERNEL_EVENT_LOGGER_SLEEP_EVENT_ID, data,
ARRAY_SIZE(data));
}
}

KERNEL_EVENT_LOGGER_THREAD_EVENT_ID

_sys_k_event_logger_thread_ready-->
_sys_k_event_logger_thread_pend-->
_sys_k_event_logger_thread_exit-->
log_thread_event static void log_thread_event(enum sys_k_event_logger_thread_event event,
struct k_thread *thread)
{
u32_t data[]; if (!sys_k_must_log_event(KERNEL_EVENT_LOGGER_THREAD_EVENT_ID)) {
return;
} data[] = _sys_k_get_time();
data[] = (u32_t)(thread ? thread : _kernel.current);
data[] = (u32_t)event;-----------------------------------记录当前线程的状态 sys_k_event_logger_put(KERNEL_EVENT_LOGGER_THREAD_EVENT_ID, data,
ARRAY_SIZE(data));
}

enum sys_k_event_logger_thread_event {
KERNEL_LOG_THREAD_EVENT_READYQ,
KERNEL_LOG_THREAD_EVENT_PEND,
KERNEL_LOG_THREAD_EVENT_EXIT,
};

3 System Logging

另外应用还可以通过终端输出Log,系统System Logging定义了四中不同等级的SYS_LOG_X:SYS_LOG_ERR、SYS_LOG_WRN、SYS_LOG_INF、SYS_LOG_DBG。

#define SYS_LOG_LEVEL_OFF 0
#define SYS_LOG_LEVEL_ERROR 1
#define SYS_LOG_LEVEL_WARNING 2
#define SYS_LOG_LEVEL_INFO 3
#define SYS_LOG_LEVEL_DEBUG 4

关于Log等级有两种:全局性和模块内部。如果模组内部定义了Log等级,设置可以设置自己的Log等级。通过定义SYS_LOG_LEVEL且包含头文件sys_log.h。

3.1 System Logging配置

CONFIG_SYS_LOG: Global switch, turns on/off all system logging.System Logging开关

CONFIG_SYS_LOG_DEFAULT_LEVEL: Default level, sets the logging level used by modules that are not setting their own logging level.

CONFIG_SYS_LOG_SHOW_TAGS: Globally sets whether level tags will be shown on log or not.

CONFIG_SYS_LOG_SHOW_COLOR: Globally sets whether ANSI colors will be used by the system log.

CONFIG_SYS_LOG_OVERRIDE_LEVEL: It overrides module logging level when it is not set or set lower than the override value.在模组等级没有设置或者低于此等级时,使用此等级。

3.2 System Logging使用

使用方法如下,当然系统CONFIG_SYS_LOG_OVERRIDE_LEVEL或者模组内部等级定义不低于WARN。

SYS_LOG_WRN("hi!");

[general] [WRN] main: Hi!

Zephyr的Logging的更多相关文章

  1. Zephyr学习专题

    1 前言 本来想学习Zyphyr的Power Management,但是看着看着就被带进去了. 你看功耗,里面的suspend涉及到时间补偿相关的吧,然后就涉及到了Kernel Clocks/Time ...

  2. 开发你的第一个NCS(Zephyr)应用程序

    Nordic有2套并存的SDK:老的nRF5 SDK和新的NCS SDK,两套SDK相互独立,大家选择其中一套进行开发即可.一般而言,如果你选择的芯片是nRF51或者nRF52系列,那么推荐使用nRF ...

  3. Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory

    学习架构探险,从零开始写Java Web框架时,在学习到springAOP时遇到一个异常: "C:\Program Files\Java\jdk1.7.0_40\bin\java" ...

  4. Oracle补全日志(Supplemental logging)

    Oracle补全日志(Supplemental logging)特性因其作用的不同可分为以下几种:最小(Minimal),支持所有字段(all),支持主键(primary key),支持唯一键(uni ...

  5. Zephyr OS 简介

    最新发布的开源 Zephyr Project™(Zephyr 项目)是一款小型且可伸缩的实时操作系统,尤其适用于资源受限的系统,可支持多种架构:该系统高度开源,对于开发人员社区完全开放,开发人员可根据 ...

  6. Java程序日志:java.util.logging.Logger类

    一.Logger 的级别 比log4j的级别详细,全部定义在java.util.logging.Level里面.各级别按降序排列如下:SEVERE(最高值)WARNINGINFOCONFIGFINEF ...

  7. python 学习笔记 -logging模块(日志)

    模块级函数 logging.getLogger([name]):返回一个logger对象,如果没有指定名字将返回root loggerlogging.debug().logging.info().lo ...

  8. python logging colorlog

    import logging LOG_LEVEL = logging.NOTSET LOGFORMAT = "[%(log_color)s%(levelname)s] [%(log_colo ...

  9. [转]ASP.NET Core 开发-Logging 使用NLog 写日志文件

    本文转自:http://www.cnblogs.com/Leo_wl/p/5561812.html ASP.NET Core 开发-Logging 使用NLog 写日志文件. NLog 可以适用于 . ...

随机推荐

  1. 关于Ajax的get与post浅分析,同步请求与异步请求,跨域请求;

    Ajax局部异步刷新全称ASynchronous JavaScript And XML.使用Javascript代码获取服务器的数据,Ajax当中有两个请求方法,一个是get方法,一个是post请求方 ...

  2. js keyup、keypress和keydown事件

    js keyup.keypress和keydown事件都是有关于键盘的事件 当一个按键被pressed 或released在每一个现代浏览器中,都可能有三种客户端事件. keydown event k ...

  3. 洛谷P2178 [NOI2015]品酒大会(后缀自动机 线段树)

    题意 题目链接 Sol 说一个后缀自动机+线段树的无脑做法 首先建出SAM,然后对parent树进行dp,维护最大次大值,最小次小值 显然一个串能更新答案的区间是\([len_{fa_{x}} + 1 ...

  4. 在 Ubuntu 18.04 下安装 fcitx 及搜狗拼音输入法

    感觉自己傻逼透了,之前在 16.04 时折腾着要装 ibus 和 rime 输入法,现在 18.04 默认安装 ibus 了,又因为 rime 的智能联想太弱,打字不爽,又想装回搜狗一劳永逸... 环 ...

  5. 排错-lr回放错误Vuser failed to initialize extensi...解决方法

    lr回放错误:Vuser failed to initialize extension LrXml.dll解决方法   by:授客 QQ:1033553122 步骤1:找到LR安装位置,打开协议目录 ...

  6. 转 fiddler常见的应用场景

    fiddler常见的应用场景   在移动互联网时代,作为软件测试工程师,fiddler绝对是值得掌握并添加进技术栈里的工具之一. 那么,fiddler在日常的测试工作中,一般都有哪些常见的应用场景呢? ...

  7. 服务器 nginx配置 防止其他域名绑定自己的服务器

    基于我的网站被其他的域名恶意绑定了,我做出了如下处理,全站转https,同时配置nginx跳转禁止其他绑定ip的域名访问(原理主机空域名可绑定任意的,参考https://www.jb51.net/ar ...

  8. 使用Anemometer基于pt-query-digest将MySQL慢查询可视化

    最近玩MySQL,发现了一个很不错的工具,可以把MySQL慢查询可视化,方便我们去找出和分析慢询语句,搭建的步骤不多,但网上详细教程比较少,说得也不够详细,一不小心,估计得蛋痛一会,哈哈 Percon ...

  9. 根据id来大量删除数据between

    id的范围来删除数据 比如要删除 110到220的id信息:delete id from 表名 where id between 110 and 220;

  10. Linksys EA6500刷ddwrt成功记

    网上刷Linksys EA6500的资料不多,然后又绕了好多个弯子,自己记录备忘. 首先EA6500有两个版本v1和v2,对应的固件不同. 区分方法: 1.v1的背后是两个颜色一样的usb2.0 2. ...