[erlang-questions] DTrace plug, was Re: Profiling tool to find bottleneck on my Erlang code

Scott Lystig Fritchie <>
Sat Oct 8 22:54:58 CEST 2011


Zabrane Mickael <> wrote:

mz> Could someone please point me to a good "high level profiling tool"
mz> (not eprof/fprof which we already now, and find not very sexy) to
mz> tracks bottlenecks?

Mickael, you didn't say if your application is perhaps CPU-bound or
I/O-bound (disk I/O or network I/O) or if that's what you're trying to
figure out.

OS system measurement tools like "iostat" and "sar" can help answer the
above question.  (Just in case you haven't considered them ... they're
quite useful, especially detailed stats generation by "iostat -xk" on
Linux or "sar -ugd" on Solaris.)

In collaboration with Michal Ptaszek (Erlang Solutions) and Dustin
Sallings (CouchBase), I've been working on adding DTrace probes to the
Erlang virtual machine.  The latest work is available on the
"dtrace-experiment+michal2" branch of the
git://github.com/slfritchie/otp.git source repo.  I know that this
compiles cleanly on a Mac Snow Leopard machine as well as Solaris 10 +
GCC 4.2.1.(*)

Though there's plenty more probes to add (and testing to do :-), I'll
include a copy of the current probe definition file below.  If it can
help with your search, great!  If not, spread the word at least.  We'll
gladly accept patches for new probes.

-Scott

(*) I haven't tried yet using Linux + SystemTap's DTrace compatibility
mode because SystemTap's user-space tracing is a case study in usability
horror and documentation ghostworld.

--- snip --- snip --- snip --- snip --- snip ---

/*
 * %CopyrightBegin%
 *
 * Copyright Dustin Sallings, Michal Ptaszek, Scott Lystig Fritchie 2011.
 * All Rights Reserved.
 *
 * The contents of this file are subject to the Erlang Public License,
 * Version 1.1, (the "License"); you may not use this file except in
 * compliance with the License. You should have received a copy of the
 * Erlang Public License along with this software. If not, it can be
 * retrieved online at http://www.erlang.org/.
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 * the License for the specific language governing rights and limitations
 * under the License.
 *
 * %CopyrightEnd%
 */

provider erlang {
    /**
     * Fired when a message is sent from one local process to another.
     *
     * @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
     */
    probe send(char *sender, char *receiver, uint32_t size);

    /**
     * Fired when a message is delivered to a local process.
     *
     * @param receiver the PID (string form) of the receiver
     * @param size the size of the message being delivered
     * @param queue_len length of the queue of the receiving process
     */
    probe receive(char *receiver, uint32_t size, uint32_t queue_len);

    /**
     * Fired when an Eterm structure is being copied.
     *
     * @param size the size of the structure
     */
    probe copy_struct(uint32_t size);

    /**
     * Fired when an Eterm is being copied onto a process.
     *
     * @param proc the PID (string form) of the recipient process
     * @param size the size of the structure
     */
    probe copy_object(char *proc, uint32_t size);

    /* PID, Module, Function, Arity */

    /**
     * Fired whenever a user function is being called.
     *
     * @param p the PID (string form) of the process
     * @param mfa the m:f/a of the function
     * @param depth the stack depth
     */
    probe function_entry(char *p, char *mfa, int depth);

    /**
     * Fired whenever a user function returns.
     *
     * @param p the PID (string form) of the process
     * @param mfa the m:f/a of the function
     * @param depth the stack depth
     */
    probe function_return(char *p, char *mfa, int depth);

    /**
     * Fired whenever a Built In Function is called.
     *
     * @param p the PID (string form) of the process
     * @param mfa the m:f/a of the function
     */
    probe bif_entry(char *p, char *mfa);

    /**
     * Fired whenever a Built In Function returns.
     *
     * @param p the PID (string form) of the process
     * @param mfa the m:f/a of the function
     */
    probe bif_return(char *p, char *mfa);

    /**
     * Fired whenever a Native Function is called.
     *
     * @param p the PID (string form) of the process
     * @param mfa the m:f/a of the function
     */
    probe nif_entry(char *p, char *mfa);

    /**
     * Fired whenever a Native Function returns.
     *
     * @param p the PID (string form) of the process
     * @param mfa the m:f/a of the function
     */
    probe nif_return(char *p, char *mfa);

    /**
     * Fired when a process is spawned.
     *
     * @param p the PID (string form) of the new process.
     * @param mfa the m:f/a of the function
     */
    probe spawn(char *p, char *mfa);

    /**
     * Fired when a process is exiting.
     *
     * @param p the PID (string form) of the exiting process
     * @param reason the reason for the exit (may be truncated)
     */
    probe exit(char *p, char *reason);

    /**
     * Fired when exit signal is delivered to a local process.
     *
     * @param sender the PID (string form) of the exiting process
     * @param receiver the PID (string form) of the process receiving EXIT signal
     * @param reason the reason for the exit (may be truncated)
     */
    probe exit_signal(char *sender, char *receiver, char *reason);

    /**
     * Fired when a major GC is starting.
     *
     * @param p the PID (string form) of the exiting process
     * @param need the number of words needed on the heap
     */
    probe gc_major_start(char *p, int need);

    /**
     * Fired when a minor GC is starting.
     *
     * @param p the PID (string form) of the exiting process
     * @param need the number of words needed on the heap
     */
    probe gc_minor_start(char *p, int need);

    /**
     * Fired when a major GC is starting.
     *
     * @param p the PID (string form) of the exiting process
     * @param reclaimed the amount of space reclaimed
     */
    probe gc_major_end(char *p, int reclaimed);

    /**
     * Fired when a minor GC is starting.
     *
     * @param p the PID (string form) of the exiting process
     * @param reclaimed the amount of space reclaimed
     */
    probe gc_minor_end(char *p, int reclaimed);

    /**
     * Fired when a process is scheduled.
     *
     * @param p the PID (string form) of the newly scheduled process
     * @param mfa the m:f/a of the function it should run next
     */
    probe process_scheduled(char *p, char *mfa);

    /**
     * Fired when a process is unscheduled.
     *
     * @param p the PID (string form) of the process that has been
     * unscheduled.
     */
    probe process_unscheduled(char *p);

    /**
     * Fired when a process goes into hibernation.
     *
     * @param p the PID (string form) of the process entering hibernation
     * @param mfa the m:f/a of the location to resume
     */
    probe hibernate(char *p, char *mfa);

    /**
     * Fired when process' heap is growing.
     *
     * @param p the PID (string form) of the existing process
     * @param old_size the size of the old heap
     * @param new_size the size of the new heap
     */
    probe process_heap_grow(char *p, int old_size, int new_size);

    /**
     * Fired when process' heap is shrinking.
     *
     * @param p the PID (string form) of the existing process
     * @param old_size the size of the old heap
     * @param new_size the size of the new heap
     */
    probe process_heap_shrink(char *p, int old_size, int new_size);

    /**
     * Fired when port_command is issued.
     *
     * @param proces the PID (string form) of the existing process
     * @param port the Port (string form) of the existing port
     * @param port_name the string used when opening a port
     * @param command_type type of the issued command, one of: "close", "command" or "connect"
     */
    probe port_command(char *process, char *port, char *port_name, char *command_type);

    /**
     * Fired when port_control is issued.
     *
     * @param proces the PID (string form) of the existing process
     * @param port the Port (string form) of the existing port
     * @param port_name the string used when opening a port
     * @param command_no command number that has been issued to the port
     */
    probe port_control(char *process, char *port, char *port_name, int command_no);


    /* Async driver pool */

    /**
     * Show the post-add length of the async driver thread pool member's queue.
     *
     * @param pool member number
     * @param new queue length
     */
    probe async_io_pool_add(int, int);

    /**
     * Show the post-get length of the async driver thread pool member's queue.
     *
     * @param pool member number
     * @param new queue length
     */
    probe async_io_pool_get(int, 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.
     *
     * @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
     */
    probe file_drv_entry(int, int, char *, int, char *, char *,
    			  int64_t, int64_t, int64_t, int64_t);

    /*     0       1              2       3     */
    /* thread-id, tag, work-thread-id,  command */
    /**
     * 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 worker pool thread-id number
     * @param command number
     */
    probe file_drv_int_entry(int, int, int, int);

    /**
     * Return from the driver's internal work function.
     *
     * @param thread-id number
     * @param tag number
     * @param worker pool thread-id number
     * @param command number
     */
    probe file_drv_int_return(int, 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
     * @param thread-id number of the scheduler Pthread executing now     arg6
     */
    probe file_drv_return(int, int, char *, int, int, int, int);
};

#pragma D attributes Evolving/Evolving/Common provider erlang provider
#pragma D attributes Private/Private/Common provider erlang module
#pragma D attributes Private/Private/Common provider erlang function
#pragma D attributes Evolving/Evolving/Common provider erlang name
#pragma D attributes Evolving/Evolving/Common provider erlang args



More information about the erlang-questions mailing list