Tuesday, January 24, 2012

A Perl tracer example

For an example of what can be done with a Perl tracer, let's make a tracer function that works like UnitTracerStringName but prints the whole rowop contents too. In a "proper" way that would be an object, but to reduce the amount of code let's just make it a standalone function. It can be then used as a method of an object as well.

Note: this code has not been tested, so it might work or not work at the moment. I'll test and fix it later.

The function would take 3 extra arguments:
  • boolean: verbosity
  • reference to a variable where to append the text of the trace
  • reference to a variable that would be used to keep the chaining level

The code is as follows:

sub traceStringRowop
{
  my ($unit, $label, $fromLabel, $rowop, $when, $verbose, $rlog, $rnest) = @_;
  return if (!$verbose && $when != &Triceps::TW_BEFORE);
  ${$rnest}-- if ($when != &Triceps::TW_BEFORE);
  my $msg =  "unit '" . $unit->getName() . "' " 
    . Triceps::tracerWhenHumanString($when) . " label '"
    . $label->getName() . "' ";
  if (defined $fromLabel) {
    $msg .= "(chain '" . $fromLabel->getName() . "') ";
  }
  ${$rlog} .=  ("  " x $rnest) . $msg . "op " . $rowop->printP() . "\n";
  if ($verbose) {
    if ($when != &Triceps::TW_AFTER) {
      ${$rnest}++;
    } else {
      ${$rnest}--;
    }
  }
}

It is then supposed to be used like:

my ($traceLog, $traceNest);
$tracer = Ticeps::UnitTracerPerl->new(
  1, \&tracerStringRowop, \$traceLog, \$traceNest);

And produce the nicely formatted nested traces. For the previous example the nesting would be:

unit 'u' before label 'lab1' op ...
  unit 'u' drain label 'lab1' op ...
  unit 'u' before-chained label 'lab1' op ...
    unit 'u' before label 'lab2' (chain 'lab1') op ...
      unit 'u' drain label 'lab2' (chain 'lab1') op ...
      unit 'u' before-chained label 'lab2' (chain 'lab1') op ...
        unit 'u' before label 'lab3' (chain 'lab2') op ...
          unit 'u' drain label 'lab3' (chain 'lab2') op ...
          unit 'u' after label 'lab3' (chain 'lab2') op ...
      unit 'u' after label 'lab2' (chain 'lab1') op ...
    unit 'u' before label 'lab3' (chain 'lab1') op ...
      unit 'u' drain label 'lab3' (chain 'lab1') op ...
      unit 'u' after label 'lab3' (chain 'lab1') op ...
  unit 'u' after label 'lab1' op ...
unit 'u' before label 'lab1' op ...
  unit 'u' drain label 'lab1' op ...
  unit 'u' before-chained label 'lab1' op ...
    unit 'u' before label 'lab2' (chain 'lab1') op ...
      unit 'u' drain label 'lab2' (chain 'lab1') op ...
      unit 'u' before-chained label 'lab2' (chain 'lab1') op ...
        unit 'u' before label 'lab3' (chain 'lab2') op ...
          unit 'u' drain label 'lab3' (chain 'lab2') op ...
          unit 'u' after label 'lab3' (chain 'lab2') op ...
      unit 'u' after label 'lab2' (chain 'lab1') op ...
    unit 'u' before label 'lab3' (chain 'lab1') op ...
      unit 'u' drain label 'lab3' (chain 'lab1') op ...
      unit 'u' after label 'lab3' (chain 'lab1') op ...
  unit 'u' after label 'lab1' op ...

Each label produces two levels of nesting: one for everything after "before", another one for the nested labels. In reality this nested idea might be not that great because when a label calls another one, that will be nested, and the long call sequences may produce some very deep and unreadable nesting.

No comments:

Post a Comment