大多数浏览器和
Developer App 均支持流媒体播放。
-
在自定 Instrument 中建模
通过自定 Instrument,您可以按照自己的方式对 app 进行性能分析,体现您的 app 在运行时的情况。每个自定 Instrument 的中心都是建模器。了解如何构建您自己的建模器来将路标输出转换为您要在 Instrument 中显示的数据。了解 Instruments 规则引擎的工作方式,以及如何优化 Instrument 来获得最高效率。这个讲座以 WWDC 2018 中的“创建自定 Instrument”为基础。
资源
相关视频
WWDC19
WWDC18
-
下载
(自定义工具建模 建立更智能的工具)
谢谢
大家下午好 我是Chad Woolf Apple的性能工具工程师 演讲421的主题是自定义工具建模 在自定义工具架构中 负责建模的是中间这个 建模模块 它是要推出 操作系统记录的原始事件 完成转换 创建可显示的事件 或导入另一个建模模块 给Air Instruments UI的工具 这个架构的完整介绍收录在 2018年“创建自定义工具”演讲 本场演讲的内容 重点关注的是 中间的这个 建模模块 建模模块对所有工具都很重要 包括这里的 Time Profiler 在Time Profiler UI中显示的数据 与内核记录的数据形式不一样 我们用建模模块进行转换 内核读取线程内容的样本时 会创建或捕捉一个叫原始回溯的东西 并添加到时间样本表格 之后由Time Profiler 的建模模块读取 再转换成可显示的回溯 放入 Time Profiler表格 最终由Time Profiler 工具显示 这样做是为了 更简单有效地捕捉原始回溯 以便之后在模块的用户空间中修复 从而有效地在内核留下记录 内核做的另一种优化是 如果内核对之前抽样过 但没有移动的线程 再次抽样 它不需要全部回溯 只要在样本表格中 放入一个占位符回溯 然后 Time Profiler模块会 提取最后一次回溯 复制到 Time Profiler表 然后由工具审阅 它做了两件事 它大量节省了内核的记录缓冲 特别是当线程为闲置状态 还能保持UI的效率 因为UI不知道这个占位符转换 因为是由建模模块转换的 下面这些主题会不断重复出现 基本上将自定义工具的复杂性 吸收到建模层面 这可以简化其他部分 特别是 对内嵌在逻辑里的追踪代码 和工具使用UI 这就今天的内容 我们会回顾建模基础 然后了解创建自定义工具的流程 在创建自定义模块时 用Scratch很难操作 因此今年的演讲中会展示样本代码 你可以模仿样本 或将其用作创建基础 现在我们要讲的是 执行和Cliff规则引擎 还有关键内容 推断 首先来重温一些建模基础
在创建模块时 你需要定义 其他架构部分 比如定义schema 整合查看器的所有内容 并最后审阅查看器的输出 所有这些都建在工具分布包中 可以在工具内安装并测试 这里我们假设 Xcode中已经有一个项目 你要做的是添加自定义模块 或使用样本代码 今年的演讲中有展示 获得设置好的项目
何时需要创建自定义模块呢 Xcode的确可以生成模块 特别是OS Signpost 作为输入时 但这些建模模块只是让你 快速运行工具 而不是开放所有功能 让你自定义建块 比如融合多个输入表的数据 自定义模块可以做到 已生成的案例就不行 更重要的是维护工作记忆 让模块记录运行总计 追踪开区间 运行更多计算 使用模块的工作记忆
另外能做的是创建自定义图表 如果想要创建图表 但工具不能在本地完成 你可以在建模模块中合成 比如 你可以计算移动平均值 或更复杂的卡尔曼滤波 这都取决于你 所有这些都能在自定义建模中完成 最终目标是建立更为智能的工具 让工具知道代码在做什么 甚至能够达到 让使用代码的人会先查找工具 然后再找你解决问题 这就解放了你 让你能投入下个项目
模块基本等于规则引擎 捆绑一套输入表和一套输出表 工具的分析内核 负责对输入表按时间排列 然后注入模块的工作记忆 工作记忆中的对象叫做事实 用来推断 工作记忆和事实的变化 是CLIPS语言的规则系统 CLIPS是开源语言 八十年代出现 并有很多优秀的案例 和文献供你参考 我们的样本代码里也有很多例子 还有幻灯片中
当建模模块发现 它想输出的东西 模块的函数可以编写绑定的输出表 要从Scratch编写模块 可以分三步 首先是 决定模块内容 意思是了解技术 创建自定义工具 也就是说 了解自定义工具的结构 和如何发挥最多用处 2019年“开发优秀的剖析体验” 演讲中 我们团队会带你了解 代码的变化如何讲故事 通过自定义工具 它可以作为了解建模内容的起点
给建模模块定义了输出后 需要一些输入 从代码输入工具的最好方法是 通过 OS Signpost API 这个API可以穿插在代码中 追踪代码变化 传递实参数据 让模块在输入流中完成推断 有了输入和输出之后 要开始定义规则系统 并编写规则 第二步和第三步都是迭代的 因此在写规则时 可能需要回溯 添加更多Signpost 或修改Signpost 都没问题 可以这样做 但要记住 Signpost是设立界限 隔离代码和工具的内容 所以 你要保证 给Signpost调用添加评论 让人们知道这实际是个合约 如果修改就会破坏工具
要了解这个过程 可能最好是要 通过实际例子 所以我要请上我们的建模专家 Alejandro Lucena 来讲解
大家下午好 感谢Chad
我要做的就是 演示Chad说的思维过程 并用一个例子演示 如何将所有组件融为一体 首先 从这个演示app开始 坦白说 这可能是我做过的最酷的事 它是列出了各种山羊 这些山羊不仅是显示在app中 app还能让我排序 排序的实现是通过 “移动主体模式” 它有很多并列的不同模式可供使用 比如future和promise 或执行序列 所以如果“移动主体”这个词 你听到我们说 你可以想象成你使用的任何模式 但本场还是称之为“移动主体”
如字面意思 移动主体模式传递的重要概念 就是移动主体 可视化为左上角的圆圈 这个主体是要完成任务 比如排序 并分成几个子任务 比如获取初始表 排序 然后确认结果 每个子任务会在“站点”执行 站点告诉主体 依赖关系或执行上下文 帮它完成子目标
下面看看如何执行任务 比如排序 通过移动主体模式 我们要做的是点击左上角的“排序” 主体会移动到第一个站点 这里的站点由UI控制 它会执行第一个子任务 获取列表 获取列表后 它可以移动到另一个站点 比如分发队列 在分发队列站点 它可以运行排序
排序完成后 它会回到UI 最后将列表按序整理排列
最后停泊到“排序”键 供以后使用
刚才演示的就是移动主体模式 主体可以是两个初始阶段中的一个 可以在一个站点执行 也可以移动到另一个站点 这就是建模有趣的地方 具体来说 有趣的是看到它们 交互的时间 为了更好的可视化 我再演示一遍这个排序的例子 带上区间 我要做的是 将设备移动到左边 因为需要一些空间 然后点击“排序”按钮 这个主体会移动到UI站点 移动发生时 看到一个区间 带描述性字符串 或告诉我们发生了什么
然后在站点 主体会执行第一个子任务 获取列表
这里有个不同的区间
然后主体会移动到分发队列 由它自己的区间显示
在分发队列 主体会执行排序
如所见 它在执行排序模式
然后回到UI站点 这是最后一个移动区间 移回UI
这个站点上 它会执行下一个也是最后一个 更新排序的子任务
有了这些区间 就可以设想区间的开始 就是活动的起始时间 无论是执行还是移动 区间的结束就是活动的终止时间 记住这些区间 就可以拥有或设计想要的工具 就是屏幕上展示的这样 最上面的轨道 显示了所有的区间 可以看到不同的移动和执行 它的下面 是轨道上不同的活动站点
除了工具的直观样式 还要看看细节视图 细节视图提供更多信息 关于每个站点的活动 比如起始时间 时长 主体是什么 等等
这里要注意最上面这一列 它定义了建模的关键兴趣点 这几列告诉了我们 起始时间 时长和主体类型 通常这几列中的定义 在工具的XML文件包中 它们共同组成输出表 这也是我们的第一个检查点 通过这些列 定义要存储的数据 这就完成了第一个目标 决定模块的内容 这就好了 下一步就是获取数据 从app到工具 通过OS Signpost实现
再回到之前的区间 就是它们 我们有个API 使用OS Signpost 是本地为区间而创建的 但我们想更进一步 使用Event Signpost 每个event Signpost 会出现在 活动区间之间的界限上 这样做不仅是为了 节省大约50%的Signpost 更是为了更准确的显示 移动主体模式 就是主体结束当前活动后 会立即开始另一个 所以只能发射一个Signpost 告诉我们 主体开始下一个活动了
为实现它 需要executeStop函数 是移动主体的一部分 在运行内部逻辑 执行该站点活动之前 要有一个Signpost 带有名称 具体的Signpost ID 和内嵌消息
除此之外 visitNextStop函数中 配置相同的OS Signpost 执行主体在站点间移动的逻辑 同样 执行移动之前 命名 Mobile Agent Moved 再给一个Signpost ID 和一条消息
现在注意看中间的模块 它会转换Signpost 把刚输入app的 变成可用的区间 写入输出表
举个例子 这个模块 一开始 工作记忆是空的 因为它不知道app的状态 但我们知道 模块与OS Signpost表 交互频繁 OS Signpost表 由app生成 假设模块想要侦测 Signpost上的移动主体
点击演示app上的排序按钮后 模块会接收一个 OS Signpost 然后将它表述为一个事实 这个事实带有信息栏 根据调用 OS Signpost的方法
现在 建模模块看到 OS Signpost事实 实际上是 移动主体的各种信息 模块就能通过 OS Signpost事实推断主体 通过确定事实 注入工作记忆 确定知道有一个排序主体 移动到后台
然后 模块要决定主体的活动 比如实际在做什么 以及时间 然后模块会查看已知事实 然后说 我知道主体正在移动 而Signpost事实的 起始时间是42 建模模块会记住它 在工作记忆中再输入一个事实 表明起始时间为42
这时Signpost事实消失了 没问题 因为我们把所有相关信息 确定的事实 都存入了工作记忆
我把它们往上挪一点 留些空间
最后建模模块要做的 是决定活动的完整区间 现在只有起始时间 没有完整区间 但我们知道某个点上 演示app会发出 另一个Signpost 同样的 建模模块接收后 会表述为相应事实 因为Signpost经过架构 会在区间间隙发出 模块知道何时接收 下一个Signpost 它可以查看任何之前打开的区间事实 并关闭 这里 它会查看事实的值 用足够的值决定完整区间 为此 它要调出输出表
删除已有的开区间事实 用完整区间替代 这里是移动到后台 并使用这个区间填写输出表
好了 在研究实际的CLIPS代码之前 还是要了解app代码 调用的API如何 能翻译成CLIPS事实
特别是当调用特殊名称的 OS Signpost 这个名称会成为 OS Signpost事实中的名称
另外 这个事件里的 Signpost类型 会成为OS Signpost 事件中的事件类型栏
最后 Signpost ID 会成为OS Signpost 事件内的标识符值 还有消息 内嵌的消息 也是OS Signpost 事实的信息值
现在我们知道 可以通过查找规则来侦测移动主体 这是一个CLIPS规则 首先要做的是 侦测OS Signpost 通过名称 比如Mobile Agent Moved
我们要捕捉这个值 位于标识符栏 在instance变量中
另外 我们可以对消息进行解析 提取有用信息 如图
第二部分 我们要表述一个条件 就是要匹配缺失的移动主体 Signpost标识过的 我们会用Signpost 去找到移动主体 但是不想增加任何重复 因此关键词not就是告诉模块 前提是没有移动主体 在这个instance变量中 被识别
如果是这样 模块可以确认这个移动主体 并注入工作记忆
同样的 在侦测移动主体活动时 会再次匹配 OS Signpost事实 因为需要确定某些属性 但这里 省略了关键词not 因为要将这个主体事实显示到 工作记忆中 现在已经解析了主体 并可以用它做更多事情
具体来说 一旦有了这两个事实 就能确定或添加移动事实 让建模模块可以追踪主体的实际活动
以上是CLIPS代码的例子 用来侦测主体和主体的活动 但我们还需要更多底层执行的知识 以便更好地架构建模模块 我要请Chad回到舞台 讲解规则执行
好的 下面来讲规则执行 CLIPS语言下的规则引擎
当我们在CLIPS中定义规则时 分为左边(LHS) 和右边(RHS) 用=>隔开 左边是描述性语言 定义了一个模式 让规则引擎在工作记忆中查找事实 当规则引擎找到了事实 满足左边的模式 会创建一个 激活 每次激活会触发规则的右边 规则的右边 是命令式语言 让你控制函数 比如“取消” 就是从工作记忆中删除事实 或“确认” 就是 在工作记忆中添加事实 还有特殊函数 让你写入模块的输出表 就能编写输出了
先讲讲事实 在工作记忆中确认事实 要用assert函数 每个新事实分配一个事实地址 标识为f-加一些数字 如果要在工作记忆中修改事实 我们还要有modify函数 它将修改的事实地址和栏 替换进工作记忆 这实际上结合了 一个撤回和一个确认 也就是先从工作记忆中撤回一个事实 修改后重新在工作记忆中确认 更新后的字段或栏 这很重要 因为 工作记忆中重新确认内容 会再次触发或激活某些规则 大部分情况下是好的 因为这就是规则系统反应 工作记忆事实变化的过程 但是在某些情况下会有麻烦 我说的是逻辑回路 我们可能一不小心 在代码中包括了逻辑回路 所以这里有个小规则 是为了给移动主体计数 工作记忆中的移动主体 它首先是带计数器的事实 初始值为0 每个进入工作记忆的移动主体 会触发规则的右边 只要修改计数器的数字栏 +1 这就很直白了 来看看实际执行的样子 首先 工作记忆中的计数器 初始值为0
之后的某个时点 一个移动主体在工作记忆中确认 现在左边足以触发右边 调用modify函数 它先是撤回这个事实 增加计数的值 然后回到工作记忆中重新确认 这样做时 注意它重新触发了同一个规则 现在对同一个移动主体实体 它会计数2 3 4 5 6 7 一直数下去 直到追踪停止 工具会警告有严重错误 规则引擎卡住了 模块界面的工具查看器中 你看到的追踪 显示了所有事件和激活 在回路中发生的 这就给你一个好的开始 让你知道怎么调试和消除 在我来看 最简单的方法 消除逻辑回路 就是目的引导式编程 不是直接修改计数器事实 而是创建目标事件 帮我们计数 现在要侦测移动主体时 就要确认目标事实 来对实体计数 计数规则中 要捕捉计数器和目标 然后撤回目标 因为已经满足 计数器计数的规则 这样规则就会不断回来 从而打破逻辑回路
现在来看规则的触发顺序 及其对模块结果的影响
现在回到 executeStop函数 它先被调用 然后移动主体才会 进入执行阶段 现在你看到 OS Signpost中 第一版代码的第一个实参 实际上是主体的类型字符串 这里就是排序主体 或者是记入追踪缓冲的 14个字节的数据 我想还可以改善 将它从字符串变成类型代码 就是一个四字节整数 每个事件可节省10个字节 如果数据成千上百的进来 就可以节省几万字节的追踪缓冲 为实现它 就要在模块里创建映射 将代码转化为字符串 通过使用事实 在侦测规则中 捕捉主体的类型代码 在确认移动主体时 类型那一栏标记为sentinel 表示还没有完整的字符串 因为在第二个规则 我们要找到所有移动主体 类型为sentinel的 然后找到对应的类型代码 就是上一张图里的类型字符串映射 找到它们后 修改类型栏 从sentinel 改为真实的字符串 这一切都基于第二个查找规则 在运行确认后立即触发 但如果系统中有其他规则 比如主体停靠规则 也是引用移动主体 捕捉和使用类型栏的 如果它出现在确认 和查找规则之间会怎样 这会有一个sentinel 鉴于这是对规则系统的修改 你要准备好 面对很多新的缺陷 为了解决问题 要添加规则限制 就是 只要类型不是sentinel 这有效的延迟了规则触发 直到查找规则实际改变了主体的类型 从sentinel变为实际内容 这完全可行 但要用于所有规则 否则就会有维护问题 特别是当现有的规则集 设为永不为sentinel时 再来看另一种方法 我们实际是让查找规则 在确认后立即触发 其中一种方法是 告诉CLIPS那个规则更重要 或比默认的0突出值更突出 只要这个规则是系统中最突出的 那么第一个规则结束时 第二个就会被触发 如果在其他位置使用突出性 就要过一遍代码 确保 100仍是最高突出值 但这是后话了 这里还有一个更直接的方法 控制规则的排序和触发 这就要了解激活 提示一下 激活实际上是 工作记忆中的事实集合 满足规则的左边 每次激活都会触发规则的右边 现在不要直接触发规则的左边 而是要将 激活记入数据结构 叫做agenda
agenda实际是激活列表 是工作记忆更新的结果 因此所有规则引擎都要 从上而下过一遍这个列表 以特定的模式触发规则 这里先触发第一个规则 然后是第二个 这个数据结构是动态的 如果规则99是要撤回事实17 而事实17由其他两个激活引用 CLIPS会先撤回激活 然后往下走 此时agenda会是这样 在执行继续时
agenda根据突出性排序 那么salience就很重要 突出值越高 agenda上的 位置就越高 但更重要的是 模块中没有单独的agenda 定义中一个模块只有一个 在分析内核中可以用它 定义部分标准模块 第一个是建模模块 这里要放入纯推理逻辑 和推理规则 将规则名设为modeler:: 第二个模块是recorder 放入的是输出规则 前缀为recorder:: 这么做的原因是 在执行这些规则时 首先执行所有模块 agenda上的内容 直到清空 然后再到recorder模块 它会让你拥有自信 在写输出规则时 不用查看工作记忆中 modeler模块推出的过程 现在你可以利用这个 自定义CLIPS模块 现在看看如何实现 更好的调整查找规则的执行 首先是定义查找规则模块 lookup 将查找规则放到 模块里 命名为lookup::
确认移动主体事实后 要立刻告诉CLIPS 关注查找agenda 就是运行查找agenda里的 所有激活进程 然后返回 modeler agenda 执行下一套建模规则 这是防止规则插入 执行顺序的好方法 以上内容已经很充足 现在可以看看调试和剖析了 现在有请Alejandro 回到舞台 讲解这一部分
谢谢Chad 我要讲的是调试和剖析基元 用于搭建这些模块 首先是日志 我们可用的日志基元 很像printf 用来定义格式化字符串 格式化标记和代表这些类别的变量 与printf或其常用方法 不同的是 在工具查看器 实际上可以动态的 开关日志声明 之后会举例说明
怎么把这些日志声明放入规则? CLIPS里有个函数 log-narrative 它的运行 如我之前所讲 很像printf 定义字符串 比如Resolved Agent Kind Code 然后用%定义格式类别 实际的工程类别 这里是UN 64 后跟% to string 然后是表示数据类别的变量
同样也可以使用不同的基元类别 就是剖析 通过工具查看器 剖析基元提供的是规则激活计数 让我们知道规则触发的次数 以及时间分布 我们能知道用了多少秒 去激活规则 按百分比计算 为了整体理解 我要做一个演示 看看它们怎样放到一起
这里是样本代码 也是可以下载的 样本代码中 有很多可用的不同目标 我首先要讲的 是这里的绘制模板建模对象
它会在创建和运行工具的时候打开
好像已经搭建成功了
然后打开工具
这里那个羊的app已经打开 我不会最大化窗口 因为我们要记在脑子里 我要做的是回到空白模板 在右上角 选择要添加的工具 为此 打开这里 查找移动主体 就是刚建的目标
这里 如我所说 日志叙述可动态开关 通过工具查看器 按下command I 打开工具查看器 这有个日志标签 默认为无 但可以改成narrative 这样就开启了日志叙述声明 关闭它 继续 代替所有进程 现在切换到山羊的列表app
现在开始记录 在这个列表里可以进行一些操作 比如给不同的列表排序 你看到查看器里弹出一些活动
再点一次 会有更多活动弹出 我想这个点已经足够清楚了
首先我们看这里 显示不同的区间 我们之前讲过 比如激活和移动等等 但在实际的叙述声明 还是command I打开查看器 有新的东西 这个模块日志表 在这个表里 存着所有日志叙述声明 比如这个解析代理类型代码 使用日志叙述的例子里看到过 还有规则里的许多其他声明
那如何从日志叙述切换到剖析呢 还是在这个日志标签 切换到profile 1 关闭查看器 再次运行工具 再次记录轨迹 这时看到列表已经排序过了 但移动主体还是发生了一些活动 这也足够说明问题了 所以停止 再次打开查看器 这里就不再有模块日志表 因为没有可显示的日志叙述了 但是如果打开这里的模块标签 会看到整洁的描述性界面 列出不同的剖析值 比如这个“查看未知执行站点”规则 有7条记录 还显示了用时和时间占比 还有其他建模过程中定义的规则
在关闭这个界面之前 我发现一些有趣的点 我要再运行一次追踪 因为我想再捕捉一次
开启排序后 我看到不同的活动出现 但如果我再次排序 我注意到这些黄色的长区间 出现在事实后面 它们对实时描述或实时解读的跟踪 不同于 我的预判 为了找到原因 搞清楚状况 并找到解决办法 我要请回Chad 讲解推断
谢谢Alejandro
为了描述Alejandro 刚才看到的现象 并解决它 就要引入一个概念 叫做推断
这些区间怎么了? 它们的特点 第一是长区间 它们出现的时间 或持续的时间有好几秒 这显而易见 第二 真正的问题是 对这些区间的记录 只在模块的工作记忆中 UI只看模块的输出表 不会看这些 所以不能把这些区间写入输出表 直到明确了 它们关闭的时间 这个例子就是这样 现在要做的是 写入临时或占位符行 给模块的输出表 为此就要介绍推断模式
模块中的推断模式表示 如果这是最后写入输入表的机会 你要写什么? 来看个例子 假设模块处理了 这条白线之前的所有数据 我们叫做视界 视界是一个时间点 此后模块看不到任何东西 原因可能是追踪停止了 或者分析内核 还没填入追踪部分 没人知道线的另一边有什么 如你所见 我们创建的区间写着 移动到后台 这样做是因为它夹在 一对移动和执行 Signpost之间 但我们不知道 这个追踪执行区间什么时候结束 因为它的结束事件在视界的另一边 因此我们要进入推断模式 只要在表中写入临时占位符事件 UI就能看到些什么 然运行区间从执行Signpost 直到视界的当前值
推断模式里的模块 因为推断事实 会被注入到工作记忆 在记录规则中 可以将推断事实 与任何开区间事实结合 把这些开区间写入表 用捕捉到的视界时间戳
这里就是写入开区间的机会 下面来看一个示例规则 首先 将推断式的 输出编写规则放入记录模块 前缀为RECORDER::
然后匹配推断事件 捕捉视界的值 这就有了区间的结束时间 理论上 对工作记忆中的每个区间事实 触发规则的右边 我们这里要做的 是基于结束时间 也就是视界值计算时长 和区间开始的时间 然后写新的行 填写栏内容 和正常的输出编写规则一样 唯一区分 正常的和推断式的输出编写规则 在于当你测试或预测推断事实的规则 你要查看开区间 而不是闭区间 像往常编写输出表那样
如果是即时模式 在记录前进的过程中 旧的推断性数据会被清洗 模块会再次进入推断模式 以新的视界值 放回推断事件 UI会跟往常一样更新 追踪停止时 模块会再次进入推断模式 但无论你写什么 实际都记录在追踪数据中 对下行模块可用 不仅是UI 如果修改现有的工具 它就会变成这样 这是移动主体轨迹 你看到 这个parking区间持续延长 它会实时更新 如果查看底部的细节表 你会看到 时长也在增加 现在如果按下停止键 终止记录 你会看到区间停住了 它实际上被记录为轨迹的一部分
总结来说 编写自定义模块 代表巨大的投入 要投入时间学习新的技术 但这是使用自定义工具的最好方式 并智能化自定义工具 我们看到 智能化工具 意味着更高效的记录机制 和更好的用户体验
更多信息 请参见随附的样本代码 以及本场演讲网站中的相关演讲
以上就是今天的内容 谢谢大家 请享受其余的讲演
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。