深入V8引擎-Time核心方法之mac篇
由于底层逻辑实现不同操作系统区别很大,所以干脆分篇来说。
主要讲一下Time、TimeTicks两个类里面对于时间戳的实现,其余的运算符重载、边缘工具方法就不看了,先是Time。
Time
类本身的说明在上一篇有,这里就去掉了。
class V8_BASE_EXPORT Time final : public time_internal::TimeBase<Time> {
public:
// Contains the nullptr time. Use Time::Now() to get the current time.
constexpr Time() : TimeBase() {} // Returns the current time. Watch out, the system might adjust its clock
// in which case time will actually go backwards. We don't guarantee that
// times are increasing, or that two calls to Now() won't be the same.
static Time Now(); // Returns the current time. Same as Now() except that this function always
// uses system time so that there are no discrepancies between the returned
// time and system time even on virtual environments including our test bot.
// For timing sensitive unittests, this function should be used.
static Time NowFromSystemTime(); // ...
};
从注释可知,这里的Now是返回国际时间戳的通用方法,但是操作系统可能会对返回值做修正,所以是有一定风险的。第二个NowFromSystemTime使用的系统时间比较准确,求精确的情况下考虑使用这一个。
但是在mac上,这两个方法是一样的。
#elif V8_OS_POSIX Time Time::Now() {
// ...
} Time Time::NowFromSystemTime() {
return Now();
}
这就很蠢了,可能是该操作系统不存在修正时间戳的情况,所以没必要分辨这两个方法了。
所以对于两种方式的解析就变成了一个,集中来看Now的实现。
// #ifndef _STRUCT_TIMEVAL
// #define _STRUCT_TIMEVAL struct timeval
// _STRUCT_TIMEVAL
// {
// __darwin_time_t tv_sec; /* seconds */
// __darwin_suseconds_t tv_usec; /* and microseconds */
// }; Time Time::Now() {
// 内置结构体 见上面
struct timeval tv;
// Linux内置时间函数
int result = gettimeofday(&tv, nullptr);
// 返回值检测
DCHECK_EQ(, result);
USE(result);
return FromTimeval(tv);
}
这里的用的都是Linux内置的方法,timeval结构体专门用来获取返回的时间,可以精确到微秒,也就是秒/毫秒/微秒的精度。
结构体两部分分别保存当前时间戳的秒部分、微秒部分,类型均为long,下面用一个简单例子来展示。
int main() {
struct timeval tv;
gettimeofday(&tv, nullptr);
cout << "current seconds is " << tv.tv_sec << endl;
cout << "current microseconds is " <<tv.tv_usec << endl;
}
在浏览器下面同时用Date.now()做一个对比,由于还是有一定的时间差,所以微秒部分肯定对不上的。
两者输出对比如下。
在秒的部分完全对上了,微秒那块就别在意了,我可没有神手速。
这样,就通过系统API得到了当前时间戳,下面就是对两个部分做一个处理。
Time Time::FromTimeval(struct timeval tv) {
// 1秒 = 1000 * 1000微秒 这里做的合法性检测
DCHECK_GE(tv.tv_usec, );
DCHECK(tv.tv_usec < static_cast<suseconds_t>(kMicrosecondsPerSecond));
// 当秒、微秒都返回0 返回默认构造类 如下
// constexpr Time() : TimeBase(0) {}
if (tv.tv_usec == && tv.tv_sec == ) {
return Time();
}
// 如果返回值达到了最大值 则返回最大值 max也是内置方法
if (tv.tv_usec == static_cast<suseconds_t>(kMicrosecondsPerSecond - ) &&
tv.tv_sec == std::numeric_limits<time_t>::max()) {
return Max();
}
// 这里返回微秒单位的数值
return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec);
}
比较简单,看一下注释就懂了,最后返回的是以微秒为单位的一个长整数,而JS中的Date.now()返回的则是毫秒单位,略有不同。
TimeTicks
class V8_BASE_EXPORT TimeTicks final : public time_internal::TimeBase<TimeTicks> {
public:
constexpr TimeTicks() : TimeBase() {}
static TimeTicks Now();
static TimeTicks HighResolutionNow();
static bool IsHighResolution(); private:
friend class time_internal::TimeBase<TimeTicks>; explicit constexpr TimeTicks(int64_t ticks) : TimeBase(ticks) {}
};
这个类看看就好了,跟上面那个类似,也有两个方法,一个是更精确的。
然而,两个方法也是一个,在mac上不存在精细度(windows上都有区别,下篇搞),V8在内部直接写了如下注释。
#error platform does not implement TimeTicks::HighResolutionNow.
所以,只看Now的实现。
struct mach_timebase_info {
uint32_t numer; // 分子
uint32_t denom; // 分母
}; TimeTicks TimeTicks::Now() {
int64_t ticks;
static struct mach_timebase_info info;
if (info.denom == ) {
kern_return_t result = mach_timebase_info(&info);
}
ticks = (mach_absolute_time() / Time::kNanosecondsPerMicrosecond * info.numer / info.denom);
// Make sure we never return 0 here.
return TimeTicks(ticks + );
}
这里涉及2个内置方法和1个内置结构体,挨个介绍一下。
- mach_timebase_info结构体作为参数传入同名函数
- mach_timebase_info方法返回两个因子,将返回的分子除以分母可以得到一个基准参数(找不到Linux的官方API文档,还是windows好啊),具体解释有兴趣可以去查看
- mach_absolute_time方法返回一个系统从启动开始保持运行的一个绝对时间,参考windows的QPC,单位为纳秒
唯一有价值的就是那个单位,由于返回的绝对时间单位是纳秒,所以需要除以TimeConstants里面的常数,最后与基准参数相乘,最终得到一个硬件时间戳。
本地做一个实验。
int main() {
static struct mach_timebase_info info;
mach_timebase_info(&info);
cout << "numer is " << info.numer << endl;
cout << "denom is " << info.denom << endl;
cout << "absolute time is " << mach_absolute_time() << endl;
cout << "current timestamp is " << (info.numer / info.denom) * (mach_absolute_time() * 1e-) << endl;
}
这样得到最终的结果理论上就是我mac电脑的活跃秒数。
7000秒,也就是大约2个小时吧,看来还是很准确的,有兴趣的可以自行实验。
下一篇换windows,apple的apidoc真是一坨屎,根本跟微软没法比。
深入V8引擎-Time核心方法之mac篇的更多相关文章
- 深入V8引擎-Time核心方法之win篇(2)
这一篇讲windows系统下TimeTicks的实现. 对于tick,V8写了相当长的一段discussion来讨论windows系统上计数的三种实现方法以及各自的优劣,注释在time.cc的572行 ...
- 深入V8引擎-Time核心方法之win篇(1)
上一篇的源码看得十分无趣,官方文档跟黑心棉一样渣. 这一篇讲讲windows操作系统上的时间戳实现,由于类的声明,方法解释上一篇都贴过了,所以这次直接上对应版本的代码. windows与mac很不一样 ...
- 深入V8引擎-默认Platform之mac篇(2)
先说结论,V8引擎在默认Platform中初始化的这个线程是用于处理类似于setTimeout的延时任务. 另外附一些图,包括继承树.关键属性归属.纯逻辑工作流程,对代码木得兴趣的看完图可以X掉了. ...
- 浅谈Chrome V8引擎中的垃圾回收机制
垃圾回收器 JavaScript的垃圾回收器 JavaScript使用垃圾回收机制来自动管理内存.垃圾回收是一把双刃剑,其好处是可以大幅简化程序的内存管理代码,降低程序员的负担,减少因 长时间运转而带 ...
- 浅谈V8引擎中的垃圾回收机制
最近在看<深入浅出nodejs>关于V8垃圾回收机制的章节,转自:http://blog.segmentfault.com/skyinlayer/1190000000440270 这篇文章 ...
- 深入出不来nodejs源码-V8引擎初探
原本打算是把node源码看得差不多了再去深入V8的,但是这两者基本上没办法分开讲. 与express是基于node的封装不同,node是基于V8的一个应用,源码内容已经渗透到V8层面,因此这章简述一下 ...
- 深入V8引擎-初始化默认Platform
本来寻思着写一篇"'Hello' + ', World'"是怎么从JS代码编译然后输出的,然而compile过程的复杂性远超我的想象,强上怕会走火入魔,还是老老实实先回家种田,找点 ...
- Chrome V8引擎系列随笔 (1):Math.Random()函数概览
先让大家来看一幅图,这幅图是V8引擎4.7版本和4.9版本Math.Random()函数的值的分布图,我可以这么理解 .从下图中,也许你会认为这是个二维码?其实这幅图告诉我们一个道理,第二张图的点的分 ...
- (译)V8引擎介绍
V8是什么? V8是谷歌在德国研发中心开发的一个JavaScript引擎.开源并且用C++实现.可以用于运行于客户端和服务端的Javascript程序. V8设计的初衷是为了提高浏览器上JavaScr ...
随机推荐
- react入门(上)
1. ReactJS是什么? 1). Facebook开源的一个js库 2). 一个用于动态构建用户界面的js库2. React的特点 * Declarative(声明式编码) * Component ...
- 前端开发中提到的“脚手架”到底指什么,CLI?gulp 和 gulp-cli有什么区别
一般来说,脚手架是帮你减少「为减少重复性工作而做的重复性工作」的工具. gulp和gulp-cli的区别可以看这个task - what does gulp-"cli" stand ...
- perl中foreach(二)
本文和大家重点讨论一下Perl foreach命令的用法,Perl foreach循环中控制变量的值会被Perl自动保存和恢复.当循环进行时,是没有办法改变其值的.循环结束时,变量的值会回到循环开始前 ...
- linux文件权限更改命令chmod及数字权限
chmod -change file mode bits :更改文件权限 chmod是用来改变文件或者目录权限的命令,但只有文件的属主和超级用户(root)才有这种权限. 更改文件权限的2种方式: 一 ...
- python--前端CSS
一.CSS介绍 CSS(Cascading Style Sheet,层叠样式表)定义了如何显示HTML元素,给HTML设置样式,让他更加美观. 当浏览器读到这个样式表, 他就会按照这个样式来对文档进行 ...
- foxmial 和 outlook设置问题
您可以使用支持POP3的客户端软件(例如Foxmail或Outlook)收发您的邮件.请配置您的电子邮件客户端,以下载QQ邮箱邮件. 了解如何进行配置,请单击您的电子邮件客户端名称: Foxmail设 ...
- Linux磁盘与文件系统管理 之 认识EXT2系统
1 磁盘组成与分区 1.1 磁盘物理组成 (1)圆形盘片-记录数据 (2)机械手臂及磁头-读写盘片数据 (3)主轴马达-使得机械手臂成功读写数据驱动 1.2 盘片物理组成 (1)扇区-最小物理存储单位 ...
- 如何在eclipse中引用第三方jar包
在用UiAutomator做手机自动化测试过程中,在UiAutomator的基础之上进一步封装了里边的方法,以使case开发更顺手.直接在工程的根目录下新建了个libs的文件夹,把封装好的框架打成ja ...
- linux中软件包管理
一.流行的软件包管理有两种: Debian Linux的Deb软件包和 Redhat Linux的Rpm软件包, Debian Linux首先提出将应用程序的二进制文件.配置文档.man/info帮助 ...
- Python开发:网络编程
Python 提供了两个级别访问的网络服务.: 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法. 高级别的网络 ...