嵌入式RTOS性能分析:测量标记与书签功能深度解析

发布时间:2026/7/20 10:53:59
嵌入式RTOS性能分析:测量标记与书签功能深度解析 1. 项目概述嵌入式系统性能分析的“听诊器”在嵌入式系统开发尤其是基于实时操作系统RTOS的项目中最让人头疼的问题往往不是功能实现不了而是系统“跑起来”之后的表现。任务调度是不是如你所愿CPU是不是总在满负荷“空转”某个关键函数为什么偶尔会“卡”一下这些问题在静态代码审查和单步调试中很难暴露因为它们往往只在全速运行、多任务并发的真实场景下才会出现。这就好比给一个奔跑中的运动员做体检你不能让他停下来还得准确测出他的心率、呼吸和肌肉负荷。RTOS Analyzer和System Analyzer正是解决这类问题的专业“听诊器”。它们不是简单的日志打印工具而是一套完整的、非侵入式的运行时性能剖析系统。其核心价值在于在不中断、不干扰目标系统运行的前提下持续采集内核调度、任务执行、CPU负载等海量运行时数据并将这些数据实时或离线地呈现给开发者把系统内部那个“黑盒”变成可视化的“玻璃盒”。我接触过不少团队他们前期功能开发很快但一到集成联调或压力测试阶段各种偶发的性能瓶颈、死锁、响应延迟问题就冒出来了定位起来如同大海捞针。手动加printf不仅效率低下其本身对时序的干扰也使得观测结果失真。而像TI Code Composer StudioCCS内置的这套分析器通过底层植入的轻量级UIAUnified Instrumentation Architecture日志框架以极小的开销通常1% CPU采集数据再通过JTAG、以太网等传输到主机实现了真正的“零干扰”观测。本文将以CCS中的RTOS/System Analyzer为蓝本但其中关于数据视图的交互、分析思路和方法论是跨平台、跨工具的通用技能。无论你用的是Keil MDK的Event Recorder、Segger的SystemView还是FreeRTOS的Tracealyzer其核心思想都是相通的从海量数据中快速、精准地找到关键信息并理解其背后的系统行为。我们将重点拆解“测量标记”和“书签”这两个看似简单、实则强大的功能看它们如何成为你性能分析工作中的“放大镜”和“记忆书签”。2. 核心功能深度解析从数据采集到可视化交互2.1 系统架构与数据流非侵入式分析的基石要玩转分析器首先得明白数据是怎么来的。很多开发者只关心怎么看图忽略了数据源头导致分析时对数据的可信度心里没底。整个数据流的管道可以概括为目标端插桩 - 数据收集与缓冲 - 主机端接收与解析 - 可视化呈现。目标端插桩是第一步。以SYS/BIOSTI-RTOS为例你需要在应用工程的.cfg配置文件中启用UIA模块。这通常意味着添加几行配置代码例如var LoggingSetup xdc.useModule(ti.uia.sysbios.LoggingSetup); LoggingSetup.sysbiosTaskLoad true; // 启用任务负载记录 LoggingSetup.sysbiosCPULoad true; // 启用CPU负载记录这些配置会在编译时将轻量级的日志记录钩子hook函数插入到RTOS内核的关键路径上如任务切换、信号量操作、时钟节拍等处。当这些事件发生时钩子函数会收集当前上下文如任务ID、时间戳、事件类型并打包成一个极短的小记录。数据收集与缓冲发生在目标系统内存中。UIA框架使用环形缓冲区Ring Buffer来存储这些记录。这里有一个关键参数需要权衡缓冲区大小。缓冲区太小在高事件率下会很快被覆盖导致历史数据丢失缓冲区太大则会占用宝贵的RAM资源。通常我会根据预估的事件频率和希望回溯的时间长度来设置。例如对于一个100MHz的系统如果每秒产生1万个事件每个事件16字节那么希望保留1秒的历史数据就需要约160KB的缓冲区。主机端接收与解析是通过CCS的分析器会话完成的。启动会话时你需要选择传输方式Transport。对于实时性要求高的调试JTAG是首选因为它能提供最低的延迟和最高的时间精度。而对于长期稳定性测试或远程调试基于以太网TCP/IP或UDP的传输则更为合适它允许目标系统在更独立的环境中运行。在会话配置对话框中正确设置目标板的IP地址和端口号是关键这一步出错会导致连接失败。实操心得传输协议的选择JTAG传输优势是延迟极低数据流稳定适合精细的时序分析。缺点是必须通过仿真器连接且在高数据率时可能占用调试接口带宽影响其他调试功能。以太网传输优势是非侵入性强目标板可以脱离仿真器独立运行适合长时间稳定性监控。缺点是网络抖动可能引入微小的时间不确定性且需要目标系统支持网络栈和额外的驱动。UART传输通常作为备选适用于没有以太网接口的简单设备。但带宽很低只能用于事件率极低的场景否则数据丢失严重。当数据流建立后主机端的分析器引擎会解析二进制数据流将其还原为带有语义的事件对象并送入时间轴数据库进行排序和关联对于多核系统这一步尤其重要它要将不同核上的事件按全局时间戳对齐。2.2 数据视图类型与适用场景解析后的数据会通过多种视图呈现。每种视图都是为回答特定类型的问题而设计的。理解它们的差异能让你在分析时事半功倍。1. 图形视图Graph View这是最直观的视图以时间为横轴展示各种指标的变化趋势。例如CPU负载图展示所有核心或单个核心的CPU利用率随时间的变化。一眼就能看出系统是闲是忙是否存在周期性峰值。执行图Execution Graph也称为时间线视图或泳道图。每个任务或中断服务程序ISR占据一条水平“泳道”其处于运行状态的时段会用一条横条表示。这是分析任务调度、并发、阻塞和优先级反转的利器。并发图Concurrency展示在任一时刻系统中有多少个核心处于活跃非空闲状态。对于评估多核系统的利用效率和负载均衡至关重要。2. 表格视图Table View / Detail View提供所有事件的原始或汇总列表以表格形式呈现。每一行代表一个事件记录包含完整字段如时间戳、事件ID、核心号、相关任务ID、附加数据等。当你在图形上看到一个异常点通常需要切换到表格视图来查看该点的精确数据。**查找Find和过滤Filter**功能主要在此视图下发挥作用。3. 摘要视图Summary View提供统计信息的概览。例如任务分析器Task Profiler以百分比形式展示每个任务处于运行Running、就绪Ready、阻塞Blocked等状态的时间占比。计数分析Count Analysis显示特定事件如信号量获取、消息队列发送发生的总次数、平均速率等。 摘要视图用于快速获取系统的整体健康指标和性能基线。注意事项视图的联动与分组分析器的一个强大特性是视图联动。当你选中一个视图中的某个时间点或事件时其他关联视图会自动滚动到同一时间点。这是通过**视图分组Group和同步滚动Synchronous Scrolling**功能实现的。例如将CPU负载图与执行图分组后在负载图的峰值处点击执行图会自动定位到同一刻让你立刻看到是哪个任务在消耗CPU。这个功能在关联不同维度的数据时极其高效务必熟练掌握。3. 核心交互功能详解测量、标记与定位图形视图虽然直观但要从一条曲线上精确读出一个点的数值或者计算两个事件间的时间差光靠肉眼是远远不够的。这时就需要用到一系列精细的交互工具。3.1 缩放与导航把握全局洞察细节面对可能长达数小时、包含数百万个数据点的性能记录如何既能纵览全局趋势又能深入查看微秒级的细节缩放与导航是基本功。工具栏上的缩放控件通常包括“放大”、“缩小”、“重置缩放”以及一个“缩放选项”下拉菜单。这里面的门道在于缩放中心和缩放因子。缩放中心默认情况下使用鼠标滚轮或点击放大镜图标进行缩放会以当前光标位置为中心进行缩放。这是一个非常符合直觉的设计你把鼠标指向你感兴趣的区域滚动滚轮视图就会以该点为中心展开或收缩。如果当前没有光标位置例如刚打开视图则会以图表中心为缩放中心。如何设置光标位置很简单在图表区域的任意位置单击就会在该处出现一条红色的垂直光标线或十字线。这条线不仅用于缩放定位也是测量标记的基准。缩放因子与方向在“缩放选项”下拉菜单中你可以选择缩放因子2倍、4倍、5倍、10倍。对于性能分析我通常先用2倍因子逐步放大接近目标区域后再用更高的倍数查看细节。更重要的是你可以选择缩放是同时影响X轴时间和Y轴数值还是仅影响其中一个轴。例如当你发现CPU负载曲线在某个时间段有一个很小的尖峰但该尖峰在Y轴幅度上被整体的大趋势“压扁”了这时就可以选择“仅缩放Y轴”将纵方向拉大从而清晰观察该尖峰的细节而时间轴保持不变。避坑技巧缩放与数据密度过度放大可能会导致图表上两个相邻的数据点之间距离过大曲线看起来变成离散的点失去了趋势意义。这是因为底层数据有固定的采样间隔。此时应该结合表格视图查看该时间点的原始数据值。另外如果缩放后性能变卡可能是因为渲染的数据点仍然过多可以尝试在显示属性中暂时隐藏一些不关心的数据通道Channel。3.2 测量标记从“大概”到“精确”“测量标记”功能是我认为图形分析中最实用、最核心的工具没有之一。它解决了“这个峰值到底是多少”、“这两个事件间隔到底有多久”这类定量问题。3.2.1 基本使用放置与读数点击工具栏上的“测量标记模式”图标通常是一个游标尺符号鼠标移动到图表上时会显示一条跟随的标记线。在感兴趣的位置单击即可放置一个标记。标记一旦放置在图例区域通常在图表上方会立即显示该点的精确X时间和Y数值坐标。例如在CPU负载图上你在一个负载尖峰处放置标记M1图例可能显示M1: X15.342s, Y92.5%这立刻告诉你在系统运行的第15.342秒CPU利用率达到了92.5%。3.2.2 差值测量计算间隔与波动单个标记的价值有限两个标记的组合才能揭示关系。当你放置第二个标记M2时图例不仅会显示M2的坐标还会自动计算并显示与上一个标记的差值Delta。M1: X15.342s, Y92.5%M2: X15.891s, Y45.2%Delta: X2-X10.549s, Y1-Y247.3%这个差值信息极其有用时间差ΔX可以精确测量一个任务的执行时长、两个中断的间隔、或者一个高负载周期的持续时间。在上例中高负载90%状态持续了约549毫秒。数值差ΔY可以计算波动幅度。例如电压的峰峰值、延迟的抖动范围等。3.2.3 高级标记模式测量标记提供了几种模式适应不同精度的需求自由模式Freeform默认模式。标记可以放在图表上的任意像素位置其坐标值通过图形像素插值得到。适用于快速估算和趋势观察。吸附到数据点Snap to Data这是进行精确测量的关键模式。在此模式下移动鼠标时图表上会高亮显示最接近的实际数据点通常以圆圈或圆点标示。单击放置标记时标记会精确“吸附”到那个真实的数据点上其显示的X、Y坐标就是该数据点的原始值完全避免了图形插值带来的误差。当需要基于原始数据进行严格的时间或数值计算时必须使用此模式。标记线类型你可以选择标记线是只与X轴相交垂直时间线、只与Y轴相交水平数值线还是与两者都相交十字线。在分析时间相关性时垂直时间线最常用在比较同一时刻不同数据通道的数值时水平线更有用。实操心得标记的灵活运用移动标记放置标记后按住Shift键并拖动标记线可以将其移动到新的位置。这在微调测量点时非常方便。删除标记双击某个标记线可将其删除。在图表上右键选择“移除所有测量标记”可以一键清空。结合视图分组在分组的视图中如CPU负载图与执行图分组在一个视图中放置的测量标记会自动在另一个视图中相同时间位置显示。这让你可以同步测量不同视图中的事件。例如在执行图上标记一个任务开始和结束的时间同时在CPU负载图上观察这两个时间点之间的CPU利用率变化。3.3 书签为关键事件插上“记忆旗标”在一次分析会话中你可能会发现数十个值得深入调查的“可疑点”一个异常的任务切换、一次突然的CPU满载、一段超长的中断延迟。如果每次想回头看都要重新缩放、搜索效率极低。**书签Bookmarks**功能就是为了解决这个痛点。3.3.1 创建与跳转在图表或表格的任何数据点上点击工具栏上的书签图标即可在该处创建一个书签。在图表上书签显示为一条垂直的红色虚线在表格中书签所在的行会高亮显示如红色背景。书签工具栏旁的下拉列表会记录所有已创建的书签通常以自动生成的ID或可自定义的名称显示。点击列表中的任何一个书签视图会立即跳转到该书签所在的位置和缩放级别。这相当于给你的分析过程留下了可快速回溯的“路标”。3.3.2 管理书签通过下拉列表中的“管理书签”选项可以打开一个对话框进行更细致的操作重命名将自动生成的“Bookmark 1”改为更有意义的描述如“Task_A_Deadline_Miss”。删除移除不再需要的书签。作用域需要注意的是书签是视图特定的。在CPU负载图中创建的书签不会自动出现在执行图中。这有其合理性因为不同视图关注的事件不同。但你可以通过视图分组在关联视图中快速定位到相近时间点。3.3.3 书签 vs 测量标记这是两个常被混淆的功能它们的核区别在于测量标记用于精确的、瞬时的测量和计算坐标、差值。它的产出是一个数值结果。标记通常是临时的分析完当前问题后就会被清除。书签用于长期的、位置性的标记和快速导航。它的产出一个可快速返回的位置。书签通常会被保留贯穿整个分析会话甚至保存到文件某些工具支持供后续分析使用。我的工作流通常是先用缩放和滚动找到可疑区域用测量标记进行精确测量和计算一旦确认这是一个需要深入分析或后续复查的问题点就立即打上书签并附上描述性名称。3.4 查找与过滤在数据海洋中精准捕捞当面对包含成千上万行事件的表格视图时手动浏览是不现实的。**查找Find和过滤Filter**功能是你的“搜索引擎”和“筛子”。3.4.1 查找功能查找用于在表格中定位下一个符合特定条件的记录。它不会隐藏其他行只是将视图滚动到匹配项并高亮显示。这对于逐个检查某个特定事件如某个任务ID的所有切换非常有用。查找对话框通常有两个标签页使用字段Use Field适用于简单查询。你从下拉列表中选择一个字段如TaskID选择一个操作符如等于、!不等于、大于然后输入要比较的值。你还可以指定是否区分大小写、搜索方向向前/向后以及是否循环搜索到达末尾后从头开始。使用表达式Use Expression支持更复杂的查询可以使用正则表达式进行模式匹配并用布尔运算符AND, OR组合多个条件。例如查找TaskID为5且EventType为“Blocked on Semaphore”的所有记录。对于高级用户这是挖掘复杂模式的利器。3.4.2 过滤功能过滤与查找不同它会永久性地隐藏所有不满足条件的记录只显示匹配的行。这对于聚焦于某一类事件进行分析至关重要。例如在分析系统死锁时我可以过滤出所有与“信号量”Semaphore和“互斥量”Mutex相关的事件瞬间让视图变得清晰。过滤对话框的界面和操作逻辑与查找非常相似也包含“使用字段”和“使用表达式”两种模式。设置好条件后点击“过滤”视图立即刷新。要取消过滤通常需要点击“清除过滤”或类似的按钮。注意事项过滤的副作用应用过滤后许多基于全量数据的统计视图如摘要视图、部分图形视图可能不会自动更新它们显示的仍然是过滤前的全局统计数据。此外过滤条件通常只应用于当前视图。在分析时要清楚自己是在全量数据还是过滤后的子集上进行观察避免得出片面结论。3.5 数据导出与后续处理分析器内置的视图功能强大但有时你需要将数据导出用更专业的工具如Excel、Python pandas、MATLAB进行二次分析、生成定制化报告或进行长期趋势统计。导出为CSV文件是最通用的方式。在表格或图形视图上右键选择“数据” - “导出所有”或“导出选中”如果先选择了部分行。导出的CSV文件包含了视图中所有列的数据包括那些当前未显示的列以及图形中数据点的数值。导出数据的用途定制化图表在Excel或Python的Matplotlib中制作更美观、更符合论文或报告要求的图表。批量计算计算分析器未直接提供的复杂指标如负载的移动平均值、标准差、任务执行时间的概率分布等。长期日志分析将多次测试运行的数据导出合并后分析系统性能的长期演变趋势。自动化脚本处理编写脚本自动解析CSV在持续集成CI流水线中自动检测性能回归。实操心得导出设置与二进制格式除了手动导出CSV在启动分析会话时配置“将收集的二进制数据保存到文件夹”选项更为重要。这会将原始的、未解析的二进制数据流保存下来。二进制文件比CSV更紧凑包含了完整的原始信息并且可以重新导入分析器进行回放分析重现当时的完整场景。这对于问题复现和团队间共享分析场景至关重要。CSV可以视为二进制数据的一种“快照”或“子集”。4. 高级分析场景与实战技巧掌握了核心交互功能我们来看几个具体的实战分析场景看看如何组合运用这些工具来解决实际问题。4.1 场景一诊断CPU利用率间歇性飙高现象系统在长时间运行中CPU负载图显示每隔几分钟会出现一个短暂的、接近100%的尖峰持续时间约几十到几百毫秒。分析步骤全局观察首先在CPU负载图形视图中使用缩放工具纵览数小时的数据确认尖峰出现的周期性或规律性。精确测量放大其中一个典型尖峰。启用“吸附到数据点”的测量标记模式在尖峰的起始上升沿和结束下降沿各放置一个标记M1, M2。记录下时间差ΔX这就是单次高负载事件的持续时间。关联分析将CPU负载图与“执行图”进行视图分组。将光标或书签定位到尖峰的中心时间点。观察执行图看在这个时间段内是哪个或哪几个任务在持续运行。很可能是一个低优先级的后台任务突然被触发或者一个高优先级任务陷入了某种循环。深入探查在执行图上对该可疑任务的时间条进行放大。右键该任务查看其详细信息或切换到该任务的“任务负载”详情视图。同时可以过滤“Printf日志”或“系统事件日志”查看在尖峰发生前后是否有相关的日志输出如“开始处理数据块”、“进入清理例程”等。标记与记录确认问题点后在CPU负载图的尖峰处打上一个书签命名为“CPU_Spike_TaskX”。在问题任务的执行时间段也打上书签。导出该时间段的CSV数据供后续代码审查使用。4.2 场景二分析多任务系统中的优先级反转现象一个高优先级任务Task_H的响应时间偶尔会异常变长似乎被低优先级任务Task_L阻塞了。分析步骤定位异常实例在“执行图”中找到Task_H的一个执行实例其结束时间明显晚于预期。在此实例的结束位置放置测量标记M1在其预期的、正常的结束位置可根据周期估算放置标记M2计算延迟时间ΔX。观察共享资源检查在Task_H被延迟的这段时间M1和M2之间执行图上发生了什么。重点关注Task_L的状态。是否发现Task_L在此期间竟然在运行同时查看是否有中优先级任务Task_M在运行检查同步对象过滤事件日志只显示与“信号量”Semaphore或“互斥量”Mutex相关的事件时间范围限定在问题时间段。寻找这样的序列Task_L 获取了某个互斥锁Mutex_A。随后Task_H 尝试获取同一个 Mutex_A但被阻塞进入Blocked状态。此时Task_M优先级介于L和H之间就绪并开始运行因为它不需要Mutex_A。Task_M 的运行阻止了Task_L释放Mutex_A从而导致高优先级的Task_H被中优先级的Task_M间接阻塞——这就是经典的优先级反转。使用持续时间分析如果已对获取和释放互斥锁的函数进行了插桩可以使用“持续时间分析”功能直接测量Task_H从尝试获取锁到实际获取到锁的等待时间并与正常情况对比。结论与优化将分析过程关键时间点、任务状态、事件序列通过书签和截图记录下来。解决方案可能包括使用优先级继承互斥量或调整任务优先级。4.3 场景三优化中断服务程序的执行时间现象系统对某个外部事件的响应时间不稳定怀疑是某个中断务程序ISR执行过长。分析步骤识别ISR在“执行图”中中断服务程序通常显示在独立的、以“Hwi”或中断号命名的泳道中。找到你怀疑的ISR。测量ISR持续时间由于ISR的触发和结束都是事件你可以使用“持续时间分析”功能如果已对ISR入口和出口插桩。如果没有可以在执行图上手动放置测量标记测量单个ISR实例从开始到结束的横条长度时间差。统计与分布手动测量多个实例的持续时间观察其波动范围抖动。更高效的方法是导出ISR相关事件的数据到CSV用脚本计算平均值、最坏情况执行时间WCET和标准差。分析内部延迟如果ISR内部又调用了其他函数或触发了任务观察其内部细节。ISR执行期间是否被更高优先级的中断抢占ISR结束后是否触发了一个低优先级的任务而该任务迟迟得不到执行关联系统负载将ISR泳道与CPU负载图分组。观察在ISR执行时间变长的时刻系统的整体CPU负载是否也处于高位这可能是因为ISR中执行了较重的处理或者因为系统负载高导致ISR的后续处理如触发的任务被延迟。5. 性能分析最佳实践与避坑指南基于多年的实战经验我总结了一些使用RTOS/System Analyzer进行性能分析的最佳实践和常见陷阱。5.1 数据采集配置的权衡缓冲区大小如前所述需要平衡历史深度和内存占用。一个实用的方法是在预估的最高事件率下让缓冲区能容纳至少1-2秒的数据。例如事件率估计为10k events/s每个事件32字节则缓冲区建议设为 10k * 32 * 2 ≈ 640 KB。时间戳精度确保目标系统的时间戳时钟源是稳定且高精度的。使用低精度或漂移的时钟源会导致所有时间测量失真。在SYS/BIOS中通常由Timestamp模块提供需确认其驱动配置正确。传输方式选择精细调试用JTAG当你需要分析微秒级甚至纳秒级的时序问题时。长期监控用以太网进行数小时或数天的稳定性测试、压力测试时。避免UART传输大量数据其带宽是硬伤只适合传输极低频率的调试信息。5.2 分析过程中的常见问题与排查问题图形视图数据点稀疏或出现“阶梯”状原因数据采样率低于图形渲染的像素密度或者缩放级别过高。解决检查目标端的事件记录频率是否足够。对于快速变化的数据如CPU负载确保记录周期如每10ms记录一次远小于你关心的现象时间尺度。在图形属性中尝试切换不同的插值或绘图模式。问题多核事件在时间线上看起来“错乱”或顺序不对原因多核事件关联Correlation依赖于精确的全局时间戳。如果各核心的本地计时器没有严格同步或者通过以太网传输时网络抖动较大就可能出现此问题。解决对于JTAG传输确保使用支持全局时间戳同步的调试架构。对于以太网传输考虑在目标端使用硬件时间同步协议如PTP或者接受较小的时间偏差专注于单核内的时序分析。一个重要的技巧是对于多核时序分析优先保存数据到二进制文件然后停止目标在离线模式下重新加载分析。离线分析器有更多计算资源进行更精确的事件排序和关联。问题分析器界面卡顿响应缓慢原因数据量过大长时间采集高频率事件超出了主机UI的实时渲染和处理能力。解决在会话配置中限制数据收集时间或设置最大收集数据大小。在图形视图中隐藏暂时不需要观察的数据通道。使用过滤功能只显示你当前关心的事件类型。考虑将数据导出用外部工具进行批量分析。问题测量标记的数值与表格中的原始数据对不上原因很可能是在“自由模式”下标记点落在了两个实际数据点之间其数值是通过图形像素插值得到的并非真实数据。解决进行精确测量时务必切换到“吸附到数据点”模式。确保标记线“吸附”到高亮的数据点圆圈上。5.3 建立有效的分析工作流由面到点层层深入不要一开始就扎进细节。先看摘要视图和整体趋势图如数分钟的CPU负载找到异常的时间段。假设驱动根据现象如响应慢、卡顿提出假设如“可能是任务A被阻塞在信号量S上”然后利用过滤、查找、分组视图去验证或推翻这个假设。善用书签记录探索路径分析过程就像侦探破案每发现一个线索异常点就打一个书签并命名。这样即使分析被打断也能快速回到上下文。定量分析避免臆测多用测量标记获取精确时间、数值和差值。“感觉变慢了”不如“延迟增加了15.3毫秒”有说服力。关联上下文孤立地看一个任务的执行图意义不大。一定要关联看同一时刻的CPU负载、其他任务状态、中断触发情况才能拼出完整的系统行为画面。性能分析既是科学也是艺术。工具提供了强大的数据获取和可视化能力但如何提出正确的问题如何设计实验如何解读数据背后的系统故事则需要经验的积累和系统性的思考。RTOS Analyzer和System Analyzer这样的工具正是将你的经验和思考转化为对嵌入式系统深刻理解的桥梁。从熟练使用测量标记和书签开始逐步掌握从数据中抽丝剥茧、定位根因的能力你就能真正驾驭复杂系统的运行状态做出精准有效的优化。