A little Morphine Tutorial

Morphine is a trace analysis system of Mercury programs. The goal of this tutorial is to give you an rough idea about what Morphine is. If you want a more exhaustive presentation, please refer to the Getting started and A debugging session with Morphine sections of the Morphine User Manual.

This tutorial consists in a Morphine trace analysis session of a Mercury version of the  program that solves the famous N-queens problem (queens.m).

  1. Running Morphine
  2. Morphine = Prolog +  current/1  +  next/0
  3. Toward an efficient extensible debugger: fget/1
  4. Toward efficient extensible monitors: collect/2 (also called foldt/2)
  5. If you want to know more about Morphine...

Running Morphine

$ mmc --trace deep queens.m
This creates the executable program `queens'.
  • Now, let's run Morphine!

  • Morphine = Prolog +  current/1  +  next/0

    Only two primitives plus Prolog are enough to build a powerful trace analysis system. In this section, we are not concerned with efficiency; we will deal with efficiency issues in the next two sections. Let me first quickly show what those two primitives `current/1' and `next/0' are.

    Toward an efficient extensible debugger: fget/1

    The problem with the previously described trace analysis system is the efficiency. Each time you need to move one event forward in the execution, you send a message to the debuggee process, receive a response from it, and then interpret it. This message exchange together with the Operating System level context switches it induces can cost a lot, especially to process a million of execution events, which is quite common.

    In order to avoid those inter process communications, we introduced a new primitive, called `fget/1', that filters out execution events in the debuggee process. Actually, fget(ListOf Attributes) does exactly the same job as the sequence of goals next_np, current(ListOfAttributes) except it requires only one communication between Morphine and the debuggee (instead of 32, as it required in the previous example).

    Toward efficient extensible monitors: collect/2 (also called foldt/2)

    The primitives fget/1 and current/1 are enough to efficiently implement most debugging commands. But when it comes to write monitors (a monitor is a program that analyses and extracts run time information about a whole program execution, like the count_call/1 program we have just given) then it turns out that it is not satisfactory. For example, the fget/1 version of the monitor that counts the number of calls may require  about 1/5 of the communications the next/0 version needs; but if we want to monitor a 5 million events execution, this means that it still requires about one million message exchanges. The idea is that for monitoring a whole program execution, it is not necessary to interact with the program as in debugging, and thus you do not want to pay the price induced by the coroutining. With collect/2, we will be able to do it in one pass.

    If you want to know more about Morphine...

  • You can have a look at the HTML version the Morphine User and Reference manual. You can also play with the on-line help features, i.e., using the `man/1' and the `apropos/1' commands.
  • [morphine]: man apropos.
    apropos(Name) {a}
    Command which displays all the commands, primitives, procedures, parameters, or
    types for which Name is a substring of.
    [morphine]: apropos man.
    Name : atom
    type of command : opium