上一篇的源码看得十分无趣,官方文档跟黑心棉一样渣。

  这一篇讲讲windows操作系统上的时间戳实现,由于类的声明,方法解释上一篇都贴过了,所以这次直接上对应版本的代码。

  windows与mac很不一样,实现了一个新的Clock类来管理时间,如下。

// We implement time using the high-resolution timers so that we can get
// timeouts which are smaller than 10-15ms. To avoid any drift, we
// periodically resync the internal clock to the system clock.
class Clock final {
public:
Clock() : initial_ticks_(GetSystemTicks()), initial_time_(GetSystemTime()) {} Time Now() { /* */ } Time NowFromSystemTime() { /* */ } private:
static TimeTicks GetSystemTicks() { /* */ } static Time GetSystemTime() { /* */ } TimeTicks initial_ticks_;
Time initial_time_;
Mutex mutex_;
};

  从注释和方法名可以看出,windows完全用这个新类代替了老的Time、TimeTicks,因为这个方法拥有更好的性能,这个类同时会周期性的与系统时间同步数据。

  下面正式开始。

  先从Now方法看起,看windows系统是如何获取本地的时间戳。

DEFINE_LAZY_LEAKY_OBJECT_GETTER(Clock, GetClock)

#define DEFINE_LAZY_LEAKY_OBJECT_GETTER(T, FunctionName, ...) \
T* FunctionName() { \
static ::v8::base::LeakyObject<T> object{__VA_ARGS__}; \
return object.get(); \
} Time Time::Now() { return GetClock()->Now(); }

  这个方法的定义也不一般,直接用了一个特殊宏,宏就不展开了,简单说就是懒加载,调用的时候会分配空间生成一个Clock类,初始化完后第二次调用就直接返回了,当成一个单例来理解。

  直接看宏的返回类型,刚好是上面的Clock,该类只有一个无参构造函数,初始化两个时间戳属性。

  先看后那个,也就是系统时间的时间戳。

static Time GetSystemTime() {
FILETIME ft;
::GetSystemTimeAsFileTime(&ft);
return Time::FromFiletime(ft);
}

  这里的FILETIME和GetSystemTimeAsFileTime都是windowsAPI,可以获取当前系统的日期和时间,但是返回值很奇怪。

typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;

Contains a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC).

  这是结构体的声明与解释,High、Low分别代表时间的高位与地位,而那个方法就是配合这个使用的。

  可以从上面看到,这个API返回的时间竟然是从1601年1月1日开始算的,不知道那一年发生了什么。

  下面写一个测试代码。

int main()
{
FILETIME ft;
LARGE_INTEGER t;
::GetSystemTimeAsFileTime(&ft);
t.LowPart = ft.dwLowDateTime;
t.HighPart = ft.dwHighDateTime;
cout << t.QuadPart << endl;
}

  得到的输出为132034487665022709,由于单位是100纳秒,所以这个数字乘以100的,然后换算一下。

  由于基准是1601年,而Date是从1970年开始算,所以年份上差了369年,刚好是2019,很合理。

  来看看V8的处理。

// Time between windows epoch and standard epoch.
static const int64_t kTimeToEpochInMicroseconds = int64_t{}; Time Time::FromFiletime(FILETIME ft) {
// 特殊情况处理
if (ft.dwLowDateTime == && ft.dwHighDateTime == ) {
return Time();
}
if (ft.dwLowDateTime == std::numeric_limits<DWORD>::max() &&
ft.dwHighDateTime == std::numeric_limits<DWORD>::max()) {
return Max();
}
// 换算
int64_t us = (static_cast<uint64_t>(ft.dwLowDateTime) +
(static_cast<uint64_t>(ft.dwHighDateTime) << )) / ;
return Time(us - kTimeToEpochInMicroseconds);
}

  前面的特殊情况看看就行了,主要是换算这一步,就是简单的将高低位的数值拼到了一起,除以10之后,单位从100纳秒变成了微秒。

  最后的计算,也是为了平衡标准的时间戳和windows时间戳两者的差异,如下。

  为什么不是1970 - 1601 = 369年整呢?因为中间有闰年,很合理。

  最后得到微秒单位的标准时间戳,将该数值赋到类的属性上。

  回到最初的Now方法,初始化完后,会调用Clock自身的Now方法获取最终的时间戳,如下。

Time Now() {
// 一个误差临界值
const TimeDelta kMaxElapsedTime = TimeDelta::FromMinutes(); // 我目前不想解析所有关于锁的东西
MutexGuard lock_guard(&mutex_); // 再次获取当前的硬件时间戳与本地时间戳
TimeTicks ticks = GetSystemTicks();
Time time = GetSystemTime(); // 这里进行误差修正
TimeDelta elapsed = ticks - initial_ticks_;
// 1.当前时间小于初始化时间 可参考上一篇中类方法的注释(the system might adjust its clock...)
// 2.硬件时间戳的时间差超过临界值 这种情况基本可以认定初始化的时间完全不可信了
if (time < initial_time_ || elapsed > kMaxElapsedTime) {
initial_ticks_ = ticks;
initial_time_ = time;
return time;
} return initial_time_ + elapsed;
}

  虽然在构造函数中获取了时间戳,但是V8考虑到由于函数调用、系统修正等原因导致的误差(比如第一次初始化),再次进行了修正,具体操作和原因可以直接看注释,最后返回的时间戳是计算获得的理论本地时间戳加上硬件时间戳差值。

  至于NewFromSystemTime就比较简单了,在mac中这两个方法是一个,在windows里如下。

Time NowFromSystemTime() {
MutexGuard lock_guard(&mutex_);
// 更新两个时间戳
initial_ticks_ = GetSystemTicks();
initial_time_ = GetSystemTime();
// 直接返回最新获得的时间戳
return initial_time_;
}

  不计算任何东西,直接返回系统API的时间戳,可以配合注释来理解这两个方法。  

  尴尬了,没想到V8在Time阶段把两个时间戳全用上了。稍微看了一下TimeTicks的实现,发现还有点意思,所以这一篇先这样了,太长了写的累。

深入V8引擎-Time核心方法之win篇(1)的更多相关文章

  1. 深入V8引擎-Time核心方法之win篇(2)

    这一篇讲windows系统下TimeTicks的实现. 对于tick,V8写了相当长的一段discussion来讨论windows系统上计数的三种实现方法以及各自的优劣,注释在time.cc的572行 ...

  2. 深入V8引擎-Time核心方法之mac篇

    由于底层逻辑实现不同操作系统区别很大,所以干脆分篇来说. 主要讲一下Time.TimeTicks两个类里面对于时间戳的实现,其余的运算符重载.边缘工具方法就不看了,先是Time. Time 类本身的说 ...

  3. 浅谈Chrome V8引擎中的垃圾回收机制

    垃圾回收器 JavaScript的垃圾回收器 JavaScript使用垃圾回收机制来自动管理内存.垃圾回收是一把双刃剑,其好处是可以大幅简化程序的内存管理代码,降低程序员的负担,减少因 长时间运转而带 ...

  4. 浅谈V8引擎中的垃圾回收机制

    最近在看<深入浅出nodejs>关于V8垃圾回收机制的章节,转自:http://blog.segmentfault.com/skyinlayer/1190000000440270 这篇文章 ...

  5. 深入出不来nodejs源码-V8引擎初探

    原本打算是把node源码看得差不多了再去深入V8的,但是这两者基本上没办法分开讲. 与express是基于node的封装不同,node是基于V8的一个应用,源码内容已经渗透到V8层面,因此这章简述一下 ...

  6. Chrome V8引擎系列随笔 (1):Math.Random()函数概览

    先让大家来看一幅图,这幅图是V8引擎4.7版本和4.9版本Math.Random()函数的值的分布图,我可以这么理解 .从下图中,也许你会认为这是个二维码?其实这幅图告诉我们一个道理,第二张图的点的分 ...

  7. (译)V8引擎介绍

    V8是什么? V8是谷歌在德国研发中心开发的一个JavaScript引擎.开源并且用C++实现.可以用于运行于客户端和服务端的Javascript程序. V8设计的初衷是为了提高浏览器上JavaScr ...

  8. V8引擎嵌入指南

    如果已读过V8编程入门那你已经熟悉了如句柄(handle).作用域(scope)和上下文(context)之类的关键概念,以及如何将V8引擎作为一个独立的虚拟机来使用.本文将进一步讨论这些概念,并介绍 ...

  9. EF5+MVC4系列(9) Razor视图引擎的核心原理;@符号的使用;输出html的转义

    一:Razor视图引擎的核心原理 Razor是ASP.NET MVC 3中新加入的技术,以作为ASPX引擎的一个新的替代项 ,他是一个视图引擎 他的核心原理,就是当读取到 @符号的时候,就认为这是开始 ...

随机推荐

  1. Hi3518EV300编译U-Boot和内核报错:loadlocale.c:130: _nl_intern_locale_data: Assertion `cnt < (sizeof (_nl_value_type_LC_TIME) / sizeof (_nl_value_type_LC_TIME[0]))' failed. Aborted (core dumped)

    下载Hi3518EV300的SDK后编译内核和U-boot,发现爆出如下错误: scripts/kconfig/conf --silentoldconfig Kconfig Aborted (core ...

  2. linux下编译openjdk8

    一.准备工作                                                           1.0 工作环境 Ubuntu 12.04,32位机 1.1.安装JD ...

  3. WPF实现QQ群文件列表动画(二)

    上篇(WPF实现QQ群文件列表动画(一))介绍了WPF实现QQ群文件列表动画的大致思路,结合我之前讲过的WPF里ItemsControl的分组实现,实现起来问题不大,以下是效果图: 其实就是个List ...

  4. Java-数据结构之栈练习

    栈(stack)可以看做是特殊类型的线性表,访问.插入和删除其中的元素只能在栈尾(栈顶)进行. 队列(queue)表示一个等待的线性表,它也可以看做是一种特殊类型的线性表,元素只能从队列的末端(队列尾 ...

  5. Windows核心编程小结2

    这一节看看内存管理相关的信息 首先看看虚拟内存 虚拟地址空间 32位系统  --- 4GB = 232 64 位系统  ---- 16EB = 264 虚拟内存表 当一个应用程序从硬盘加载到RAM时, ...

  6. RSA进阶之共模攻击

    适用场景: 同一个n,对相同的m进行了加密,e取值不一样. e1和e2互质,gcd(e1,e2)=1 如果满足上述条件,那么就可以在不分解n的情况下求解m 原理 复杂的东西简单说: 如果gcd(e1, ...

  7. Codeforces 1139D(期望dp)

    题意是模拟一个循环,一开始有一个空序列,之后每次循环: 1.从1到m中随机选出一个数字添加进去,每个数字被选的概率相同. 2.检查这个序列的gcd是否为1,如果为1则停止,若否则重复1操作直至gcd为 ...

  8. Halcon18 Linux For Armv7a 下载

    Halcon18 Linux For Armv7a 下载地址:http://www.211xun.com/download_page_16.html HALCON 18 是一套机器视觉图像处理库,由一 ...

  9. OgnlContext 源码

    // Copyright (c) 1998-2004, Drew Davidson and Luke Blanshard package ognl; import ognl.enhance.Local ...

  10. spring IOC注解方式详解

    本文分为三个部分:概述.使用注解进行属性注入.使用注解进行Bean的自动定义. 一,概述 注释配置相对于 XML 配置具有很多的优势: 它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以 ...