除了前面介绍的tm struct 和 time_t定义,标准C的库还有clock_t的定义。相比前面两者,这个是一个更加单纯的“计时”定义,前两者更像是日期时间的定义。
对于 clock_t ,在 EadkPkg_A2\StdLib\Include\time.h 有如下定义
/** An arithmetic type capable of representing values returned by clock(); **/ #ifdef _EFI_CLOCK_T typedef _EFI_CLOCK_T clock_t; #undef _EFI_CLOCK_T #endif
在 StdLib\Include\sys\EfiCdefs.h 有下面的定义
#define _EFI_CLOCK_T UINT64
和 clock_t 配合的还有CLOCKS_PER_SEC ,定义了一秒中的Clock数
EadkPkg_A2\StdLib\Include\time.h
#define CLOCKS_PER_SEC __getCPS()
这个函数的具体实现在 EadkPkg_A2\StdLib\LibC\Time\Time.c
clock_t EFIAPI __getCPS(void) { return gMD->ClocksPerSecond; }
函数 clock() 的作用是取得从程序开始运行的处理器时钟数。特别需要注意:在NT32模拟环境中和实际环境中,这个函数是不同的。之前提到过,如果想在NT32环境中正常使用C Library,必须在AppPkg.dsc中做一些修改
[LibraryClasses.IA32] #TimerLib|PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf ## Comment out the above line and un-comment the line below for running under Nt32 emulation. TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
当然,修改之后,能在NT32环境中运行了,但是无法取得clock值。输出始终为 0。
为了验证,我尝试在实际环境下测试。首先是要将上面的设定恢复原装。恢复完之后无法通过编译,需要修改成下面的样子(下面ORG给出的是原来的路径)。
[LibraryClasses.IA32] #ORG TimerLib|PerformancePkg/Library/DxeTscTimerLib/DxeTscTimerLib.inf TimerLib|PerformancePkg/Library/TscTimerLib/DxeTscTimerLib.inf ## Comment out the above line and un-comment the line below for running under Nt32 emulation. #TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
之后,我用WinISO做了一个 ISO镜像,将main.efi放在iso文件中,直接挂接到virtualbox的虚拟机中(4.3.10 r93012),发现运行之后无任何输出.
拷贝到实际机器上运行,看起来结果正常:
这次实验使用的代码如下,依然是从 Demo 的Main.c中修改而来
/** @file A simple, basic, application showing how the Hello application could be built using the "Standard C Libraries" from StdLib. Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR> This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license. THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ //#include <Uefi.h> //#include <Library/UefiLib.h> //#include <Library/ShellCEntryLib.h> #include <stdio.h> #include <time.h> /*** Demonstrates basic workings of the main() function by displaying a welcoming message. Note that the UEFI command line is composed of 16-bit UCS2 wide characters. The easiest way to access the command line parameters is to cast Argv as: wchar_t **wArgv = (wchar_t **)Argv; @param[in] Argc Number of argument tokens pointed to by Argv. @param[in] Argv Array of Argc pointers to command line tokens. @retval 0 The application exited normally. @retval Other An error occurred. ***/ int EFIAPI main ( IN int Argc, IN char **Argv ) { int i; printf("Sizeof Clock_T %d\n",sizeof(clock_t)); printf("CLOCKS_PER_SEC %d\n",CLOCKS_PER_SEC); printf("Start %d\n",clock()); for (i=1;i<0xFFFF; i++) { } printf("End %d\n",clock()); return EFI_SUCCESS; }
依旧是使用 AppPkg 的环境进行编译。
代码下载
编译的可以在实际机器上运行的EFI文件
根据上面的 CLOCKS_PER_SEC 我们同样能做出来一个测算当前CPU频率的程序。同时我们也完全可以写出一个 delay 函数(我在C 标准库中查看了一下,惊奇的发现这个函数并非标准函数......)
为了总结关于时间的库函数,总结下面这个图表
参考:
1.http://ganquan.info/standard-c/function/clock