NVIDIA Holoscan SDK v2.9.0

数据流跟踪

Holoscan SDK 提供了数据流跟踪 API,作为一种机制来分析您的应用程序,并分析片段图中运算符之间细粒度的定时属性和数据流。

目前,数据流跟踪仅支持图的根运算符和叶运算符之间以及图中的简单循环(计划未来支持跟踪图中任意一对运算符之间的数据流)。

  • 根运算符 是指没有任何前置节点的运算符。

  • 叶运算符(也称为宿运算符)是指没有任何后继节点的运算符。

当启用数据流跟踪时,每个消息都会从根运算符跟踪到叶运算符和循环中。然后,可以使用数据流跟踪 API 检索一个或多个路径的最大(最坏情况)、平均和最小端到端延迟。

提示
  • 根运算符和叶运算符之间的端到端延迟是指从根运算符开始到叶运算符结束所花费的时间。数据流跟踪支持跟踪在根运算符和叶运算符之间传递的每个消息的端到端延迟。

  • 循环路径的报告端到端延迟是指从循环的第一个运算符开始到消息再次被循环的第一个运算符接收时所花费的时间。

该 API 还提供了检索从根运算符发送的消息数量的功能。

提示
  • 数据流跟踪功能也在 flow_tracker 中进行了说明

  • 请查看 C++python API 文档以获取详尽的定义

在应用程序(C++/python)使用 run() 方法运行之前,可以启用数据流跟踪。对于单片段应用程序,可以通过在 C++ 中调用 track() 方法,并在 python 中使用 Tracker 类来完成。

复制
已复制!
            

auto app = holoscan::make_application<MyPingApp>(); auto& tracker = app->track(); // Enable Data Flow Tracking // Change tracker and application configurations ... app->run();

复制
已复制!
            

from holoscan.core import Tracker ... app = MyPingApp() with Tracker(app) as tracker: # Change tracker and application configurations ... app.run()

对于分布式(多片段)应用程序,每个片段使用单独的 tracker 对象,因此 API 与单片段情况略有不同。

复制
已复制!
            

auto app = holoscan::make_application<MyPingApp>(); auto trackers = app->track_distributed(); // Enable data flow tracking for a distributed app // Change tracker and application configurations ... app->run();

请注意,track_distributed 方法返回 std::unordered_map<std::string, DataFlowTracker*>,而不是像 track 一样返回单个 DataFlowTracker*std::unordered_map<std::string, DataFlowTracker*> 其中键是片段的名称。

复制
已复制!
            

with Tracker(app) as trackers: app.run()

Tracker 上下文管理器检测应用程序是否为分布式应用程序,并在分布式情况下返回 dict[str, DataFlowTracker] 作为 trackers。对于单片段应用程序,返回值只是一个 DataFlowTracker 对象。

应用程序运行后,可以通过 DataFlowTracker (C++/python) 类的各种方法访问数据流跟踪结果。

  1. print() (C++/python)

    • 将所有数据流跟踪结果(包括端到端延迟和源消息数量)打印到标准输出。

  2. get_num_paths() (C++/python)

    • 返回根运算符和叶运算符之间路径的数量。

  3. get_path_strings() (C++/python)

    • 返回字符串向量,其中每个字符串表示根运算符和叶运算符之间的路径。路径是以逗号分隔的运算符名称列表。

  4. get_metric() (C++/python)

    • 根据参数返回不同指标的值。

    • get_metric(std::string pathstring, holoscan::DataFlowMetric metric) 返回路径 pathstring 的指标 metric 的值。指标可以是以下之一

      • holoscan::DataFlowMetric::kMaxE2ELatency (python): 路径中的最大端到端延迟。

      • holoscan::DataFlowMetric::kAvgE2ELatency (python): 路径中的平均端到端延迟。

      • holoscan::DataFlowMetric::kMinE2ELatency (python): 路径中的最小端到端延迟。

      • holoscan::DataFlowMetric::kMaxMessageID (python): 导致最大端到端延迟的消息编号或 ID。

      • holoscan::DataFlowMetric::kMinMessageID (python): 导致最小端到端延迟的消息编号或 ID。

    • get_metric(holoscan::DataFlowMetric metric = DataFlowMetric::kNumSrcMessages) 返回源运算符及其边缘的映射,以及从源运算符发送到边缘的消息数量。

在上面的示例中,数据流跟踪结果可以像下面这样打印到标准输出

复制
已复制!
            

auto app = holoscan::make_application<MyPingApp>(); auto& tracker = app->track(); // Enable Data Flow Tracking // Change application configurations ... app->run(); tracker.print();

复制
已复制!
            

from holoscan.core import Tracker ... app = MyPingApp() with Tracker(app) as trackers: # Change tracker and application configurations ... app.run() tracker.print()

如果这是一个分布式应用程序,则每个片段将有一个单独的 DataFlowTracker。所有片段的总体流跟踪结果可以像下面这样打印

复制
已复制!
            

auto app = holoscan::make_application<MyPingApp>(); auto trackers = app->track_distributed(); // Enable data flow tracking for a distributed app // Change application configurations ... app->run(); // print the data flow tracking results for (const auto& [name, tracker] : trackers) { std::cout << "Fragment: " << name << std::endl; tracker->print(); }

复制
已复制!
            

from holoscan.core import Tracker ... app = MyPingApp() with Tracker(app) as trackers: # Change tracker and application configurations ... app.run() # print the data flow tracking results for fragment_name, tracker in trackers.items(): print(f"Fragment:{fragment_name}") tracker.print()

可以使用一些可选的配置参数自定义数据流跟踪。track() 方法(C++//Python)或 track_distributed 方法(C++/Python)`(对于分布式应用程序)可以配置为在应用程序执行开始时跳过一些消息作为预热期。也可以在应用程序运行结束时丢弃一些消息作为收尾期。此外,可以通过设置延迟阈值(以毫秒为单位)来忽略异常的端到端延迟,该阈值是忽略观察到的延迟的最小延迟值。最后,可以限制除根运算符和叶运算符之外的所有节点上的消息时间戳,从而减少时间戳和发送带时间戳消息的开销。通过这种方式,仍然可以计算端到端延迟,但不会为唯一的根运算符和叶运算符对存储按路径的细粒度数据。

对于 Python,建议使用 Tracker 上下文管理器类,而不是 tracktrack_distributed 方法。此类将自动检测应用程序是单片段应用程序还是分布式应用程序,并为每个应用程序使用适当的方法。

提示

为了进行有效的基准测试,通常的做法是包括预热和冷却期,方法是跳过初始和最终消息。

列表 41 track() 的可选参数

复制
已复制!
            

Fragment::track(uint64_t num_start_messages_to_skip = kDefaultNumStartMessagesToSkip, uint64_t num_last_messages_to_discard = kDefaultNumLastMessagesToDiscard, int latency_threshold = kDefaultLatencyThreshold, bool is_limited_tracking = false);


列表 42 Tracker 的可选参数

复制
已复制!
            

Tracker(num_start_messages_to_skip=num_start_messages_to_skip, num_last_messages_to_discard=num_last_messages_to_discard, latency_threshold=latency_threshold, is_limited_tracking=False)


track() 的这些参数的默认值如下

  • kDefaultNumStartMessagesToSkip: 10

  • kDefaultNumLastMessagesToDiscard: 10

  • kDefaultLatencyThreshold: 0(不滤除任何延迟值)

  • is_limited_tracking: false

这些参数也可以使用辅助函数进行配置:set_skip_starting_messagesset_discard_last_messagesset_skip_latenciesset_limited_tracking

数据流跟踪 API 提供了将每个消息的图遍历信息记录到文件的功能。这使您可以细粒度地分析数据流。启用日志记录后,在叶运算符处理完消息后,将记录每个消息在根运算符和叶运算符之间每个运算符处的接收和发送时间戳。

通过在 C++ 中调用 enable_logging 方法,并在 python 中为 Tracker 提供 filename 参数来启用日志记录。

复制
已复制!
            

auto app = holoscan::make_application<MyPingApp>(); auto& tracker = app->track(); // Enable Data Flow Tracking tracker.enable_logging("logging_file_name.log"); ... app->run();

复制
已复制!
            

from holoscan.core import Tracker ... app = MyPingApp() with Tracker(app, filename="logger.log") as tracker: ... app.run()

记录器文件在叶运算符完成其 compute 方法后记录消息的路径。日志文件中的每个路径都包含一个元组数组,格式如下

“(根运算符名称, 消息接收时间戳, 消息发布时间戳) -> … -> (叶运算符名称, 消息接收时间戳, 消息发布时间戳)”。

可以进一步分析此日志文件,以了解应用程序的延迟分布、瓶颈、数据流和其他特性。

对于跨越多台机器的分布式应用程序中的流跟踪,系统管理员必须确保所有机器的时钟同步。如何同步时钟取决于管理员的偏好。Linux PTP 是一种流行的常用时钟同步机制。

在所有机器上安装 linuxptp 软件包

复制
已复制!
            

git clone http://git.code.sf.net/p/linuxptp/code linuxptp cd linuxptp/ make sudo make install

提示

Ubuntu linuxptp 软件包也可以使用。但是,上面的存储库提供了对不同 PTP 配置的访问。

检查 PTP 硬件时间戳支持

检查您的机器和网卡是否支持 PTP 硬件时间戳

复制
已复制!
            

$ sudo apt-get update && sudo apt-get install ethtool $ ethtool -T <interface_name>

如果上述命令的输出类似于下面提供的输出,则表示可能支持 PTP 硬件时间戳

复制
已复制!
            

$ ethtool -T eno1 Time stamping parameters for eno1: Capabilities: hardware-transmit (SOF_TIMESTAMPING_TX_HARDWARE) software-transmit (SOF_TIMESTAMPING_TX_SOFTWARE) hardware-receive (SOF_TIMESTAMPING_RX_HARDWARE) software-receive (SOF_TIMESTAMPING_RX_SOFTWARE) software-system-clock (SOF_TIMESTAMPING_SOFTWARE) hardware-raw-clock (SOF_TIMESTAMPING_RAW_HARDWARE) PTP Hardware Clock: 0 Hardware Transmit Timestamp Modes: off (HWTSTAMP_TX_OFF) on (HWTSTAMP_TX_ON) Hardware Receive Filter Modes: none (HWTSTAMP_FILTER_NONE) all (HWTSTAMP_FILTER_ALL) ptpv1-l4-sync (HWTSTAMP_FILTER_PTP_V1_L4_SYNC) ptpv1-l4-delay-req (HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) ptpv2-l4-sync (HWTSTAMP_FILTER_PTP_V2_L4_SYNC) ptpv2-l4-delay-req (HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) ptpv2-l2-sync (HWTSTAMP_FILTER_PTP_V2_L2_SYNC) ptpv2-l2-delay-req (HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) ptpv2-event (HWTSTAMP_FILTER_PTP_V2_EVENT) ptpv2-sync (HWTSTAMP_FILTER_PTP_V2_SYNC) ptpv2-delay-req (HWTSTAMP_FILTER_PTP_V2_DELAY_REQ)

但是,如果输出是下面提供的输出,则表示不支持 PTP 硬件时间戳

复制
已复制!
            

$ ethtool -T eno1 $ ethtool -T eno1 Time stamping parameters for eno1: Capabilities: software-transmit software-receive software-system-clock PTP Hardware Clock: none Hardware Transmit Timestamp Modes: none Hardware Receive Filter Modes: none

在没有 PTP 硬件时间戳支持的情况下

即使不支持 PTP 硬件时间戳,也可以使用基于软件的时钟同步来同步不同机器的时钟。在这里,我们展示了一个如何使用 汽车 PTP 配置文件 同步两台机器时钟的示例。开发人员和管理员可以使用自己的配置文件。

选择一台机器作为时钟服务器,其他机器作为客户端。在服务器上,运行以下命令

复制
已复制!
            

sudo ptp4l -i eno1 -f linuxptp/configs/automotive-master.cfg -m -S ptp4l[7526757.990]: port 1 (eno1): INITIALIZING to MASTER on INIT_COMPLETE ptp4l[7526757.991]: port 0 (/var/run/ptp4l): INITIALIZING to LISTENING on INIT_COMPLETE ptp4l[7526757.991]: port 0 (/var/run/ptp4lro): INITIALIZING to LISTENING on INIT_COMPLETE

在客户端上,运行以下命令

复制
已复制!
            

$ sudo ptp4l -i eno1 -f linuxptp/configs/automotive-slave.cfg -m -S ptp4l[7370954.836]: port 1 (eno1): INITIALIZING to SLAVE on INIT_COMPLETE ptp4l[7370954.836]: port 0 (/var/run/ptp4l): INITIALIZING to LISTENING on INIT_COMPLETE ptp4l[7370954.836]: port 0 (/var/run/ptp4lro): INITIALIZING to LISTENING on INIT_COMPLETE ptp4l[7370956.785]: rms 5451145770 max 5451387307 freq -32919 +/- 0 delay 72882 +/- 0 ptp4l[7370957.785]: rms 5451209853 max 5451525811 freq -32919 +/- 0 delay 71671 +/- 0 ... ... wait until rms value drops in the range of orders of microseconds ptp4l[7371017.791]: rms 196201 max 324853 freq -13722 +/- 34129 delay 73814 +/- 0 ptp4l[7371018.791]: rms 167568 max 249998 freq +6509 +/- 30532 delay 73609 +/- 0 ptp4l[7371019.791]: rms 158762 max 216309 freq -8778 +/- 28459 delay 73060 +/- 0

Linux 机器上的 CLOCK_REALTIME 都同步到微秒范围。现在,分布式应用程序的不同片段可以在这些机器上运行,通过流跟踪,可以跨这些机器测量应用程序的端到端延迟。

最终,可以将 ptp4l 命令添加为 system-d 服务,以便在启动时自动启动。

在具有 PTP 硬件时间戳支持的情况下

如果支持 PTP 硬件时间戳,则可以将网卡的物理时钟同步到系统时钟 CLOCK_REALTIME。这可以通过运行以下命令来完成

复制
已复制!
            

$ sudo ptp4l -i eno1 -f linuxptp/configs/gPTP.cfg --step_threshold=1 -m & ptp4l[7527677.746]: port 1 (eno1): INITIALIZING to LISTENING on INIT_COMPLETE ptp4l[7527677.747]: port 0 (/var/run/ptp4l): INITIALIZING to LISTENING on INIT_COMPLETE ptp4l[7527677.747]: port 0 (/var/run/ptp4lro): INITIALIZING to LISTENING on INIT_COMPLETE ptp4l[7527681.663]: port 1 (eno1): LISTENING to MASTER on ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES ptp4l[7527681.663]: selected local clock f02f74.fffe.cb3590 as best master ptp4l[7527681.663]: port 1 (eno1): assuming the grand master role $ sudo pmc -u -b 0 -t 1 "SET GRANDMASTER_SETTINGS_NP clockClass 248 \ clockAccuracy 0xfe offsetScaledLogVariance 0xffff \ currentUtcOffset 37 leap61 0 leap59 0 currentUtcOffsetValid 1 \ ptpTimescale 1 timeTraceable 1 frequencyTraceable 0 \ timeSource 0xa0" sending: SET GRANDMASTER_SETTINGS_NP ptp4l[7527704.409]: port 1 (eno1): assuming the grand master role f02f74.fffe.cb3590-0 seq 0 RESPONSE MANAGEMENT GRANDMASTER_SETTINGS_NP clockClass 248 clockAccuracy 0xfe offsetScaledLogVariance 0xffff currentUtcOffset 37 leap61 0 leap59 0 currentUtcOffsetValid 1 ptpTimescale 1 timeTraceable 1 frequencyTraceable 0 timeSource 0xa0 $ sudo phc2sys -s eno1 -c CLOCK_REALTIME --step_threshold=1 --transportSpecific=1 -w -m phc2sys[7527727.996]: ioctl PTP_SYS_OFFSET_PRECISE: Invalid argument phc2sys[7527728.997]: CLOCK_REALTIME phc offset 7422791 s0 freq +628 delay 1394 phc2sys[7527729.997]: CLOCK_REALTIME phc offset 7422778 s1 freq +615 delay 1474 phc2sys[7527730.997]: CLOCK_REALTIME phc offset 118 s2 freq +733 delay 1375 phc2sys[7527731.997]: CLOCK_REALTIME phc offset 57 s2 freq +708 delay 1294 phc2sys[7527732.998]: CLOCK_REALTIME phc offset -42 s2 freq +626 delay 1422 phc2sys[7527733.998]: CLOCK_REALTIME phc offset 52 s2 freq +707 delay 1392 phc2sys[7527734.998]: CLOCK_REALTIME phc offset -65 s2 freq +606 delay 1421 phc2sys[7527735.998]: CLOCK_REALTIME phc offset -48 s2 freq +603 delay 1453 phc2sys[7527736.999]: CLOCK_REALTIME phc offset -2 s2 freq +635 delay 1392

从这里开始,其他机器上的时钟也可以同步到上述服务器时钟。

更多参考

上一篇 StandardExtension
下一篇 GXF 作业统计信息
© 版权所有 2022-2024 NVIDIA Corporation。 上次更新时间:2025 年 1 月 27 日。