非常教程

Erlang 20参考手册

runtime_tools

2. DTrace and Erlang/OTP

2.1历史

为Erlang虚拟机提供的DTrace探测器的第一个实现在2008 Erlang User Conference。基于Erlang / OTP R12版本的这项工作由于似乎与原始开发人员沟通不畅而终止。

几个用户已经创建了Erlang端口驱动程序,链接驱动程序或允许Erlang代码尝试激活探针的NIF,例如foo_module:dtrace_probe("message goes here!")

2.2 目标

  • 尽可能多地注释ErlangVM是可行的。
  • 最初的目标是跟踪文件I/O操作。
  • 支持所有实现DTrace的平台:OS X,Solaris和(我希望)FreeBSD和NetBSD。
  • 在实际应用中,通过DTrace提供程序兼容性支持Linux上的SystemTap。
  • 允许Erlang代码提供注释。

2.3支撑平台

  • OS X 10.6.x / Snow Leopard,OS X 10.7.x / Lion以及可能更新的版本。
  • Solaris 10.我已经在Solaris 11和OpenIndiana 151a上进行了有限的测试,并且两者似乎都可以工作。
  • FreeBSD 9.0和10.0。
  • Linux通过SystemTap兼容。请参阅$ERL_TOP/HOWTO/SYSTEMTAP.md更多细节。

--with-dynamic-trace=dtrace运行configure脚本时,只需将该选项添加到您的命令中即可。如果您正在使用systemtap,则配置选项为--with-dynamic-trace=systemtap

2.4状态

从R15B01开始,动态跟踪代码包含在OTP源代码分发中,尽管它被认为是实验性的。dtrace代码的主要发展仍然发生在爱立信之外,但是不需要获取补丁版本的OTP源以获得基本的功能。

2.5执行摘要

到目前为止,大部分工作都集中efile_drv.c在代表Erlang虚拟机实现大多数文件I / O 的代码上。该驱动程序也提出了一个很大的挑战:使用I / O工作池(erl +A 8例如使用标志启用)使跟踪I / O活动变得更加困难,因为以下每一项都可能在不同的Pthread中执行:

  • I / O启动(Erlang代码)
  • I / O代理进程处理,例如文件未在raw模式下打开时的读/写操作,由代码和文件服务器进程执行的操作。(Erlang代码)
  • efile_drv 命令设置(C代码)
  • efile_drv 命令执行(C代码)
  • efile_drv 状态返回(C代码)

示例输出lib/runtime_tools/examples/efile_drv.d执行时file:rename("old-name", "new-name")*

efile_drv enter tag={3,84} user tag some-user-tag | RENAME (12) | args: old-name new-name ,\
      0 0 (port #Port<0.59>)
async I/O worker tag={3,83} | RENAME (12) | efile_drv-int_entry
async I/O worker tag={3,83} | RENAME (12) | efile_drv-int_return
efile_drv return tag={3,83} user tag  | RENAME (12) | errno 2

...以下密钥可帮助解密输出:

  • {3,83}是分配给该I / O操作的Erlang调度程序线程号(3)和操作计数器号(83)。这两个数字一起构成I / O操作的唯一ID。
  • 12重命名操作的命令号。见定义FILE_RENAME在源代码文件中efile_drv.c或者BEGIND脚本的部分lib/runtime_tools/examples/efile_drv.d...
  • old-name并且new-namerename(2)系统调用的源和目标的两个字符串参数。两个整数参数未使用; 无论如何,简单的格式代码打印参数0和0。
  • 代表Erlang端口调用了工作池代码#Port<0.59>
  • 系统调用失败,POSIX errno值为2 ENOENT,因为路径old-name不存在。
  • efile_drv-int_entryefile_drv_int_return探针的情况下,所提供的用户感兴趣的测量仅由执行的代码的延迟efile_drv通过I / O工作池线程异步功能和OS的系统调用,它们封装。

那么,some-user-tag字符串从哪里来?

目前,用户标记来自如下代码:

dyntrace:put_tag("some-user-tag"),
file:rename("old-name", "new-name"),

这种在Erlang级别标记I/O的方法可能会改变。

2.6 示例DTrace探针规范

/**
 * Fired when a message is sent from one local process to another.
 *
 * NOTE: The 'size' parameter is in machine-dependent words and
 *       that the actual size of any binary terms in the message
 *       are not included.
 *
 * @param sender the PID (string form) of the sender
 * @param receiver the PID (string form) of the receiver
 * @param size the size of the message being delivered (words)
 * @param token_label for the sender's sequential trace token
 * @param token_previous count for the sender's sequential trace token
 * @param token_current count for the sender's sequential trace token
 */
probe message__send(char *sender, char *receiver, uint32_t size,
                    int token_label, int token_previous, int token_current);

/**
 * Fired when a message is sent from a local process to a remote process.
 *
 * NOTE: The 'size' parameter is in machine-dependent words and
 *       that the actual size of any binary terms in the message
 *       are not included.
 *
 * @param sender the PID (string form) of the sender
 * @param node_name the Erlang node name (string form) of the receiver
 * @param receiver the PID/name (string form) of the receiver
 * @param size the size of the message being delivered (words)
 * @param token_label for the sender's sequential trace token
 * @param token_previous count for the sender's sequential trace token
 * @param token_current count for the sender's sequential trace token
 */
probe message__send__remote(char *sender, char *node_name, char *receiver,
                            uint32_t size,
                    int token_label, int token_previous, int token_current);

/**
 * Fired when a message is queued to a local process.  This probe
 * will not fire if the sender's pid == receiver's pid.
 *
 * NOTE: The 'size' parameter is in machine-dependent words and
 *       that the actual size of any binary terms in the message
 *       are not included.
 *
 * @param receiver the PID (string form) of the receiver
 * @param size the size of the message being delivered (words)
 * @param queue_len length of the queue of the receiving process
 * @param token_label for the sender's sequential trace token
 * @param token_previous count for the sender's sequential trace token
 * @param token_current count for the sender's sequential trace token
 */
probe message__queued(char *receiver, uint32_t size, uint32_t queue_len,
                    int token_label, int token_previous, int token_current);

/**
 * Fired when a message is 'receive'd by a local process and removed
 * from its mailbox.
 *
 * NOTE: The 'size' parameter is in machine-dependent words and
 *       that the actual size of any binary terms in the message
 *       are not included.
 *
 * @param receiver the PID (string form) of the receiver
 * @param size the size of the message being delivered (words)
 * @param queue_len length of the queue of the receiving process
 * @param token_label for the sender's sequential trace token
 * @param token_previous count for the sender's sequential trace token
 * @param token_current count for the sender's sequential trace token
 */
probe message__receive(char *receiver, uint32_t size, uint32_t queue_len,
                    int token_label, int token_previous, int token_current);

/* ... */

/* Async driver pool */

/**
 * Show the post-add length of the async driver thread pool member's queue.
 *
 * NOTE: The port name is not available: additional lock(s) must
 *       be acquired in order to get the port name safely in an SMP
 *       environment.  The same is true for the aio__pool_get probe.
 *
 * @param port the Port (string form)
 * @param new queue length
 */
probe aio_pool__add(char *, int);

/**
 * Show the post-get length of the async driver thread pool member's queue.
 *
 * @param port the Port (string form)
 * @param new queue length
 */
probe aio_pool__get(char *, int);

/* Probes for efile_drv.c */

/**
 * Entry into the efile_drv.c file I/O driver
 *
 * For a list of command numbers used by this driver, see the section
 * "Guide to probe arguments" in ../../../README.md.  That section
 * also contains explanation of the various integer and string
 * arguments that may be present when any particular probe fires.
 *
 * TODO: Adding the port string, args[10], is a pain.  Making that
 *       port string available to all the other efile_drv.c probes
 *       will be more pain.  Is the pain worth it?  If yes, then
 *       add them everywhere else and grit our teeth.  If no, then
 *       rip it out.
 *
 * @param thread-id number of the scheduler Pthread                   arg0
 * @param tag number: {thread-id, tag} uniquely names a driver operation
 * @param user-tag string                                             arg2
 * @param command number                                              arg3
 * @param string argument 1                                           arg4
 * @param string argument 2                                           arg5
 * @param integer argument 1                                          arg6
 * @param integer argument 2                                          arg7
 * @param integer argument 3                                          arg8
 * @param integer argument 4                                          arg9
 * @param port the port ID of the busy port                       args[10]
 */
probe efile_drv__entry(int, int, char *, int, char *, char *,
                       int64_t, int64_t, int64_t, int64_t, char *);

/**
 * Entry into the driver's internal work function.  Computation here
 * is performed by a async worker pool Pthread.
 *
 * @param thread-id number
 * @param tag number
 * @param command number
 */
probe efile_drv__int_entry(int, int, int);

/**
 * Return from the driver's internal work function.
 *
 * @param thread-id number
 * @param tag number
 * @param command number
 */
probe efile_drv__int_return(int, int, int);

/**
 * Return from the efile_drv.c file I/O driver
 *
 * @param thread-id number                                            arg0
 * @param tag number                                                  arg1
 * @param user-tag string                                             arg2
 * @param command number                                              arg3
 * @param Success? 1 is success, 0 is failure                         arg4
 * @param If failure, the errno of the error.                         arg5
 */
probe efile_drv__return(int, int, char *, int, int, int);

2.7 efile_drv.c探针参数指南

/* Driver op code: used by efile_drv-entry      arg3 */
/*                 used by efile_drv-int_entry  arg3 */
/*                 used by efile_drv-int_return arg3 */
/*                 used by efile_drv-return     arg3 */

#define FILE_OPEN            1                 (probe arg3)
        probe arg6 = C driver dt_i1 = flags;
        probe arg4 = C driver dt_s1 = path;

#define FILE_READ            2                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;
        probe arg7 = C driver dt_i2 = flags;
        probe arg8 = C driver dt_i3 = size;

#define FILE_LSEEK           3                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;
        probe arg7 = C driver dt_i2 = offset;
        probe arg8 = C driver dt_i3 = origin;

#define FILE_WRITE           4                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;
        probe arg7 = C driver dt_i2 = flags;
        probe arg8 = C driver dt_i3 = size;

#define FILE_FSTAT           5                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;

#define FILE_PWD             6                 (probe arg3)
        none

#define FILE_READDIR         7                 (probe arg3)
        probe arg4 = C driver dt_s1 = path;

#define FILE_CHDIR           8                 (probe arg3)
        probe arg4 = C driver dt_s1 = path;

#define FILE_FSYNC           9                 (probe arg3)
            probe arg6 = C driver dt_i1 = fd;

#define FILE_MKDIR          10                 (probe arg3)
        probe arg4 = C driver dt_s1 = path;

#define FILE_DELETE         11                 (probe arg3)
        probe arg4 = C driver dt_s1 = path;

#define FILE_RENAME         12                 (probe arg3)
        probe arg4 = C driver dt_s1 = old_name;
        probe arg5 = C driver dt_s2 = new_name;

#define FILE_RMDIR          13                 (probe arg3)
        probe arg4 = C driver dt_s1 = path;

#define FILE_TRUNCATE       14                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;
        probe arg7 = C driver dt_i2 = flags;

#define FILE_READ_FILE      15                 (probe arg3)
        probe arg4 = C driver dt_s1 = path;

#define FILE_WRITE_INFO     16                 (probe arg3)
        probe arg6 = C driver dt_i1 = mode;
        probe arg7 = C driver dt_i2 = uid;
        probe arg8 = C driver dt_i3 = gid;

#define FILE_LSTAT          19                 (probe arg3)
        probe arg4 = C driver dt_s1 = path;

#define FILE_READLINK       20                 (probe arg3)
        probe arg4 = C driver dt_s1 = path;

#define FILE_LINK           21                 (probe arg3)
        probe arg4 = C driver dt_s1 = existing_path;
        probe arg5 = C driver dt_s2 = new_path;

#define FILE_SYMLINK        22                 (probe arg3)
        probe arg4 = C driver dt_s1 = existing_path;
        probe arg5 = C driver dt_s2 = new_path;

#define FILE_CLOSE          23                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;
        probe arg7 = C driver dt_i2 = flags;

#define FILE_PWRITEV        24                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;
        probe arg7 = C driver dt_i2 = flags;
        probe arg8 = C driver dt_i3 = size;

#define FILE_PREADV         25                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;
        probe arg7 = C driver dt_i2 = flags;
        probe arg8 = C driver dt_i3 = size;

#define FILE_SETOPT         26                 (probe arg3)
        probe arg6 = C driver dt_i1 = opt_name;
        probe arg7 = C driver dt_i2 = opt_specific_value;

#define FILE_IPREAD         27                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;
        probe arg7 = C driver dt_i2 = flags;
        probe arg8 = C driver dt_i3 = offsets[0];
        probe arg9 = C driver dt_i4 = size;

#define FILE_ALTNAME        28                 (probe arg3)
        probe arg4 = C driver dt_s1 = path;

#define FILE_READ_LINE      29                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;
        probe arg7 = C driver dt_i2 = flags;
        probe arg8 = C driver dt_i3 = read_offset;
        probe arg9 = C driver dt_i4 = read_ahead;

#define FILE_FDATASYNC      30                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;

#define FILE_FADVISE        31                 (probe arg3)
        probe arg6 = C driver dt_i1 = fd;
        probe arg7 = C driver dt_i2 = offset;
        probe arg8 = C driver dt_i3 = length;
        probe arg9 = C driver dt_i4 = advise_type;
Erlang 20

Erlang 是一种通用的面向并发的编程语言,可应付大规模开发活动的程序设计语言和运行环境。

主页 https://www.erlang.org/
源码 https://github.com/erlang/otp
版本 20
发布版本 20.1