2020-03-27 06:12:40
2018 年 12 月 ,Google 宣布 Flutter 1.0 版本正式发布。截至目前, Flutter 在 Github 上已获得 88000+ 的关注和 11000+ 的 Fork ,其发展速度相当惊人,是今年移动端最火热的开发框架之一。
Flutter 大火背后的原因是什么?为什么越来越多的企业和开发者会选择使用 Flutter?Flutter 会成为跨平台开发的终极之选吗?我认为“ Flutter 并非跨平台终极之选,最初选择 Flutter,不是因为它一定会成为未来终极之选,而是因为它有可能成为不一样的未来。”
有人说 Flutter 大火主要原因是它选择了 Dart 语言,Dart 有着高性能的表现和可快速分配内存的能力,能同时支持 JIT 和 AOT 模式,允许在带类型的语言中支持形变和有状态热重载,能编译出高效率的 ARM 机器码指令,Dart 作为面向对象的语言也能让绝大多数开发者更快速上手。我认可 Dart 语言有一定的优势,但这样的优势并非 Dart 独有,我想这更不会是大家选择 Flutter 的核心原因,这是因果倒置。事实上,Dart 是 2011 年推出的,在 Flutter 出现之前,Dart 曾一度几乎被人遗忘。正是因为近年来 Flutter 的火爆,才让 Dart 重新进入大众的视线。Flutter 当初选择 Dart,或者仅因为 Google 的 Flutter 和 Dart 这两个团队离得比较近,交流比较方便。 我认为 Flutter 之所以大火,主要是以下几个原因:
在移动互联网时代,Android 和 iOS 两大阵营长期共存,再加上体系成熟的 Web 前端技术,导致出现同一个应用需多端重复开发的人力成本问题。正因如此,移动时代下的跨平台技术是一个需要长期研究的课题。如果当下的跨平台技术已经有比较完美的解决方案,可能就没有新技术萌芽的机会。而事实上,目前业界比较成熟的跨平台技术都存在一定的缺陷,比如小程序(WebView)渲染耗时过长,白屏率会影响转化收益,能实现的功能非常受限;再比如 React Native 的性能不足、问题排除难、维护成本高等。而 Flutter 的出现,让这些跨平台开发问题有所改善,它还是 Google 开源的技术,自身也具备一定的热度。另外,一直备受关注且神秘的 Fuchsia 系统在 UI 框架上使用的也是 Flutter,可作为长期战略投入,这也增强了大家对 Flutter 的信心。
移动互联网进入下半场,出现一些新兴互联网独角兽、小巨头,在没有历史包袱的情况下,更愿意尝试技术上限更高的新技术。从校招和社招的难度上不难发现:客户端的人才相比之前更为稀缺,尤其是 iOS 工程师。而下半场会有更多竞争和更为激烈的赛道,比如教育等方向。Flutter 本身非常适合从零开始的没有历史包袱的应用开发,对于新业务尤其是在团队人力紧缺的情况下,在技术选型上考虑 Flutter,能加快产品在多端落地、快速试错。
Flutter “一出生”就以“UI 漂亮、像素级可控、性能流畅、可媲美原生性能”等特点吸引广大开发者的眼球,自渲染引擎甚至具备开发游戏的能力。移动下半场,没有人口红利,竞争更为激烈,如何能更好地满足用户对高品质、高流畅的需求,便是移动端一种强有力的竞争力。跨平台技术想要拥有更高的流畅度,采用自渲染技术的方案便是更优解,也是一个更为彻底的跨平台技术方向。
说到这里,先分享一下 Flutter 最初是如何诞生的故事。Flutter 创始人 Eric 之前在 Chrome 团队工作,期间遇到一些难以解决的问题, 希望 Web 中的一部分能够拥有更加平滑的体验, 为此他花了几周时间做了一个实验,不考虑 Web 的兼容方式,删除了大量为了兼容访问的代码和一些 Web 开发者不常用的功能, 删除到有不少 Web 元素的渲染已经不支持了,然后做了一个基准测试,得出结论是某些关注指标的速度快了 20 倍。于是,Eric 决定再做点什么,后面投入了大量研究和开发,便有了现在的 Flutter 。
听到这里给人的感觉是,对于 Web 工程师而言 Flutter 应该容易上手。我跟公司很多正在使用或者调研 Flutter 的业务团队做过沟通,发现客户端比前端的同学对 Flutter 接受度更高,我个人从 Android 端技术出身,的确觉得学习 Flutter 还是非常容易上手的,但公司内前端的同学对 Flutter 使用的吐槽会多一点。所以,我认为 Flutter 更像是以客户端视角的跨平台技术,Flutter 与其说是大前端技术,不如说是大移动端技术。Flutter 发展的 Roadmap 也是先全面支持 Android/iOS 端能力,再进一步完善 Web 端能力支持的。
字节跳动对于客户端技术还是非常重视的,字节跳动有很多客户端工程师,之前客户端深入点的基础技术更多是搞插件化、热修复、性能优化、安全加固等,跨平台方向一直都是前端工程师在不遗余力地推进,属于大前端方向。而 Flutter 是客户端更有主导的跨平台技术方案。另外说明,字节跳动并不是说只有一套跨平台技术栈,公司内部也是多套跨端技术栈并存,也包括自研的方案。
在字节跳动,跨平台技术并没有形成大规模的落地,之前也提到没有历史包袱,所以在面对跨平台技术选型的时候,更关注跨平台技术的技术上限以及发展潜力,自渲染技术的 Flutter 可以理解为更彻底更纯粹的跨平台技术,伴随着媲美原生的流畅度,这便是我们选择 Flutter 的初心。
截至目前,字节跳动有很多业务落地了 Flutter 技术方案,包括今日头条、西瓜视频、皮皮虾等 20 多个业务在使用 Flutter 开发,有纯 Flutter 工程,也有 Flutter 与 Native 的混合工程。如果大家想要了解更多业务落地情况,后续我会在今年的 QCon 北京 2020 大会上分享。
Flutter 虽潜力上限很高,但仍需打磨和雕琢,我们在 Flutter 推动过程中遇到很多问题,比如包体积过大的问题、性能达不到预期、对混合工程的支持不够友好、各宿主 Flutter 引擎版本不一致、基础库不完善、Flutter 改造后各项数据打平等。除此之外,还有很多非技术的困难,比如业务团队并不认可 Flutter 新技术,工程师缺乏 Flutter 经验,担忧审核风险等,都会影响业务方是否采用 Flutter 技术,每一个困难都需要去解决,不然就难以落地。下面就其中两个难点,我来展开聊一下。
字节跳动内的大型 APP,比如今日头条、抖音等对包体积的增量非常敏感,Flutter 的包体积涉及两个部分,一个是一次性 Flutter 引擎的包体积问题,一个是每次写 Dart 代码比写 OC 代码代码增量的问题。这两个问题对我们来说都非常棘手,我们成立了包体积优化专项进行全力攻坚,同时跟 Google 工程师多次会议沟通,不断精简包体积。最终我们通过一系列优化手段,包含 Data 压缩、编译优化、Skia 裁剪、BoringSSL/ICU 库 / 文字渲染 /libwebp 等库裁剪取得了不少的效果;通过实践我们发现用 OC 代码和 Dart 代码写相同的业务逻辑,Dart 生成的机器码指令比 OC 多,主要在生成的二进制指令头、指令冗余、指令对齐的精简,以及 StackMap 和 CodeSourceMap 的精简等方面。同时我们也向 Google 反馈了这些情况。关于指令精简,可以查看 Issue 进展,里面有记录详细的推进过程: https://github.com/flutter/flutter/issues/40345
这是我们遇到的棘手问题之一,我们用 Flutter 官方提供的性能分析工具 Timeline 来分析一个比较诡异的性能问题,始终无法发现任何异常。困扰已久,后来干脆重新撸了一遍 Timeline 整个性能分析工具的源码,最终找到了其缺陷,并向 Flutter 社区提及,合入了 10 个 PR ,基于此让我有幸成为了 Flutter Member ,后续会持续向社区贡献更多力量:https://github.com/flutter/flutter/issues/47771.
Flutter 是一个自渲染的跨平台技术,有着很高的性能上限,但并不代表现在性能各方面都很优秀,毕竟 Flutter 作为一个“新生儿”,还是有一些需要进一步改造的地方。除性能工具改造之外,其实在 Flutter 落地场景中,我们也解决了不少性能问题,同时优化了自身的引擎,比如 UI 预加载策略、Flutter Turbo 技术、Vsync 调度策略等,让引擎提速,争取让 Flutter 性能发挥到极致。
引入 Flutter 之后,在公司的业务也创造了不少价值。主要体现在这几个方面:其一,Flutter 多端一致性上表现良好,能做到所见即所得,无需针对某一平台做额外适配工作;其二,热重载技术使得设计团队和工程团队可以非常快速的修改和调试 UI,设计师只需要关注一个平台实现,UI 验收效率明显提高,跨端开发可以提高工程师的人效(有团队初步估算人效大致提升了 1.8 倍);其三,性能流畅度提升,相较于 H5 版本首屏时间有较大提升,最后,产品商业化数据都有明显的收益,能直观地看到 Flutter 给公司带来的创收。
不过,现阶段 Flutter 的发展仍有一些阻力:
作为前端工程师可能更希望是 Flutter 上层采用的是 JavaScript 或者 TypeScript,未来可考虑提供高性能的 Dart 与 JS 互转能力。另外,Flutter 开发对于前端开发工程师而言,还是有一些挑战的,纯前端不一定能 Cover 的技术,比如 Flutter 的一个硬件相关的 Plugin 只在某款手机出现 Bug,如果社区没有现存解决方案,可能就需要花比较大的时间成本去学习 Native 技术,或者请教客户端工程师。
Flutter 生态还不够完善,新业务接入需要自己造轮子,尤其是在业务团队对 Flutter 掌握不够熟练的情况下,会增加额外的成本,Flutter 在大中型企业会更容易推广起来,有人力可以去造轮子让公司内其他的业务复用;另外,Flutter 文档有点少,能借鉴的经验不多,未来需加强和鼓励更多开发者加入到生态共建。
有朋友跟我说起过这样一件事,看到 Flutter 这么火,Android 开发团队就问他,“大家为什么要用 Flutter 开发 App,我们 Android 哪一点不好,告诉我们,我们可以改进它”。姑且不说他们对跨平台理解不够,但至少能看出原生平台对跨端技术的担忧,不少 Android 团队在推出 Kotlin Multiplatform ,希望能争夺更多市场。 另外,苹果商店的审核风险也是大家所担忧的,官方的公告原意是说应用程序的核心特性和功能必须包含在软件的二进制文件中,而不是通过类似 HTML5 的技术来实现动态更新,苹果要打压的是动态更新技术,考虑到 Flutter 的合规性,Google 主动把 Flutter 的 iOS 动态化能力去掉了,Flutter 最终打包生成的产物就是 IPA,Flutter 其实是完全符合规范的,甚至还有使用 Flutter 开发的应用还被 Apple 推荐过。相反,React Native、Weex、H5 等技术都是一种动态化解决方案,这正是苹果要管控的,目前苹果的态度更多的是不提倡,但也不保证不封杀。即便如此,苹果不希望原生开发生态被其他跨平台技术抢占,苹果也在不断推行 SwiftUI 框架,力图抵挡 Flutter 等跨平台技术对原生开发的蚕食。Flutter 未来要加强推进步伐,让更多的大型 App 通过 Flutter 技术得到收益,只有用户群体上来,未来的地位和话语权才会更高,就像现在小程序,原则上是不符合苹果的审核要求的,但各大型应用基本都上线了小程序功能,目前来看不至于说苹果把小程序直接干掉。
从 Hybrid App 到 React Native,再到 Flutter,跨平台技术层出不穷。目前来看,Flutter 是跨平台开发的最热门技术,但我并不认为 Flutter 就一定是跨平台开发的终极之选,它有着历史局限性,我只能说 Flutter 可能是当下最有潜力的跨平台技术。如果你对性能流畅度有高要求,或者有多个产品希望快速在多端试错迭代,我会推荐你尝试 Flutter。
未来一段时间,还应该是多套跨平台技术并存的时代, 目前 Flutter 也没有全面做到可以碾压其他跨平台技术,可根据团队以及业务特点来考虑更适合的方案。有一定客户端经验的同学入手 Flutter 会更快一些,如果团队在 React Native 上有很好落地,业务没有遇到性能等瓶颈,且团队缺少客户端能力,建议先做技术调研和沉淀,不要盲目追求新技术,只有当团队有能力且业务有需求的情况下,建议再考虑切换技术栈。
我们前面提到过,一直备受关注且神秘的 Fuchsia 系统在 UI 框架上使用的也是 Flutter。Fuchsia 是 Google 开发的下一代操作系统。Fuchsia 是采用全新模块化设计思想、跨平台框架技术的系统。它能支持快捷裁剪定制,更能适应未来的多元化设备,包含手机、平板、笔记本、路由器、智能设备、机器人等,Fuchsia 有可能成为一个全新的跨全平台的通用操作系统。
在现阶段,开始尝试探索和积累沉淀 Flutter 技术能力,并在业务上使用 Flutter 技术的应用,从战略上来将已经处于领先。选择 Flutter,正可谓是“进可攻退可守”,往前进一步,Flutter 应用未来可无缝迁移到 Fuchsia 系统,借用 Fuchsia 系统的能量扩展到更广泛的用户场景;退一步,Flutter 技术自身在 Android/iOS 平台的表现相比其他跨平台技术已经是很优秀。
最初选择 Flutter,不是因为它一定会成为未来终极之选,而是它有可能成为不一样的未来。
回顾整移动操作系统的演变历程,从塞班功能机到 Android/iOS 智能机,从小屏手机到全面屏、刘海屏、水滴屏。任何系统的演变最终体现在输入和输出两个环节,接收到输入信号后经过操作系统处理后输出信息给用户。从按键式交互到触屏式交互,伴随着塞班系统到 Android 系统的转变,未来的交互方式一定会更加生物智能化,当下的触屏交互可以理解成人类的触觉输入方式,未来将朝着人们更常见的听觉(语音)输入和视觉(身体姿势、表情等)输入,甚至嗅觉(气味变化)输入,这些都会伴随着新的操作系统而诞生。屏幕从小尺寸到大尺寸,并没有引发操作系统变革,因为技术创新是非连续性,非连续性才会引发第二曲线,诞生新技术。从 1960 年大型机,到 1990 年个人笔记本,再到现在的智能手机,设备本身越来越小。未来的设备如果发展非连续变革,可能不再需要实体硬件,随处可输出,一张白纸、一面墙,到那时操作系统的 UI 架构必然会有全新的变化。
随着科技的发展,5G 时代的到来,人工智能的日趋成熟,端到底会有哪些变化?是否会出现新的操作系统?系统的 UI 架构是否会出现新的变革?Android/iOS 平台是否能与之并存?搭载 Flutter UI 框架的 Fuchsia 系统能否在 IOT 领域以及新的交互方式大放异彩,再领风骚?是否有万物互联互通的超级平台出现?
技术在不断演变中螺旋前进,平台自身也随之演进,未来 Flutter 会朝着多端一体化的方向发展,能支持更多的端(包括平板、笔记本、智能设备等)。作为一套跨平台的 UI 框架,Flutter 采用自渲染的技术方案,是一个上限很高的跨平台技术,但 Flutter 更重要的是需要提升工程化能力以及生态圈的建设,才能吸引更多的开发者加入。
欢迎更多小伙伴加入字节跳动移动平台部,探索和深耕移动端技术,团队技术氛围浓厚,和我们开创可能成为不一样的未来,Android/iOS/Flutter等在北上深杭招聘各级别岗位,可简历发送至[email protected], 详细内推岗位见 http://gityuan.com/job。
2019-10-20 06:15:40
#include "flutter/fml/trace_event.h"
#define TRACE_EVENT0(category_group, name)
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)
#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, arg2_val)
#define FML_TRACE_EVENT(category_group, name, ...)
fml::tracing::TraceEvent0(category_group, name);
fml::tracing::TraceEventEnd(name);
//示例:
TRACE_EVENT0("flutter", "PipelineConsume");
TRACE_EVENT2("flutter", "Framework Workload",
"mode", "basic", "frame", FrameParity());
#include "flutter/fml/trace_event.h"
#define TRACE_EVENT_ASYNC_BEGIN0(category_group, name, id)
#define TRACE_EVENT_ASYNC_END0(category_group, name, id)
#define TRACE_EVENT_ASYNC_BEGIN1(category_group, name, id, arg1_name, arg1_val)
#define TRACE_EVENT_ASYNC_END1(category_group, name, id, arg1_name, arg1_val)
void TraceEventAsyncComplete(TraceArg category_group, TraceArg name,
TimePoint begin, TimePoint end)
//示例:
TRACE_EVENT_ASYNC_BEGIN0("flutter", "Frame Request Pending", frame_number);
TRACE_EVENT_ASYNC_END0("flutter", "Frame Request Pending", frame_number_++);
另外,这里还有一种比较特别的异步事件,事件的开始和结束都是可以手动指定的,TraceEventAsyncComplete 等于TRACE_EVENT_ASYNC_BEGIN0 + TRACE_EVENT_ASYNC_END0, 如下所示:
void TraceEventAsyncComplete(TraceArg category_group, TraceArg name,
TimePoint begin, TimePoint end);
#include "flutter/fml/trace_event.h"
#define TRACE_FLOW_BEGIN(category, name, id)
#define TRACE_FLOW_STEP(category, name, id)
#define TRACE_FLOW_END(category, name, id)
//示例:
TRACE_FLOW_BEGIN("flutter", "PipelineItem", trace_id_)
TRACE_FLOW_STEP("flutter", "PipelineItem", trace_id_)
TRACE_FLOW_END("flutter", "PipelineItem", trace_id_)
#define API_TIMELINE_DURATION(thread)
#define API_TIMELINE_BEGIN_END(thread)
// 示例:
#define T (thread())
API_TIMELINE_DURATION(T);
API_TIMELINE_BEGIN_END(T);
import 'dart:developer';
Timeline.startSync(String name, {Map arguments, Flow flow});
Timeline.finishSync();
//示例:
Timeline.startSync('Warm-up frame'); //静态方法
Timeline.finishSync();
import 'dart:developer';
TimelineTask.start(String name, {Map arguments});
TimelineTask.finish();
//示例:
final TimelineTask timelineTask = TimelineTask(); //普通方法,需要实例化
timelineTask.start('Warm-up shader');
timelineTask.finish();
Timeline.timeSync('flow_test', () {
doSomething();
}, flow: flow);
Timeline.timeSync('flow_test', () {
doSomething();
}, flow: Flow.step(flow.id));
Timeline.timeSync('flow_test', () {
doSomething();
}, flow: Flow.end(flow.id));
TimelineEventRingRecorder默认大小为32KB,也就是说该Recorder共有512个TimelineEventBlock(事件块),每个TimelineEventBlock有64个TimelineEvent(事件)。
1)TimelineEventRecorder:主要还有以下四种:ring, endless, startup, systrace
2)TimelineEventBlock
另外关于时间计数,以Android为例,此处调用的是clock_gettime()系统方法,精确到纳秒,这里有CLOCK_MONOTONIC和CLOCK_THREAD_CPUTIME_ID两种不同的参数,Timeline最终记录的事件事件信息单位是微秒。
所有的这些最终都调用Dart_TimelineEvent()方法。
[-> flutter/fml/trace_event.cc]
#define TRACE_EVENT0(category_group, name) \
::fml::tracing::TraceEvent0(category_group, name); \ //事件开始
__FML__AUTO_TRACE_END(name)
#define __FML__AUTO_TRACE_END(name) \
::fml::tracing::ScopedInstantEnd __FML__TOKEN_CAT__2(__trace_end_, __LINE__)(name);
class ScopedInstantEnd {
public:
ScopedInstantEnd(const char* str) : label_(str) {}
~ScopedInstantEnd() { TraceEventEnd(label_); } //事件结束
private:
const char* label_;
};
void TraceEvent0(TraceArg category_group, TraceArg name) {
Dart_TimelineEvent(DCHECK_LITERAL(name),
Dart_TimelineGetMicros(), 0,
Dart_Timeline_Event_Begin, 0,
nullptr, nullptr);
}
void TraceEventEnd(TraceArg name) {
Dart_TimelineEvent(DCHECK_LITERAL(name),
Dart_TimelineGetMicros(), 0,
Dart_Timeline_Event_End, 0,
nullptr, nullptr);
}
[-> flutter/fml/trace_event.cc]
void TraceEventAsyncBegin0(TraceArg category_group, TraceArg name, TraceIDArg id) {
Dart_TimelineEvent(DCHECK_LITERAL(name),
Dart_TimelineGetMicros(), id,
Dart_Timeline_Event_Async_Begin, 0,
nullptr, nullptr);
}
void TRACE_EVENT_ASYNC_END0(TraceArg category_group, TraceArg name, TraceIDArg id) {
Dart_TimelineEvent(DCHECK_LITERAL(name),
Dart_TimelineGetMicros(), id,
Dart_Timeline_Event_Async_End, 0,
nullptr, nullptr);
}
void TraceEventAsyncComplete(TraceArg category_group, TraceArg name,
TimePoint begin, TimePoint end) {
auto identifier = TraceNonce();
if (begin > end) {
std::swap(begin, end);
}
Dart_TimelineEvent(DCHECK_LITERAL(name),
begin.ToEpochDelta().ToMicroseconds(), identifier,
Dart_Timeline_Event_Async_Begin, 0,
nullptr, nullptr);
Dart_TimelineEvent(DCHECK_LITERAL(name),
begin.ToEpochDelta().ToMicroseconds(), identifier,
Dart_Timeline_Event_Async_End, 0,
nullptr, nullptr);
}
[-> flutter/fml/trace_event.cc]
void TraceEventFlowBegin0(TraceArg category_group, TraceArg name, TraceIDArg id) {
Dart_TimelineEvent(DCHECK_LITERAL(name),
Dart_TimelineGetMicros(), id,
Dart_Timeline_Event_Flow_Begin, 0,
nullptr, nullptr);
}
void TraceEventFlowStep0(TraceArg category_group, TraceArg name, TraceIDArg id) {
Dart_TimelineEvent(DCHECK_LITERAL(name),
Dart_TimelineGetMicros(), id,
Dart_Timeline_Event_Flow_Step, 0,
nullptr, nullptr);
}
void TraceEventFlowEnd0(TraceArg category_group, TraceArg name, TraceIDArg id) {
Dart_TimelineEvent(DCHECK_LITERAL(name),
Dart_TimelineGetMicros(), id,
Dart_Timeline_Event_Flow_End, 0,
nullptr, nullptr);
}
可见,所有这些事件最终都是调用Dart_TimelineEvent,不同的主要在事件类型:
时间戳的获取除了TraceEventAsyncComplete()是直接传递的时间参数,其他都是通过Dart_TimelineGetMicros()命令获取执行该命令当下的时间戳,单位是微秒。
DART_EXPORT int64_t Dart_TimelineGetMicros() {
return OS::GetCurrentMonotonicMicros();
}
//以Android为例
int64_t OS::GetCurrentMonotonicMicros() {
int64_t ticks = GetCurrentMonotonicTicks();
return ticks / kNanosecondsPerMicrosecond;
}
int64_t OS::GetCurrentMonotonicTicks() {
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
return 0;
}
int64_t result = ts.tv_sec;
result *= kNanosecondsPerSecond;
result += ts.tv_nsec;
return result;
}
通过clock_gettime系统调用获取CLOCK_MONOTONIC类型的时间,也就是系统从启动到现在的时间戳;
[-> third_party/dart/runtime/vm/dart_api_impl.cc]
DART_EXPORT void Dart_TimelineEvent(const char* label,
int64_t timestamp0,
int64_t timestamp1_or_async_id,
Dart_Timeline_Event_Type type,
intptr_t argument_count,
const char** argument_names,
const char** argument_values) {
#if defined(SUPPORT_TIMELINE)
//采用的是Embedder Stream
TimelineStream* stream = Timeline::GetEmbedderStream();
//[见小节2.3.1]
TimelineEvent* event = stream->StartEvent();
switch (type) {
case Dart_Timeline_Event_Begin:
event->Begin(label, timestamp0); //[见小节2.3.3]
break;
case Dart_Timeline_Event_End:
event->End(label, timestamp0);
break;
case Dart_Timeline_Event_Instant:
event->Instant(label, timestamp0);
break;
case Dart_Timeline_Event_Duration:
event->Duration(label, timestamp0, timestamp1_or_async_id);
break;
case Dart_Timeline_Event_Async_Begin:
event->AsyncBegin(label, timestamp1_or_async_id, timestamp0);
break;
case Dart_Timeline_Event_Async_End:
event->AsyncEnd(label, timestamp1_or_async_id, timestamp0);
break;
case Dart_Timeline_Event_Async_Instant:
event->AsyncInstant(label, timestamp1_or_async_id, timestamp0);
break;
case Dart_Timeline_Event_Counter:
event->Counter(label, timestamp0);
break;
case Dart_Timeline_Event_Flow_Begin:
event->FlowBegin(label, timestamp1_or_async_id, timestamp0);
break;
case Dart_Timeline_Event_Flow_Step:
event->FlowStep(label, timestamp1_or_async_id, timestamp0);
break;
case Dart_Timeline_Event_Flow_End:
event->FlowEnd(label, timestamp1_or_async_id, timestamp0);
break;
default:
FATAL("Unknown Dart_Timeline_Event_Type");
}
event->SetNumArguments(argument_count);
for (intptr_t i = 0; i < argument_count; i++) {
event->CopyArgument(i, argument_names[i], argument_values[i]);
}
// [见小节2.3.4]
event->Complete();
#endif
}
先以目前timeline的默认记录器TimelineEventRingRecorder来展开说明。
[-> third_party/dart/runtime/vm/timeline.cc]
TimelineEvent* TimelineEventFixedBufferRecorder::StartEvent() {
return ThreadBlockStartEvent(); //【见下方】
}
TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() {
OSThread* thread = OSThread::Current();
Mutex* thread_block_lock = thread->timeline_block_lock();
thread_block_lock->Lock(); //这个锁会一直持有,直到调用CompleteEvent()
TimelineEventBlock* thread_block = thread->timeline_block();
if ((thread_block != NULL) && thread_block->IsFull()) {
MutexLocker ml(&lock_); //加锁,保证每次只有一个线程申请新的事件块
thread_block->Finish(); //该事件块已满【见小节2.3.5】
thread_block = GetNewBlockLocked(); //分配新的事件块
thread->set_timeline_block(thread_block);
} else if (thread_block == NULL) {
MutexLocker ml(&lock_);
thread_block = GetNewBlockLocked(); //没有事件块,则创建事件块
thread->set_timeline_block(thread_block);
}
if (thread_block != NULL) {
//持锁状态退出该函数 见下方】
TimelineEvent* event = thread_block->StartEvent();
return event;
}
thread_block_lock->Unlock(); //没有任何事件,则释放锁
return NULL;
}
TimelineEvent* TimelineEventBlock::StartEvent() {
return &events_[length_++];
}
说明:
TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() {
if (block_cursor_ == num_blocks_) {
block_cursor_ = 0;
}
TimelineEventBlock* block = &blocks_[block_cursor_++];
block->Reset(); //事件重置
block->Open(); // [见下文]
return block;
}
void TimelineEventBlock::Open() {
OSThread* os_thread = OSThread::Current();
//将当前线程id记录到该事件块中的thread_id_
thread_id_ = os_thread->trace_id();
in_use_ = true;
}
OSThread对象里面有一个TimelineEventBlock指针,记录着当前正在操作的事件块。事件块里面有一个events_,记录着TimelineEvent数组,大小为kBlockSize=64。
void Begin(const char* label,
int64_t micros = OS::GetCurrentMonotonicMicros(),
int64_t thread_micros = OS::GetCurrentThreadCPUMicros());
void AsyncBegin(const char* label,
int64_t async_id,
int64_t micros = OS::GetCurrentMonotonicMicros());
事件定义过程会设置默认值,同步与异步的区别是异步事件会记录async_id,同步事件会记录当前线程的cpu运行时间戳。
void TimelineEvent::Begin(const char* label,
int64_t micros,
int64_t thread_micros) {
Init(kBegin, label);
set_timestamp0(micros); //系统启动后运行的时间戳
set_thread_timestamp0(thread_micros); //该线程CPU运行的时间戳
}
void TimelineEvent::End(const char* label,
int64_t micros,
int64_t thread_micros) {
Init(kEnd, label);
set_timestamp0(micros); //系统启动后运行的时间戳
set_thread_timestamp0(thread_micros);//该线程CPU运行的时间戳
}
void TimelineEvent::AsyncBegin(const char* label,
int64_t async_id,
int64_t micros) {
Init(kAsyncBegin, label);
set_timestamp0(micros);
set_timestamp1(async_id); //async_id记录到timestamp1_
}
void TimelineEvent::AsyncEnd(const char* label,
int64_t async_id,
int64_t micros) {
Init(kAsyncEnd, label);
set_timestamp0(micros);
set_timestamp1(async_id); //async_id记录到timestamp1_
}
void TimelineEvent::Init(EventType event_type, const char* label) {
state_ = 0;
timestamp0_ = 0;
timestamp1_ = 0;
thread_timestamp0_ = -1;
thread_timestamp1_ = -1;
OSThread* os_thread = OSThread::Current();
thread_ = os_thread->trace_id(); //记录线程id
Isolate* isolate = Isolate::Current();
if (isolate != NULL) {
isolate_id_ = isolate->main_port(); //记录isolate端口号
} else {
isolate_id_ = ILLEGAL_PORT;
}
label_ = label; //事件标签名
arguments_.Free();
set_event_type(event_type); //事件类型,比如kBegin,kEnd
set_pre_serialized_args(false);
set_owns_label(false);
}
void TimelineEvent::Complete() {
TimelineEventRecorder* recorder = Timeline::recorder();
if (recorder != NULL) {
recorder->CompleteEvent(this); //[见下文]
}
}
void TimelineEventFixedBufferRecorder::CompleteEvent(TimelineEvent* event) {
ThreadBlockCompleteEvent(event); //[见下文]
}
void TimelineEventRecorder::ThreadBlockCompleteEvent(TimelineEvent* event) {
OSThread* thread = OSThread::Current();
Mutex* thread_block_lock = thread->timeline_block_lock();
thread_block_lock->Unlock(); //释放同步锁
}
当OSThread的thread_block写满,则需要执行Finish(),将该事件块的数据发送给ServiceIsolate来处理,如下所示。
void TimelineEventBlock::Finish() {
in_use_ = false;
#ifndef PRODUCT
if (Service::timeline_stream.enabled()) {
ServiceEvent service_event(NULL, ServiceEvent::kTimelineEvents);
service_event.set_timeline_event_block(this);
Service::HandleEvent(&service_event); //[见下文]
}
#endif
}
[-> third_party/dart/runtime/vm/service.cc]
void Service::HandleEvent(ServiceEvent* event) {
if (event->stream_info() != NULL && !event->stream_info()->enabled()) {
return; //当没有地方监听事件流,则忽略
}
if (!ServiceIsolate::IsRunning()) {
return; //当ServiceIsolate没有运行,则停止
}
JSONStream js;
const char* stream_id = event->stream_id();
{
JSONObject jsobj(&js);
jsobj.AddProperty("jsonrpc", "2.0");
jsobj.AddProperty("method", "streamNotify");
JSONObject params(&jsobj, "params");
params.AddProperty("streamId", stream_id);
params.AddProperty("event", event);
}
//此处isoalte为空,[见小节]
PostEvent(event->isolate(), stream_id, event->KindAsCString(), &js);
if (event->stream_info() != nullptr &&
event->stream_info()->consumer() != nullptr) {
auto length = js.buffer()->length();
event->stream_info()->consumer()(
reinterpret_cast<uint8_t*>(js.buffer()->buf()), length);
}
}
可通过Dart_SetNativeServiceStreamCallback()来设置Dart_NativeStreamConsumer回调方法。
[-> third_party/dart/runtime/vm/service.cc]
void Service::PostEvent(Isolate* isolate,
const char* stream_id,
const char* kind,
JSONStream* event) {
//消息格式[<stream id>, <json string>]
Dart_CObject list_cobj;
Dart_CObject* list_values[2];
list_cobj.type = Dart_CObject_kArray;
list_cobj.value.as_array.length = 2;
list_cobj.value.as_array.values = list_values;
Dart_CObject stream_id_cobj;
stream_id_cobj.type = Dart_CObject_kString;
stream_id_cobj.value.as_string = const_cast<char*>(stream_id); //stream_id
list_values[0] = &stream_id_cobj;
Dart_CObject json_cobj;
json_cobj.type = Dart_CObject_kString;
json_cobj.value.as_string = const_cast<char*>(event->ToCString()); //event
list_values[1] = &json_cobj;
auto thread = Thread::Current();
if (thread != nullptr) {
TransitionVMToNative transition(thread);
//向service isolate发送事件
Dart_PostCObject(ServiceIsolate::Port(), &list_cobj);
} else {
Dart_PostCObject(ServiceIsolate::Port(), &list_cobj);
}
}
DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message) {
return PostCObjectHelper(port_id, message);
}
static bool PostCObjectHelper(Dart_Port port_id, Dart_CObject* message) {
ApiMessageWriter writer;
Message* msg = writer.WriteCMessage(message, port_id, Message::kNormalPriority);
if (msg == NULL) {
return false;
}
return PortMap::PostMessage(msg);
}
最终会把数据传递给ServiceIsolate来进行处理。
[-> third_party/dart/runtime/vm/timeline.cc]
TimelineEvent* TimelineEventPlatformRecorder::StartEvent() {
TimelineEvent* event = new TimelineEvent();
return event;
}
[-> third_party/dart/runtime/vm/timeline.cc]
TimelineEvent::TimelineEvent()
: timestamp0_(0),
timestamp1_(0),
thread_timestamp0_(-1),
thread_timestamp1_(-1),
state_(0),
label_(NULL),
stream_(NULL),
thread_(OSThread::kInvalidThreadId),
isolate_id_(ILLEGAL_PORT) {}
[-> third_party/dart/runtime/vm/timeline.cc]
void TimelineEvent::Begin(const char* label,
int64_t micros,
int64_t thread_micros) {
Init(kBegin, label);
set_timestamp0(micros); //系统启动后运行的时间戳
set_thread_timestamp0(thread_micros); //该线程CPU运行的时间戳
}
[-> third_party/dart/runtime/vm/timeline.cc]
void TimelineEvent::Complete() {
TimelineEventRecorder* recorder = Timeline::recorder();
if (recorder != NULL) {
recorder->CompleteEvent(this); //[见下文]
}
}
void TimelineEventPlatformRecorder::CompleteEvent(TimelineEvent* event) {
OnEvent(event);
delete event;
}
[-> third_party/dart/runtime/vm/timeline_android.cc]
void TimelineEventSystraceRecorder::OnEvent(TimelineEvent* event) {
const intptr_t kBufferLength = 1024;
char buffer[kBufferLength];
//[小节2.4.6]
const intptr_t event_length = PrintSystrace(event, &buffer[0], kBufferLength);
if (event_length > 0) {
ssize_t result;
do {
result = write(systrace_fd_, buffer, event_length);
} while ((result == -1L) && (errno == EINTR));
}
}
此处的systrace_fd_是指/sys/kernel/debug/tracing/trace_marker,也就是ftrace的buffer。
其中PrintSystrace过程如下所示:
intptr_t TimelineEventSystraceRecorder::PrintSystrace(TimelineEvent* event,
char* buffer,
intptr_t buffer_size) {
buffer[0] = '\0';
intptr_t length = 0;
int64_t pid = OS::ProcessId();
switch (event->event_type()) {
case TimelineEvent::kBegin: {
length = Utils::SNPrint(buffer, buffer_size, "B|%" Pd64 "|%s", pid,
event->label());
break;
}
case TimelineEvent::kEnd: {
length = Utils::SNPrint(buffer, buffer_size, "E");
break;
}
case TimelineEvent::kCounter: {
if (event->arguments_length() > 0) {
length = Utils::SNPrint(buffer, buffer_size, "C|%" Pd64 "|%s|%s", pid,
event->label(), event->arguments()[0].value);
}
break;
}
default:
break;
}
return length;
}
可见kBegin、kEnd、kCounter记录的信息如下所示:
B|pid|name
E
C|pid|name|count
每一个Timeline时间的执行流程:
ring和endless、startup记录器实现方式非常相近,都需要ServiceIsolate才能工作,其核心区别是GetNewBlockLocked()中buffer分配的方式。ring和startup都是采用的是固定大小,ring是在buffer已满的情况下循环写;startup则是写满buffer则不再写入;endless采用的是无上限的buffer空间。 systrace实现方式则跟前三者完全不同,systrace依赖的是linux底层的ftrace,无需额外开辟buffer。
[-> third_party/dart/sdk/lib/developer/timeline.dart]
class Timeline {
static final List<_SyncBlock> _stack = new List<_SyncBlock>();
static void startSync(String name, {Map arguments, Flow flow}) {
if (!_hasTimeline) return;
if (!_isDartStreamEnabled()) {
_stack.add(null);
return;
}
//创建同步块
var block = new _SyncBlock._(name, _getTraceClock(), _getThreadCpuClock());
if (arguments != null) {
block._arguments = arguments;
}
if (flow != null) {
block.flow = flow;
}
_stack.add(block);
}
}
关于时间的两个方法如下所示:
DEFINE_NATIVE_ENTRY(Timeline_getTraceClock, 0, 0) {
return Integer::New(OS::GetCurrentMonotonicMicros(), Heap::kNew);
}
DEFINE_NATIVE_ENTRY(Timeline_getThreadCpuClock, 0, 0) {
return Integer::New(OS::GetCurrentThreadCPUMicros(), Heap::kNew);
}
class _SyncBlock {
final String category = 'Dart';
final String name;
Map _arguments;
final int _start; //启动运行时间戳
final int _startCpu; //该线程CPU运行时间戳
Flow _flow;
_SyncBlock._(this.name, this._start, this._startCpu);
}
[-> third_party/dart/sdk/lib/developer/timeline.dart]
class Timeline {
static void finishSync() {
if (!_hasTimeline) {
return;
}
if (_stack.length == 0) {
throw new StateError('Uneven calls to startSync and finishSync');
}
var block = _stack.removeLast();
block.finish(); //[见小节]
}
}
[-> third_party/dart/sdk/lib/developer/timeline.dart]
class _SyncBlock {
void finish() {
// [见小节]
_reportCompleteEvent(
_start, _startCpu, category, name, _argumentsAsJson(_arguments));
if (_flow != null) {
_reportFlowEvent(_start, _startCpu, category, name, _flow._type, _flow.id,
_argumentsAsJson(null));
}
}
}
[-> third_party/dart/runtime/lib/timeline.cc]
DEFINE_NATIVE_ENTRY(Timeline_reportCompleteEvent, 0, 5) {
#if defined(SUPPORT_TIMELINE)
GET_NON_NULL_NATIVE_ARGUMENT(Integer, start, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Integer, start_cpu, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(String, category, arguments->NativeArgAt(2));
GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(3));
GET_NON_NULL_NATIVE_ARGUMENT(String, args, arguments->NativeArgAt(4));
TimelineEventRecorder* recorder = Timeline::recorder();
//获取TimelineEvent对象
TimelineEvent* event = Timeline::GetDartStream()->StartEvent();
//见小节
DartTimelineEventHelpers::ReportCompleteEvent(
thread, event, start.AsInt64Value(), start_cpu.AsInt64Value(),
category.ToCString(), name.ToMallocCString(), args.ToMallocCString());
#endif
return Object::null();
}
[-> third_party/dart/runtime/vm/timeline.cc]
void DartTimelineEventHelpers::ReportCompleteEvent(Thread* thread,
TimelineEvent* event,
int64_t start,
int64_t start_cpu,
const char* category,
char* name,
char* args) {
const int64_t end = OS::GetCurrentMonotonicMicros();
const int64_t end_cpu = OS::GetCurrentThreadCPUMicros();
//将四个时间戳记录到TimelineEvent
event->Duration(name, start, end, start_cpu, end_cpu);
event->set_owns_label(true);
// 见小节
event->CompleteWithPreSerializedArgs(args);
}
void TimelineEvent::Duration(const char* label,
int64_t start_micros,
int64_t end_micros,
int64_t thread_start_micros,
int64_t thread_end_micros) {
Init(kDuration, label);
set_timestamp0(start_micros);
set_timestamp1(end_micros);
set_thread_timestamp0(thread_start_micros);
set_thread_timestamp1(thread_end_micros);
}
将名字记录到TimelineEvent的成员变量label_,将四个时间戳记录到TimelineEvent的相应成员变量。
[-> third_party/dart/runtime/vm/timeline.cc]
void TimelineEvent::CompleteWithPreSerializedArgs(char* args_json) {
set_pre_serialized_args(true);
SetNumArguments(1);
SetArgument(0, "Dart Arguments", args_json);
Complete();
}
接着执行Complete(),根据不同的recorder回到了前面已介绍[小节2.3.4]/[小节2.4.4]过程。
class TimelineTask {
final int _taskId;
final List<_AsyncBlock> _stack = [];
//需要先初始化
TimelineTask() : _taskId = _getNextAsyncId() {}
void start(String name, {Map arguments}) {
if (!_hasTimeline) return;
var block = new _AsyncBlock._(name, _taskId);
if (arguments != null) {
block._arguments = arguments;
}
_stack.add(block);
block._start(); //[见小节]
}
}
class _AsyncBlock {
final String category = 'Dart';
final String name;
final int _taskId;
Map _arguments;
void _start() {
_reportTaskEvent(
_getTraceClock(), _taskId, 'b', category, name, _argumentsAsJson(null));
}
}
_AsyncBlock相比_SyncBlock少了,少了两个时间相关的成员变量,多了一个记录taskid的成员变量
class TimelineTask {
void finish() {
if (!_hasTimeline) {
return;
}
var block = _stack.removeLast();
block._finish(); //[见小节]
}
}
class TimelineTask {
void _finish() {
_reportTaskEvent(_getTraceClock(), _taskId, 'e', category, name,
_argumentsAsJson(_arguments));
}
}
DEFINE_NATIVE_ENTRY(Timeline_reportTaskEvent, 0, 6) {
#if defined(SUPPORT_TIMELINE)
GET_NON_NULL_NATIVE_ARGUMENT(Integer, start, arguments->NativeArgAt(0));
GET_NON_NULL_NATIVE_ARGUMENT(Integer, id, arguments->NativeArgAt(1));
GET_NON_NULL_NATIVE_ARGUMENT(String, phase, arguments->NativeArgAt(2));
GET_NON_NULL_NATIVE_ARGUMENT(String, category, arguments->NativeArgAt(3));
GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(4));
GET_NON_NULL_NATIVE_ARGUMENT(String, args, arguments->NativeArgAt(5));
TimelineEventRecorder* recorder = Timeline::recorder();
//获取TimelineEvent对象
TimelineEvent* event = Timeline::GetDartStream()->StartEvent();
//见小节
DartTimelineEventHelpers::ReportTaskEvent(
thread, event, start.AsInt64Value(), id.AsInt64Value(), phase.ToCString(),
category.ToCString(), name.ToMallocCString(), args.ToMallocCString());
#endif // SUPPORT_TIMELINE
return Object::null();
}
void DartTimelineEventHelpers::ReportTaskEvent(Thread* thread,
TimelineEvent* event,
int64_t start,
int64_t id,
const char* phase,
const char* category,
char* name,
char* args) {
switch (phase[0]) {
case 'n':
event->AsyncInstant(name, id, start);
break;
case 'b':
event->AsyncBegin(name, id, start);
break;
case 'e':
event->AsyncEnd(name, id, start);
break;
default:
UNREACHABLE();
}
event->set_owns_label(true);
event->CompleteWithPreSerializedArgs(args);
}
void TimelineEvent::CompleteWithPreSerializedArgs(char* args_json) {
set_pre_serialized_args(true);
SetNumArguments(1);
SetArgument(0, "Dart Arguments", args_json);
Complete();
}
接着执行Complete(),根据不同的recorder回到了前面已介绍[小节2.3.4]/[小节2.4.4]过程。
这两个宏目前主要用于dart_api_impl.cc文件
#define API_TIMELINE_DURATION(thread) \
TimelineDurationScope api_tds(thread, Timeline::GetAPIStream(), CURRENT_FUNC)
#define API_TIMELINE_BEGIN_END(thread) \
TimelineBeginEndScope api_tbes(thread, Timeline::GetAPIStream(), CURRENT_FUNC)
TimelineDurationScope::TimelineDurationScope(Thread* thread,
TimelineStream* stream,
const char* label)
: TimelineEventScope(thread, stream, label) {
if (!enabled()) {
return;
}
timestamp_ = OS::GetCurrentMonotonicMicros();
thread_timestamp_ = OS::GetCurrentThreadCPUMicros();
}
该timeline事件的标签名为CURRENT_FUNC,也就是函数名;
TimelineDurationScope::~TimelineDurationScope() {
if (!ShouldEmitEvent()) {
return;
}
TimelineEvent* event = stream()->StartEvent();
if (event == NULL) {
return;
}
//创建事件
event->Duration(label(), timestamp_, OS::GetCurrentMonotonicMicros(),
thread_timestamp_, OS::GetCurrentThreadCPUMicros());
StealArguments(event);
//事件完成
event->Complete();
}
TimelineBeginEndScope::TimelineBeginEndScope(Thread* thread,
TimelineStream* stream,
const char* label)
: TimelineEventScope(thread, stream, label) {
EmitBegin();
}
TimelineBeginEndScope::~TimelineBeginEndScope() {
EmitEnd();
}
该timeline事件的标签名为CURRENT_FUNC,也就是函数名
void TimelineBeginEndScope::EmitBegin() {
if (!ShouldEmitEvent()) {
return;
}
TimelineEvent* event = stream()->StartEvent();
if (event == NULL) {
set_enabled(false);
return;
}
event->Begin(label()); //事件开始
event->Complete();
}
void TimelineBeginEndScope::EmitEnd() {
if (!ShouldEmitEvent()) {
return;
}
TimelineEvent* event = stream()->StartEvent();
if (event == NULL) {
set_enabled(false);
return;
}
event->End(label()); //事件结束
StealArguments(event);
event->Complete();
}
对于timeline来说功能是一致的,但对于systrace则不同,因为事件的方式不同,建议时候用API_TIMELINE_BEGIN_END,不推荐使用API_TIMELINE_DURATION。
TimelineEventRecorder:主要还有以下四种:ring, endless, startup, systrace,本身timeline是能够转换为systrace的,但是在转换过程中有很多坑,需要去解决,下一篇文章再进一步讲解如何解决对systrace更友好的支持。
附录:
flutter/fml/trace_event.cc
third_party/dart/sdk/lib/developer/timeline.dart
third_party/dart/runtime/lib/timeline.cc
third_party/dart/runtime/vm/
- dart_api_impl.cc
- timeline.cc
- timeline_android.cc
- service.cc
2019-10-13 06:15:40
在前面文章深入理解Dart虚拟机启动中,有讲到Dart虚拟机中有一个比较重要的isolate,创建的isolate名为”vm-service”,运行在独立的线程,也就是ServiceIsolate,这是用于系统调试相关功能的一个isolate,提供虚拟机相关服务, 比如hot reload,timeline等。这里先来看看ServiceIsolate的启动过程以及监听处理流程。
在dart虚拟机启动过程,会执行Dart::Init()操作,该过程中初始化timeline以及在线程池中启动ServiceIsolate。
[-> third_party/dart/runtime/vm/dart.cc]
char* Dart::Init(Dart_IsolateCreateCallback create,
Dart_IsolateShutdownCallback shutdown,
Dart_IsolateCleanupCallback cleanup,
Dart_ThreadExitCallback thread_exit,
...) {
...
#if defined(SUPPORT_TIMELINE)
Timeline::Init();
#endif
Isolate::SetCreateCallback(create);
Isolate::SetShutdownCallback(shutdown);
Isolate::SetCleanupCallback(cleanup);
const bool is_dart2_aot_precompiler = FLAG_precompiled_mode && !kDartPrecompiledRuntime;
if (!is_dart2_aot_precompiler &&
(FLAG_support_service || !kDartPrecompiledRuntime)) {
ServiceIsolate::Run(); //[见小节]
}
...
}
启动ServiceIsolate的条件,需要满足以下两者之一:
再来看一看DartVM初始化过程
DartVM::DartVM(std::shared_ptr<const DartVMData> vm_data,
std::shared_ptr<IsolateNameServer> isolate_name_server) {
...
TRACE_EVENT0("flutter", "Dart_Initialize");
Dart_InitializeParams params = {};
params.create = reinterpret_cast<decltype(params.create)>(
DartIsolate::DartIsolateCreateCallback);
params.shutdown = reinterpret_cast<decltype(params.shutdown)>(
DartIsolate::DartIsolateShutdownCallback);
params.cleanup = reinterpret_cast<decltype(params.cleanup)>(
DartIsolate::DartIsolateCleanupCallback);
params.thread_exit = ThreadExitCallback;
...
}
可见,ServiceIsolate的创建callback方法是指DartIsolate::DartIsolateCreateCallback(),后面会用到这个信息。
[-> third_party/dart/runtime/vm/service_isolate.cc]
void ServiceIsolate::Run() {
{
MonitorLocker ml(monitor_);
state_ = kStarting;
ml.NotifyAll();
}
//将任务交给线程池中的worker线程来执行任务[见小节]
bool task_started = Dart::thread_pool()->Run(new RunServiceTask());
}
将RunServiceTask任务交给线程池中的worker线程来执行任务,过程会创建创建名为“vm-service”的isolate。
[-> third_party/dart/runtime/vm/service_isolate.cc]
class RunServiceTask : public ThreadPool::Task {
public:
virtual void Run() {
char* error = NULL;
Isolate* isolate = NULL;
Dart_IsolateCreateCallback create_callback =
ServiceIsolate::create_callback();
Dart_IsolateFlags api_flags;
Isolate::FlagsInitialize(&api_flags);
//创建ServiceIsolate [见小节2.3]
isolate = reinterpret_cast<Isolate*>(
create_callback(ServiceIsolate::kName, ServiceIsolate::kName, NULL,
NULL, &api_flags, NULL, &error));
bool got_unwind;
{
StartIsolateScope start_scope(isolate);
//[见小节2.4]
got_unwind = RunMain(isolate);
}
...
isolate->message_handler()->Run(Dart::thread_pool(), NULL, ShutdownIsolate,
reinterpret_cast<uword>(isolate));
}
此处的create_callback便是DartIsolate::DartIsolateCreateCallback,如下所示。
[-> flutter/runtime/dart_isolate.cc]
Dart_Isolate DartIsolate::DartIsolateCreateCallback(
const char* advisory_script_uri,
const char* advisory_script_entrypoint,
const char* package_root,
const char* package_config,
Dart_IsolateFlags* flags,
std::shared_ptr<DartIsolate>* parent_embedder_isolate,
char** error) {
if (parent_embedder_isolate == nullptr &&
strcmp(advisory_script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) {
return DartCreateAndStartServiceIsolate(package_root,package_config,
flags, error
);
}
...
}
此处DART_VM_SERVICE_ISOLATE_NAME就是”vm-service”。
Dart_Isolate DartIsolate::DartCreateAndStartServiceIsolate(
const char* package_root,
const char* package_config,
Dart_IsolateFlags* flags,
char** error) {
auto vm_data = DartVMRef::GetVMData();
const auto& settings = vm_data->GetSettings();
if (!settings.enable_observatory) {
return nullptr;
}
TaskRunners null_task_runners("io.flutter." DART_VM_SERVICE_ISOLATE_NAME,
nullptr, nullptr, nullptr, nullptr);
flags->load_vmservice_library = true;
std::weak_ptr<DartIsolate> weak_service_isolate =
DartIsolate::CreateRootIsolate(
vm_data->GetSettings(), // settings
vm_data->GetIsolateSnapshot(), // isolate snapshot
vm_data->GetSharedSnapshot(), // shared snapshot
null_task_runners, // task runners
nullptr, // window
{}, // snapshot delegate
{}, // IO Manager
DART_VM_SERVICE_ISOLATE_NAME, // script uri
DART_VM_SERVICE_ISOLATE_NAME, // script entrypoint
flags // flags
);
tonic::DartState::Scope scope(service_isolate);
//[见小节2.3.2]
if (!DartServiceIsolate::Startup(
settings.ipv6 ? "::1" : "127.0.0.1", // server IP address
settings.observatory_port, // server observatory port
tonic::DartState::HandleLibraryTag, // embedder library tag handler
false, // disable websocket origin check
settings.disable_service_auth_codes, // disable VM service auth codes
error // error (out)
)) {
return nullptr;
}
...
return service_isolate->isolate();
}
[-> flutter/runtime/dart_service_isolate.cc]
bool DartServiceIsolate::Startup(std::string server_ip,
intptr_t server_port,
Dart_LibraryTagHandler embedder_tag_handler,
bool disable_origin_check,
bool disable_service_auth_codes,
char** error) {
Dart_Isolate isolate = Dart_CurrentIsolate();
...
Dart_Handle uri = Dart_NewStringFromCString("dart:vmservice_io");
Dart_Handle library = Dart_LookupLibrary(uri);
Dart_Handle result = Dart_SetRootLibrary(library);
result = Dart_SetNativeResolver(library, GetNativeFunction, GetSymbol);
Dart_ExitScope();
Dart_ExitIsolate();
//该过程会执行Isolate::Run()方法
Dart_IsolateMakeRunnable(isolate);
Dart_EnterIsolate(isolate);
Dart_EnterScope();
library = Dart_RootLibrary();
//设置HTTP server的ip地址,对于ipv4则为127.0.0.1
Dart_SetField(library, Dart_NewStringFromCString("_ip"),
Dart_NewStringFromCString(server_ip.c_str()));
//当指定端口号,则立即启动服务;如果没有指定,则找到第一个可用的端口号
bool auto_start = server_port >= 0;
if (server_port < 0) {
server_port = 0;
}
//设置HTTP server的端口号,
Dart_SetField(library, Dart_NewStringFromCString("_port"),
Dart_NewInteger(server_port));
Dart_SetField(library, Dart_NewStringFromCString("_autoStart"),
Dart_NewBoolean(auto_start));
Dart_SetField(library, Dart_NewStringFromCString("_originCheckDisabled"),
Dart_NewBoolean(disable_origin_check));
Dart_SetField(library, Dart_NewStringFromCString("_authCodesDisabled"),
Dart_NewBoolean(disable_service_auth_codes));
return true;
}
设置root library为dart:vmservice_io。
[-> third_party/dart/runtime/vm/service_isolate.cc]
bool RunMain(Isolate* I) {
Thread* T = Thread::Current();
StackZone zone(T);
HANDLESCOPE(T);
const Library& root_library = Library::Handle(Z, I->object_store()->root_library());
const String& entry_name = String::Handle(Z, String::New("main"));
const Function& entry = Function::Handle(
Z, root_library.LookupFunctionAllowPrivate(entry_name));
//找到并执行dart:vmservice_io库的main()方法 [见小节2.5]
const Object& result = Object::Handle(
Z, DartEntry::InvokeFunction(entry, Object::empty_array()));
const ReceivePort& rp = ReceivePort::Cast(result);
ServiceIsolate::SetLoadPort(rp.Id());
return false;
}
[-> third_party/dart/runtime/bin/vmservice/vmservice_io.dart]
main() {
new VMService();
if (_autoStart) {
_lazyServerBoot(); //[见小节2.5.1]
server.startup(); //[见小节2.6]
Timer.run(() {}); //用于执行所有的microtasks.
}
scriptLoadPort.handler = _processLoadRequest;
_registerSignalHandlerTimer = new Timer(shortDelay, _registerSignalHandler);
return scriptLoadPort;
}
[-> third_party/dart/runtime/bin/vmservice/vmservice_io.dart]
_lazyServerBoot() {
if (server != null) {
return;
}
//[见小节2.5.2]
var service = new VMService();
//[见小节2.5.4]
server = new Server(service, _ip, _port, _originCheckDisabled, _authCodesDisabled);
}
该过程创建VMService和Server对象
[-> third_party/dart/sdk/lib/vmservice/vmservice.dart]
final RawReceivePort isolateControlPort = new RawReceivePort();
class VMService extends MessageRouter {
factory VMService() {
if (VMService._instance == null) {
VMService._instance = new VMService._internal(); //如下文
_onStart(); //通知虚拟机,服务正在运行
}
return _instance;
}
VMService._internal() : eventPort = isolateControlPort {
eventPort.handler = messageHandler; //设置消息处理handler
}
}
[-> third_party/dart/sdk/lib/vmservice/vmservice.dart]
void messageHandler(message) {
if (message is List) {
if (message.length == 2) {
// 事件处理
_eventMessageHandler(message[0], new Response.from(message[1]));
return;
}
if (message.length == 1) {
_exit(); //vm service退出的消息
return;
}
if (message.length == 3) {
final opcode = message[0];
if (opcode == Constants.METHOD_CALL_FROM_NATIVE) {
_handleNativeRpcCall(message[1], message[2]);
return;
} else {
assert((opcode == Constants.WEB_SERVER_CONTROL_MESSAGE_ID) ||
(opcode == Constants.SERVER_INFO_MESSAGE_ID));
_serverMessageHandler(message[0], message[1], message[2]);
return;
}
}
if (message.length == 4) {
//关于isolate的创建和销毁的消息
_controlMessageHandler(message[0], message[1], message[2], message[3]);
return;
}
}
}
根据消息长度调用相应的Handler:
[-> third_party/dart/runtime/bin/vmservice/server.dart]
class Server {
static const WEBSOCKET_PATH = '/ws';
static const ROOT_REDIRECT_PATH = '/index.html';
final VMService _service;
final String _ip;
final int _port;
final bool _originCheckDisabled;
final bool _authCodesDisabled;
HttpServer _server;
Server(this._service, this._ip, this._port, this._originCheckDisabled,
bool authCodesDisabled)
: _authCodesDisabled = (authCodesDisabled || Platform.isFuchsia);
}
[-> third_party/dart/runtime/bin/vmservice/server.dart]
Future startup() async {
...
Future<bool> poll() async {
try {
var address;
var addresses = await InternetAddress.lookup(_ip);
for (var i = 0; i < addresses.length; i++) {
address = addresses[i];
if (address.type == InternetAddressType.IP_V4) break;
}
//监听HTTP请求
_server = await HttpServer.bind(address, _port);
return true;
} catch (e, st) {
return false;
}
}
//轮询尝试,最多10次没有连接成功,则退出
int attempts = 0;
final int maxAttempts = 10;
//尝试跟指定地址和端口建立http请求进行绑定
while (!await poll()) {
attempts++;
if (attempts > maxAttempts) {
_notifyServerState("");
onServerAddressChange(null);
return this;
}
await new Future<Null>.delayed(const Duration(seconds: 1));
}
//进入监听状态
_server.listen(_requestHandler, cancelOnError: true);
//这便是熟悉的那行,标志着服务启动成功
serverPrint('Observatory listening on $serverAddress');
//将服务地址通知到VmService,写入其成员变量server_uri_
_notifyServerState(serverAddress.toString());
//将服务地址通知到ServiceIsolate,写入其成员变量server_address_
onServerAddressChange('$serverAddress');
return this;
}
服务进入监听状态,一旦收到请求,则会调用_requestHandler。
Server._requestHandler
client.onRequest
vmservice.routeRequest
vmservice._routeRequestImpl
message.sendToVM
message.sendRootServiceMessage (接下来进入C++)
Service::HandleRootMessage
Service::InvokeMethod
[-> third_party/dart/runtime/bin/vmservice/server.dart]
Future _requestHandler(HttpRequest request) async {
...
final String path = _checkAuthTokenAndGetPath(request.uri);
//创建一个client对象,内有vmservice [见小节3.1.1]
final client = new HttpRequestClient(request, _service);
//创建message对象,[见小节3.1.3]
final message = new Message.fromUri(client, Uri.parse(path));
// [见小节3.2]
client.onRequest(message);
}
[-> third_party/dart/runtime/bin/vmservice/server.dart]
class HttpRequestClient extends Client {
final HttpRequest request;
HttpRequestClient(this.request, VMService service)
: super(service, sendEvents: false); //见下文
}
[-> third_party/dart/sdk/lib/vmservice/client.dart]
abstract class Client {
final VMService service;
final bool sendEvents;
Client(this.service, {bool sendEvents: true}) : this.sendEvents = sendEvents {
service._addClient(this); //将当前的client添加到VMService
}
}
[-> third_party/dart/sdk/lib/vmservice/vmservice.dart]
class VMService extends MessageRouter {
static const serviceNamespace = 's';
final NamedLookup<Client> clients =
new NamedLookup<Client>(prologue: serviceNamespace);
void _addClient(Client client) {
clients.add(client);
}
}
[-> third_party/dart/sdk/lib/vmservice/message.dart]
Message.fromUri(this.client, Uri uri)
: type = MessageType.Request,
serial = '',
method = _methodNameFromUri(uri) { //从uri中获取方法名
params.addAll(uri.queryParameters);
}
Message对象都有一个成员变量method
[-> third_party/dart/sdk/lib/vmservice/client.dart]
abstract class Client {
final VMService service;
void onRequest(Message message) {
// 【见小节3.3/38】
service.routeRequest(service, message).then(post);
}
}
这里有两个过程:
[-> third_party/dart/sdk/lib/vmservice/vmservice.dart]
Future<Response> routeRequest(VMService _, Message message) async {
return new Response.from(await _routeRequestImpl(message));
}
Future _routeRequestImpl(Message message) async {
try {
if (message.completed) {
return await message.response;
}
if (message.method == 'streamListen') {
return await _streamListen(message);
}
if (message.method == 'streamCancel') {
return await _streamCancel(message);
}
if (message.method == '_registerService') {
return await _registerService(message);
}
if (message.method == '_spawnUri') {
return await _spawnUri(message);
}
if (devfs.shouldHandleMessage(message)) {
return await devfs.handleMessage(message);
}
if (_hasNamespace(message.method)) {
return await _handleService(message);
}
if (message.params['isolateId'] != null) {
return await runningIsolates.routeRequest(this, message);
}
return await message.sendToVM(); //[见小节3.4]
} catch (e, st) {
return message.response;
}
}
[-> third_party/dart/sdk/lib/vmservice/message.dart]
Future<Response> sendToVM() {
final receivePort = new RawReceivePort();
receivePort.handler = (value) {
receivePort.close();
_setResponseFromPort(value);
};
var keys = params.keys.toList(growable: false);
var values = params.values.toList(growable: false);
if (!_methodNeedsObjectParameters(method)) {
keys = _makeAllString(keys);
values = _makeAllString(values);
}
final request = new List(6)
..[0] = 0
..[1] = receivePort.sendPort
..[2] = serial
..[3] = method
..[4] = keys
..[5] = values;
if (_methodNeedsObjectParameters(method)) {
sendObjectRootServiceMessage(request); //[见小节3.5]
} else {
sendRootServiceMessage(request); //[见小节3.5]
}
return _completer.future;
}
sendRootServiceMessage,这是一个native方法,调用到vmservice.cc中相应的方法
[-> third_party/dart/runtime/lib/vmservice.cc]
DEFINE_NATIVE_ENTRY(VMService_SendRootServiceMessage, 0, 1) {
#ifndef PRODUCT
GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
if (FLAG_support_service) {
return Service::HandleRootMessage(message); //[见小节3.6]
}
#endif
return Object::null();
}
DEFINE_NATIVE_ENTRY(VMService_SendObjectRootServiceMessage, 0, 1) {
#ifndef PRODUCT
GET_NON_NULL_NATIVE_ARGUMENT(Array, message, arguments->NativeArgAt(0));
if (FLAG_support_service) {
return Service::HandleObjectRootMessage(message);
}
#endif
return Object::null();
}
[-> third_party/dart/runtime/vm/service.cc]
RawError* Service::HandleRootMessage(const Array& msg_instance) {
Isolate* isolate = Isolate::Current();
return InvokeMethod(isolate, msg_instance); //[见小节3.7]
}
RawError* Service::HandleObjectRootMessage(const Array& msg_instance) {
Isolate* isolate = Isolate::Current();
return InvokeMethod(isolate, msg_instance, true); //[见小节3.7]
}
[-> third_party/dart/runtime/vm/service.cc]
RawError* Service::InvokeMethod(Isolate* I, const Array& msg,
bool parameters_are_dart_objects) {
Thread* T = Thread::Current();
{
StackZone zone(T);
HANDLESCOPE(T);
Instance& reply_port = Instance::Handle(Z);
Instance& seq = String::Handle(Z);
String& method_name = String::Handle(Z);
Array& param_keys = Array::Handle(Z);
Array& param_values = Array::Handle(Z);
reply_port ^= msg.At(1);
seq ^= msg.At(2);
method_name ^= msg.At(3);
param_keys ^= msg.At(4);
param_values ^= msg.At(5);
JSONStream js;
Dart_Port reply_port_id =
(reply_port.IsNull() ? ILLEGAL_PORT : SendPort::Cast(reply_port).Id());
js.Setup(zone.GetZone(), reply_port_id, seq, method_name, param_keys,
param_values, parameters_are_dart_objects);
...
const char* c_method_name = method_name.ToCString();
//从service_methods_[]找到目标方法 [3.7.1]
const ServiceMethodDescriptor* method = FindMethod(c_method_name);
if (method != NULL) {
if (method->entry(T, &js)) { //执行相应方法
js.PostReply();
}
return T->StealStickyError();
}
...
}
}
[-> third_party/dart/runtime/vm/service.cc]
const ServiceMethodDescriptor* FindMethod(const char* method_name) {
intptr_t num_methods = sizeof(service_methods_) / sizeof(service_methods_[0]);
for (intptr_t i = 0; i < num_methods; i++) {
const ServiceMethodDescriptor& method = service_methods_[i];
if (strcmp(method_name, method.name) == 0) {
return &method;
}
}
return NULL;
}
在service.cc中有一个成员变量service_methods_[]记录了所有的定义的方法。比如获取timeline的过程,如下所示。
struct ServiceMethodDescriptor {
const char* name;
const ServiceMethodEntry entry;
const MethodParameter* const* parameters;
};
static const ServiceMethodDescriptor service_methods_[] = {
{ "_echo", Echo,
NULL },
{ "_respondWithMalformedJson", RespondWithMalformedJson,
NULL },
{ "_respondWithMalformedObject", RespondWithMalformedObject,
NULL },
{ "_triggerEchoEvent", TriggerEchoEvent,
NULL },
{ "addBreakpoint", AddBreakpoint,
add_breakpoint_params },
{ "addBreakpointWithScriptUri", AddBreakpointWithScriptUri,
add_breakpoint_with_script_uri_params },
{ "addBreakpointAtEntry", AddBreakpointAtEntry,
add_breakpoint_at_entry_params },
{ "_addBreakpointAtActivation", AddBreakpointAtActivation,
add_breakpoint_at_activation_params },
{ "_buildExpressionEvaluationScope", BuildExpressionEvaluationScope,
build_expression_evaluation_scope_params },
{ "_clearCpuProfile", ClearCpuProfile,
clear_cpu_profile_params },
{ "_clearVMTimeline", ClearVMTimeline,
clear_vm_timeline_params, },
{ "_compileExpression", CompileExpression, compile_expression_params },
{ "_enableProfiler", EnableProfiler,
enable_profiler_params, },
{ "evaluate", Evaluate,
evaluate_params },
{ "evaluateInFrame", EvaluateInFrame,
evaluate_in_frame_params },
{ "_getAllocationProfile", GetAllocationProfile,
get_allocation_profile_params },
{ "_getAllocationSamples", GetAllocationSamples,
get_allocation_samples_params },
{ "_getNativeAllocationSamples", GetNativeAllocationSamples,
get_native_allocation_samples_params },
{ "getClassList", GetClassList,
get_class_list_params },
{ "_getCpuProfile", GetCpuProfile,
get_cpu_profile_params },
{ "_getCpuProfileTimeline", GetCpuProfileTimeline,
get_cpu_profile_timeline_params },
{ "_writeCpuProfileTimeline", WriteCpuProfileTimeline,
write_cpu_profile_timeline_params },
{ "getFlagList", GetFlagList,
get_flag_list_params },
{ "_getHeapMap", GetHeapMap,
get_heap_map_params },
{ "_getInboundReferences", GetInboundReferences,
get_inbound_references_params },
{ "_getInstances", GetInstances,
get_instances_params },
{ "getIsolate", GetIsolate,
get_isolate_params },
{ "getMemoryUsage", GetMemoryUsage,
get_memory_usage_params },
{ "_getIsolateMetric", GetIsolateMetric,
get_isolate_metric_params },
{ "_getIsolateMetricList", GetIsolateMetricList,
get_isolate_metric_list_params },
{ "getObject", GetObject,
get_object_params },
{ "_getObjectStore", GetObjectStore,
get_object_store_params },
{ "_getObjectByAddress", GetObjectByAddress,
get_object_by_address_params },
{ "_getPersistentHandles", GetPersistentHandles,
get_persistent_handles_params, },
{ "_getPorts", GetPorts,
get_ports_params },
{ "_getReachableSize", GetReachableSize,
get_reachable_size_params },
{ "_getRetainedSize", GetRetainedSize,
get_retained_size_params },
{ "_getRetainingPath", GetRetainingPath,
get_retaining_path_params },
{ "getScripts", GetScripts,
get_scripts_params },
{ "getSourceReport", GetSourceReport,
get_source_report_params },
{ "getStack", GetStack,
get_stack_params },
{ "_getUnusedChangesInLastReload", GetUnusedChangesInLastReload,
get_unused_changes_in_last_reload_params },
{ "_getTagProfile", GetTagProfile,
get_tag_profile_params },
{ "_getTypeArgumentsList", GetTypeArgumentsList,
get_type_arguments_list_params },
{ "getVersion", GetVersion,
get_version_params },
{ "getVM", GetVM,
get_vm_params },
{ "_getVMMetric", GetVMMetric,
get_vm_metric_params },
{ "_getVMMetricList", GetVMMetricList,
get_vm_metric_list_params },
{ "_getVMTimeline", GetVMTimeline,
get_vm_timeline_params },
{ "_getVMTimelineFlags", GetVMTimelineFlags,
get_vm_timeline_flags_params },
{ "invoke", Invoke, invoke_params },
{ "kill", Kill, kill_params },
{ "pause", Pause,
pause_params },
{ "removeBreakpoint", RemoveBreakpoint,
remove_breakpoint_params },
{ "reloadSources", ReloadSources,
reload_sources_params },
{ "_reloadSources", ReloadSources,
reload_sources_params },
{ "resume", Resume,
resume_params },
{ "_requestHeapSnapshot", RequestHeapSnapshot,
request_heap_snapshot_params },
{ "_evaluateCompiledExpression", EvaluateCompiledExpression,
evaluate_compiled_expression_params },
{ "setExceptionPauseMode", SetExceptionPauseMode,
set_exception_pause_mode_params },
{ "setFlag", SetFlag,
set_flags_params },
{ "setLibraryDebuggable", SetLibraryDebuggable,
set_library_debuggable_params },
{ "setName", SetName,
set_name_params },
{ "_setTraceClassAllocation", SetTraceClassAllocation,
set_trace_class_allocation_params },
{ "setVMName", SetVMName,
set_vm_name_params },
{ "_setVMTimelineFlags", SetVMTimelineFlags,
set_vm_timeline_flags_params },
{ "_collectAllGarbage", CollectAllGarbage,
collect_all_garbage_params },
{ "_getDefaultClassesAliases", GetDefaultClassesAliases,
get_default_classes_aliases_params },
};
class HttpRequestClient extends Client {
static ContentType jsonContentType =
new ContentType("application", "json", charset: "utf-8");
final HttpRequest request;
void post(Response result) {
HttpResponse response = request.response;
response.headers.add('Access-Control-Allow-Origin', '*');
response.headers.contentType = jsonContentType;
switch (result.kind) {
case ResponsePayloadKind.String:
response.write(result.payload);
break;
case ResponsePayloadKind.Utf8String:
response.add(result.payload);
break;
case ResponsePayloadKind.Binary:
throw 'Can not handle binary responses';
}
response.close();
close();
}
ServiceIsolate处理监听状态,根据具体的命令,最终会执行执行到service.cc的成service_methods_数组中所定义的方法。看到这里,你可能还不了解其功能。 这只是为下一篇文章介绍timeline工作原理做铺垫而已。
2019-10-06 06:15:40
Dart VM是一种虚拟机,为高级编程语言Dart提供执行环境,但这并意味着Dart在D虚拟机上执行时,总是采用解释执行或者JIT编译。 例如还可以使用Dart虚拟机的AOT管道将Dart代码编译为机器代码,然后运行在Dart虚拟机的精简版环境,称之为预编译运行时(precompiled runtime)环境,该环境不包含任何编译器组件,且无法动态加载Dart源代码。
Dart VM有多钟方式来执行代码:
区别主要在于什么时机以及如何将Dart代码转换为可执行的代码。
先来看看dart虚拟机中isolate的组成:
isolate拥有内存堆和控制线程,虚拟机中可以有很多isolate,但彼此之间不能直接状态,只能通过dart特有的端口;isolate除了拥有一个mutator控制线程,还有一些其他辅助线程:
线程和isolate的关系是什么呢?
虚拟机采用线程池的方式来管理线程,定义在runtime/vm/thread_pool.h
ThreadPool的核心成员变量:
ThreadPool核心方法:
对应关系图:
count_started_ | count_stopped_ | count_running_ | count_idle_ | |
---|---|---|---|---|
Run() | +1(无空闲worker) | +1 | -1(有空闲worker) | |
Shutdown() | +all_workers_个数 | 清零 | 清零 | |
SetIdleLocked() | -1 | +1 | ||
ReleaseIdleWorker() | +1 | -1 |
可见,count_started_ - count_stopped_ = count_running_ + count_idle_;
看看dart是如何直接理解并执行dart源码
// gityuan.dart
main() => print('Hello Gityuan!');
//dart位于flutter/bin/cache/dart-sdk/bin/dart
$ dart gityuan.dart
Hello, World!
说明:
有一个辅助类isolate叫作kernel service,其核心工作就是CFE,将dart转为Kernel二进制,然后VM可直接使用Kernel二进制运行在主isolate里面运行。
将dart代码转换为kernel二进制和执行kernel二进制,这两个过程也可以分离开来,在两个不同的机器执行,比如host机器执行编译,移动设备执行kernel文件。
图解:
虚拟机内部对象的命名约定:使用C++定义的,其名称在头文件raw_object.h中以Raw开头,比如RawClass是描述Dart类的VM对象,RawField是描述Dart类中的Dart字段的VM对象。
1)将内核二进制文件加载到VM后,将对其进行解析以创建表示各种程序实体的对象。这里采用了懒加载模式,一开始只有库和类的基本信息被加载,内核二进制文件中的每一个实体都会保留指向该二进制文件的指针,以便后续可根据需要加载更多信息。
2)仅在以后需要运行时,才完全反序列化有关类的信息。(例如查找类的成员变量,创建类的实例对象等),便会从内核二进制文件中读取类的成员信息。 但功能完整的主体(FunctionNode)在此阶段并不会反序列化,而只是获取其签名。
到此,已从内核二进制文件加载了足够的信息以供运行时成功解析和调用的方法。
所有函数的主体都具有占位符code_,而不是实际的可执行代码:它们指向LazyCompileStub,该Stub只是简单地要求系统Runtime为当前函数生成可执行代码,然后对这些新生成的代码进行尾部调用。
gen_kernel.dart利用CFE将Dart源码编译为kernel binary文件(也就是dill),可利用dump_kernel.dart能反解kernel binary文件,命令如下所示:
//将hello.dart编译成hello.dill
$ cd <FLUTTER_ENGINE_ROOT>
$ dart third_party/dart/pkg/vm/bin/gen_kernel.dart \
--platform out/android_debug/vm_platform_strong.dill \
-o hello.dill \
hello.dart
//转储AST的文本表示形式
$ dart third_party/dart/pkg/vm/bin/dump_kernel.dart hello.dill hello.kernel.txt
gen_kernel.dart文件,需要平台dill文件,这是一个包括所有核心库(dart:core, dart:async等)的AST的kernel binary文件。如果Dart SDK已经编译过,可直接使用out/ReleaseX64/vm_platform_strong.dill,否则需要使用compile_platform.dart来生成平台dill文件,如下命令:
//根据给定的库列表,来生成platform和outline文件
$ cd <FLUTTER_ENGINE_ROOT>
$ dart third_party/dart/pkg/front_end/tool/_fasta/compile_platform.dart \
dart:core \
third_party/dart/sdk/lib/libraries.json \
vm_outline.dill vm_platform.dill vm_outline.dill
首次编译函数时,这是通过未优化编译器来完成的。
未优化的编译器分两步生成机器代码:
在此阶段没有执行优化,未优化编译器的主要目标是快速生成可执行代码。
未优化编译过程,编译器不会尝试静态解析任何未在Kernel二进制文件中解析的调用,因此(MethodInvocation或PropertyGet AST节点)的调用被编译为完全动态的。虚拟机当前不使用任何形式的基于虚拟表(virtual table)或接口表(interface table)的调度,而是使用内联缓存实现动态调用。
虚拟机的内联缓存的核心思想是缓存方法解析后的站点结果信息,对于内联缓存最初是为了解决函数的本地代码:
未优化编译器产生的代码执行比较慢,需要自适应优化,通过profile配置文件来驱动优化策略。内联优化,当与某个功能关联的执行计数器达到某个阈值时,该功能将提交给后台优化编译器进行优化。
优化编译的方式与未优化编译的方式相同:通过序列化内核AST来构建未优化的IL。但是,优化编译器不是直接将IL编译为机器码,而是将未优化的IL转换为基于静态单分配(SSA)形式的优化的IL。
对基于SSA的IL通过基于收集到的类型反馈,内联,范围分析,类型传播,表示选择,存储到加载,加载到加载转发,全局值编号,分配接收等一系列经典和Dart特定的优化来进行专业化推测。最后,使用线性扫描寄存器分配器和一个简单的一对多的IL指令。优化编译完成后,后台编译器会请求mutator线程输入安全点,并将优化的代码附加到该函数。下次调用该函数时,它将使用优化的代码。
另外,有些函数包含很长的运行循环,因此在函数仍在运行时将执行从未优化的代码切换到优化的代码是有意义的,此过程之所以称为“堆栈替换”(OSR)。
VM还具有可用于控制JIT并使其转储IL以及用于JIT正在编译的功能的机器代码的标志
$ dart --print-flow-graph-optimized \
--disassemble-optimized \
--print-flow-graph-filter=myFunc \
--no-background-compilation \
hel.dart
优化是基于统计的,可能出现违反优化的情况
void printAnimal(obj) {
print('Animal {');
print(' ${obj.toString()}');
print('}');
}
// 大量调用的情况下,会推测printAnimal假设总是Cat的情况下来优化代码
for (var i = 0; i < 50000; i++)
printAnimal(Cat());
// 此处出现的是Dog,优化版本失效,则触发反优化
printAnimal(Dog());
每当只要优化版本遇到无法解决的情况,它就会将执行转移到未优化功能的匹配点,然后继续执行,这个恢复过程称为去优化:未优化的功能版本不做任何假设,可以处理所有可能的输入。
虚拟机通常会在执行一次反优化后,放弃该功能的优化版本,然后在以后使用优化的类型反馈再次对其进行重新优化。虚拟机保护编译器进行推测性假设的方式有两种:
1)虚拟机有能力将isolate的堆(驻留在堆上的对象图)序列化成二进制的快照,启动虚拟机isolate的时候可以从快照中重新创建相同的状态。
Snapshot的格式是低级的,并且针对快速启动进行了优化,本质上是要创建的对象列表以及如何将它们连接在一起的说明。那是快照背后的原始思想:代替解析Dart源码并逐步创建虚拟机内部的数据结构,这样虚拟机通过快照中的所有必要数据结构来快速启动isolate。
2)最初,快照不包括机器代码,但是后来在开发AOT编译器时添加了此功能。开发AOT编译器和带代码快照的动机是为了允许虚拟机在由于平台级别限制而无法进行JIT的平台上使用。
带代码的快照的工作方式几乎与普通快照相同,只是有一点点不同:它们包括一个代码部分,该部分与快照的其余部分不同,不需要反序列化。该代码节的放置方式使其可以在映射到内存后直接成为堆的一部分
引入AppJIT快照可减少大型Dart应用程序(如dartanalyzer或dart2js)的JIT预热时间。当这些工具用于小型项目时,它们花费的实际时间与VM花费的JIT编译这些应用程序的时间一样多。
AppJIT快照可以解决此问题:可以使用一些模拟训练数据在VM上运行应用程序,然后将所有生成的代码和VM内部数据结构序列化为AppJIT快照。然后可以分发此快照,而不是以源(或内核二进制)形式分发应用程序。如果出现实际数据上的执行配置文件与培训期间观察到的执行配置文件不匹配,快照开始的VM仍可以采用JIT模式执行。
AOT快照最初是为无法进行JIT编译的平台引入的,对于无法进行JIT意味着:
为了满足这些要求,AOT编译过程会进行全局静态分析(类型流分析, TFA),以确定从已知入口点集中可访问应用程序的哪些部分,分配了哪些类的实例以及类型如何在程序中流动。 所有这些分析都是保守的:这意味着它们会在正确性方面出错,与可以在性能方面出错的JIT形成鲜明对比,因为它始终可以取消优化为未优化的代码以实现正确的行为。
然后,所有可能达到的功能都将编译为本地代码,而无需进行任何推测性优化。但是,类型流信息仍用于专门化代码(例如,取消虚拟化调用),编译完所有函数后,即可获取堆的快照。
最终的快照snapshot可以运行在预编译Runtime,该Runtime是Dart VM的特殊变体,其中不包括诸如JIT和动态代码加载工具之类的组件。
AOT编译工具没有包含进Dart SDK。
//需要构建正常的dart可执行文件和运行AOT代码的runtime
$ tool/build.py -m release -a x64 runtime dart_precompiled_runtime
// 使用AOT编译器来编译APP
$ pkg/vm/tool/precompiler2 hello.dart hello.aot
//执行AOT快照
$ out/ReleaseX64/dart_precompiled_runtime hello.aot
Hello, World!
1)即使进行了全局和局部分析,AOT编译的代码仍可能包含无法静态的去虚拟化的调用站点。为了补偿此AOT编译代码和运行时,采用JIT中使用的内联缓存技术的扩展。此扩展版本称为可切换呼叫 (Switchable Calls)。
JIT部分已经描述过,与调用站点关联的每个内联缓存均由两部分组成:一个缓存对象(由RawICData实例表示)和一个要调用的本机代码块(例如InlineCacheStub)。在JIT模式下,运行时只会更新缓存本身。但在AOT运行时中,可以根据内联缓存的状态选择同时替换缓存和要调用的本机代码。
最初,所有动态呼叫均以未链接状态开始。首次调用此类呼叫站点时,将调用UnlinkedCallStub,它只是调用运行时帮助程序DRT_UnlinkedCall来链接此呼叫站点。
2)如果可能,DRT_UnlinkedCall尝试将呼叫站点转换为单态状态。在这种状态下,呼叫站点变成直接呼叫,该呼叫通过特殊的单态入口点进入方法,该入口点验证接收方是否具有预期的类。
在上面的示例中,假设第一次执行obj.method()时,obj是C的实例,而obj.method则解析为C.method。
下次执行相同的调用站点时,它将直接调用C.method,从而绕过任何类型的方法查找过程。但是,它将通过特殊的入口点(已验证obj仍然是C的实例)进入C.method。如果不是这种情况,将调用DRT_MonomorphicMiss并将尝试选择下一个调用站点状态。
3)C.method可能仍然是调用的有效目标,例如obj是C的扩展类但不覆盖C.method的D类的实例。在这种情况下,检查呼叫站点是否可以转换为由SingleTargetCallStub实现的单个目标状态(见RawSingleTargetCache)。
此存根基于以下事实:对于AOT编译,大多数类都使用继承层次结构的深度优先遍历来分配整数ID。如果C是具有D0,…,Dn子类的基类,并且没有一个覆盖C.method,则C.:cid <= classId(obj)<= max(D0.:cid,…,Dn .:cid)表示obj.method解析为C.method。在这种情况下,我们可以将类ID范围检查(单个目标状态)用于C的所有子类,而不是与单个类(单态)进行比较
否则,呼叫站点将切换为使用线性搜索内联缓存,类似于在JIT模式下使用的缓存。
最后,如果线性数组中的检查数量超过阈值,则呼叫站点将切换为使用类似字典的结构
整个过程相关的核心源码,简要说明:
https://mrale.ph/dartvm/
2019-09-23 05:15:40
在third_party/dart/runtime/vm/flag_list.h定义了Dart虚拟机中所有标志的列表,标志分为以下几大类别:
Product、Release、Precompile、Debug这四类可控参数,可使用的范围逐次递减,比如Product flags可用于所有模式,Debug flags只能用于调试模式。Dart虚拟机总共有106个flags参数
用法:PRODUCT_FLAG_MARCO(名称,类型,默认值,注解)
名称 | 默认值 | 注解 |
---|---|---|
collect_dynamic_function_names | true | 收集所有动态函数名称以标识唯一目标 |
enable_kernel_expression_compilation | true | 启用内核前端来编译表达式 |
enable_mirrors | true | 允许导入dart:mirrors |
enable_ffi | true | 允许导入dart:ffi |
guess_icdata_cid | true | 创建算法等操作的类型反馈 |
lazy_dispatchers | true | 懒惰地生成调度程序 |
polymorphic_with_deopt | true | 反优化的多态调用、巨形调用 |
reorder_basic_blocks | true | 对基本块重新排序 |
use_bare_instructions | true | 启用裸指令模式 |
truncating_left_shift | true | 尽可能优化左移以截断 |
use_cha_deopt | true | 使用类层次分析,即使会导致反优化 |
use_strong_mode_types | true | 基于强模式类型的优化 |
enable_slow_path_sharing | true | 启用共享慢速路径代码 |
enable_multiple_entrypoints | true | 启用多个入口点 |
experimental_unsafe_mode_use_ at_your_own_risk | false | 省略运行时强模式类型检查并禁用基于类型的优化 |
abort_on_oom | false | 如果内存分配失败则中止,仅与–old-gen-heap-size一起使用 |
collect_code | false | 尝试GC不常用代码 |
dwarf_stack_traces | false | 在dylib快照中发出dwarf行号和内联信息,而不表示堆栈跟踪 |
fields_may_be_reset | false | 不要优化静态字段初始化 |
link_natives_lazily | false | 懒加载链接本地调用 |
precompiled_mode | false | 预编译编译器模式 |
print_snapshot_sizes | false | 打印生成snapshot的大小 |
print_snapshot_sizes_verbose | false | 打印生成snapshot的详细大小 |
print_benchmarking_metrics | false | 打印其他内存和延迟指标以进行基准测试 |
shared_slow_path_triggers_gc | false | 测试:慢路径触发GC |
trace_strong_mode_types | false | 跟踪基于强模式类型的优化 |
use_bytecode_compiler | false | 从字节码编译 |
use_compactor | false | 当在旧空间执行GC时则压缩堆 |
enable_testing_pragmas | false | 启用神奇的编译指示以进行测试 |
enable_interpreter | false | 启用解释内核字节码 |
verify_entry_points | false | 通过native API访问无效成员时抛出API错误 |
background_compilation | USING_MULTICORE | 根据是否多核来决定是否后台运行优化编译 |
concurrent_mark | USING_MULTICORE | 老年代的并发标记 |
concurrent_sweep | USING_MULTICORE | 老年代的并发扫描 |
use_field_guards | !USING_DBC | 使用字段gurad,跟踪字段类型 |
interpret_irregexp | USING_DBC | 使用irregexp字节码解释器 |
causal_async_stacks | !USING_PRODUCT | 非product 则开启改进异步堆栈 |
marker_tasks | USING_MULTICORE ? 2 : 0 | 老生代GC标记的任务数,0代表在主线程执行 |
idle_timeout_micros | 1000 * 1000 | 长时间后将空闲任务从线程池隔离,单位微秒 |
idle_duration_micros | 500 * 1000 | 允许空闲任务运行的时长 |
old_gen_heap_size | (kWordSize <= 4) ? 1536 : 0 | 旧一代堆的最大大小,或0(无限制),单位MB |
new_gen_semi_max_size | (kWordSize <= 4) ? 8 : 16 | 新一代半空间的最大大小,单位MB |
new_gen_semi_initial_size | (kWordSize <= 4) ? 1 : 2 | 新一代半空间的最大初始大小,单位MB |
compactor_tasks | 2 | 并行压缩使用的任务数 |
getter_setter_ratio | 13 | 用于double拆箱启发式的getter/setter使用率? |
huge_method_cutoff_in_tokens | 20000 | 令牌中的大量方法中断:禁用大量方法的优化? |
max_polymorphic_checks | 4 | 多态检查的最大数量,否则为巨形的? |
max_equality_polymorphic_checks | 32 | 等式运算符中的多态检查的最大数量 |
compilation_counter_threshold | 10 | 在解释执行函数编译完成前的函数使用次数要求,-1表示从不 |
optimization_counter_threshold | 30000 | 函数在优化前的用法计数值,-1表示从不 |
optimization_level | 2 | 优化级别:1(有利大小),2(默认),3(有利速度) |
optimization_level这是一个可以尝试的参数
用法:RELEASE_FLAG_MARCO(名称,product_value,类型,默认值,注解)
名称 | product值 | 默认值 | 注解 |
---|---|---|---|
eliminate_type_checks | true | true | 静态类型分析允许时消除类型检查 |
dedup_instructions | true | false | 预编译时规范化指令 |
support_disassembler | false | true | 支持反汇编 |
support_il_printer | false | true | 支持IL打印 |
support_service | false | true | 支持服务协议 |
disable_alloc_stubs_after_gc | false | false | 压力测试标识 |
disassemble | false | false | 反汇编dart代码 |
disassemble_optimized | false | false | 反汇编优化代码 |
dump_megamorphic_stats | false | false | dump巨形缓存统计信息 |
dump_symbol_stats | false | false | dump符合表统计信息 |
enable_asserts | false | false | 启用断言语句 |
log_marker_tasks | false | false | 记录老年代GC标记任务的调试信息 |
randomize_optimization_counter | false | false | 基于每个功能随机化优化计数器阈值,用于测试 |
pause_isolates_on_start | false | false | 在isolate开始前暂停 |
pause_isolates_on_exit | false | false | 在isolate退出前暂停 |
pause_isolates_on_unhandled_exceptions | false | false | 在isolate发生未捕获异常前暂停 |
print_ssa_liveranges | false | false | 内存分配后打印有效范围 |
print_stacktrace_at_api_error | false | false | 当API发生错误时,打印native堆栈 |
profiler | false | false | 开启profiler |
profiler_native_memory | false | false | 开启native内存统计收集 |
trace_profiler | false | false | 跟踪profiler |
trace_field_guards | false | false | 跟踪字段cids的变化 |
verify_after_gc | false | false | 在GC之后启用堆验证 |
verify_before_gc | false | false | 在GC之前启用堆验证 |
verbose_gc | false | false | 开启详细GC |
verbose_gc_hdr | 40 | 40 | 打印详细的GC标头间隔 |
用法:PRECOMPILE_FLAG_MARCO(名称,precompiled_value,product_value,类型,默认值,注释)
名称 | precompiled值 | product值 | 默认值 | 说明 |
---|---|---|---|---|
load_deferred_eagerly | true | true | false | 急切加载延迟的库 |
use_osr | false | true | true | 使用OSR |
async_debugger | false | false | true | 调试器支持异步功能 |
support_reload | false | false | true | 支持isolate重新加载 |
force_clone_compiler_objects | false | false | false | 强制克隆编译器中所需的对象(ICData和字段) |
stress_async_stacks | false | false | false | 压测异步堆栈 |
trace_irregexp | false | false | false | 跟踪irregexps |
deoptimize_alot | false | false | false | 取消优化,从native条目返回到dart代码 |
deoptimize_every | 0 | 0 | 0 | 在每N次堆栈溢出检查中取消优化 |
用法:DEBUG_FLAG_MARCO(名称,类型,默认值,注解)
名称 | 默认值 | 注解 |
---|---|---|
print_variable_descriptors | false | 在反汇编中打印变量描述符 |
trace_cha | false | 跟踪类层次分析(CHA)操作 |
trace_ic | false | 跟踪IC处理? |
trace_ic_miss_in_optimized | false | 跟踪优化中的IC未命中情况 |
trace_intrinsified_natives | false | 跟踪是否调用固有native |
trace_isolates | false | 跟踪isolate的创建与关闭 |
trace_handles | false | 跟踪handles的分配 |
trace_kernel_binary | false | 跟踪内核的读写 |
trace_natives | false | 跟踪native调用 |
trace_optimization | false | 打印优化详情 |
trace_profiler_verbose | false | 跟踪profiler详情 |
trace_runtime_calls | false | 跟踪runtime调用 |
trace_ssa_allocator | false | 跟踪通过SSA的寄存器分配 |
trace_type_checks | false | 跟踪运行时类型检测 |
trace_patching | false | 跟踪代码修补 |
trace_optimized_ic_calls | false | 跟踪优化代码中的IC调用? |
trace_zones | false | 跟踪zone的内存分配大小 |
verify_gc_contains | false | 在GC期间开启地址是否包含的验证 |
verify_on_transition | false | 验证dart/vm的过渡? |
support_rr | false | 支持在RR中运行? |
默认值全部都为false,
[-> third_party/dart/runtime/vm/flags.cc]
FLAG_LIST(PRODUCT_FLAG_MARCO,
RELEASE_FLAG_MARCO,
DEBUG_FLAG_MARCO,
PRECOMPILE_FLAG_MARCO)
FLAG_LIST列举了所有的宏定义,这里有四种不同的宏,接下来逐一展开说明
[-> third_party/dart/runtime/vm/flags.cc]
// (1) Product标记:可以在任何部署模式中设置
#define PRODUCT_FLAG_MARCO(name, type, default_value, comment) \
type FLAG_##name = Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
// (2) Release标志:通常可用的标志,除Product模式以外
#if !defined(PRODUCT)
#define RELEASE_FLAG_MARCO(name, product_value, type, default_value, comment) \
type FLAG_##name = Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
// (3) Precompile标志:通常可用的标志,除Product模式或已预编译的运行时以外
#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
#define PRECOMPILE_FLAG_MARCO(name, pre_value, product_value, type, default_value, comment) \
type FLAG_##name = Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
// (4) Debug标志:只能在debug调试模式运行
#if defined(DEBUG)
#define DEBUG_FLAG_MARCO(name, type, default_value, comment) \
type FLAG_##name = Flags::Register_##type(&FLAG_##name, #name, default_value, comment);
这里涉及到3个宏定义:
可见,宏定义最终都是调用Flags::Register_XXX()方法,这里以FLAG_LIST中的其中一条定义来展开说明:
P(collect_code, bool, false, "Attempt to GC infrequently used code.")
//展开后等价如下
type FLAG_collect_code = Flags::Register_bool(&FLAG_collect_code, collect_code, false,
"Attempt to GC infrequently used code.");
[-> third_party/dart/runtime/vm/flags.cc]
bool Flags::Register_bool(bool* addr,
const char* name,
bool default_value,
const char* comment) {
Flag* flag = Lookup(name); //[见小节3.4]
if (flag != NULL) {
return default_value;
}
flag = new Flag(name, comment, addr, Flag::kBoolean);
AddFlag(flag);
return default_value;
}
[-> third_party/dart/runtime/vm/flags.cc]
Flag* Flags::Lookup(const char* name) {
//遍历flags_来查找是否已存在
for (intptr_t i = 0; i < num_flags_; i++) {
Flag* flag = flags_[i];
if (strcmp(flag->name_, name) == 0) {
return flag;
}
}
return NULL;
}
Flags类中有3个重要的静态成员变量:
static Flag** flags_; //记录所有的flags对象指针
static intptr_t capacity_; //代表数组的容量大小
static intptr_t num_flags_; //代表当前flags对象指针的个数
[-> third_party/dart/runtime/vm/flags.cc]
class Flag {
Flag(const char* name, const char* comment, void* addr, FlagType type)
: name_(name), comment_(comment), addr_(addr), type_(type) {}
const char* name_;
const char* comment_;
union {
void* addr_;
bool* bool_ptr_;
int* int_ptr_;
uint64_t* uint64_ptr_;
charp* charp_ptr_;
FlagHandler flag_handler_;
OptionHandler option_handler_;
};
FlagType type_;
}
[-> third_party/dart/runtime/vm/flags.cc]
class Flag {
void Flags::AddFlag(Flag* flag) {
if (num_flags_ == capacity_) {
if (flags_ == NULL) {
capacity_ = 256; //初始化大小为256
flags_ = new Flag*[capacity_];
} else {
intptr_t new_capacity = capacity_ * 2; //扩容
Flag** new_flags = new Flag*[new_capacity];
for (intptr_t i = 0; i < num_flags_; i++) {
new_flags[i] = flags_[i];
}
delete[] flags_;
flags_ = new_flags;
capacity_ = new_capacity;
}
}
//将flag记录到flags_
flags_[num_flags_++] = flag;
}
}
最终,所有的flag信息都记录在Flags类的静态成员变量flags_中。