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. regular.js

    //手机号验证 var regMobile=/^1[3,5,8]\d{9}$/; //固定电话 var regPhone=/^(^0\d{2}-?\d{8}$)|(^0\d{3}-?\d{7}$)|( ...

  2. c语言学习笔记-do......while

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 一.do......while函数意义 循环执行(人机交互) 二.do......while函数结构 do{ 语句1: 语句2: ...

  3. ES6学习之变量的解构赋值

    前言:什么是ES6?ECMAScript 6(简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了.其中相比较于ES5新增了诸多的特性,并且ES6可转换为ES5的语法.- ...

  4. CSS3属性-webkit-font-smoothing字体抗锯齿渲染

    对字体进行抗锯齿渲染可以使字体看起来会更清晰舒服.在图标字体成为一种趋势的今天,抗锯齿渲染使用也越来越多. font-smoothing是非标准的CSS定义.它被列入标准规范的草案中,后由于某些原因从 ...

  5. 测试思想-流程规范 SVN代码管理与版本控制

    SVN代码管理与版本控制 by:授客 QQ:1033553122   欢迎加入软件性能测试交流群(QQ群):7156436   目录 一. 二. 三. 四. 五. 六. 七. 一. 创建根目录 创建一 ...

  6. springcloud 入门 10 (eureka高可用)

    eureka高可用: 说白了,就是加一个实例作为原实例的备份,然后一起对外提供服务.这样可以保证在一台机器宕机的时候,整个系统不会死掉.保证其继续对外服务. eureka的集群化: 服务注册中心Eur ...

  7. OCaml相关

    1.open Core.Std 时报Unbound module Core 先安装库 $ opam init $ opam install core $ opam install utop 在~/.o ...

  8. python第八天)——购物车作业优化完成

    发现之前的三级菜单代码有BUG现已经修改过来了 购物车程序:启动程序后,输入用户名密码后,如果是第一次登录,让用户输入工资,然后打印商品列表允许用户根据商品编号购买商品用户选择商品后,检测余额是否够, ...

  9. 修改sqlserver2008数据库的排序规则 (转)

    修改sqlserver2008数据库的排序规则 (转)      修改SQL server 2008服务器排序规则 SQL Server 2008安装好后,发现服务器排序规则不对,又不想重装SQL S ...

  10. sql2008和sql2012混合安装后打开SQL Server 配置管理器查看出现“远程过程调用失败”0x800706be

    sql2008和sql2012混合安装后打开SQL Server 配置管理器SQL Server服务出现“远程过程调用失败”0x800706be 网上很多人都说这个解决方案,通过卸载“Microsof ...