MOO-cows Mailing List Archive

[Prev][Next][Index][Thread]

profiling



Well, I've been silent another week, but rest assured, I _have_ been
paying attention; it's been really interesting, not least because I've
seen a good number of proposals that I hadn't seen before.  Rather
than try to respond to each message individually, I'm going to try,
over the next few days, to group the discussion into some common areas
and give some thoughts on those.

I think the feature that's been requested most and argued about the
least is a MOO-code profiler--tools that would allow programmers to
determine what parts of their code are slowing things down, what's
called most, what would be good to optimize, and so on.  Some of you
know that Pavel asked would-be server maintainers to write a profiler;
a few of you know that I got a design and much of an implementation
done, but not the whole thing.  Since there's demand and I have some
grasp on the issues already, I'm likely to do this one.

(People who aren't interested in profiling can safely stop reading here.)

The main problem with my design was that it was made in a near-vacuum.
I'd like to hear from the rest of you--and particularly those of you
who really want a profiler--how you think it should work.  There are
radically different ways to do it; I'd like to hear alternatives,
although I reserve the final decision for myself.

I'll start by throwing out my design, so people can point out the
flaws and suggest improvements or complete rewrites.  Here's an
excerpt from the documentation I wrote for the main profiling
facility:

------------------------------------------------------------------------
In order for programmers to write efficient code with reasonable effort,
it is often useful to find out where the MOO virtual machine is spending
most of its time in executing some application or utility.  This allows
them to concentrate their efforts on code that is actually called often
or noticeably expensive, rather than perhaps spending too much time on
code sections that will have little effect on overall execution time.

The /profile/ statement can be used to gather this data about
execution cost.  It provides a listing of the verbs called in executing
a particular sequence of statements, along with information about how
many times they are used, how long each of them runs, and so on.  Its
syntax is this:

    profile variable
      statements
    endprofile

The /profile/ statement first executes the statements; the given
variable is not assigned a value prior to or during their execution.
After the statements are executed, the variable is assigned a value
containing profiling data from the execution of the statements.  (Any
tasks forked during their execution will not be profiled.)

[ ... details about the format of profiling data deleted; suffice it
  to say it's a list of lists with information about each verb. ]

Where execution enters a verb not readable by the programmer of the
profile statement, no information is provided about the verbs it calls.
(Otherwise, a programmer would be able to infer much of the contents of
an unreadable verb just by calling it inside a profile statement.)
Profiling data for the unreadable verb itself is still provided; the
verb name used will be the name it is called with.

After the profiled statements execute, the given variable is available
and initially contains the profiling data -- even if the profiled
statements exit by returning a value or raising an error.  In this
way, the /profile/ statement is similar to the /try/ statement.
However, /profile/ does *not* guarantee that code following it will be
run; the /try/ statement must still be used if that is required.

A typical method of profiling, then, would be to wrap a /profile/
statement around a verb one wishes to gather data on, using a variable
known not to be used in the verb; wrap a /try/ statement around
that; and provide a /finally/ clause that will store the data in
some useful place, so that data from multiple invocations under typical
use can be examined later, summed and averaged.  The code for this might
then look something like this:

    try
      profile profile_data
        this:go_about_my_usual_business();
      endprofile
    finally
      this.profile = {@this.profile_data, profile_data};
    endtry
------------------------------------------------------------------------

The idea is that you could fairly easily write a verb `@profile
object:verb', which would automatically wrap foo:bar's code in try/profile
statements.  Note that any programmer could do this for eir own code.

In addition, since a lot of the demand for profiling is (I think) from
wizards who want to speed up their MUDs, there was to be a global
profiling facility:

  x = global_profile(NUM n)

/global_profile/ suspends for n seconds, then returns profiling data
(in the same form as the /profile/ statement) for all the code
executed during that time.

So, things for people to react to, off the top of my head:

  * Do we need a programmer-level profiling facility?
  * Do we need a global profiling facility?
  * Is it appropriate to use a statement for profiling?
  * (What are other alternatives?)
  * What, if anything, should be done about forked tasks?
  * Are lists of lists a good format?
  * (What are other alternatives?)
  * What should the user interface to profiling be?  (I.e., is
    `@profile object:verb' sufficient?  I don't intend to write
    the in-db layers of profiling, but requirements for that
    may affect the design of the server facility.)
  * Did you have some totally different model in your head for
    how this would work?
  * Anything else?

Comments, please.

--Erik


Follow-Ups:

Home | Subject Index | Thread Index