本文主要是介绍鸿蒙反震时间怎么计算,鸿蒙内核源码分析(时间管理篇) | Tick是操作系统的基本时间单位...,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本篇说清楚时间概念
读本篇之前建议先读鸿蒙内核源码分析(总目录)其他篇.
时间概念太重要了,在鸿蒙内核又是如何管理和使用时间的呢?
时间管理以系统时钟 g_sysClock 为基础,给应用程序提供所有和时间有关的服务。
● 用户以秒、毫秒为单位计时.
● 操作系统以Tick为单位计时,这个认识很重要. 每秒的tick大小很大程度上决定了内核调度的次数多少.
● 当用户需要对系统进行操作时,例如任务挂起、延时等,此时需要时间管理模块对Tick和秒/毫秒进行转换。
熟悉两个概念:
● Cycle(周期):系统最小的计时单位。Cycle的时长由系统主时钟频率决定,系统主时钟频率就是每秒钟的Cycle数。
● Tick(节拍):Tick是操作系统的基本时间单位,由用户配置的每秒Tick数决定,可大可小.
怎么去理解他们之间的关系呢?看几个宏定义就清楚了.
时钟周期(振荡周期)
在鸿蒙g_sysClock表示时钟周期,是CPU的赫兹,也就是上面说的Cycle,这是固定不变的,由硬件晶振的频率决定的. OsMain是内核运行的第一个C函数,首个子函数就是 osRegister,完成对g_sysClock的赋值
CPU周期也叫(机器周期)
在鸿蒙宏OS_CYCLE_PER_TICK表示机器周期,Tick由用户根据实际情况配置. 例如:主频为1G的CPU,其振荡周期为: 1吉赫 (GHz 109 Hz) = 1 000 000 000 Hz 当Tick为100时,则1 000 000 000/100 = 10000000 ,即一秒内可产生1千万个CPU周期.CPU就是用这1千万个周期去执行指令的.
指令周期
指令周期是执行一条指令所需要的时间,一般由若干个机器周期组成。指令不同,所需的机器周期数也不同。 对于一些简单的的单字节指令,在取指令周期中,指令取出到指令寄存器后,立即译码执行,不再需要其它的机器周期。 对于一些比较复杂的指令,例如转移指令、乘法指令,则需要两个或者两个以上的机器周期。 通常含一个机器周期的指令称为单周期指令,包含两个机器周期的指令称为双周期指令。
Tick硬中断函数
LITE_OS_SEC_BSS volatile UINT64 g_tickCount[LOSCFG_KERNEL_CORE_NUM] = {0};//tick计数器,系统一旦启动,一直在++, 为防止溢出,这是一个 UINT64 的变量
LITE_OS_SEC_DATA_INIT UINT32 g_sysClock;//系统时钟,是绝大部分部件工作的时钟源,也是其他所有外设的时钟的来源
LITE_OS_SEC_DATA_INIT UINT32 g_tickPerSecond;//每秒Tick数,鸿蒙默认是每秒100次,即:10ms
LITE_OS_SEC_BSS DOUBLEg_cycle2NsScale; //周期转纳秒级
/* spinlock fortask module */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_tickSpin); //节拍器自旋锁
#define TICK_LOCK(state) LOS_SpinLockSave(&g_tickSpin, &(state))
/*
* Description : Tick interruption handler
*///节拍中断处理函数 ,鸿蒙默认10ms触发一次
LITE_OS_SEC_TEXT VOID OsTickHandler(VOID)
{
UINT32 intSave;
TICK_LOCK(intSave);
g_tickCount[ArchCurrCpuid()]++;//当前CPU核计数器
TICK_UNLOCK(intSave);
#ifdef LOSCFG_KERNEL_VDSO
OsUpdateVdsoTimeval();
#endif
#ifdef LOSCFG_KERNEL_TICKLESS
OsTickIrqFlagSet(OsTicklessFlagGet());
#endif
#if (LOSCFG_BASE_CORE_TICK_HW_TIME == YES)
HalClockIrqClear(); /* diff fromevery platform */
#endif
OsTimesliceCheck();//时间片检查
OsTaskScan(); /* task timeout scan *///任务扫描
#if (LOSCFG_BASE_CORE_SWTMR == YES)
OsSwtmrScan();//定时器扫描,看是否有超时的定时器
#endif
}
#ifdef __cplusplus
#if __cplusplus
}
解读
● g_tickCount记录每个CPU核tick的数组,每次硬中断都触发 OsTickHandler,每个CPU核单独计数.
● OsTickHandler是内核调度的动力,其中会检查任务时间片是否用完,定时器是否超时.主动delay的任务是否需要被唤醒,其本质是个硬中断,在HalClockInit硬时钟初始化时创建的,具体在硬中断篇中会详细讲解.
● TICK_LOCK是tick操作的自旋锁,宏原型LOS_SpinLockSave在自旋锁篇中已详细介绍.
功能函数
#define OS_SYS_MS_PER_SECOND 1000 //一秒多少毫秒
//获取自系统启动以来的Tick数
LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID)
{
UINT32 intSave;
UINT64 tick;
/*
* use core0's tick as system's timeline,
* the tick needs tobe atomic.
*/
TICK_LOCK(intSave);
tick = g_tickCount[0];//使用CPU core0作为系统的 tick数
TICK_UNLOCK(intSave);
returntick;
}
//每个Tick多少Cycle数
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CyclePerTickGet(VOID)
{
returng_sysClock / LOSCFG_BASE_CORE_TICK_PER_SECOND;
}
//毫秒转换成Tick
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec)
{
if (millisec == OS_MAX_VALUE) {
returnOS_MAX_VALUE;
}
return((UINT64)millisec * LOSCFG_BASE_CORE_TICK_PER_SECOND) / OS_SYS_MS_PER_SECOND;
}
//Tick转化为毫秒
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_Tick2MS(UINT32 tick)
{
return((UINT64)tick * OS_SYS_MS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND;
}
说明
● 在CPU篇中讲过,0号CPU核默认为主核,默认获取自系统启动以来的Tick数使用的是g_tickCount[0]
● 因每个CPU核的tick是独立计数的,所以g_tickCount中各值是不一样的.
● 系统的Tick数在关中断的情况下不进行计数,因为OsTickHandler本质是由硬中断触发的,屏蔽硬中断的情况下就不会触发OsTickHandler,自然也就不会有g_tickCount[ArchCurrCpuid()]++的计数,所以系统Tick数不能作为准确时间使用.
● 追问下,什么情况下硬中断会被屏蔽?
编程示例
前提条件:
● 使用每秒的Tick数LOSCFG_BASE_CORE_TICK_PER_SECOND的默认值100。
● 配好OS_SYS_CLOCK系统主时钟频率。
时间转换
VOID Example_TransformTime(VOID)
{
UINT32 ms;
UINT32 tick;
tick = LOS_MS2Tick(10000); // 10000ms转换为tick
dprintf("tick = %d \n",tick);
ms = LOS_Tick2MS(100); // 100tick转换为ms
dprintf("ms = %d \n",ms);
}
时间转换结果
tick = 1000
ms = 1000
时间统计和时间延迟
LITE_OS_SEC_TEXT UINT32 LOS_TaskDelay(UINT32 tick);
VOID Example_GetTime(VOID)
{
UINT32 cyclePerTick;
UINT64 tickCount;
cyclePerTick = LOS_CyclePerTickGet();
if(0 != cyclePerTick) {
dprintf("LOS_CyclePerTickGet = %d \n", cyclePerTick);
}
tickCount = LOS_TickCountGet();
if(0 != tickCount) {
dprintf("LOS_TickCountGet = %d \n", (UINT32)tickCount);
}
LOS_TaskDelay(200);//延迟200个tick
tickCount = LOS_TickCountGet();
if(0 != tickCount) {
dprintf("LOS_TickCountGet after delay = %d \n", (UINT32)tickCount);
}
}
时间统计和时间延迟结果
LOS_CyclePerTickGet = 495000 //取决于CPU的频率
LOS_TickCountGet = 1 //实际情况不一定是1的
LOS_TickCountGet afterdelay = 201 //实际情况不一定是201,但二者的差距会是200
【编辑推荐】
【责任编辑:jianghua TEL:(010)68476606】
点赞 0
这篇关于鸿蒙反震时间怎么计算,鸿蒙内核源码分析(时间管理篇) | Tick是操作系统的基本时间单位...的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!