Adding custom load URL probes to Mozilla

Hi - having fun at the minute with an onsite workshop on DTrace with the Mozilla folks in Menlo Park. Brendan Gregg treated us to a bunch of live DTrace demos that really showed how you can get that system wide view across the stack that is impossible with conventional tools :) Now if we could just clone Brendan that would be ideal. The real learning comes from doing and just watching how Brendan formulates questions then explores the problem with dtrace, doing some quick profiling, identifying areas of interest, dumping ustacks, grabbing functions, checking timings and so on. The syntax is easy, the mind set is a lot tougher to capture.

The reason we are over with Mozilla having the workshop in the first place is to help work on the DTrace Tracing framework in Mozilla, which should really help the community identify and fix performance issues in Mozilla, be it in the Javascript XUL layer, the C++ layer or in some dependent platform or system lib.

Having a framework is pretty cool, but not much use if you have no useful probes built on top of it. Brendan has created Javascript probes which hopefully will help dig into a lot of performance issues in this layer. In addition to the Javascript probes we want to add some C++ probes to track things like page loading.

With Johnny Steinbeck's help, Brendan and crew added loadURI_start / done probes.

Here's a quick brain dump of what we needed to do to add them. I'll blog later when we start using them to do some interesting timing analysis.

 

Using new Load URI Probes

$dtrace -nl mozilla\*::mozdtrace_load_uri_start:load_uri_start

$ dtrace -ln "moz\*:::"
   ID   PROVIDER            MODULE                          FUNCTION NAME
71986 mozilla18214         libxul.so          mozdtrace_load_uri_start load-uri-start
71987 mozilla18214         libxul.so          mozdtrace_load_uri_done load-uri-done

$ dtrace -qn moz\*:::'{printf("%s\\n",copyinstr(arg0));}'
http://www.mozilla.org/


Adding Load URI Probes

mozilla/mozilla-dtrace.d

Add the new dtrace probes:

/\*
 \* load__uri__start        (char \* uri)
 \* load__uri__done        (char \* uri)
\*/

provider mozilla {
    :
 probe load__uri__start(char \* );
 probe load__uri__done(char \* );
    :
};

mozilla/toolkit/library/Makefile.in

Add probe lib to MOZILLA_PROBE_LIBS:

ifdef HAVE_DTRACE
ifdef MOZ_ENABLE_LIBXUL
NEED_DTRACE_PROBE_OBJ = mozilla-dtrace.$(OBJ_SUFFIX)
MOZILLA_PROBE_LIBS = $(DEPTH)/staticlib/components/$(LIB_PREFIX)docshell.$(LIB_SUFFIX)
MOZILLA_DTRACE_SRC = $(DEPTH)/mozilla-trace.d
endif
endif
    :
include $(topsrcdir)/config/rules.mk

Note: Adding probe lib to MOZILLA_PROBE_LIBS here so object file with probe can be post processed by dtrace -G
Processing step pulled in to the make from mozilla/config/rules.mk

ifdef HAVE_DTRACE
ifdef DTRACE_PROBE_OBJ
$(DTRACE_PROBE_OBJ): $(OBJS)
    dtrace -G -C -32 -s $(MOZILLA_DTRACE_SRC) -o $(DTRACE_PROBE_OBJ) $(OBJS)
endif
endif

-G: tells dtrace to process the list of .o's looking for USDT probes, change
their status to IGNORE and generate a special <probe>.o that you should link
against so the kernel linker can correctly initialize things when the shared
lib is loaded.
-C: use the C preprocessor to process the specified .d file, allows you to have
#includes
-32: compile for 32 bit architecture, we need to change this so it
will work on 64 bit arch as well
-s: source of probes, mozilla-trace.d in this instance
-o: output special <probe>.o file, call it anything you want, just need to link
against it.

mozilla/docshell/build/Makefile.in

Note: If building debug, components of XUL shared lib are not linked into it, so need to add probe libs below.

EXTRA_DSO_LDOPTS= \\
        $(LIBS_DIR) \\
        $(EXTRA_DSO_LIBS) \\
        $(MOZ_JS_LIBS) \\
        $(MOZ_UNICHARUTIL_LIBS) \\
        $(MOZ_COMPONENT_LIBS) \\
        $(NULL)

ifdef HAVE_DTRACE
ifndef MOZ_ENABLE_LIBXUL
NEED_DTRACE_PROBE_OBJ = mozilla-dtrace.$(OBJ_SUFFIX)
MOZILLA_PROBE_LIBS = ../base/$(LIB_PREFIX)docshell.$(LIB_SUFFIX)
MOZILLA_DTRACE_SRC = $(DEPTH)/mozilla-trace.d
endif
endif

include $(topsrcdir)/config/rules.mk

LOCAL_INCLUDES    = \\
        -I$(srcdir) \\
    :

mozilla/docshell/base/nsDocShell.h

Add wrapper functions for the probes to give sensible function names, otherwise get mangled C++ enclosing function names :(

#ifdef INCLUDE_MOZILLA_DTRACE
#include "mozilla-trace.h"

extern "C" {
void mozdtrace_load_uri_start(nsIURI \* aURI);
void mozdtrace_load_uri_done(nsIChannel \* aChannel);
}
#endif /\* INCLUDE_MOZILLA_DTRACE \*/

#ifdef INCLUDE_MOZILLA_DTRACE
#define TRACE_MOZILLA_LOAD_URI_START_POINT(uri_) \\
  mozdtrace_load_uri_start((uri_))
#define TRACE_MOZILLA_LOAD_URI_DONE_POINT(uri_) \\
  mozdtrace_load_uri_done((uri_))

#else
#define TRACE_MOZILLA_LOAD_URI_START_POINT(uri_) \\
  PR_BEGIN_MACRO PR_END_MACRO
#define TRACE_MOZILLA_LOAD_URI_DONE_POINT(uri_) \\
  PR_BEGIN_MACRO PR_END_MACRO

#endif /\* INCLUDE_MOZILLA_DTRACE \*/


Note: Tried putting MOZILLA_LOAD_URI_START_ENABLED() around wrapper func, mozdtrace_load_uri_start, but get two func probes
if we do this.
6202 mozilla23090         libxul.so             __1cKnsDocShellJDoURILoad6MpnGnsIURI_2ipnLnsISupports_pkcpnOnsIInputStream_8ippnLnsIDocShell_ppnKnsIRequest_i_I_ load-uri-start
6203 mozilla23090         libxul.so             mozdtrace_load_uri_start load-uri-start

mozilla/docshell/base/nsDocShell.cpp

Define wrapper probe functions and add custom probe macros to load URI start and end points.

#include "mozilla-trace.h"
    :

// Implementation of probe func wrapper
#ifdef INCLUDE_MOZILLA_DTRACE
void mozdtrace_load_uri_start(nsIURI \* aURI)
{
    if (MOZILLA_LOAD_URI_START_ENABLED()) { 
        nsCAutoString spec;
        aURI->GetASCIISpec(spec);

        MOZILLA_LOAD_URI_START((char \*)spec.get());
    }
}

void mozdtrace_load_uri_done(nsIChannel \* aChannel)
{
   /\* XXX DTrace load-uri-done \*/
    if (MOZILLA_LOAD_URI_DONE_ENABLED()) {
       nsCOMPtr<nsIURI> uri;
       nsCAutoString spec;
       aChannel->GetURI(getter_AddRefs(uri));

       uri->GetASCIISpec(spec);
       MOZILLA_LOAD_URI_DONE((char \*)spec.get());
    }
}
#endif

    :

nsresult
nsDocShell::DoURILoad(nsIURI \* aURI, ....)
    :

     /\* DTrace URI probe \*/
    TRACE_MOZILLA_LOAD_URI_START_POINT(aURI);

    rv = DoChannelLoad(channel, uriLoader);
    :   
}

nsresult
nsDocShell::EndPageLoad(nsIWebProgress \* aProgress,
                        nsIChannel \* aChannel, nsresult aStatus)
{
    :
    nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
    :
// NOTE: if this is moved to the top of the function then we get two USDT probes instead of one:
// mozilla7863         libxul.so __1cKnsDocShellLEndPageLoad6MpnOnsIWebProgress_pnKnsIChannel_I_I_ load-uri-done
// mozilla7863         libxul.so           mozdtrace_load_uri_done load-uri-done
    TRACE_MOZILLA_LOAD_URI_DONE_POINT(aChannel);

DTrace request for enhancement:

Allow an optional function name to be specified in probe description:

provider mozilla {
    :
 probe mozdtrace_load_uri_start:load__uri__start(char \* );
 probe mozdtrace_load_uri_done:load__uri__done(char \* );
}
 

This would be so handy when putting USDT probes into C++ code. No need for the wrapper funcs we are using above :) 

 


 

Comments:

Post a Comment:
Comments are closed for this entry.
About

jmr

Search

Top Tags
Categories
Archives
« April 2014
MonTueWedThuFriSatSun
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    
       
Today