This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] PROCESSOR-SDK-J721E:R5F 上使用&gt 的 FreeRTOS 应用程序;100% CPU (根据统计数据)

Guru**** 2747375 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1125099/processor-sdk-j721e-freertos-application-on-r5f-using-100-cpu-according-to-the-stats

器件型号:PROCESSOR-SDK-J721E

您好!

希望您能帮助解决我发现的差异。

我修改了 FreeRTOS | ut 演示以检索  ping_main()末尾的运行时统计信息(vTaskGetRunTimeStats)。  请注意,PING_MAIN 被简化为只调用 test_taskSwitchWithSemaphore(),它的优点是减少运行时间并确保在获得统计数据时'pong'任务仍然有效。

我很惊讶地看到、累积的乒乓/闲置% CPU 使用率大于100%。  实际数字因执行情况而异、示例为:

启动 FreeRTOS ut

[freertos] ping 任务... 开始!!!

任务切换的执行时间= 3614ms
任务开关数量= 2000000
每个任务切换的时间(信标给出/接受)= 1807ns

所有测试均已通过!!

运行时间统计
Ping     1494683  38%
空闲     304801   7%
Pong     3697129  94%
TMR 服务   19.     <1%

任务列表
Ping      x 2 32520 5.
空闲      R 0 945 2
TMR 服务    B 15 172 3
Pong      S 3 32656 4

为了总结我的调查结果,当在运行环境切换期间(在本例中) 通过信标在 ping 和 pong 任务之间切换时,当计时器节拍中断发生时,vTaskSwitchContext()中 ulTaskSwitchSchedulInTime 的值似乎已损坏。  损坏是指 之前上下文切换中基于 ulTotalRunTime 的 ulTaskSwitchedInTime 值已被一个看起来是 tickCount*1000的值覆盖。  "新"值大约比旧值小1000、 因此,在下次执行  vTaskSwitchContext()时,pxCurrentTCB->ulRunTimeCounter += ulTotalRunTime - ulTaskSwitchInTime 的计算 最终会将任务 ulRunTimeCounter 的增加 量增加大约1000us,因此基于 ulRunTimeCounter 的统计 数据显示出比实际情况高得多的 CPU 使用率。   下面显示的跟踪数据对此进行了演示。  

同样令人关注的是,此跟踪还显示 ,被中断的 vTaskSwitchContext()永远不会恢复。  例如,在显示的'pong'的 traceTASK_switched_out ()已被调用,但  ping 的预期 traceTASK_switched_in ()不是。

希望注释澄清上述说明。


此致

斯蒂芬

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、Stepehn、

    您能否分享一下您如何获得运行时间统计信息? 如果可能、请分享您在结尾处运行的修改后的代码

    此致、
    Parth

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Parth、

    我 通过 从  ping_main()调用 vTaskGetRunTimeStats()并通过 UART 卸载来获取统计信息。  这是初始 配置、它确定了需要研究的问题

    void ping_main (void *args)

     FreeRTOS_LOG ("启动 FreeRTOS ut\n");  
     Unity_Begine();  

     run_test (test_taskSwitchWithSemaphore、1、NULL);
     /*注释掉的其它测试*/

     Unity_End();

     if (Unity.TestFailures =0)
     {
      FreeRTOS_LOG ("\r\n");
      FreeRTOS_LOG ("所有测试均已通过!!\r\n");
     }

     FreeRTOS_LOG ("\r\nRun Time Stats\r\n");
     char dataBuffer[255]={0};
     vTaskGetRunTimeStats (dataBuffer);
     UART_dataWrite (dataBuffer、strlen (dataBuffer));

     /*不能从 FreeRTOS 任务中返回,而必须调用 vTaskDelete */
     vTaskDelete (NULL);

    随后 、为了显示数据、我添加了跟踪宏

    #define traceTASK_switched_in() rtLogTaskSwitch (switch_in);
    #define traceTASK_switched_out () rtLogTaskSwitch (switch_out);
    #define traceTASK_Increment_tick (xTickCount) rtttLogTimerTick (xTickCount);

    并 检测 了 vTaskSwitchContext()

    if (ulTotalRunTime > ulTaskSwitchInTime)

     pxCurrentTCB->ulRunTimeCounter +=(ulTotalRunTime - ulTaskSwitchInTime);
     if (pxCurrentTCB->uxTaskNumber = UMD_PING_OUT){
      rtLogUserMarkerData (UMD_PING_OUT、ulTotalRunTime、pxCurrentTCB->ulRunTimeCounter、ulTaskSwitchInTime);
     }否则、如果(pxCurrentTCB->uxTaskNumber == UMD_Pong_OUT){
      rtLogUserMarkerData (UMD_Pong_OUT、ulTotalRunTime、pxCurrentTCB->ulRunTimeCounter、ulTaskSwitchInTime);
     }

    其他

    mtCOVERAGE_TEST_MARK();

    if (ulTaskSwitchInTime < lastInTime){
     rtLogUserMarkerData (UMD_RTC_blip、ulTotalRunTime、lastInTime、ulTaskSwitchInTime);

    lastInTime = ulTaskSwitchInTime;

    ulTaskSwitchInTime = ulTotalRunTime;

    自定义'RTT'函数将数据结构的实例添加到缓冲区中,该缓冲区在写入 RunTimeStats 后通过 UART 在 ping_main()中卸载。

    typedef 结构{
     /*事件数据、4字节记录中*/
     RTTraceDataType traceData[TRC_CFG_NUM_Records];
    }HttTracedRecorderType;

    RTTraceTM 记录器类型 RTTraceTM 记录器;
    HttTraceRecorderType* HttTraceRecorderPtr =&HttTraceRecorder;

    //记录 start_activity 和 end_activity 事件
    void rttLogTaskSwitch (rttAction_t action)

     TaskStatus_t xTaskStatus;
     vTaskGetInfo( xTaskGetCurrentTaskHandle(),
                 &xTaskStatus、
                pdfALSE、
                eRunning);

     RTTraceDataType traceData;
     traceData.timestamp = portGET_run_time_counter_value ();
     traceData.id = xTaskStatus.xTaskNumber;

     if (action = switch_in){
        traceData.event = start_activity;
     }
     否则、如果(action = switch_out){
       traceData.event = end_activity;
     }

     rtRecordEvent(&traceData);

    void rttLogUserMarkerData (umid_t ID、uint32_t CurrentTime、uint32_t taskTime、uint32_t lastSwitchTime){
     RTTraceDataType traceData;
     traceData.event = USER_MARGER_ITH_DATA;
     traceData.timestamp = portGET_run_time_counter_value ();
     traceData.id = ID;
     traceData.dataLength = 3;
     traceData.dataContent[0]= CurrentTime;
     traceData.dataContent[1]= taskTime;
     traceData.dataContent[2]= lastSwitchTime;

     rtRecordEvent(&traceData);

    void rttLogTimerTick (int xTickCount){
     rtLogUserMarkerData (UMD_timer_tick、xTickCount、0、0);

    void rttRecordEvent(RttTraceDataType* traceData){
     if (traceDataIndex < TRC_CFG_NUM_Records){
     rtTraceRecorderPtr->traceData[traceDataIndex]=*traceData;
     traceDataIndex++;
     }

    此致

    Steve

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    对此有任何进一步的想法、或者我是否应该提出支持请求?

    谢谢

    Steve

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Steve、

    对延迟回复表示歉意。 您可以在此处分享您的确切用例吗? 我们将能够在此基础上提供更好的建议。

    此致、
    Parth

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Steve、

    此外、除了上述查询之外、请说明您如何获得超过100%的数字?

    通常、通过捕获空闲时间来计算 CPU 负载。 获取统计数据的方式似乎不是正确的方式、因为在这种情况下、如果发生任何中断、也会添加中断 ISR 时间。

    此致、
    Parth  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Parth、

    我分配的任务是  对 Jacinto 平台上的 FreeRTOS 进行一般评估。  在此过程中、我将研究获取 CPU 负载信息的可用工具、以及我们如何将内部跟踪方法与 FreeRTOS 的功能(即跟踪宏)集成在一起。

    此致

    Steve

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    >>此外,除上述查询外,请说明您如何获得超过100%的数字?

    参考原始统计数据输出  

    Ping     1494683  38%
    空闲     304801   7%
    Pong     3697129  94%

    对每个任务的加载求和大于100%。   报告的每个任务加载必须有一些错误。

    我使用的方法是内置 FreeRTOS 功能 https://www.freertos.org/rtos-run-time-stats.html。  通过将  CONFIGGENERATE_RUN_TIME_STATS 设置为  1生成的基本信息 与 PDK 第9.1.3.1.3节中所述功能使用的信息相同。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Stephen:

    [引用 userid="529954" URL"~/support/processors-group/processors/f/processors-forum/1125099/processor-sdk-j721e-freertos-application-on-r5f-using-100-cpu-according-to-the-stats/4182073 #4182073">我使用的方法是内置 FreeRTOS 功能 https://www.freertos.org/rtos-run-time-stats.html.

    您应该将此内容发送到 FreeRTOS 论坛、因为这是针对 FreeRTOS 功能的。 您还可以检查一些通用 FreeRTOS 示例是否可用。 在 PDK 侧、我们没有任何可提供与您的用例类似信息的功能。

    此致、
    Parth

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如原始问题中所述、当计时器节拍 ISR (在 TI 为 R5F 提供的硬件端口中处理)中断标准任务开关时、会出现问题。

    "在 PDK 侧、我们没有任何可提供与您的用例类似信息的功能"

    在我之前的消息中、我在 PDK 用户指南中的部分中专门标识了该消息、其中介绍了提供相同信息的 PDK。  这是 LoadP_getTaskLoad()函数。

    为了更加明确、我附加了 一个基于 OSAL 的版本、TI 提供了'FreeRTOS_TEST_taskswitch'代码、对其进行了修改以添加 LoadP_getTaskLoad()函数。

    下面还附加了为 MCU_2_0构建并运行的同一二进制文件4次执行的结果、并进行了总结。  所有4个实例都显示了截然不同的任务负载、这应该是其自身的问题指示器、其中3个实例显示组合的任务负载大于100%。

    任务 Ping、任务 RT 4422904、总计 RT 7647006、任务 PC 57
    Task PONG、Task RT 4597771、Total RT 7647013、Task PC 60
    Task FreeRTOS_MAIN、Task RT 455、Total RT 7647018、Task PC 0
    CPU 负载93 -表示7pc 空闲任务

    任务 ping、任务 RT 2941010、总计 RT 7017008、任务 PC 41
    Task PONG、Task RT 3655018、Total RT 7017014、Task PC 52
    Task FreeRTOS_MAIN、Task RT 440、Total RT 7017019、Task PC 0
    CPU 负载92-表示8pc 空闲任务

    任务 Ping、任务 RT 4476743、总 RT 7013007、任务 PC 63
    Task PONG、Task RT 4818577、Total RT 7013014、Task PC 68
    Task FreeRTOS_MAIN、Task RT 441、Total RT 7013020、Task PC 0
    CPU 负载92-表示8pc 空闲任务

    任务 Ping、任务 RT 7398142、总 RT 7007、任务 PC 100
    Task PONG、Task RT 4259948、Total RT 7007014、Task PC 60
    Task FreeRTOS_MAIN、Task RT 448、Total RT 7007020、Task PC 0
    CPU 负载92  -表示8pc 空闲任务

    e2e.ti.com/.../taskswitch_5F00_load_5F00_output.txte2e.ti.com/.../task_5F00_switch.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    请进一步考虑这个问题吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    保持活动状态。  仍在寻求对此问题的某种考虑。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Stephen:

    很抱歉耽误了很长时间。 解锁主题以进行进一步讨论。

    我正在查看此主题、同时请告诉我您是否有任何新的更新。

    此致、
    Parth

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Stephen:

    我与团队一起检查了这个问题、得到了以下回应:

    "我们需要调用 API LoadP_RESET、以便在开始负载测量之前清除所有计数器。 您可以看到 OSAL UT 的典型用法。"

    您是否在您的案例中完成了此操作、如果不是、您可以尝试一下并分享观察结果?

    此致、
    Parth

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Parth、

    再次感谢您的观看。   

    否,  未调用 LoadP_RESET()。  初始 测试是使用 不使用 OSAL 的 FreeRTOS_TEST_ut 演示完成的。  使用 FreeRTOS_TEST_taskswitch 演示的后续测试  从应用程序启动开始加载信息。  但是, 由于 gLoadP_FreeRTOS 结构在未调用 LoadP_RESET()的情况下未显式初始化,因此我添加了调用,如所附 task_switch.c 中所示

    从下面的结果可以看出、它没有影响。  这并不奇怪、因为从这个线程前面的分析中可以看出 、这个问题是由累积任务时间内的增量错误引起的、每当信号量触发的上下文切换被计时器节拍中断时、这些错误就会发生。  与初始值无关。

    e2e.ti.com/.../LoadP_5F00_reset_5F00_results.txte2e.ti.com/.../task_5F00_switch.c

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Stephen:

    我们在中将其作为漏洞进行跟踪、PDK 团队正在对此进行分析。 这将在8.6中修复、如果我从团队那里获得任何更新、我将向您提供最新信息。

    jira.itg.ti.com/.../PDK-12327

    此致、
    Parth

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的、谢谢。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    保持活动状态、直到在 SDK 中修复此问题。

    此致、
    Parth

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我们已导致此问题,并已验证修复程序。 下面是根本原因的详细信息

    FreeRTOS 使用可移植层中实现的 uiGetRunTimeCounter() API 来获取总运行时间和每个任务的 CPU 使用时间。

    在 J721E R5内核上,性能计数器 API uiGetRunTimeCounter()是使用名为 dmtimer 的 SoC 计时器实现的  

    dmtimer 的工作方式如下图所示  

    • 有一个向上计数的32位计数器
    • 在定时器初始化时、我们对 RELOAD 值进行编程、该值是计数器开始的初始值
    • 它以定时器输入时钟的速率递增计数、直到达到0xFFF_FFFF 的饱和值
    • 当达到饱和值时、会发生两件事情
      • DM定时器 触发 R5内核上的定时器中断
      • Dmtimer 自动将计数器重置回 RELOAD 值
    • 我们在计时器初始化时编程的重新加载值设置为以1000Hz 的速率触发中断(每毫秒1个中断)
    • 这个定时器中断也被用作 RTOS 调度程序节拍
    • 在 RTOS 调度程序节拍中、每次 ISR 发生时、软件计数器都会递增。让我们将其调用 swOSTickCount

    uiGetRunTimeCounter()返回64位值,它是一个单调计数器,返回自计时器启动以来经过的微秒数。

    它返回当前 uiGetRunTimeCounter()为

    • swOSTickCount * 1000 +((Dmtimer 计数器值- Dmtimer ReloadValue)* DMTIMER_TICK 至微秒)

    您发现的错误发生在以下情况下

    uiGetRunTimeCounter() 调用#1

    •    swOSTickCount = 72
    •    DMTimerCounter 值= 0xFFF_FFFF、转换为999us
      • 因此返回的值为 72 * 1000 + 999 = 72999

    --此时,dmtimer 将饱和。 它将指示挂起中断的中断线路提升至 R5

       -- DMTimerCounter 值也被自动复位以重新加载值

    --但是由于 中断已经被禁用(也许是一个关键部分),所以 dmtimer ISR 不会被处理。

    uiGetRunTimeCounter()  调用#2

    •    swOSTickCount = 72  
      • 计数仍然为72、因为我们没有处理 ISR
    •    DMTimerCounter 值= 0x0、转换为 0us
      • 无论是否为 ISR 提供服务、DMTimerCounter 都会自动复位为0
      • 因此返回的值为 72  * 1000 + 0 = 72000

    由于此错误 ,uiGetRunTimeCounter()不再单调,因此 CPU 负载计算出错

    为了解决这个问题,我们不使用 PMU 计数器来保持微秒已用部分,而使用 swOSTickCount 来表示 uiGetRunTimeCounter()的毫秒部分。 PMU 计数器是 R5内核内部32位计数器。  

    这可确保 uiGetRunTimeCounter()是单调的。 我们在修复后确认加载问题已解决

    非常感谢您的出色分析、使我们能够找出问题的根源

      多米尼加供参考

    此致

    Badri

     

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢 Badri 的反馈。 我理解这种情况是如何 产生 的,但请你进一步说明这种情况是如何解决的。  swOSTickCount 是否仍然从 DM 定时器的 ISR 递增? 还是从不可屏蔽中断递增?

    我们是否可以预期 SDK 8.6中的修复程序?

    此致

    斯蒂芬

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Stephen:

    是的、该修复程序将是8.6 SDK 的一部分

    此致、
    Parth

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    以下是错误修复的详细信息:

    • 在计时器 ISR 中,我们递增软件计数器(swOSTickCount)  并记录当前 PMU 计数器值。
      • PMU 计数器是一个32位计数器、它以 CPU 频率运行、在1GHz 的 R5 CPU 频率下将在4秒内完成回绕。
    • 我们不再使用计时器计数器来确定自上一次计时器中断以来经过的微秒数。 这  是因为 DMTimer 在达到饱和值时会自动重置、如我之前的帖子中所述
    • 即使定时器 ISR 延迟、PMU 计数器也会正确计算经过的微秒数
      • 这样、我们就可以确保我们有一个单调计数器。

    请告诉我您是否希望通过错误修复的源代码 diff 进行进一步分析。 我将附上这篇文章。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    啊、好的、我看到、谢谢。
    是的、此差动很有用。

    此致

    斯蒂芬

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Stephen:

    PFA 补丁文件。
    e2e.ti.com/.../0001_2D00_PDK_2D00_12327_2D00_freertos_2D00_r5f_2D00_port_2D00_use_2D00_pmu_2D00_counter_2D00_for_2D00_runt.patch

    谢谢、此致

    Don Dominic

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    看起来也更高效!