圆形路标
In one of the sprints, we were tasked with implementing the generation of a pdf-document on the client-side. We completed the task. But we wanted to make sure the effectiveness of the technical nuances of the decision. Signpost helped us with this. Using it we increased he document’s displaying speed several times.
在其中一个冲刺中,我们的任务是在客户端实现pdf文档的生成。 我们完成了任务。 但是我们要确保该决定的技术细微差别的有效性。 路标帮助了我们。 使用它,我们将文档的显示速度提高了数倍。
To learn more about os_signpost application technology, see where it can help you and how it has already helped us, go further forward.
要了解有关os_signpost应用程序技术的更多信息,请参见os_signpost应用程序技术在哪些方面可以为您提供帮助以及如何为我们提供帮助,请继续前进。
深潜 (Deepdive)
There are lot of applications on the user's mobile device, and all of them use common system resources, such as: CPU, RAM, network, battery, etc. If your application performs its tasks and does not crash, it doesn’t mean that it works efficiently and correctly.
用户的移动设备上有很多应用程序,并且它们都使用公用的系统资源,例如:CPU,RAM,网络,电池等。如果您的应用程序执行了任务并且没有崩溃,则并不意味着它有效且正确地工作。
Below we describe the cases that you may potentially encounter.
下面我们描述您可能遇到的情况。
次优算法可能导致较长的CPU负载 (Suboptimal algorithm can lead to a long CPU load)
At the start of the application, after 20 seconds of waiting, the system will shut down the application, and the user will not even see the app's first screen. In this case, the system will set a crash report, the distinguishing feature of which will be an exception type — EXC_CRASH (SIGKILL), type 0x8badf00d.在应用程序启动时,等待20秒后,系统将关闭该应用程序,并且用户甚至不会看到该应用程序的第一个屏幕。 在这种情况下,系统将设置一个崩溃报告,其区别特征是异常类型EXC_CRASH(SIGKILL),类型为0x8badf00d。 Resource-intensive processes in the background thread can affect the responsiveness of the UI, increase battery consumption and force the application to terminate the system (in case of prolonged CPU overheating).后台线程中的资源密集型进程可能会影响UI的响应能力,增加电池消耗并迫使应用程序终止系统(如果CPU长时间长时间过热)。低内存 (Low RAM)
The specifications for the phones on the Apple website do not provide information on RAM, but other sources provide the following memory allocation for phone models:
Apple网站上的电话规格未提供有关RAM的信息,但是其他来源为电话型号提供了以下内存分配:When there is too little free RAM, iOS starts looking for memory to free up, simultaneously sending a memory warning to all running applications. This process implicitly affects the CPU and battery of the device. If the memory warning is ignored, and the allocation of memory continues, the system forcibly terminates the application process. For the user, this looks like crash, with no backtraces in the crash report.当可用内存太少时,iOS将开始寻找要释放的内存,同时向所有正在运行的应用程序发送内存警告。 此过程隐式影响设备的CPU和电池。 如果忽略内存警告,并且继续分配内存,则系统将强制终止应用程序进程。 对于用户而言,这看起来像崩溃,崩溃报告中没有回溯。 Excessive use of network requests. This also leads to a battery-life decreasing. Duplication of requests and / or lack of cancellation of unnecessary requests additionally leads to inefficient use of the CPU.过度使用网络请求。 这也导致电池寿命的减少。 请求重复和/或缺少不必要请求的取消还导致CPU使用效率低下。 Do not forget about CoreLocation. The more often and more accurately we request the user's location, the more the device’s battery is spent. 不要忘记CoreLocation。 我们请求用户位置的频率越高,越准确,设备的电池消耗就越多。
To verify the correctness of processing the described cases, we suggest using os_signpost to profile the application processes and then analyze the data obtained.
为了验证处理上述情况的正确性,我们建议使用os_signpost对应用程序进行概要分析,然后分析所获得的数据。
项目中的OSLog集成 (OSLog integration in the project)
At the top level, the process of creating a PDF consists of three steps:
在顶层,创建PDF的过程包括三个步骤: Receiving data over the network;通过网络接收数据; Document formation;文件形成; Document displaying on the screen屏幕上显示的文件
We decided to split and log the stages of document generation, starting from the user clicking the «Generate» button and ending with the display of the document on the screen.
我们决定拆分并记录文档生成的各个阶段,从用户单击“生成”按钮开始,直到在屏幕上显示文档为止。
Suppose we are faced with the task of analyzing an asynchronous network request. The markup in the code will look like this:
假设我们面临分析异步网络请求的任务。 代码中的标记将如下所示:
import os.signpostlet pointsOfInterestLog = OSLog(subsystem: "com.example.your-app", category: . pointsOfInterest)let networkLog = OSLog(subsystem: "com.example.your-app", category: "NetworkOperations")os_signpost(.event, log: pointsOfInterestLog, name: "Start work")os_signpost(.begin, log: networkLog, name: "Overall work")for element in elements {os_signpost(.begin, log: networkLog, name: "Element work")makeWork(for: element)os_signpost(.end, log: networkLog, name: "Element work")}os_signpost(.end, log: networkLog, name: "Overall work")
Steps for using signpost are as follows:
使用路标的步骤如下: Import the os.signpost framework.导入os.signpost框架。 Create an instance of OSLog. It is worth considering that there are several types of events: for interval events (for example, a network request), you can use an arbitrary category, and for simultaneous events (for example, clicking a button), the predefined category pointsOfInterest / OS_LOG_CATEGORY_POINTS_OF_INTEREST.创建一个OSLog实例。 值得考虑的事件有几种类型:对于间隔事件(例如,网络请求),可以使用任意类别;对于同时发生的事件(例如,单击按钮),可以使用预定义的类别pointsOfInterest / OS_LOG_CATEGORY_POINTS_OF_INTEREST 。 For interval events, call the os_signpost function with the .begin and .end type at the beginning and at the end of the stage under investigation. For simultaneous events, use the .event type.对于间隔事件,请在调查阶段的开始和结束时使用.begin和.end类型调用os_signpost函数。 对于同时发生的事件,请使用.event类型。 If the code can be executed asynchronously, then add a Signpost ID, which will allow you to separate the intervals of the same type of operations with different objects.如果代码可以异步执行,则添加路标ID,这将使您可以将具有不同对象的同一类型操作的间隔分开。 Optionally, you can add additional data (metadata) to dispatched events. For example, the size of the images downloaded or the number of the generated PDF page. Such information will help to understand what exactly happens in the investigated stage of code execution.(可选)您可以将其他数据(元数据)添加到调度的事件中。 例如,下载的图像大小或生成的PDF页面数。 这些信息将有助于了解在代码执行的调查阶段究竟发生了什么。
Similarly on obj-c:
同样在obj-c上:
@import os.signpost;os_log_t pointsOfInterestLog = os_log_create("com.example.your-app", OS_LOG_CATEGORY_POINTS_OF_INTEREST);os_log_t networkLog = os_log_create("com.example.your-app", "NetworkOperations");os_signpost_id_t operationIdentifier = os_signpost_id_generate(networkLog);os_signpost_event_emit(pointsOfInterestLog, operationIdentifier, "Start work");os_signpost_interval_begin(networkLog, operationIdentifier, "Overall work");for element in elements {os_signpost_id_t elementIdentifier = os_signpost_id_make_with_pointer(networkLog, element);os_signpost_interval_begin(networkLog, elementIdentifier, "Element work");[element makeWork];os_signpost_interval_end(networkLog, elementIdentifier, "Element work");}os_signpost_interval_end(networkLog, operationIdentifier, "Overall work");
Note that if the project should run on iOS prior to version 12.0, Xcode will offer to wrap os_signpost calls in the if #available construct. In order not to clutter up the code, you can put this logic in a separate class.
请注意,如果项目应在12.0版之前的iOS上运行,则Xcode会将os_signpost调用包装在if #available结构中。 为了不使代码混乱,可以将此逻辑放在单独的类中。
It is worth considering that os_signpost requires a static string literal as the parameter of the event name. To add more stringent typing, you can create an enum with event types, and in the class implementation, map them to string literals. Putting OSLog in a separate class will add the logic to disable it for the release scheme (there is a separate OSLog command for this).
值得考虑的是,os_signpost需要静态字符串文字作为事件名称的参数。 要添加更严格的类型,可以创建具有事件类型的枚举,然后在类实现中将它们映射到字符串文字。 将OSLog放在单独的类中将添加逻辑以针对发布方案禁用它(为此存在单独的OSLog命令)。
import os.signpostlet networkLog: OSLogif ProcessInfo.processInfo.environment.keys.contains("SIGNPOSTS_FOR_NETWORK") {networkLog = OSLog(subsystem: "com.example.your-app", category: "NetworkOperations"} else {networkLog = .disabled}
You can add values from any properties to the event marking with the following type decoders for convenient formatting:
您可以使用以下类型解码器将任何属性的值添加到事件标记中,以方便格式化:
Now, when profiling the application, events from os_signpost will be sent to Instruments in the form of tabular data. To switch to tools, use the keyboard shortcut Cmd + I, then select the tool necessary for profiling. To see the marked data, just turn on the os_signpost and Point of Interest tools on the right side of the tool interface.
现在,在对应用程序进行性能分析时,来自os_signpost的事件将以表格数据的形式发送到Instruments。 要切换到工具,请使用键盘快捷键Cmd + I,然后选择进行分析所需的工具。 要查看标记的数据,只需打开工具界面右侧的os_signpost和Point of Interest工具。
By default, events are grouped into categories and displayed in a table, where their number and statistics on runtime are calculated. Additionally, there is a graphical display on the timeline, which makes it easy to compare the received events with the results in other tools. There is also the possibility of customizing the display of statistics and writing expert systems — but this topic deserves a separate article.
默认情况下,事件被分组并显示在表格中,在表格中计算事件的数量和统计信息。 此外,时间轴上有图形显示,可轻松将接收到的事件与其他工具中的结果进行比较。 也可以自定义统计数据的显示并编写专家系统,但是该主题值得另作文章。
使用实例 (Examples of using)
情况1。 PDFKit与WKWebView (Case #1. PDFKit vs WKWebView)
Through the use of os_signpost, we saw that for small documents (a couple of pages) the longest step was the last step — displaying the document — rather than working with a network or graphics. This led us to the decision to replace WKWebView with PDFView, which accelerated the display of the document from 1.5 seconds to 30 milliseconds. On the graphs, it looks like this:
通过使用os_signpost,我们看到对于小型文档(几页),最长的一步是最后一步-显示文档-而不是使用网络或图形。 这导致我们决定将WKWebView替换为PDFView,从而将文档的显示时间从1.5秒加速到30毫秒。 在图形上,它看起来像这样:Rendering PDF document (WKWebView) intime profiler.在时间分析器中呈现PDF文档(WKWebView)。time profiler.时间分析器中呈现PDF文档(PDFView)。
The resulting data can be implemented in other tools that Xcode provides. As the Allocations tool showed, the gain in download speed was achieved by increasing the use of RAM.
所得数据可以在Xcode提供的其他工具中实现。 如分配工具所示,下载速度的提高是通过增加RAM的使用来实现的。
案例2低内存警告 (Case #2 LowMemory Warning)
A PDF document generates asynchronously, and its formation requires the allocation of a significant amount of memory. In case of insufficient memory, we decided to add the ability to stop the asynchronous operation of creating a document.
PDF文档是异步生成的,其形成需要分配大量的内存。 在内存不足的情况下,我们决定增加停止创建文档的异步操作的功能。
As you know, when using NSOperationQueue, the cancelAllOperation method frees an existing queue but does not stop already running operations. From this, we conclude that in the implementation of the operation it is necessary to periodically determine its condition and stop working. Thus freeing up resources if it is set to Canceled status.
如您所知,在使用NSOperationQueue时,cancelAllOperation方法将释放现有队列,但不会停止已在运行的操作。 由此得出的结论是,在实施该操作时,有必要定期确定其状况并停止工作。 如果设置为“取消”状态,则释放资源。
The next step is an asynchronous operation that we need to check for cancellation. But at the same time, it is not clear with what frequency to do this check. We had two options — line-by-line checking and page-by-page checking. os_signpost helped here too. As it turned out, adding a check for cancellation in the line-by-line cycle of rendering the table in the document, we increased the time it took to generate the document (by 150 pages) by 2 times. The second option was more optimal in terms of performance and actually did not increase the time it took to create the document. As a result, when we receive the memory warning event, we cancel the operation programmatically and display the error screen for the user.
下一步是异步操作,我们需要检查是否取消。 但同时,尚不清楚以何种频率进行此检查。 我们有两个选项-逐行检查和逐页检查。 os_signpost也提供了帮助。 事实证明,在逐行显示文档中的表格的周期中添加了用于取消的检查,我们将生成文档的时间(增加了150页)增加了2倍。 第二个选项在性能方面更为理想,实际上并没有增加创建文档所花费的时间。 结果,当我们收到内存警告事件时,我们将以编程方式取消该操作并为用户显示错误屏幕。
To make sure that memory is indeed freed, we can also use os_signpost. This time, by adding a marker about the start of the event in the didRecieveMemoryWarning method and a marker about the end of the error screen in viewDidLoad. By the way, you can emulate an insufficient memory event in the simulator (shift + command + m).
为了确保确实释放了内存,我们还可以使用os_signpost。 这次,通过在didRecieveMemoryWarning方法中添加有关事件开始的标记,并在viewDidLoad中添加有关错误屏幕结束的标记。 顺便说一下,您可以在模拟器中模拟内存不足事件(Shift + Command + m)。
案例3。 更新约束 (Case #3. Update Constraints)
Signpost may be useful in the layout process. To create constraints, we use the masonry framework. The documentation for the framework says that it is recommended to use the updateConstraints () method to create constrates. But Apple strongly discourages doing so, and you can verify this with signpost markup.
路标可能在布局过程中很有用。 为了创建约束,我们使用砌体框架。 该框架的文档说,建议使用updateConstraints()方法创建构造。 但是Apple强烈建议您不要这样做,您可以使用路标标记进行验证。
According to Apple's documentation, updateConstraints should only be used to change constraints if we cannot do it at the place the change occurred.
根据Apple的文档,如果我们不能在更改发生的地方进行更改,则只能将updateConstraints用于更改约束。
After analyzing the results, we concluded that in our application the updateConstraints call is not so frequent — approximately every time the view appears on the screen. Despite this, in order to avoid potential performance defects, we recommend following Apple's advice on this.
在分析了结果之后,我们得出结论,在我们的应用程序中,updateConstraints调用不是那么频繁-大约每次视图出现在屏幕上时。 尽管如此,为了避免潜在的性能缺陷,我们建议遵循Apple的建议。
摘要 (Summary)
In , Apple provided developers with the opportunity to independently expand profiling tools. Of course, you can use other debugging tools: breakpoints, output to the console, timers, custom profilers. But it takes more time to implement or do not always give a complete picture of what is happening.
苹果在为开发人员提供了独立扩展性能分析工具的机会。 当然,您可以使用其他调试工具:断点,输出到控制台,计时器,自定义探查器。 但是,这需要花费更多的时间来实施,或者不一定总能对发生的事情有一个完整的了解。
In the next article, we will consider how to use the information received from signpost more efficiently by writing our own expert system (Custom Instruments).
在下一篇文章中,我们将考虑如何通过编写我们自己的专家系统(Custom Instruments)更有效地使用从路标收到的信息。
有用的链接 (Useful links)
Measuring Performance Using Logging (WWDC)
使用日志记录(WWDC)评估性能
Creating Custom Instruments (WWDC)
创建自定义工具(WWDC)
What’s New in Energy Debugging (WWDC)
能源调试(WWDC)的新功能
iOS Memory Deep Dive (WWDC)
iOS记忆深潜(WWDC)
Practical Approaches to Great App Performance (WWDC)
出色的应用程序性能(WWDC)的实用方法
High Performance Auto Layout (WWDC)
高性能自动版式(WWDC)
Understanding and Analyzing Application Crash Reports
了解和分析应用程序崩溃报告
Logging
记录中
List of iOS devices
iOS设备列表
Using Signposts for Performance Tuning on iOS
在iOS上使用路标进行性能调整
Getting started with signposts
路标入门
os_signpost API 尝鲜
os_signpost API尝鲜
victoriaqb — Victoria Kashlina, iOS-developer.victoriaqb撰写的-iOS开发人员Victoria Kashlina。
翻译自: /en/company/sberbank/blog/498480/
圆形路标
如果觉得《圆形路标_自定义工具:路标不足时》对你有帮助,请点赞、收藏,并留下你的观点哦!