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. nginx 匹配规则小总结

    nginx location 等号类型(=)的优先级最高,需要精确匹配.一旦匹配成功,则不再查找其他匹配项. ^~类型表达式.一旦匹配成功,则不再查找其他匹配项. 正则表达式类型(~ ~*)的优先级次 ...

  2. 【读书笔记】iOS-应用内购买

    Store Kit框架是一个应用内支付引擎.通过这个框架,付费应用可以实现用户付费购买内容的功能(比如为了获取额外的内容) 如果你发现Store Kit框架很难用,而且应用内付款不需要服务器端的支持, ...

  3. 【读书笔记】iOS-Interface Builder

    IBOutlet或IBAction符号对编译不产生任何影响,它们只是标记,用于告诉Xcode这些对象可以和UI控件进行关联,以便于在编辑Interface Builder上的UI控件的时候Xcode可 ...

  4. python之管道, 事件, 信号量, 进程池

    管道:双向通信 2个进程之间相互通信 from multiprocessing import Process, Pipe def f1(conn): from_zjc_msg = conn.recv( ...

  5. OSGI企业应用开发(十四)整合Spring、Mybatis、Spring MVC

    作为一个企业级的Web应用,MVC框架是必不可少的.Spring MVC目前使用也比较广泛,本文就来介绍一下如何在OSGI应用中实现Spring.Mybatis.Spring MVC框架的整合,其中S ...

  6. Salesforce 数据库操作简介

    Salesforce 中的数据库操作方式 Salesforce 为用户和开发者提供了四种基本的数据库操作方式: Apex 中的 DML 语句 Apex 中的 Database 类 SOQL 查询 SO ...

  7. python网络编程:socketserver的基本使用

    本文内容: socketserver的介绍 socketserver的使用 socketserver的异步服务端 首发时间:2018-03-21 也可以使用socketserver来创建socket ...

  8. Centos7下安装与卸载docker应用容器引擎

    Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Li ...

  9. Beta冲刺(2/5)(麻瓜制造者)

    今日完成任务 邓弘立:继续完成了昨天未完成的登录接口的重编码与测试. 李佳铭|:进一步完善了收藏UI 江郑: 对使用前端框架页面元素的进一步优化,基本功能进行中 刘双玉:部分图书馆租借接口修改 肖小强 ...

  10. String类的常用方法详解

    1:获取字符串的长度length(),下标从1开始 2:将其他类型转换为String类型toStrings() 3:去除字符串首尾的空格trim() 4:分割字符串spilt() 5:比较两个字符串是 ...