使用Streamline分析RTOS系统性能

本文翻译自Analyzing the performance of RTOS-based systems using Streamline

=============================================================

Streamline是DS-5中的性能分析工具, Streamline可以用来分析裸机系统,RTOS,Linux,Android和Tizen系统的性能。

通过Streamline可以更详细地了解软件的运行,让arm优化工作更简单,你可以将游戏运行的更流畅,榨干GPU性能,找到程序的热点让SoC运行的更有效率。

本文描述了如何在RTOS系统中使用Streamline进行性能分析,Streamline可以揭示哪个函数在系统运行中占用时间最多,以及线程的活动

文中例子基于Keil RTOS RTX5,目标系统基于arm Cortex M33,但在Cortex-A, Cortex-R, Cortex-M系统中都可以运行。DS-5中还包含一个基于Cortex-A9的例子,这里有一个视频可以用来辅助理解本文。

用Streamline分析基于RTOS的应用可以分为以下四步:

  1. 生成采集数据的代码,barman。
  2. 把barman代码集成到待分析的应用中。
  3. 运行程序,收集数据
  4. 将采集来的数据导入Streamline

为了演示这些步骤,我们来导入一个DS-5中已经准备好的例子,这是一个用C语言编写的多线程程序,使用arm compiler 6进行编译,和CMSIS Pack中的RTX5库链接生成镜像。为了导入这个例子,我们执行如下步骤,File > Import > DS-5 > Examples & Programming Libraries,在Import对话框,展开Examples > Streamline Bare-Metal Agent Examples,选择RTX5_Cortex-M33_Blinky_Streamline例子,点击Finish。用到的CMSIS包会自动导入,这里也可以看到基于arm Cortex A9的例子。

例子中已经做好了上面要求的第一步和第二步,但是我们这里还是演示了如何操作,方便你将来在自己的项目中集成。

第一步,生成数据采集代码

第一步使用Streamline中的Generate Barman sources代码向导,生成barman代码。启动Streamline,选择Streamline > Generate Barman sources:

向导对话框会指引你进行一系列配置。比如,如何保存和传输采集来的数据(保存在板载的内存上,还是通过ITM输入到Debugger)?对几个CPU进行分析?本文中只用了一个核,但是多核也是可以的。应用中最多有几个任务?

系统中使用了哪种CPU,本文是Cortex-M33

要采集来自哪些Counter数据?可以在左边的窗口按Ctrl+A进行全选,拖入右边的窗口

接下来会设置采样率,和你自己定制的Counter,最后生成barman代码,包含两个代码文件,barman.c/barman.h。这两个文件会编译链接到你的程序中,同时还有barman.xml文件,这个文件包含你前面的配置信息,可以后面用来修改,重新生成代码文件。

第二步,将barman代码集成到RTOS应用中

将barman代码集成到应用中,这样才可以采集数据。Streamline已经帮我们生成了barman代码,我们只需要后面再应用中调用它即可。

  • 初始化barman
  • 允许barman从RTOS中读取当前threadID
  • 让RTOS在任务切换的时候通知barman

完整的barman API和参数说明可以在Streamline的文档中找到。

将barman初始化代码加入main函数。

 enable_barman();                      // Enable barman

barman集成代码如下

#include "barman.h"
#include "rtx_lib.h" // provides osRtxThreadxxx functions and os_thread_t type

/*
 * Perform the necessary initialization of the bare-metal agent
 */
static void enable_barman(void)
{
   /* For M-class, the cycle counter provides the timestamps, so convert it to nS by multiplying by 10**9 and dividing by the clock frequency in Hz */
    const struct bm_protocol_clock_info clock_info = { .timestamp_base = 0,
                                                       .timestamp_multiplier = 1000000000,
                                                       .timestamp_divisor = 25000000, /* 25MHz system freq of AN521 FPGA */
                                                       .unix_base_ns = 0 };

#if BM_CONFIG_MAX_TASK_INFOS > 0
    const struct bm_protocol_task_info task_entries[] =
    {
        { (bm_task_id_t)tid_phaseA,   "phaseA" },
        { (bm_task_id_t)tid_phaseB,   "phaseB" },
        { (bm_task_id_t)tid_phaseC,   "phaseC" },
        { (bm_task_id_t)tid_phaseD,   "phaseD" },
        { (bm_task_id_t)tid_clock,    "clock" },
        { (bm_task_id_t)tid_app_main, "app_main" },
        { (bm_task_id_t)(osRtxConfig.idle_thread_attr->cb_mem), "osRtxIdleThread" },
        { (bm_task_id_t)(osRtxConfig.timer_thread_attr->cb_mem), "osRtxTimerThread" },
    };
#endif

    /* Initialize barman but if there is a problem we will loop here */
    while (!barman_initialize_with_itm_interface("RTX5 Cortex-M33 Streamline bare-metal example", &clock_info,
#if BM_CONFIG_MAX_TASK_INFOS > 0
                              /* All the tasks */
                              8, task_entries,
#endif
#if BM_CONFIG_MAX_MMAP_LAYOUTS > 0
                              /* We only have one image for all tasks so we don't need to provide these */
                              0, BM_NULL,
#endif
                              1));

    /* Now we are ready to enable sampling */
    barman_enable_sampling();
}

/* Allow barman to read the current thread id from RTX */
bm_task_id_t barman_ext_get_current_task_id(void)
{
  return (bm_task_id_t)osRtxThreadGetRunning();
}

/* Allow RTX to inform barman when a task switch occurs */
extern void $Super$$osRtxThreadSwitch(os_thread_t *thread);

void $Sub$$osRtxThreadSwitch(os_thread_t *thread)
{
  $Super$$osRtxThreadSwitch(thread);                               // Call the original osRtxThreadSwitch
  barman_record_task_switch(BM_TASK_SWITCH_REASON_PREEMPTED);      // Record the task switch
}

注意代码中的 Arm Linker (armlink) $Sub/$Super mechanism ,这里我们使用arm链接器的特性去修改RTOS代码中的一个函数,从而避免直接修改RTOS代码。GCC链接器也可以通过参数"--wrap"添加类似功能。

然后用arm编译器6编译整个工程。如果你是使用makefile来管理整个工程,你需要将barman.c加入到编译文件中,并将生成的barman.o链接到最后应用里。如果你是使用Eclipse,它会自动完成文件添加并重新编译。

第三步,运行应用进行数据采集

重新编译整个工程后,下载,在目标设备上运行应用进行数据采集。本例使用 Arm MPS2+ board,基于FPGA的arm Cortex-M33软核。通过DStream连接开发板,Dstream用来启动/停止控制,并通过ITM从开发板采集数据,所以我们在开始前要配置DS-5,采集ITM Trace信息。将Dstream和板子连接,启动应用,采集数据,停止,通过"trace dump"命令将数据保存到PC上。如果你的应用是将数据保存在内存中,请使用“dump memory”。

  1. 启动DS-5。
  2. 选择Run > Debug Configurations。
  3. Debug Configurations对话框中创建一个调试连接,本例中展开左边对话框的DS-5配置选项,选择RTX5_Cortex-M33_Blinky_Streamline_MPS2。
  4. Connections面板,在调试器地址中输入DStream的IP地址或者USB ID,或者从列表中选择。
  5. ITM配置可以点击 DTSL Options Edit... 按钮,在Trace Capture栏选择DSTREAM 4GB Trace Buffer,在ITM栏勾选Enable CSITM Trace,点击OK,保存DTSL配置。
  6. 点击Debug开始调试,本例将下载编译好的镜像到开发板,并将PC设到程序第一条指令。
  7. 调试需要DS-5调试视图,如果这个时候出现视图切换对话框,点击确认。
  8. 通过电子调试视图中的绿色Continue按钮 ,或F8执行程序。
  9. 程序运行时DStream通过ITM采集数据,你会看到Trace视图中的Buffer Used数字一直在增长。
  10. 几秒钟后,点击调试视图中的Interrup,或者按F9停止应用。
  11. 在命令行,输入 trace dump [path\to\a\local\folder] CSITM

第四步,将数据导入Streamline

最后一步是将采集到的数据用Streamline的采集向导导入,采样的数据可以用来分析源码的符号信息,Streamline可以用来将它可视化。

  1. 启动Streamline
  2. 在Streamline Data视图,点击Import Capture File(s)...,选择刚刚保存的CSITM_0.bin。
  3. Select what to Import中,选择Barman Agent Capture (via ITM),点击Next。
  4. Provide Required Files,选择刚才执行的镜像文件(本例中是RTX5_Cortex-M33_Blinky_Streamline.axf),和barman.xml文件。
  5. 在左侧的Streamline Data视图,右键单击刚才创建的工程,选择Analyse...,勾选执行镜像(RTX5_Cortex-M33_Blinky_Streamline.axf),点击Analyse
  6. 经过一会处理,Streamline会显示barman.xml中选择的那些计数器的时序图

我们来看看图形化效果

时序图中将计数器和线程活动相关联,本例中,我们通过代码标注不同线程运行的时间,下图中的红色长条表示phaseA,绿色长条表示phaseB,蓝色表示phaseC,黄色表示phaseD。 

函数调用栏显示每个函数在该线程中占用的时间比例。

函数栏,显示每个函数在整个运行中占用的时间。

双击函数,可以得到每个函数被采样的次数,以及相应源码。

最后,Log栏显示应用代码中添加的标注。

如果你想改变时序图中显示的计数器,你可以通过Streamline > Generate Barman sources进行修改。重新生成barman.c/.h/.xml,重新编译代码,运行,分析。

综上,我们看见了如何利用Streamline分析RTOS系统的性能,找到系统或者应用的热点,你可以集中精力优化这些热点来最大效率地提高系统的整体性能。

Anonymous
  • [Arm中国生态]来2018 未来科技创芯大会,体验一次与众不同的原力觉醒!

    想要把握高速发展的科学潮流吗? 想要了解未来未知的技术发展吗? 想在互联网科技时代投资自己吗? 如果你的回答是“YES” 那么请你把握住这次机会 一场不容错过的未来科技大会 大会介绍   安创加速器(Arm Accelerator)是Arm全球唯一加速器,聚焦于人工智能和物联网产业的创新创业服务平台。自2016年成立以来,坚持以“驱动全球创新,服务产业升级”为宗旨,通过每年2期的…
  • CiiF现场速递丨好多人围观!Arm物联网设备到数据平台一系列解决方案太秀了

    本周三,第二十届中国国际工业博览会在上海国家会展中心拉开帷幕,并将持续到23日。恰逢周末假日,大伙组队去看一看? 此次Arm同样“盛装出席”,携最新物联网设备管理平台诸多解决方案参展。在此,小编为还没到现场的小伙伴们稍稍剧透一下,希望都能有空去现场感受满满的干货吧~ 谁才是物联网架构首选?有图有真相 Arm此次展位号E170,位于7.2馆的信息与通信技术应用展,今年重点聚焦“工业互联网”领域,吸引了国内外权威的工业互联网…
  • Arm NN 软件开发套件

    Arm NN 填补了现有 NN 框架和底层 IP 之间的空白。它可以帮助 TensorFlow 和 Caffe 等现有神经网络框架实现高效转换,并在 Arm Cortex CPU 和 Arm Mali GPU 上高效运行,无需修改。 Arm NN 不收取任何费用。 下载 Arm NN SDK (GitHub) 关于 Arm NN SDK Arm NN SDK 是一套开源 Linux 软件和工具,支持在高能效的设备上运行机器学习工作负载…