大多数浏览器和
Developer App 均支持流媒体播放。
-
System Trace in Depth
Join engineers from the Instruments team for another focused look at the System Trace Instruments profiling template and how to get the most out of it. Discover how threads, virtual memory, and locking interact to affect performance. Dive deep for a practical look at how you can improve your app's responsiveness and keep your users engaged.
资源
相关视频
WWDC23
WWDC21
WWDC16
-
下载
深入系统追溯
早安 这是演讲411 “深入系统追溯” 我的名字是Chad Woolf 我是Joe Grzywacz 我们是Apple的性能工具工程师 去年的“深入”演讲中 我们谈了时间分析器 我们向你展示了如何分析你的应用 直到反汇编水平 我们的目标是向你展示 如何使你的代码变得尽量迅速 有时你也许想让你的优化代码 运行在多个CPU上 以完成更多工作 但这么做的同时会增加系统负荷 随着系统负荷增加 一些次级反应开始显现 例如抢占的增加 锁竞争和虚拟内存活动 这三者任何一个都足以抵消 你通过时间分析 获得的优化 在今天的演讲 我们展示如何通过系统追溯 分析次级反应 我们也会展示如何有效地加载系统 同时维持最佳性能
我们今天的演讲是这样的 我们会谈到一些关于系统追溯的内容 以及为什么它适用于应用开发者 之后我和Joe会带你了解系统追溯 我们会谈到线程 指示 一点关于虚拟内存的内容 以及展示一些最佳实例 告诉你如何尽可能利用工具
为何应用开发者需要系统追溯? 当你的应用成为设备的焦点 从用户的角度 它就是系统 他们不把你的应用 与全部这些系统服务和守护进程相等同 共同争夺共享资源 如CPU时间和内存 他们只会看到你的应用 如果你的应用出现卡顿 因为紧张的虚拟内存活动 或是因为错误优先的线程 他们会找你以寻找解决方案 这就是坏消息
好消息是 当你的应用成为设备的焦点 它是整个设备最重要的 操作系统知道这一点 它会毫无保留尽可能多地分配给你 CPU时间和内存 当我们谈到通过系统追溯优化 我们不是指优化系统 而是优化你的应用 使用分配所得的资源
系统追溯 是Instruments的模板之一 它可以在我们全部四个平台完美运行 当你使用它记录 它把内核设置成特别的追踪模式 记录全部调度活动 系统调用 以及发生的虚拟内存操作 它会随时间累积 产生大量数据 所以我们对Instruments 8 的改进之一 是我们把模板默认地设置成 Windowed Mode 这代表我们只保留前五秒左右的数据 优势是 你可以开始记录 设置你的应用 随便花多久时间来复现性能问题 当它复现 按停止键 然后你得到了前五秒的可行动数据 这是这五秒数据可能的样子 追溯记录会很密集 我们发现它会很有用 如果你可以把这数据 和你的应用里的高级活动相关联 比如我是否在更新表视图 后台是否在进行下载 我是否在更新图表 这类高级活动 今年在Instruments 8 我们新增了 兴趣点工具 兴趣点工具其实是一个空白的画布 你可以告诉Instruments 你感兴趣的地方 然后我们会为你把它放进图表中 通过你的代码中使用Signpost 来实现这一功能
Signposts已经发布一段时间了 不过以往的使用方法是 调用这个直接系统调用 从头文件提取这些宏 然后把它们放在一起 这有点臃肿 不仅臃肿 在今天的Swift世界里 它甚至无法运行 我们会抛弃这个方法 不过在新的操作系统里 我们增加了这些新的函数 它们的功能完全一样 kdebug_signpost 它们可以在C Objective-C C++运行 现在还可以在Swift里运行
首先 最简单的方法是 把一个点事件放入时间轴 就是这里的红色标志 你要做的仅仅是 调用kdebug_signpost 在我们的Mouse Down事件中 每当我们点击Mouse Down 你会看到时间轴上出现一个标志 它接受一些参数 第一个是代码 它只是一个0到16383之间的整数 用来帮你确定Signpost 另外四个参数也是整数 可以是你想要的任何数值 默认情况下 Instruments 会把它带到UI
现你可命名这些东西 切换到Instruments 的配置部分 然后加入到表视图 现在代码5代表Mouse Down 下次当我记录时 我可以看到那些兴趣点 变成了Mouse Downs
如果你喜欢兴趣点工具 你也会喜欢兴趣区域工具 它们基本上是一样的 只不过它们用来记录状态和动作 或是发生在一段时间里的事件 它稍微复杂些 因为你需要两次调用而非一次 你有一个开始和一个结束 在Instruments里 还有一个配对规则 默认情况下规则很简单 只是使用代码 你只需要 在开始和结束提供相同的代码
我们知道这不适用于所有应用 因为有些应用会产生一堆开始事件 紧接着一堆结束事件 这会导致... 在Instruments内 如何把它们配对会模糊不清 所以我们允许你改变配对规则 来到设置页 你可以选择代码和第一参数 或是代码和线程
代码和第一参数 代表你的开始和结束 需要有一样的代码和第一个参数 在这个例子中我们并行开始了 一堆URL下载 我们用了URL下载任务指针 作为第一个参数 你可以看到 Instruments时间轴上的 这些并行下载
如果你使用 代码和线程 你必须让 相同代码的开始和结束 在同一个线程上产生 这是一个例子 不过你可看到它发生在 dispatch_apply块内 现在我们的图表里有四个兴趣区域 每个线程或工作线程一个
目前你看到的兴趣区域都是红色的 非常单调 如果你愿意牺牲最后一个参数 你可以来到这里 勾选这个方格 用最后的参数代表颜色
在你的第四个参数 你只需提供 0到4之间的数字 代表Instruments里的 五个基本颜色 在这例子中 当我的下载任务成功 我把它设置为绿色 如果完成时产生了错误 我把它设置为红色 这样可以清楚地区分成功和失败
我们把这全部放在一起 你可以看到这是多么简单 把我之前展示的巨大复杂的追溯数据 和你应用中的高级活动关联起来 比如 你可以看到 这一堆活动其实是 我们的下载任务创建的
我们来说说今天的演示应用 今天研究的是我们给你们写好的一款 叫做Graphasaurus 2的应用 它是去年演讲中 Graphasaurus的灵魂继承者 和去年的演讲一样 我们会研究现实的问题 这是我们优化 Instruments 8时遇到的问题 我们决定把它们放进一个 iOS应用进行演示 这是一个新的图形风格 更像你在Instruments 所看到的状态界面的风格 因为这是我们今年优化的东西 另一个和去年不一样的是 我们会假设我们的代码 已被时间分析了 它已经是在目前条件约束下最优的了 和去年一样 图表的生成 通过Core Graphics 在CPU上进行
我们首先要做的是初始计时 我们发现生成全部四个图表 总共会花费20毫秒 这是在全部放大的最坏情况下的 它超过了16毫秒的限制 如果我们想达到每秒60帧 我们决定需要引入些并行运行 因为我们知道 四个图表可以各自独立生成 最坏情况下需要5毫秒 如果我们把所有任务放到dispatch里 我们有完美的扩展性 那么在我们的双核iPad上 应该可以把任务时间缩短一半 为了看看效果如何 向你展示如何使用系统追溯 我会交给Joe 好的 谢谢你Chad
你现在看到的是 Quick Time上的镜像 显示的是我使用的iPad Pro 你看到就像在Instruments里 你可以顺畅地滑动 不过当我放大的时候 动画变得有些延迟 不算糟糕 不过可以更好 我要做的是找出为何如此 现在打开Xcode
按下并长按Run按钮 并选择Profile 那会编译发布版本的应用 在设备上安装 然后Instruments会出现 同时还有模板选择器 你可以选择想要使用的工具 我们继续 双击选择 System Trace模板
在这里我开始记录前 我增加了一些 kdebug_signpost的起止点 到我的代码里 我要设置它们 在Instruments里出现的方式 你需要到右下角 在Record设置里 开始时 我要用第一个参数设置颜色 我在kdebug_signpost 添加了一些不同的数字 并添加了三个不同的代码 代码0是CADisplayLink 它是用于驱动动画的60Hz计时器 基本上这个区域 符合我的帧时间 因为这是我做所有渲染的地方 下一个是代码1 它是... 我称之为CreatePath 这是我实际创建CGPath的地方 屏幕上出现的长方形和标签 最后代码2叫做 RenderGraph 指的是我把那些CGPath 实际渲染成CGBitmapContext 然后在屏幕上显示 最后因为我的代码会并行运行 它们会产生同样的代码 我必须告诉Instruments 如何分辨它们 这个情况 线程足够了 因为它们会运行在不同的线程 好的 我完成了全部的配置 我不想每次打开Instruments 重复做这个 所以点击文件目录 然后选择保存为模板 设置一个具有描述性的名字
Graphasaurus System Trace 按下Save 比如你关闭了这个文件 关闭了Instruments 一星期后 你来到模板选择器 选择Custom标签 你的模板就在那里可供使用 你不用重新设置 直接点击Record即可
Instruments会等我复现问题 所以我会双指张开 就像你之前看的 张开到产生问题为止 我只需复现问题几秒钟 这样它可以在视窗缓冲区 填充我感兴趣的数据 做完后我停止记录 现在Instruments 会从设备下载全部数据 然后开始分析它 因为这是窗口模式录制 你只会得到最后几秒的数据 确保在你复现问题后 立即停止记录 不然 新的事件会出现 挤掉你感兴趣的事件
我们等待Instruments完成分析
好了 我们看到有很多东西 我们放大一些 这样就能看到发生了什么
好的 第一个选择的工具 是新的兴趣点工具 随便放大这里的一个区域
我们可以看到那些都是我创建的代码 我看到DisplayLink CreatePath RenderGraph 如我想的一样 这有一个大的蓝色的 CADisplayLink时间 以及四对绿色和紫色的 CreatePath和RenderGraph 看起来很好 不过当我移动鼠标到这个部分 你看到一个小工具提示显示你 你提供的参数和时段 这里我实际运行了接近30毫秒 是我希望的速度的一半 这可不太好 这还只是一帧 我渲染了很多很多 累积起来会是什么样子的? 我们看这个详表 现在显示的是按时间排序的所有区域的列表 你可以浏览这个巨大的列表 看看参数等等 我们做了一个表为你汇总 叫做KDebug Interval Signposts by Code列表 当我选择它 这是所有Graphasaurus 2产生的代码 可以看到这是我的 CADisplayLink 我渲染了152帧 它们平均花费28毫秒 所以平均运行并不好 你可以看到最小值最大值 标准差之类的 你可以通过代码旁边的聚焦按钮查看详情 它会给你全部数据的表 这些事件都是我的 CADisplayLink事件 在这里你可以随意排序 不同参数 任何对你的应用重要的 这里我根据持续时间排序
我要做的是 选择中间某个地方的一条数据 我想指出的是当我点击其中一行 上面的图表会移动 它会显示我感兴趣的区域 就是这里 我把蓝色视察头标放在那区域的开端 你把下面点击的项目 和上面追踪视图中 它出现的位置关联了起来 我正在看这一帧 你也可以按住Ctrl点击那一行 并选择设置时间过滤器 它会把所有详细视图中在时间范围之外 的事件变成灰色 上面的跟踪视图同样如此 你可以用它过滤出你要的数据 或者作为视觉上的提示 现在完成了 我正在看这一帧 我可以看到我的 CADisplayLink在此开始 在这里结束 我不知道为什么会这样 它只会告诉你何时开始 何时结束 你不知道你的应用是在运行 还是进入了睡眠状态 从图表你无法得知 我们必须更深入
在Instruments工具栏的右上角 我们目前在 Instruments策略 也就是这个模板里全部的工具列表 你可以点击这个线程数据 查看你应用中的全部线程 另外 假设我们已经在详细视图里深入查看线程 如果你按着选项并点击 你会看到这些可以按下的超链接 选择线程策略显示 它会把你带到线程策略 并为你预先选择那个线程 我们可以看到这里 放大它一点
它为我们选择了主线程 如果我看这里 还有许多其它的dispatch工作线程 它们正在运行 特别是这两个 这个和它下面的这个 正在运行很多工作 这些都是那些出现的红点 如果我按住选项并拖拽 以放大其中一个区域 我们其实可以开始看到它们是什么 通过把鼠标停留在它们上面 这是一个ulock_wake系统调用 它从某种锁被唤醒 这是ulock_wait系统调用 它正在某个锁上等待 如果你一直把鼠标放在它们上面 你会看到这个模式一直重复 有很多ulock_wait 和waking正发生 如果你点击鼠标 你可以把视察头标定在那点 如果你来到 我们称为线程和描述视图的地方
在这张表的下面 它会给你展示 在我点击的上面那张图里 在这个时刻线程在做些什么 这是一个显示了线程做的所有事的列表 线程生命周期的故事 这里我们可以看到wait调用之一 好的 那它是在哪里产生的? 如果可能 Instruments 会生成一个回溯表 串联这些系统事件 你可以在这里找到它们 这边右侧的扩展详情视图
我们可以看到一些Swift代码 用于创建路径 这里其实它是在创建 NSAttributedString 好的 在它下面的几帧里 它在获取锁 我没想到在NSAttributedString 里面会出现锁 不过确实有 那么后果是什么? 回到线程描述视图 看看发生了什么 仅仅获取锁就花了109微秒 然后我们又被阻塞了6微秒 今年很酷的是 它会给你展示 哪个线程使你的线程可执行 基本上就是释放锁的线程 以便你可以获取它 可以看到 一个Graphasarus线程 0x8468b让它进入可执行状态 好的 我们可以看见就算锁被释放了 在我们实际切换回CPU之前 还等待了98微秒
我们看看其它线程在做什么 为什么它释放了锁? 按下选项点击它 选择在线程策略中显示 这会选中上面的那个线程 然后在描述视图的下面 我们会看到线程那时在做什么 我们看见 它正调用ulock_wake 它正在释放锁 合情合理 我们可以看见这两个线程在并行执行 除了它们正在这个锁上竞争 它们实际做了很多事情 而不是只在运行 另一个查看方式是 在上面的跟踪视图里 这里可以看到线程的状态 我把它放大一点 如果你悬停在这个线程状态 你看见它运行了这段时间 64微秒 然后它被阻塞了一会儿 然后很长时间它处于可运行状态 这代表它其实没有在运作 最终它得以运行 如果我们继续查看 我们会看到这个模式不停重复 很清楚的是 这两个线程正在这个锁上竞争 在这期间 我创建了很多字符串 如果这占用了这么多时间 并且这么重要 为何我不能在时间分析器 里看到它们 说实话若你回去查看时间分析器 它确实出现了 不过仅仅是百分之四或五左右 没有以红色大旗标的形式突出 一个主要原因是这些线程 很长时间处于被阻塞和可执行的状态 时间分析器只是采样 真正在CPU上运行的东西 所以它不会在那里出现 为了解决问题 我需要意识到 我只是在状态图上放了一些属性字符串 其实没有那么多需要显示的状态 我应该提前缓存它们 然后在字典上查找它 不需要用到锁 一切都会运行的更加顺畅 为了展示它看起来是什么样的 我交回给Chad
好的 Joe看到是一个标准的锁竞争 我们有两个线程正在执行 它们正在争夺共享资源 在属性字符串创建锁的代码附近 就算我们只持有那个锁几毫秒 性能的折损也远比那大得多 Joe向你展示了一些 不过我还要多说几句
当你的线程处于执行状态 代表线程在CPU上 它正在全速执运行 你使用时间分析器 所做的所有性能优化 现在有回报了 在某些时刻 你调用ulock_wake 在一小时段后 它把线程变成了阻塞状态 这里发生的是 ulock_wait系统调用 发觉那个锁正被另一个线程持有 所以它请求内核把它移出CPU 当它实际获得到了锁时 再放回CPU 3.42微秒之后这确实发生了 我们进入了可运行状态 但现在在可运行状态中 这是回到CPU所消耗的时间 你看我们在可运行状态 持续了约7微秒 这是竞争锁的时间的两倍左右 这里的额外开销太大 另一种定量查看的方式是 你可以进入线程策略视图 选择线程 像Joe展示的一样 创建一个时间过滤器 接着把详细视图部分 从描述切换成线程概述 它会展示给你 每个线程状态所花费的时间总和 在这个例子里 我们可以看到我们的线程 只有82%的时间在运行 这意味我们从多核还是有所收益 我们做到了一些改进 但这个扩展仍然不是 我们所期待的完美的线性扩展 还是浪费了一些时间
当Joe采取他说的解决措施时 会发生两件事情 第一是UpdateGraph区域 会变短一些 因为我们需要做的工作变少了 我们对这些字符串进行了缓存 但更重要的是 线程没有占用100%的时间运行 所以你可以获得完美的扩展性 所以 当你把CPU的数量增加一倍 那段代码的运行时间 会变成一半 这非常棒 所以 如果你有这样的一个解决方案 一定要设法用上它
我们再来讲讲抢占 在我们的例子中没有看到任何抢占 但它在系统追踪里也十分常见 抢占指的是 非自愿地把你的线程挪出CPU 也就是说 有些其他的 更高优先级的工作需要CPU 但现在没有可用的 于是你的线程不得不让步 有一个例外情况 你可能会看到 自愿性的抢占 它出现在自旋锁的内部 当一个自旋锁发现 它的工作没有任何推进 它可以产生线程切换系统调用 最终放弃它占用的 锁持有者的时间片 在系统追踪的线程描述里 你会看到它调用了 thread_switch 抢占的描述会说 它主动放弃了CPU 而不是被移出CPU
另一种更轻量级的抢占 叫做中断状态 中断状态指的是 当你的线程在CPU上执行时 CPU必须处理一个硬件中断 所以你的线程被挂起 中断处理程序运行 然后你的线程重新开始 此时 你线程的优先级 起不到任何作用 你可以具有最高优先级 但这也没有用 中断始终更加优先 好消息是 这些通常是短暂的 几微秒而已 通常它们不会给你的应用 带来任何内部的性能问题 但它们的确会出现 这就是为什么我想提一下 Instruments 8的另一功能是 全新的系统负载工具 这个工具可以帮助你找到系统追踪中的 一些高负载事件 比如会导致丢帧的事件 它通过两种方式显示 第一种是下面的表视图 它会给你展示一张图表 显示了调度状态的样子 在蓝色审视线的下方 列出了所有可执行的线程 你可以知道在这个时间点 有三个线程 一个是内核线程 另两个是 Graphasaurus线程 它们是未被阻塞的线程 正在尝试运行 你可以看到它们的核心任务
这个工具的另一个功能 称为可交互负载平均图 这里每一个竖条 代表一个时间10毫秒的窗口 竖条的高度 是在10毫秒期间的活动线程的平均数 这些线程处于执行 可执行 被抢占或者被中断状态 就是所有没有被阻塞的线程 由于它是可交互负载平均 我们只包括 优先级大于或等于33的线程 因为这些线程的优先级 足以对服务类的 用户交互的质量产生影响 更明白的说 当线程变成橘色 这说明你的平均负载 已经超过了该设备上的核心数 所以当你看到一片橘色 你可以预测会有个丢帧发生 你可能想放大 这些橘色的区域 确保正在执行的线程 在服务质量水平上相互平衡
当Joe修改时 最终给负载留有了一些空间 我们可以添加一项新的功能 这个新功能是悬浮标签 类似你在Instrument 看到的悬浮标签 除了Graphasaurus 你进行长按 悬浮标签会跟随你的手指 为了展示这个特性 我把演讲交换给Joe
谢谢 Chad 所以我添加了 NSAttributedString的解决方案 回到了每秒60帧 看起来不错 增加了新一代的Tool Tips事件 再次慢了下来 你可以看到这里和那里掉了几帧 查看时间分析器 没有什么是明显我能删除的 我也没有做什么额外的工作 于是我回去 检查系统追溯 也就是你们现在正看到的 在我查看追溯之前 我新添加了一个Signpost代码 代码为3 它代表GenToolTips事件 你可以看到上面以红色显示 我们来放大其中的一个区域
好的 现在我们可以看到 这是我们新的红色柱状图 这些GenToolTips 我必须介绍一下我的算法的原理 这非常重要 基本上每当这个 CADisplayLink区域开始 对于界面上每一个图 我对它调用异步渲染 同时我异步生成Tool Tip字典 用于查询 对于界面里的每一张图 我都做同样的事情 但后来我做了一个巧妙的实现
为了调用我的渲染 我实际上并不需要 等待Tool Tip完成 所以我创建了调度组 让它们只等待渲染工作 我们可以看到 它实际在这里运行地非常好 这是我的帧的起点 CADisplayLink时间 我们可以看到一些 Tool Tip在这工作 我向右滑动一些 你可以看到 实际上它们中有一个 直到我的渲染帧完成 才刚刚开始启动 看起来我的工作做得很好 我拍拍我的背 这看起来不错
然而当我看这里的 CADisplayLink时间
它花费了17.4毫秒 非常接近了 但还不是我想要的16.6毫秒 同样 这只是一个区域 我们来看看汇总起来怎么样 我们回到 KDebug Interval Signpost by Code表 这里可以看到我们的 CADisplayLinks执行了大概260次 比我们之前要多 听起来不错 16毫秒的平均水平 比我的16.6还要少 这听起来相当不错 但是 这个最大值 仍然是19.27左右 如果我们看所有的单个事件
按花费时间从长到短排列 我们可以看到这个19毫秒的 一堆18毫秒的 这里是一些17毫秒的 很多17毫秒的 更多的是16毫秒(近17毫秒)的 所以我们还有一些帧 实际渲染得太慢 慢的不多 但还是慢了 这意味着我们会丢帧 这次我们该何去何从? 我们重新深入线程策略 观察我们所有的线程 系统调用 VM事件 线程事件之类的 但只要有可能 这个系统跟踪模板 有一堆工具 它们可以给你提供 更高级别的汇总信息 一开始看看它们会很有帮助 所以在你深入到那 100,000多个事件之前 看看这些更高层次的聚合信息 我要做的是看看这个 用户交互负载图 这是该系统负载工具之一 我们继续 缩小一点至合适大小 现在我们又可以在屏幕上 看到所有数据
做好这些后 我放大这里 你可以看到 这个图里有非常多的橘色 再放大一点 你可以看到 这里有非常多的橘色 这表示正在运行的用户交互线程 要比核心数多 这些线程说 我有很多活 现在就要做 给我一个CPU 可是我们没有CPU了 所以这里才会是橘色 我们放大这里 一大片橘色的地方 你可以看到数值 只需悬停在一个区域上 放大一点点 在这个10毫秒块里 平均有2.84个用户交互线程 在尝试运行 再次 在双核的机器上 有0.8个线程 缺乏CPU时间 这就是为什么这是橙色的 平均来看 有很多区域太大 这里实际上是四 我们在尝试运行 两倍于核心数量的线程 我们来看看 该区域的更多细节 我把它挪过来一点 这样你就能看到了 正如Chad所说 你可以看到 这段时间里哪些线程在尝试运行 点击并按住上面这里的尺标视图 你可以来回移动这个蓝色标志头 Instruments会告诉你 那个时间点我们在尝试运行 哪些线程 如果我们看看下面这张表 我按照优先级排序 我们可以看到 在这里 有两个Graphasaurus线程 正在运行 不错
有两个location D线程 在尝试运行 它们优先级稍低 这是真实系统的一部分 你会看到系统守护进程进来 并试图做好自己的工作 但没关系 它们的优先级比我们的稍低 所以我仍然持有CPU 看起来不错 我还有第三个线程在同时运行 尝试在同一时间运行 但它没有得到任何CPU资源 我知道这些线程是什么了 其中两个是我的渲染工作 然后我让这第三个线程尝试 完成我的Tool Tip生成工作 所以发生的是 它们其中之一没能获得CPU 我们又能看到这个了 如果我们查看 比如 我们的一帧 让我们回到那个兴趣点区域
我们可以看到 我们在帧内进行渲染 ToolTips的产生也是在这里 所以它得到了一点CPU时间 但当它获得的CPU时间时 是从我的渲染这里分走的 所以基本上我错误调度了我的工作 因为当我停下来想想 我需要渲染现在就进行 站在用户交互的级别非常有意义 因为我希望它完美而流畅 60帧每秒 但这些Tool Tip 它们的优先级不够高 我确实很希望它们能尽快完成 因为我希望 当用户长按屏幕的时候 它们能立即出现 但它们其实 并没有渲染工作重要 你可以清楚的看到 它们拿走了一部分时间 从CPU的给渲染分配的资源 现在渲染被延迟了 就是拖慢CADisplayLink 时间的原因 对于此的解决方案 其实非常简单 我们回到Xcode 这里我有个 ViewController类 它做的事情之一是 创建一个Tool Tip队列 我们可以看到它就创建在下面这里 这是我处理所有Tool Tip工作的地方 创建它的同时还包含了些属性 其中之一是 它是并行的 很不错 所以它们能在多个CPU上执行 如果存在的话 它被设置为用户交互的QOS类 这个QOS类 和我正在进行的渲染工作相同 所以它们互相竞争资源 如我所说的 它实际上不是那么重要 所以我要改变这个类 你可以在头文件中读到不同的类 我把它降低几个级别 使用Utility级别的类 这会让CPU优先做我的渲染工作 然后当CPU有一点空闲时间 比如每一帧的结尾或者其它时间 Tool Tip就会开始工作 它们仍然处于足够高的优先级 当用户点击屏幕 它们应该准备好随时运行 为了给你们展示这是什么样子的 我们交还给Chad
好的 当Joe做了这个修改 图表会是这个样子 我们会发现我们的 CADisplayLink时间 降低到了平均12.7毫秒 是比以前好多了 但更好的是 我们的最大持续时间仅为14.6毫秒 所以我们不会丢失任何帧 同时我们达到了16毫秒的限制 即使系统仍然处于过载状态 我们仍然能够达成 如果你想想看 我们仍然在运行三个不同的线程 但是因为我们已经 正确地安排了工作的优先级 我们的GenToolTips代码 在下面这里 以优先级四运行 它不会阻挡用户交互代码 我们仍然在CPU上做了很多事情 我们仍然有一个非常高的系统负载 但与此同时 我们仍然得到了完美流畅的用户体验
什么是服务质量真正的意义 服务质量 如果你还没有看到它 是你附加到块 队列以及线程上的属性 基本上它用于告诉内核 你愿意献出多少系统资源 以便让某一工作快速完成 不同的QOS类 会限制优先级的范围 所以你可看到我们的Utility类 把它的优先级降到了四 所以我们的用户交互代码 在三十多四十多的高优先级运行 但QOS类还是可以 限制类似IO这类工作 以及代码运行的CPU频率 所以当你为你的代码 选择QOS时 请非常详细地阅读文档 并确保它 与你正在做的工作种类相匹配
另一件能影响你应用性能的是 虚拟内存错误 随着内存压力的增加 它们的负载表现会变差 但好消息是 它们是可控的
系统跟踪拥有所有 为了分析虚拟内存故障所需的工具 在线程策略里 虚拟内存错误以这种 蓝色小胶囊的形式出现 在线程描述里面 它会报告虚拟内存错误 甚至附上一个回溯表 表明产生错误的位置 在代码内的什么地方
我们也有一个工具 专门用来分析虚拟内存错误 举个例子 你可以看到 你的代码的哪些部分 容易产生特定的错误而不是其它错误 比如你有一段代码 需要进行更多的零填充 或者写时复制
下一个你需要知道的 关于虚拟内存错误的事情是 错误是在访问时发生的 而不是分配时 所以你可以向内核 请求一大片内存 比方说500M 但实际上你并不需要 把它转化成物理内存 直到你开始修改或访问 进程中分配的相关页面 这是你分配内存时 需要想到的
另一需要知道的重要的事情是 虚拟内存错误 可以通过代码内联解决 所以你不需要进行显式调用 来解决一个虚拟内存错误 你需要做的是修改页面内 任何被标需要错误处理的字节 内核会获得你的线程控制权 解决故障 然后把控制权交还给你 当你看到这些蓝色胶囊 在你线程策略的系统追踪里 这就是会发生的事情
如何处理你的应用内的 虚拟内存错误? 最简单的是 不好意思 最简单的是消化掉它们 我的意思是 在性能预算上留足够的空间 便于你处理一定数量的 虚拟内存错误 在你达到限制之前 这会使你的负荷更有弹性 随着内存压力的增大 如果你的预算足够大 你有足够的空间 你不会发现性能上的差别 现在我们发现 有些人不设置这种松散的限制 在其UI生成方面 所以另一种选择是 尝试在后台线程解决错误 比如说你有个游戏 你的玩家玩到了第一关的结尾 他们马上就要进入第二关 你可以做的是 异步分配到后台队列 然后在后台队列里 创建与第二关内容相关的页面 这样当你的渲染线程 开始获取这些新内容时 不会有延迟 关于使用这种方法 我们在这里要给你一个警告 确保只创建一定会用到的页 因为如果你开始创建比所需更多的页面 实际上会使问题变得更糟
这就是今天的会谈内容了 我们相信系统跟踪器 是时间分析器的绝佳搭档 时间分析器可以让你的代码更快 但系统跟踪可以让你的应用 更易扩展到更高的负载 我们鼓励你在自己的应用中 尝试使用系统跟踪 我们知道当使用 Instrument检测我们的应用时 总能找到值得修补的地方 如果过去你用过系统跟踪 请你到Instruments 8 重新看看它 因为我们做了一些重要的改进 包括易用性和功能性 我们相信它会是你的工具箱中 又一新的利器
欲了解更多信息 这是我们411号演讲的链接 我们今天有一些相关演讲 在这一周以及周五也同样有
剩下的上午时光过得愉快 -
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。