文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

鸿蒙内核源码分析(时间管理篇) | Tick是操作系统的基本时间单位

2024-12-03 08:08

关注

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

本篇说清楚时间概念

读本篇之前建议先读鸿蒙内核源码分析(总目录)其他篇.

时间概念太重要了,在鸿蒙内核又是如何管理和使用时间的呢?

时间管理以系统时钟 g_sysClock 为基础,给应用程序提供所有和时间有关的服务。

[[390986]]

● 用户以秒、毫秒为单位计时.

● 操作系统以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硬中断函数

  1. LITE_OS_SEC_BSS volatile UINT64 g_tickCount[LOSCFG_KERNEL_CORE_NUM] = {0};//tick计数器,系统一旦启动,一直在++, 为防止溢出,这是一个 UINT64 的变量 
  2. LITE_OS_SEC_DATA_INIT UINT32 g_sysClock;//系统时钟,是绝大部分部件工作的时钟源,也是其他所有外设的时钟的来源  
  3. LITE_OS_SEC_DATA_INIT UINT32 g_tickPerSecond;//每秒Tick数,鸿蒙默认是每秒100次,即:10ms 
  4. LITE_OS_SEC_BSS DOUBLE g_cycle2NsScale; //周期转纳秒级 
  5.  
  6.  
  7. LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_tickSpin); //节拍器自旋锁 
  8. #define TICK_LOCK(state)                       LOS_SpinLockSave(&g_tickSpin, &(state)) 
  9. //节拍中断处理函数 ,鸿蒙默认10ms触发一次 
  10. LITE_OS_SEC_TEXT VOID OsTickHandler(VOID) 
  11.     UINT32 intSave; 
  12.  
  13.     TICK_LOCK(intSave); 
  14.     g_tickCount[ArchCurrCpuid()]++;//当前CPU核计数器 
  15.     TICK_UNLOCK(intSave); 
  16.  
  17. #ifdef LOSCFG_KERNEL_VDSO 
  18.     OsUpdateVdsoTimeval(); 
  19. #endif 
  20.  
  21. #ifdef LOSCFG_KERNEL_TICKLESS 
  22.     OsTickIrqFlagSet(OsTicklessFlagGet()); 
  23. #endif 
  24.  
  25. #if (LOSCFG_BASE_CORE_TICK_HW_TIME == YES) 
  26.     HalClockIrqClear();  
  27. #endif 
  28.  
  29.     OsTimesliceCheck();//时间片检查 
  30.  
  31.     OsTaskScan(); //任务扫描 
  32.  
  33. #if (LOSCFG_BASE_CORE_SWTMR == YES) 
  34.     OsSwtmrScan();//定时器扫描,看是否有超时的定时器 
  35. #endif 
  36.  
  37. #ifdef __cplusplus 
  38. #if __cplusplus 
  39.   

解读

● g_tickCount记录每个CPU核tick的数组,每次硬中断都触发 OsTickHandler,每个CPU核单独计数.

● OsTickHandler是内核调度的动力,其中会检查任务时间片是否用完,定时器是否超时.主动delay的任务是否需要被唤醒,其本质是个硬中断,在HalClockInit硬时钟初始化时创建的,具体在硬中断篇中会详细讲解.

● TICK_LOCK是tick操作的自旋锁,宏原型LOS_SpinLockSave在自旋锁篇中已详细介绍.

功能函数

  1. #define OS_SYS_MS_PER_SECOND   1000         //一秒多少毫秒 
  2. //获取自系统启动以来的Tick数 
  3. LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID) 
  4.     UINT32 intSave; 
  5.     UINT64 tick; 
  6.  
  7.      
  8.     TICK_LOCK(intSave); 
  9.     tick = g_tickCount[0];//使用CPU core0作为系统的 tick数 
  10.     TICK_UNLOCK(intSave); 
  11.  
  12.     return tick; 
  13. //每个Tick多少Cycle数 
  14. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CyclePerTickGet(VOID) 
  15.     return g_sysClock / LOSCFG_BASE_CORE_TICK_PER_SECOND; 
  16. //毫秒转换成Tick 
  17. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec) 
  18.     if (millisec == OS_MAX_VALUE) { 
  19.         return OS_MAX_VALUE; 
  20.     } 
  21.  
  22.     return ((UINT64)millisec * LOSCFG_BASE_CORE_TICK_PER_SECOND) / OS_SYS_MS_PER_SECOND; 
  23. //Tick转化为毫秒 
  24. LITE_OS_SEC_TEXT_MINOR UINT32 LOS_Tick2MS(UINT32 tick) 
  25.     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系统主时钟频率。

时间转换

  1. VOID Example_TransformTime(VOID) 
  2.     UINT32 ms; 
  3.     UINT32 tick; 
  4.  
  5.     tick = LOS_MS2Tick(10000);    // 10000ms转换为tick 
  6.     dprintf("tick = %d \n",tick); 
  7.     ms = LOS_Tick2MS(100);        // 100tick转换为ms 
  8.     dprintf("ms = %d \n",ms); 

时间转换结果

  1. tick = 1000 
  2. ms = 1000 

时间统计和时间延迟

  1. LITE_OS_SEC_TEXT UINT32 LOS_TaskDelay(UINT32 tick); 
  2. VOID Example_GetTime(VOID) 
  3.     UINT32 cyclePerTick; 
  4.     UINT64 tickCount; 
  5.  
  6.     cyclePerTick  = LOS_CyclePerTickGet(); 
  7.     if(0 != cyclePerTick) { 
  8.         dprintf("LOS_CyclePerTickGet = %d \n", cyclePerTick); 
  9.     } 
  10.  
  11.     tickCount = LOS_TickCountGet(); 
  12.     if(0 != tickCount) { 
  13.         dprintf("LOS_TickCountGet = %d \n", (UINT32)tickCount); 
  14.     } 
  15.  
  16.     LOS_TaskDelay(200);//延迟200个tick 
  17.     tickCount = LOS_TickCountGet(); 
  18.     if(0 != tickCount) { 
  19.         dprintf("LOS_TickCountGet after delay = %d \n", (UINT32)tickCount); 
  20.     } 

时间统计和时间延迟结果

  1. LOS_CyclePerTickGet = 495000 //取决于CPU的频率 
  2. LOS_TickCountGet = 1 //实际情况不一定是1的 
  3. LOS_TickCountGet after delay = 201 //实际情况不一定是201,但二者的差距会是200 

想了解更多内容,请访问:

51CTO和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

 

来源:鸿蒙社区内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯