Linux用户态程序计时方式详解[转]

您所在的位置:网站首页 linux计时函数 Linux用户态程序计时方式详解[转]

Linux用户态程序计时方式详解[转]

#Linux用户态程序计时方式详解[转]| 来源: 网络整理| 查看: 265

转自: http://www.cnblogs.com/clover-toeic/p/3845210.html

 

前言

     良好的计时器可帮助程序开发人员确定程序的性能瓶颈,或对不同算法进行性能比较。但要精确测量程序的运行时间并不容易,因为进程切换、中断、共享的多用户、网络流量、高速缓存访问及转移预测等因素都会对程序计时产生影响。

     本文将不考虑这些影响因素(相关资料可参考《深入理解计算机系统》一书),而仅仅关注Linux系统中用户态程序执行时间的计算方式。除本文所述计时方式外,还可借助外部工具统计耗时,如《Linux调试分析诊断利器——strace》一文中介绍的strace。

     本文示例代码的运行环境如下:

 

 

 

一  基本概念 1.1 日历时间

     Coordinated Universal Time(UTC):世界协调时间(又称世界标准时间),旧称格林威治标准时间(Greenwich Mean Time, GMT)。

     Calendar Time:日历时间,即从一个标准时间点到此时的时间所经过的秒数。该标准时间点因编译器而异,但对编译系统而言标准时间点不变。该编译系统中的时间对应的日历时间都通过该标准时间点衡量,故日历时间是“相对时间”。UNIX/Linux的时间系统由“新纪元时间(Epoch)”开始算起,该起点指定为1970年1月1日凌晨0时0分0秒(格林威治时间)。Microsoft C/C++ 7.0中标准时间点指定为1899年12月31日0时0分0秒,而其它版本的Microsoft C/C++和所有不同版本的Visual C++中标准时间点指定为1970年1月1日0时0分0秒。日历时间与时区无关。

     Epoch:时间点。时间点在标准C/C++中是一个整数(time_t),它用此刻的时间和标准时间点相差的秒数(即日历时间)来表示。目前大部分UNIX系统采用32位记录时间,正值表示为1970年以后,负值则表示1970年以前。可简单地估算出所能表达的时间范围:1970±((231-1)/3600/24/365)≈[1901,2038]年。为表示更久远的时间,某些编译器厂商引入64位甚至更长的整型数来保存日历时间。

1.2 进程时间

     进程时间也称CPU时间,用以度量进程使用的中央处理器资源。进程时间以时钟滴嗒计算,通常使用三个进程时间值,即实际时间(Real)、用户CPU时间(User)和系统CPU时间(Sys)。

     实际时间指实际流逝的时间;用户时间和系统时间指特定进程使用的CPU时间。具体区别如下:

Real是从进程开始执行到完成所经历的挂钟(wall clock)时间,包括其他进程使用的时间片(time slice)和本进程耗费在阻塞(如等待I/O操作完成)上的时间。该时间对应秒表(stopwatch)直接测量。 User是进程执行用户态代码(内核外)耗费的CPU时间,仅统计该进程执行时实际使用的CPU时间,而不计入其他进程使用的时间片和本进程阻塞的时间。 Sys是该进程在内核态运行所耗费的CPU时间,即内核执行系统调用所使用的CPU时间。

     CPU总时间(User+Sys)是CPU执行用户进程操作和内核(代表用户进程执行)系统调用所耗时间的总和,即该进程(包括其线程和子进程)所使用的实际CPU时间。若程序循环遍历数组,则增加用户CPU时间;若程序执行exec或fork等系统调用,则增加系统CPU时间。

     在多核处理器机器上,若进程含有多个线程或通过fork调用创建子进程,则实际时间可能小于CPU总时间——因为不同线程或进程可并行执行,但其时间会计入主进程的CPU总时间。若程序在某段时间处于等待状态而并未执行,则实际时间可能大于CPU总时间。其数值关系总结如下:

Real < CPU,表明进程为计算密集型(CPU bound),利用多核处理器的并行执行优势; Real ≈ CPU,表明进程为计算密集型(CPU bound),未并行执行; Real > CPU,表明进程为I/O密集型(I/O bound),多核并行执行优势并不明显。

     在单核处理器上,Real时间和CPU时间之差,即Real- (User + Sys)是所有延迟程序执行的因素的总和。可估算程序运行期间的CPU利用率为CpuUsage = (User + Sys)/ Real * 100(%)。

     在SMP(对称多处理系统)上,该差值近似为Real* ProcessorNum - (User + Sys)。这些因素包括:

调入程序文本和数据的I/O操作; 获取程序实际使用内存的I/O操作; 由其它程序消耗的CPU用时; 由操作系统消耗的CPU用时。

 

二  计时方式

     本节将基于下面的函数来讨论和对比各种计时方式:

复制代码 1 #include 2 #define TIME_LOOP_NUM 1000000*20 3 void TimingFunc(void){ 4 unsigned int i = 0; 5 double y = 0.0; 6 for(; i < TIME_LOOP_NUM; i++) 7 y = sin((double)i); 8 } 复制代码 2.1 间隔计数

     操作系统用计时器(timer)来记录每个进程使用的累计时间,该时间只是程序执行时间的粗略测量值。

     操作系统维护着每个进程使用的用户时间量和系统时间量的计数值。当计时器中断发生时,操作系统会在当前进程列表中寻找活动的进程,并对该进程的计数值增加计时器时间间隔(通常10毫秒)。若该进程在内核模式中运行,则增加系统时间,否则增加用户时间。

     这种间隔计数(“记账”)方法原理虽然简单但并不精确。若某进程运行时间很短(与系统计时器间隔相同数量级),且计时中断发生时发现进程正在运行,则不论进程已运行一段时间还是中断前1毫秒才开始运行,都会对计数器增加计时器时间间隔;中断发生时进程已切换的情况与之类似。因此,间隔计数时头尾都有误差。不过,若程序运行时间足够长(至少数秒),间隔计数的不准确性可能相互弥补(高估和低估的测量值平均后误差接近0)。理论上很难分析该误差值,故通常只有程序运行时间达到秒级时,采用间隔计数方法才有意义。此外,该方法的主要优点是其准确性不是非常依赖于系统负载。

     Linux系统time命令和times库函数采用间隔计数方法测量命令或程序执行时间。

2.1.1 time命令

     time命令可测量命令或脚本执行所耗时间及系统资源使用等信息,统计结果包含以下时间(以秒计):

实际执行时间(real time):从命令行执行到运行结束所消耗的时间; 用户CPU时间(user CPU time):命令在用户态中执行所消耗的CPU时间,即程序本身及其调用的库函数所使用的时间; 系统CPU时间(system CPU time):命令在内核态中执行所消耗的CPU时间,即由程序直接或间接调用的系统调用执行的时间。

     Linux系统中,可使用Shell内置命令time,或GNU一般命令time(/usr/bin/time)来测试程序运行的时间。前者只负责计时,精度可达10毫秒;后者精度略低,但可访问getrusage系统调用的信息,并提供丰富的参数选项,包括指定输出文件等功能。

     time命令不能用于测量程序内某个函数或某段代码的执行时间。

2.1.1.1 Shell命令

     Shell内置命令time的使用格式为

time []

     命令行执行完成后,会在标准输出中打印执行该命令行的时间统计结果。例如:

 

     可见Real>(User+Sys),说明处理器可能同时在执行其他进程,或本进程被阻塞或睡眠(sleep)。睡眠时间不计入用户时间和系统时间。阻塞可能是因为系统调用的错误使用,也可能是系统中的慢设备引起的。

     又如统计在当前目录下查找文件hello.c所消耗的时间:

 

     可见Real远大于(User+Sys),因为find命令遍历各个目录时进行大量磁盘I/O操作,这些操作比较耗时,因此大部分时间find进程都在等待磁盘I/O完成。此外,与文件相关的系统调用也会消耗系统时间。

     再次运行find命令时,real时间将显著减小:

 

     这得益于系统文件缓存,磁盘I/O操作次数显著减少。

     以下两种方法可将time命令输出的时间信息重定向到文件里,如下所示:

{ time find . -name "hello.c"; } 2>hello.txt //代码块(花括号内侧空格符不可少) (time find . -name "hello.c") 2>hello.txt //子Shell(多占些资源)

     注意上面示例中的花括号和小括号不可缺少,否则Shell会把time关键字后面的命令行作为一个整体进行处理,time命令本身的输出不会被重定向。内置命令time输出到标准错误,文件描述符2表示标准错误stderr。若还要包括find命令执行的结果,则可用:

(time find . -name "hello.c") 2>hello.txt 2>&1 2.1.1.2 GNU命令

     GNU命令time的简单使用格式为

/usr/bin/time [options] [] 或

\time [options] []

     命令执行完成后,输出与Shell内置命令time相似,但更详细。例如:

 

     还可加上-v选项得到时间、内存和I/O等更具体的输出:

 

     以下几种方法可将GNU工具time的输出信息重定向到文件里,如下所示:

1 /usr/bin/time --output=hello.txt find . -name "hello.c" 2 /usr/bin/time find . -name "hello.c" 2> hello.txt 3 \time --output=hello.txt find . -name "hello.c" 4 \time find . -name "hello.c" 2> hello.txt

     若还要包括find命令执行的结果,则可用:

\time --output=hello.txt --append find . -name "hello.c" > hello.txt

     若要控制输出时间的格式,可使用-f选项进行格式化(格式控制符用法见相关手册):

\time -f "\\t%E real,\\t%U user,\\t%S sys" find . -name "hello.c"

     输出结果如下所示:

 

     time命令的输出时间值中,用户时间和系统时间来自wait(2)或times(2)系统调用(依赖特定系统),实际时间由gettimeofday(2)中结束时间和起始时间相减得到。因为时间来源不同,故time命令对运行时间较短的任务计时时,会产生舍入错误(Rounding Errors),导致输出的时间精度仅为毫秒级(10毫秒)。

2.1.2 times函数

     times是个GNU标准库函数,函数原型声明在sys/times.h头文件中:

clock_t times(struct tms *buf);

     该函数读取进程计时器,返回自系统启动以来(Linux 2.4及以前)或启动前(232/HZ)-300秒以来(Linux 2.6)经过的时钟滴嗒数(即挂钟时间)。Linux系统中,若参数buf为NULL指针,则时间值也通过返回值获取(POSIX未指定该行为,其他Unix系统实现多要求非空指针)。若执行失败,则函数返回(clock_t)-1。返回类型clock_t通常定义为长整型(long int)。tms结构体定义为:

1 struct tms{ 2 clock_t tms_utime; //user time 3 clock_t tms_stime; //system time 4 clock_t tms_cutime; //user time of reaped children 5 clock_t tms_cstime; //system time of reaped children 6 };

     该结构体成员utime/stime含义与time命令输出相同,而cutime(用户CPU时间+子进程用户CPU时间)和cstime给出已经终止且被回收的子进程使用的累计时间。因此,times函数不能用于监视任何正在进行的子进程所使用的时间。此外,times函数返回相对时间,故其差值才有实用意义。

     测量某程序执行时间时,可在待计时程序段起始和结束处分别调用times函数,用后一次返回值减去前一次返回值得到运行该程序所消耗的时钟滴嗒数,再除以sysconf(_SC_CLK_TCK)转换为秒。如:

复制代码 1 #include 2 void TimesTiming(void){ 3 clock_t tBeginTime = times(NULL); 4 TimingFunc(); 5 clock_t tEndTime = times(NULL); 6 double fCostTime = (double)(tEndTime - tBeginTime)/sysconf(_SC_CLK_TCK); 7 printf("[times]Cost Time = %fSec\n", fCostTime); 8 } 复制代码

     注意,库函数times与clock均获取CPU时间片数量,但计时单位不同,即sysconf(_SC_CLK_TCK)的值不一定等于CLOCKS_PER_SEC(通常前者为100,后者为1,000,000)——这可降低溢出的可能性。 

     sysconf(_SC_CLK_TCK)单位是次数每秒(或Hz),即每秒时钟滴嗒数。

2.2 周期计数rdtsc

     从Intel Pentium开始,很多80x86微处理器都引入一个运行在时钟周期级别的时间戳计数寄存器TSC(Time Stamp Counter)。该寄存器以64位无符号整型数的格式,记录CPU上电以来所经过的时钟周期数,并在每个时钟信号(CLK,即处理器中用于接收外部振荡器的时钟信号输入引线)到来时加一。目前的处理器主频非常高,因此该寄存器可达到纳秒级的计时精度(在1GHz处理器上每个时钟周期为1纳秒)。

     关于周期计时的最大长度,可用下列公式简单估算:

自CPU上电以来的秒数 = RDTSC读出的周期数 / CPU主频速率(Hz)

     若处理器主频为1GHz,则大约需要583~584年,才会从2的64次方(64位无符号整数所能表达的最大数字+1)绕回到0,所以大可不必考虑溢出问题。

     通过机器指令RDTSC(Read Time Stamp Counter)可读取TSC时间戳值,并将其高32位存入EDX寄存器,低32位存入EAX寄存器。现有的C/C++编译器多数不直接支持使用RDTSC指令,需用内嵌汇编的方式访问。以下给出常见的几个RDTSC宏定义和封装函数:

复制代码 1 #define RDTSC(low, high) asm volatile("rdtsc" : "=a" (low), "=d" (high)) 2 #define RDTSC_L(low) asm volatile("rdtsc" : "=a" (low) : : "edx") 3 #define RDTSC_LL(val) asm volatile("rdtsc" : "=A" (val)) 4 5 /* Set *hi and *lo to the high and low order bits of the cycle counter. 6 * Implementation requires assembly code to use the rdtsc instruction. */ 7 void AccessCounter(unsigned *hi, unsigned *lo){ 8 asm volatile("rdtsc; movl %%edx,%0; movl %%eax, %1" 9 : "=r" (*hi), "=r" (*lo) 10 : /* No input */ 11 : "%edx", "%eax"); 12 } 13 14 typedef unsigned long long cycle_t; 15 /* Record the current value of the cycle counter. */ 16 inline cycle_t CurrentCycle(void){ 17 cycle_t tRdtscRes; 18 asm volatile("rdtsc" : "=A" (tRdtscRes)); 19 return tRdtscRes; 20 } 21 inline cycle_t CurrentCycle2(void){ 22 unsigned hi, lo; 23 asm volatile ("rdtsc" : "=a"(lo), "=d"(hi)); 24 return ((cycle_t)lo) | (((cycle_t)hi)=0 4 }; 5 struct timezone{ 6 int tz_minuteswest; //和Greenwich时间相差多少分钟 7 int tz_dsttime; //日光节约时间的状态 8 }; 复制代码

     tv或tz均可为空,为空时不返回对应的结构体。通常只会获取当前时间,故置时区指针tz为空。

     相对于间隔计数的小适用范围和周期计数的麻烦性,gettimeofday是一个可移植性更好相对较准确的方法。在Linux系统中,该函数计时精度可达到微秒级。

    测量某程序执行时间时,可在待计时程序段起始和结束处分别调用gettimeofday函数,用后一次获取的当前时间减去前一次获取的当前时间得到运行该程序所消耗的秒或微秒数。如:

复制代码 1 #include 2 #define TIME_ELAPSED(codeToTime) do{ \ 3 struct timeval beginTime, endTime; \ 4 gettimeofday(&beginTime, NULL); \ 5 {codeToTime;} \ 6 gettimeofday(&endTime, NULL); \ 7 long secTime = endTime.tv_sec - beginTime.tv_sec; \ 8 long usecTime = endTime.tv_usec - beginTime.tv_usec; \ 9 printf("[%s(%d)]Elapsed Time: SecTime = %lds, UsecTime = %ldus!\n", __FUNCTION__, __LINE__, secTime, usecTime); \ 10 }while(0) 11 12 void GetTimeofDayTiming(void){ 13 struct timeval tBeginTime, tEndTime; 14 gettimeofday(&tBeginTime, NULL); 15 TimingFunc(); 16 gettimeofday(&tEndTime, NULL); 17 float fCostTime = 1000000*(tEndTime.tv_sec-tBeginTime.tv_sec)+ //先减后加避免溢出! 18 (tEndTime.tv_usec-tBeginTime.tv_usec); 19 fCostTime /= 1000000; 20 printf("[gettimeofday]Cost Time = %fSec\n", fCostTime); 21 } 复制代码

     使用gettimeofday函数计时时应注意:

     1) 该函数的实现因系统和平台而异,故计时精度也随之而异。Linux系统直接提取硬件时钟来实现该函数,故精度接近周期计数精度;而Windows NT系统使用间隔计数实现,故精度较低。i386平台下采用内核sys_gettimeofday系统调用实现,调用时会向内核发送软中断,然后陷入内核态,内核进行软中断等处理并将执行结果复制到用户态,这些成本超过1微秒;而x86_64平台下采用vsyscall虚拟系统调用实现,创建一个用户态有权限访问的内核态共享内存页面,不通过中断即可获取系统时间,调用成本不到1微秒。

     2) 该函数依赖于系统时间,若系统时间被人为改变则获取的时间随之改变。

     3) 若计时过程中系统正在运行其他后台程序,可能会影响到最终的计时结果。

     可用gettimeofday函数和usleep调用精确地计算处理器主频,如下:

复制代码 1 void CalcCpuFreq3(void){ 2 struct timeval tStartTime, tEndTime; 3 4 cycle_t tStart = CurrentCycle(); 5 gettimeofday(&tStartTime, NULL); 6 usleep(1000000); //精度不高,由gettimeofday加以补偿 7 cycle_t tEnd = CurrentCycle(); 8 gettimeofday(&tEndTime, NULL); 9 10 int dwUsecDelay = 1000000 * (tEndTime.tv_sec - tStartTime.tv_sec) + 11 (tEndTime.tv_usec - tStartTime.tv_usec); 12 printf("CPU Frequency: %lldMHz\n", (tEnd-tStart)/dwUsecDelay); 13 } 复制代码 2.4 clock函数

     clock是ANSI C标准库函数,其函数原型声明在time.h头文件中:

clock_t clock(void);

     该函数返回自待测试程序进程开始运行起,到程序中调用clock函数时的处理器时钟计时单元数(俗称clock tick,即硬件时钟滴答次数)。若无法得到处理器时间,则返回-1。时钟计时单元的长短由CPU控制,但clock tick并非CPU时钟周期,而是一个C/C++基本计时单位。返回类型clock_t通常定义为有符号长整型(long int)。

     使用clock函数时应注意以下几点:

     1) 该函数返回处理器耗费在某程序上的时间(CPU时间片数量)。若程序中存在sleep函数,则sleep所消耗的时间将不计算在内,因为此时CPU资源被释放。

     2) 返回值若以秒计需除以CLOCKS_PER_SEC宏,该宏表示一秒钟有多少个时钟计时单元(硬件滴答数),取值因系统而异。在POSIX兼容系统中,CLOCKS_PER_SEC值为1,000,000,即1MHz(此时返回值单位为微秒)。通过(231-1)/1000000/60≈35.8可估算出clock函数超过半小时后将会溢出。

     3) 该函数仅能返回毫秒级的计时精度(大致与操作系统的线程切换时间相当),低于精度的程序计为0毫秒。因此,该函数适用于测量一些耗时较长(大于10ms)的大型程序或循环程序。

     4) 当程序单线程或单核心机器运行时,该函数计时准确;但多线程环境下并发执行时不可使用,因为结束时间与起始时间之差是多个核心总共执行的时钟滴答数,会造成计时偏大。

     5) 该函数未考虑CPU被子进程使用的情况,也不能区分用户模式和内核模式。该函数计量进程占用的CPU时间,大约是用户时间和系统时间的总和。

    测量某程序执行时间时,可在待计时程序段起始和结束处分别调用clock函数,用后一次的返回值减去前一次的返回值得到运行该程序所消耗的处理器时钟计时单元数,再除以CLOCKS_PER_SEC转换为秒。如:

复制代码 1 #include 2 void ClockTiming(void){ //可尝试在计时间隔内调用sleep(5),观察计时结果是否增加5秒 3 clock_t tBeginTime = clock(); //记录起始时间 4 TimingFunc(); //待计时函数 5 clock_t tEndTime = clock(); //记录结束时间 6 double fCostTime = (double)(tEndTime - tBeginTime)/CLOCKS_PER_SEC; //注意类型强制转换 7 printf("[clock]Cost Time = %fSec\n", fCostTime); 8 } 复制代码 2.5 time函数

     time是ANSI C标准库函数,其函数原型声明在time.h头文件中:

time_t time(time_t * timer);

     该函数返回当前的日历时间(以秒计)。若参数timer为非NULL指针,则时间值也通过该指针存储。若机器无法提供当前时间,或时间值过大而无法用time_t表示,则函数返回(time_t)-1。返回类型time_t通常定义为有符号长整型(long)。

     测量某程序执行时间时,可在待计时程序段起始和结束处分别调用time函数,用后一次的返回值减去前一次的返回值即可得到运行该程序所消耗的秒数。如:

复制代码 1 #include 2 void TimeTiming(void){ 3 time_t tBeginTime = time(NULL); 4 TimingFunc(); 5 time_t tEndTime = time(NULL); 6 double fCostTime = difftime(tEndTime, tBeginTime); 7 printf("[time]Cost Time = %fSec\n", fCostTime); 8 } 复制代码

     注意,时间类型time_t是个“可表示时间的算术类型(arithmetic type capable of representing times)”别名。但C标准并未规定time函数中该算术类型的时间编码方式。POSIX规定time函数必须返回一个时间整数,表示自Epoch(00:00 hours, Jan 1, 1970 UTC)以来的秒数;但库函数可能采用不同的时间表示方式。因此不应使用字面值常量,因其含义可能因编译器而异。

     遵循POSIX规范的程序可直接对time_t对象进行算术运算;可移植程序则应调用相关标准库函数(如localtime、gmtime或difftime),将time_t对象转换为可移植类型。TimeTiming函数即使用difftime函数将先后调用time所获得的时间差值转换为秒。

     Linux下time返回值为秒数,故difftime调用处等效于double fCostTime = (double)(tEndTime-tBeginTime)。注意,虽然difftime函数返回类型为double类型,但其值为以秒计的时间间隔,故只能精确到秒。

     以下代码分别给出两种版本,以实现在至少dwWorkSec(秒)时间内多次执行TimingFunc:

复制代码 1 #include 2 int NoncompliantWork(int dwWorkSec){ 3 time_t tStart = time(NULL); 4 if(tStart == (time_t)(-1)) 5 return -1; 6 7 while(time(NULL) < tStart + dwWorkSec){ //时间编码方式未定义,故加法运算不能保证增加dwWorkSec秒 8 TimingFunc(); //Do some work 9 } 10 return 0; 11 } 12 int CompliantWork(int dwWorkSec){ 13 time_t tStart = time(NULL); 14 time_t tCurrent = tStart; 15 if(tStart == (time_t)(-1)) 16 return -1; 17 18 while(difftime(tCurrent, tStart) < dwWorkSec){ //因time_t表示范围所限,可能造成死循环(infinite loop) 19 TimingFunc(); //Do some work 20 tCurrent = time(NULL); 21 if(tCurrent == (time_t)(-1)) 22 return -1; 23 } 24 return 0; 25 } 复制代码 2.6 clock_gettime函数

     clock_gettime是POSIX1003.1实时函数,其函数原型声明在time.h头文件中:

int clock_gettime(clockid_t clk_id, struct timespec *tp);

     该函数获取tp关于指定时钟的当前timespec值,并将其存入指针tp所指结构体。其结构体定义为:

1 struct timespec{ 2 time_t tv_sec; //自1970年7月1日以来经过的秒数 3 long tv_nsec; //自上一秒开始经过的纳秒数(nanoseconds) 4 }

     可见,该函数计时精度达到纳秒级。若函数执行成功,则返回0;否则返回一个错误码。

     clockid_t值用于指定计时器的类型,POSIX.1b所支持的标准计时器如下:

CLOCK_REALTIME:系统范围内的实时时钟,反映挂钟时间(wall clock time),即绝对时间。若系统时钟源被改变或系统时间被重置,该时钟会相应地调整。若指定该时钟类型,clock_gettime函数等效于gettimeofday函数,尽管精度有所不同。 CLOCK_MONOTONIC:单调时间,不可设置。该时间通过jiffies值计算,其值为当前时间减去起始时间之差,即从系统启动至今所经过的时间。单调时间在运行期间会一直稳定增加,而不受系统时钟的影响。若指定该时钟类型,则tv_sec值与“cat /proc/uptime”第一个输出值(秒)相同。 CLOCK_PROCESS_CPUTIME_ID:每个进程的CPU高精度硬件计时器。 CLOCK_THREAD_CPUTIME_ID:每个线程的CPU高精度硬件计时器。

    因为CLOCK_MONOTONIC计时器更加稳定,故推荐以此获得系统的运行时间。结合/proc/uptime文件,可通过以下几种方式获得系统自举以来的秒数:

复制代码 1 #include 2 #include 3 //通过文件接口读取/proc/uptime中的值进行字符串的转换 4 int GetSysTime(int *pSec, int *pMsec){ 5 if(NULL == pSec && NULL == pMsec) 6 return -1; 7 8 int dwFd = open("/proc/uptime", O_RDONLY); 9 if(dwFd


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3