查看源代码 instrument (runtime_tools v2.1.1)

用于插桩的分析和实用工具函数

instrument 模块包含用于研究 Erlang 运行时系统中资源使用情况的支持。目前,只能研究内存的分配情况。

注意

由于此模块检查运行时系统的内部细节,因此不同版本之间可能存在很大差异。我们不保证此模块的兼容性。

另请参阅

erts_alloc(3), erl(1)

摘要

类型

按其 OriginType 分组的已分配块大小(包括其头部)的摘要。

块大小的直方图,其中每个间隔的上限是前一个间隔的两倍。

AllocatorType 是采用此载体的分配器类型。

函数

返回系统中所有已标记分配的摘要,可选择按分配器类型和调度器 ID 进行筛选。

等效于 carriers(#{})

返回系统中所有载体的摘要,可选择按分配器类型和调度器 ID 进行筛选。

类型

链接到此类型

allocation_origin()

查看源代码 (未导出)
-type allocation_origin() :: atom() | mfa() | pid() | port().
链接到此类型

allocation_summary()

查看源代码 (未导出)
-type allocation_summary() ::
          {HistogramStart :: non_neg_integer(),
           UnscannedSize :: non_neg_integer(),
           Allocations :: #{Origin :: allocation_origin() => #{Type :: atom() => block_histogram()}}}.

按其 OriginType 分组的已分配块大小(包括其头部)的摘要。

Origin 通常是分配块的 NIF 或驱动程序,如果无法确定,则为“system”。

Type 是块所属的分配类别,例如 db_termmessagebinary。这些类别对应于 erl_alloc.types 中的类别。

如果一个或多个载体在不损害系统响应能力的情况下无法完全扫描,则 UnscannedSize 是必须跳过的字节数。

链接到此类型

block_histogram()

查看源代码 (未导出)
-type block_histogram() :: tuple().

块大小的直方图,其中每个间隔的上限是前一个间隔的两倍。

第一个间隔的上限由返回直方图的函数提供,最后一个间隔没有上限。

例如,下面的直方图在 128-256 字节大小之间有 40 个 (message) 块,在 256-512 字节之间有 78 个块,在 512-1024 字节之间有 2 个块,在 1-2KB 之间有 2 个块。

> instrument:allocations(#{ histogram_start => 128, histogram_width => 15 }).
{ok, {128, 0, #{ message => {0,40,78,2,2,0,0,0,0,0,0,0,0,0,0}, ... } }}
链接到此类型

carrier_info_list()

查看源代码 (未导出)
-type carrier_info_list() ::
          {HistogramStart :: non_neg_integer(),
           Carriers ::
               [{AllocatorType :: atom(),
                 InPool :: boolean(),
                 TotalSize :: non_neg_integer(),
                 UnscannedSize :: non_neg_integer(),
                 Allocations ::
                     [{Type :: atom(), Count :: non_neg_integer(), Size :: non_neg_integer()}],
                 FreeBlocks :: block_histogram()}]}.

AllocatorType 是采用此载体的分配器类型。

InPool 表示载体是否在迁移池中。

TotalSize 是载体的总大小,包括其头部。

Allocations 是载体中已分配块的摘要。请注意,当不同的分配器类型之间共享载体池时,载体可能包含多个不同的块类型(有关更多详细信息,请参阅 erts_alloc 文档)。

FreeBlocks 是载体中空闲块大小的直方图。

如果载体在不损害系统响应能力的情况下无法完全扫描,则 UnscannedSize 是必须跳过的字节数。

函数

链接到此函数

allocations()

查看源代码 (自 OTP 21.0 起)
-spec allocations() -> {ok, Result} | {error, Reason}
                     when Result :: allocation_summary(), Reason :: not_enabled.

等效于 allocations(#{})

链接到此函数

allocations(Options)

查看源代码 (自 OTP 21.0 起)
-spec allocations(Options) -> {ok, Result} | {error, Reason}
                     when
                         Result :: allocation_summary(),
                         Reason :: not_enabled,
                         Options ::
                             #{scheduler_ids => [non_neg_integer()],
                               allocator_types => [atom()],
                               histogram_start => pos_integer(),
                               histogram_width => pos_integer(),
                               flags => [per_process | per_port | per_mfa]}.

返回系统中所有已标记分配的摘要,可选择按分配器类型和调度器 ID 进行筛选。

默认情况下,只有二进制文件和 NIF 和驱动程序进行的分配会被标记,但这可以通过 +M<S>atags 模拟器选项在每个分配器的基础上进行配置。

如果指定的分配器类型未启用,则调用将失败并返回 {error, not_enabled}

可以使用以下选项

  • allocator_types - 将要搜索的分配器类型。

    当启用不同分配器类型之间的载体迁移时,指定特定的分配器类型可能会导致奇怪的结果:您可能会看到意外的类型(例如,在搜索 binary_alloc 时出现进程堆),或者如果块所在的载体已迁移到其他类型的分配器,则块数会少于预期。

    默认为所有 alloc_util 分配器。

  • scheduler_ids - 将要搜索其分配器实例的调度器 ID。调度器 ID 为 0 表示不与任何特定调度器绑定的全局实例。默认为所有调度器和全局实例。

  • histogram_start - 分配的块大小直方图中第一个间隔的上限。默认为 128。

  • histogram_width - 分配的块大小直方图中间隔的数量。默认为 18。

  • flags - 控制如何对输出进行分组,例如,显示每个进程的分配(如果可能),而不仅仅是 NIF/驱动程序基础。默认为 []

示例

> instrument:allocations(#{ histogram_start => 128, histogram_width => 15 }).
{ok,{128,0,
     #{udp_inet =>
           #{driver_event_state => {0,0,0,0,0,0,0,0,0,1,0,0,0,0,0}},
       system =>
           #{heap => {0,0,0,0,20,4,2,2,2,3,0,1,0,0,1},
             db_term => {271,3,1,52,80,1,0,0,0,0,0,0,0,0,0},
             code => {0,0,0,5,3,6,11,22,19,20,10,2,1,0,0},
             binary => {18,0,0,0,7,0,0,1,0,0,0,0,0,0,0},
             message => {0,40,78,2,2,0,0,0,0,0,0,0,0,0,0},
             ... }
       spawn_forker =>
           #{driver_select_data_state =>
                 {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}},
       ram_file_drv => #{drv_binary => {0,0,0,0,0,0,1,0,0,0,0,0,0,0,0}},
       prim_file =>
           #{process_specific_data => {2,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
             nif_trap_export_entry => {0,4,0,0,0,0,0,0,0,0,0,0,0,0,0},
             monitor_extended => {0,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
             drv_binary => {0,0,0,0,0,0,1,0,3,5,0,0,0,1,0},
             binary => {0,4,0,0,0,0,0,0,0,0,0,0,0,0,0}},
       prim_buffer =>
           #{nif_internal => {0,4,0,0,0,0,0,0,0,0,0,0,0,0,0},
             binary => {0,4,0,0,0,0,0,0,0,0,0,0,0,0,0}}}}}
链接到此函数

carriers()

查看源代码 (自 OTP 21.0 起)
-spec carriers() -> {ok, Result} | {error, Reason}
                  when Result :: carrier_info_list(), Reason :: not_enabled.

等效于 carriers(#{})

链接到此函数

carriers(Options)

查看源代码 (自 OTP 21.0 起)
-spec carriers(Options) -> {ok, Result} | {error, Reason}
                  when
                      Result :: carrier_info_list(),
                      Reason :: not_enabled,
                      Options ::
                          #{scheduler_ids => [non_neg_integer()],
                            allocator_types => [atom()],
                            histogram_start => pos_integer(),
                            histogram_width => pos_integer()}.

返回系统中所有载体的摘要,可选择按分配器类型和调度器 ID 进行筛选。

如果指定的分配器类型未启用,则调用将失败并返回 {error, not_enabled}

可以使用以下选项

  • allocator_types - 将要搜索的分配器类型。默认为所有 alloc_util 分配器。

  • scheduler_ids - 将要搜索其分配器实例的调度器 ID。调度器 ID 为 0 表示不与任何特定调度器绑定的全局实例。默认为所有调度器和全局实例。

  • histogram_start - 空闲块大小直方图中第一个间隔的上限。默认为 512。

  • histogram_width - 空闲块大小直方图中间隔的数量。默认为 14。

示例

> instrument:carriers(#{ histogram_start => 512, histogram_width => 8 }).
{ok,{512,
     [{driver_alloc,false,262144,0,
                    [{driver_alloc,1,32784}],
                    {0,0,0,0,0,0,0,1}},
      {binary_alloc,false,32768,0,
                    [{binary_alloc,15,4304}],
                    {3,0,0,0,1,0,0,0}},
      {...}|...]}}