[Back to RTFL documentation.]

Tips and tricks

Here, I'll summarize some useful experiences during the work on dillo, for which RTFL was initially written.

Preparing the tested program

rtfl-objview

Work around bugs and flaws

Currently, RTFL is not at the top of my priority list, but just a mean to an end (with dillo being the end). This means that I am not too motivated to fix bugs which can be worked around:

General approach

Run the tested program and pass the standard output via pipe to rtfl-objview. The command line options -M and -O are useful to get an overview, -a and -A will help you to filter out irrelevant messages.

Then search for an entry point:

If you have troubles to find the respective object, try to color it via obj-object-color, using a filter like this:[1]

sed 's/^\(\[rtfl-obj-1\.[0-9]*\].*\):set:\([^:]*\):words\.0\.text\/widget\/breakSpace:"Abc"$/\0\n\1:object-color:\2:#ff80ff/g'

which colors all objects to light purple which have the attribute words.0.text/widget/breakSpace set to the value "Abc". This example is again taken from dillo, like the following one, which colors objects in the color in which they are rendered (represented by the attribute style.background-color):[2]

sed 's/^\(\[rtfl-obj-1\.[0-9]*\].*\):set:\([^:]*\):style.background-color:\(#[0-9a-f]*\)$/\0\n\1:object-color:\2:\3/g'

As soon as you have selected a specific command, try to determine the commands before:

Advanced problems

CPU hogging

In this case, the number of messages (infinite) will be too large for rtfl-objview. Simply use head(1) to reduce them; for the number of lines, some trial and error is necessary.

Too many messages

In some cases, it is useful to concentrate on what happens at the end, especially if the program aborts. In this cases, the script rtfl-objtail helps to filter messages, but preserve relevant object creations, associations etc. at the beginning. Again, some tests are needed for the number of lines.

Transformation of attributes

While obj-set is used to set actual attributes, it is sometimes useful to accumulate values. Instead of adding code to the tested program, filters can do this and add respective pseudo attributes. The following snippet counts for each object (and each process) the number of calls of the method draw:[3]

rtfl-tee -b sh -c \
   "grep '^\[rtfl\].*:obj-enter:[^:]*:[^:]*:[^:]*:draw:' | \
    sed 's/^.*:\([^:]*\):obj-enter:\([^:]*\):.*$/\1:\2/g' | \
    sort | uniq -c | \
    sed 's/^ *\([^ ]*\)  *\([^:]*\):\(.*\)$/[rtfl]:0:\2:obj-set:\3:<b>called <i>draw<\/i><\/b>:\1/g'"

More tips

Attic

Some ideas proved to be less practical that they looked at first. Here, you will find several smaller projects which I have abandoned, but you might find them useful as an inspiration.

Dillo: HTML attribute rtfl-id

To make finding the exact relation between HTML elements of a tested page and the dillo widgets simpler, one could define a new HTML element, rtfl-id, which is recognized by the HTML parser of dillo and eventually passed to the respective widget. (Printing a obj-set message is sufficient, storage in the widget is not necessary.) This is demonstrated by the patch dillo-rtfl-id.diff below.

Furthermore, a simple Perl script, add-rtfl-id.pl, adds unique rtfl-id's to a given HTML page (standard input to standard output).

(Warning: both are incomplete.)

rtfl-findrepeat

Rtfl-findrepeat is a program which searches in a stream for identical sequences. See comment at the beginning of common/rtfl_findrepeat.cc for more details on usage. Suitable arguments should be achieved by trial and error.

The idea behind this: if a program hogs the CPU, it is most likely that it does similar things again and again, by error. With a bit of luck, this will result in identical RTFL messages, which rtfl-findrepeat helps to find. With dillo, however, this rendered not as really usable, so I have moved rtfl-findrepeat to here.

Appendix

dillo-rtfl-id.diff

diff -r 45a8d0d4b0d6 dw/widget.hh
--- a/dw/widget.hh	Mon Sep 08 23:20:10 2014 +0200
+++ b/dw/widget.hh	Tue Sep 09 13:09:08 2014 +0200
@@ -502,6 +502,11 @@
     */
    virtual Iterator *iterator (Content::Type mask, bool atEnd) = 0;
    virtual void removeChild (Widget *child);
+
+   void setRtflId (const char *rtflId) {
+      if (rtflId) DBG_OBJ_SET_STR ("rtfl-id", rtflId);
+      else DBG_OBJ_SET_SYM ("rtfl-id", "none");
+   }
 };
 
 void splitHeightPreserveAscent (int height, int *ascent, int *descent);
diff -r 45a8d0d4b0d6 src/doctree.hh
--- a/src/doctree.hh	Mon Sep 08 23:20:10 2014 +0200
+++ b/src/doctree.hh	Tue Sep 09 13:09:08 2014 +0200
@@ -13,6 +13,7 @@
       lout::misc::SimpleVector<char*> *klass;
       const char *pseudo;
       const char *id;
+      const char *rtflId;
 
       DoctreeNode () {
          parent = NULL;
@@ -21,11 +22,13 @@
          klass = NULL;
          pseudo = NULL;
          id = NULL;
+         rtflId = NULL;
          element = 0;
       };
 
       ~DoctreeNode () {
          dFree ((void*) id);
+         dFree ((void*) rtflId);
          while (lastChild) {
             DoctreeNode *n = lastChild;
             lastChild = lastChild->sibling;
diff -r 45a8d0d4b0d6 src/form.cc
--- a/src/form.cc	Mon Sep 08 23:20:10 2014 +0200
+++ b/src/form.cc	Tue Sep 09 13:09:08 2014 +0200
@@ -938,6 +938,7 @@
        * but it caused 100% CPU usage.
        */
       page = new Textblock (false);
+      page->setRtflId (html->rtflId ());
       page->setStyle (html->backgroundStyle ());
 
       ResourceFactory *factory = HT2LT(html)->getResourceFactory();
diff -r 45a8d0d4b0d6 src/html.cc
--- a/src/html.cc	Mon Sep 08 23:20:10 2014 +0200
+++ b/src/html.cc	Tue Sep 09 13:09:08 2014 +0200
@@ -362,6 +362,7 @@
 static void Html_add_textblock(DilloHtml *html, bool addBreaks, int breakSpace)
 {
    Textblock *textblock = new Textblock (prefs.limit_text_width);
+   textblock->setRtflId (html->rtflId ());
 
    if (addBreaks)
       HT2TB(html)->addParbreak (breakSpace, html->wordStyle ());
@@ -2186,6 +2187,7 @@
    }
 
    dw::Image *dw = new dw::Image(alt_ptr);
+   dw->setRtflId (html->rtflId ());
    image =
       a_Image_new(html->dw->getLayout(), (void*)(dw::core::ImgRenderer*)dw, 0);
 
@@ -3038,6 +3040,7 @@
    HT2TB(html)->addParbreak (5, html->wordStyle ());
 
    hruler = new Ruler();
+   hruler->setRtflId (html->rtflId ());
    hruler->setStyle (html->style ());
    HT2TB(html)->addWidget (hruler, html->style ());
    HT2TB(html)->addParbreak (5, html->wordStyle ());
@@ -3783,6 +3786,10 @@
    const char *attrbuf;
    char lang[3];
 
+   if (tagsize >= 13 &&        /* length of "<t rtfl-id=i>" */
+       (attrbuf = a_Html_get_attr(html, tag, tagsize, "rtfl-id")))
+      html->styleEngine->setRtflId(attrbuf);
+
    if (tagsize >= 8 &&        /* length of "<t id=i>" */
        (attrbuf = a_Html_get_attr(html, tag, tagsize, "id"))) {
       /* According to the SGML declaration of HTML 4, all NAME values
@@ -3882,6 +3889,7 @@
    HT2TB(html)->addParbreak (0, wordStyle);
 
    list_item = new ListItem ((ListItem*)*ref_list_item,prefs.limit_text_width);
+   list_item->setRtflId (html->rtflId ());
    HT2TB(html)->addWidget (list_item, style);
    HT2TB(html)->addParbreak (0, wordStyle);
    *ref_list_item = list_item;
diff -r 45a8d0d4b0d6 src/html_common.hh
--- a/src/html_common.hh	Mon Sep 08 23:20:10 2014 +0200
+++ b/src/html_common.hh	Tue Sep 09 13:09:08 2014 +0200
@@ -234,6 +234,7 @@
 
    inline void restyle () { styleEngine->restyle (bw); }
 
+   inline const char *rtflId () { return styleEngine->rtflId (); }
 };
 
 /*
diff -r 45a8d0d4b0d6 src/styleengine.cc
--- a/src/styleengine.cc	Mon Sep 08 23:20:10 2014 +0200
+++ b/src/styleengine.cc	Tue Sep 09 13:09:08 2014 +0200
@@ -160,6 +160,12 @@
    dn->id = dStrdup (id);
 }
 
+void StyleEngine::setRtflId (const char *rtflId) {
+   DoctreeNode *dn =  doctree->top ();
+   assert (dn->rtflId == NULL);
+   dn->rtflId = dStrdup (rtflId);
+}
+
 /**
  * \brief split a string at sep chars and return a SimpleVector of strings
  */
diff -r 45a8d0d4b0d6 src/styleengine.hh
--- a/src/styleengine.hh	Mon Sep 08 23:20:10 2014 +0200
+++ b/src/styleengine.hh	Tue Sep 09 13:09:08 2014 +0200
@@ -77,6 +77,7 @@
       void startElement (int tag, BrowserWindow *bw);
       void startElement (const char *tagname, BrowserWindow *bw);
       void setId (const char *id);
+      void setRtflId (const char *rtflId);
       const char * getId () { return doctree->top ()->id; };
       void setClass (const char *klass);
       void setStyle (const char *style);
@@ -122,6 +123,10 @@
          else
             return wordStyle0 (bw);
       };
+
+      inline const char *rtflId () {
+         return stack->getRef(stack->size()-1)->doctreeNode->rtflId;
+      };
 };
 
 #endif
diff -r 45a8d0d4b0d6 src/table.cc
--- a/src/table.cc	Mon Sep 08 23:20:10 2014 +0200
+++ b/src/table.cc	Tue Sep 09 13:09:08 2014 +0200
@@ -158,6 +158,7 @@
 
    HT2TB(html)->addParbreak (0, html->wordStyle ());
    table = new dw::Table(prefs.limit_text_width);
+   table->setRtflId (html->rtflId ());
    HT2TB(html)->addWidget (table, html->style ());
    HT2TB(html)->addParbreak (0, html->wordStyle ());
 
@@ -451,6 +452,7 @@
                      prefs.limit_text_width);
       else
          col_tb = new SimpleTableCell (prefs.limit_text_width);
+      col_tb->setRtflId (html->rtflId ());
 
       if (html->style()->borderCollapse == BORDER_MODEL_COLLAPSE){
          Html_set_collapsing_border_model(html, col_tb);

add-rtfl-id.pl

#!/usr/bin/perl

$id = 0;

while(<STDIN>) {
   chomp;
   $first = 1;
   foreach $part (split /w</) {
      if ($first) {
         print $part;
      } else {
         if ($part =~ /^\//) {
            print "<$part";
         } else {
            $part =~ s/([^ >]*)/\1 rtfl-id="$id"/;
            $id++;
            print "<$part";
         }
      }
      $first = 0;
   }
   print "\n";
}

[1] Use this for the pre-version protocol:

sed 's/^\(\[rtfl\].*\):obj-set:\([^:]*\):words\.0\.text\/widget\/breakSpace:"Abc"$/\0\n\1:obj-object-color:\2:#ff80ff/g'

[2] Again, for the pre-version protocol:

sed 's/^\(\[rtfl\].*\):obj-set:\([^:]*\):style.background-color:\(#[0-9a-f]*\)$/\0\n\1:obj-object-color:\2:\3/g'

[3] This works only with the pre-version protocol. Should be adjusted eventually.