Development Infrastructure: Tooling with Open Source Software

Diomidis Spinellis
Department of Management Science and Technology
Athens University of Economics and Business
Athens, Greece
dds@aueb.gr

Overview

Goals

Your Instructor

The Case for Tooling

Capital expenditures in different industries

Industry

Revenue ($ bn)

Capital Expenditure ($ bn)

CE / R (%)

Semiconductors

430,360

99,577

23.1%

Motor vehicles

1,094,157

90,042

8.2%

Prepackaged software

105,356

3,402

3.2%

Programming services

18,216

438

2.4%

The Case for Open Source

Ten Software Tool Sins (10-6)

Ten Software Tool Sins (5-1)

Overview

System Software

Operating System

Command Line Tools

1000-5000 commands in a typical operating system installation. The package manager is your friend!

Scripting Language

The Unix Toolchest

Available under Unix, GNU/Linux, *BSD.

For Windows:

Working with Unix Tools

Data Fetching and Generation

Selection

Processing

Summarizing

Plumbing

Example: Analyze Java Files

Examine all Java files located in the directory src, and print the ten files with the highest number of occurrences of a method call to substring.
find src -name ’*.java’ -print |
xargs fgrep -c .substring |
sort -t-rn -k2 |
head -10

Example: Determine Commit Times

find . -type f |
grep -v CVS |
xargs cvs -d /home/ncvs log -SN 2>/dev/null |
awk '/^date/{
    hour = substr($3, 0, 2)
    lines[$5 " " hour] += $9
  }
 END {
    for (i in lines) print i, lines[i]
  }' |
sed 's/;//g' |
sort >dev-times-lines.dat
join dev-times-lines.dat devlong >dev-times-lines-long.dat

Example Result:Plotted Commit Times

Round the clock development

Program Development

(More on the above later.)

Outwit Tools

Outwit Examples

Create an list of fax recipients ordered by the number of faxes they have received.
readlog Application |
awk -F: "/Outbound: Information: Fax Sent/{print $12}" |
sort |
uniq -c |
sort -rn
Extracts the email address from all records from the table users which is part of the database userDB and sends them the file message by email.
fmt message |
mail $(odbc DSN=userDB "select email from users")

An Editor Checklist

Two candidates: Emacs, vim.

Version Control

Version Control

The Great Debate

Version Control Operations

Branching

Revision Tree Example

cat.c revision tree
cat.c revision tree

Life Under a VCS

The Goodies

Example of a Change Log

RCS file: /cvsroot/basesrc/bin/cat/cat.c,v
Working file: cat.c
head: 1.28
branch:
locks: strict
access list:
symbolic names:
    netbsd-1-5-PATCH002: 1.23
    [...]
    netbsd-1-5: 1.23.0.4
    [...]
    netbsd-1-2-BETA: 1.11
    netbsd-1-2-base: 1.11
    netbsd-1-2: 1.11.0.6
    [...]
keyword substitution: kv
total revisions: 33;    selected revisions: 33
description:
----------------------------
revision 1.28
date: 2001/09/16 12:12:13;  author: wiz;  state: Exp;  lines: +6 -4
Some KNF, via patch by Petri Koistinen in private mail.
----------------------------
revision 1.27
date: 2001/07/29 22:40:57;  author: wiz;  state: Exp;  lines: +6 -6
Some style improvements. [Nearly] #13592 by Petri Koistinen.
[...]
----------------------------
revision 1.15.2.1
date: 1998/02/08 21:45:36;  author: mellon;  state: Exp;  lines: +18 -9
Pull up 1.16 and 1.17 (kleink)

Example of a File Difference List

$ cvs diff -c -r1.12 -r1.13 basesrc/bin/cat/cat.c
Index: basesrc/bin/cat/cat.c
===================================================================
RCS file: /cvsroot/basesrc/bin/cat/cat.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -c -r1.12 -r1.13
[...]
***************
*** 136,141 ****
--- 136,142 ----
                                fp = stdin;
                        else if ((fp = fopen(*argv, "r")) == NULL) {
                                warn("%s", *argv);
+                               rval = 1;
                                ++argv;
                                continue;
                        }

Example of an Annotated Listing

1.166        (jhb      16-Oct-02):      fdp = p->p_fd;
1.114        (alfred   13-Jan-02):      FILEDESC_LOCK(fdp);
1.157        (iedowse  02-Sep-02):      if ((unsigned)fd >= fdp->fd_nfiles ||
1.157        (iedowse  02-Sep-02):          (fp = fdp->fd_ofiles[fd]) == NULL) {
1.114        (alfred   13-Jan-02):              FILEDESC_UNLOCK(fdp);
1.106        (dillon   01-Sep-01):              error = EBADF;
1.106        (dillon   01-Sep-01):              goto done2;
1.106        (dillon   01-Sep-01):      }
1.157        (iedowse  02-Sep-02):      pop = &fdp->fd_ofileflags[fd];
1.94         (dillon   18-Nov-00):
1.157        (iedowse  02-Sep-02):      switch (cmd) {
1.1          (rgrimes  24-May-94):      case F_DUPFD:
1.241        (rwatson  07-Aug-04):              /* mtx_assert(&Giant, MA_NOTOWNED); */
1.158        (jhb      03-Sep-02):              FILEDESC_UNLOCK(fdp);

Extracting Metrics

Tracking Example

Maintainability index over time in the FreeBSD kernel.
Maintainability index over time in the FreeBSD kernel.

Best Practices

Build Management

The Build Process

Diagram of the build process

Typical Project Dependencies

Typical project dependencies

Example: Apache Project Dependencies

Apache dependencies

Makefiles

Part of an Apache Makefile

OBJS\
  modules.o \
  $(MODULES) \
  main/libmain.a \
  $(OSDIR)/libos.a \
  ap/libap.a

.c.o:
        $(CC) -c $(INCLUDES) $(CFLAGS) $<

.SUFFIXES: .def
.def.a:
        emximp -o $@ $<


$(TARGET): $(EXTRA_DEPS) $(SUBTARGET)

lib$(TARGET).$(SHLIB_SUFFIX_NAME): subdirs modules.o
        $(CC) -c $(INCLUDES) $(CFLAGS) buildmark.c
        [...]

target_static: subdirs modules.o
        $(CC) -c $(INCLUDES) $(CFLAGS) buildmark.c
        $(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_SHLIB_EXPORT) \
              -o $(TARGET) buildmark.o $(OBJS) $(REGLIB) $(EXPATLIB) $(LIBS)


clean:
        -rm -f $(TARGET) lib$(TARGET).* *.o
        @for i in $(SUBDIRS); do \
                echo "===> $(SDP)$$i"\
                ( cd $$i && $(MAKE) $(MFLAGS_STATIC) SDP='$(SDP)' $@ ) || exit 1; \
                echo "<=== $(SDP)$$i"\
        done

#Dependencies

$(OBJS): Makefile subdirs

# DO NOT REMOVE
buildmark.o: buildmark.c include/ap_config.h include/ap_mmn.h \
 include/ap_config_auto.h os/unix/os.h include/ap_ctype.h \
 include/hsregex.h include/httpd.h include/ap_alloc.h include/buff.h \
 include/ap.h include/util_uri.h
modules.o: modules.c include/httpd.h include/ap_config.h \
 include/ap_mmn.h include/ap_config_auto.h os/unix/os.h \
 include/ap_ctype.h include/hsregex.h include/ap_alloc.h include/buff.h \
 include/ap.h include/util_uri.h include/http_config.h

Make Problems and Solutions

Complexity
Portability

The Ant Approach

Some ant tasks

Examples of ant built-in tasks:

Example Ant Build File

<project name="Jasper" default="deploy" basedir=".">
  <!-- ===================== Initialize Property Values =================== -->

  <!-- See "build.properties.sample" in the top level directory for all     -->
  <!-- property values you must customize for successful building!!!        -->
  <property file="build.properties"/>
  <property file="../build.properties"/>
  <property file="${user.home}/build.properties"/>

  <!-- Build Defaults -->
  <property name="build.compiler"    value="classic"/>
  <property name="copy.crimson.jar"  value="../lib/crimson.jar"/>


  <!-- =================== BUILD: Create Directories ====================== -->
  <target name="build-prepare">

    <available classname="junit.framework.TestCase" property="junit.present" />

    <mkdir dir="${jasper.build}"/>
    <mkdir dir="${jasper.build}/jasper"/>
    <mkdir dir="${jasper.build}/lib"/>

  </target>


  <!-- =================== BUILD: Copy Static Files ======================= -->
  <target name="build-static" depends="build-prepare">

    <!-- Executable Commands -->
    <copy todir="${jasper.build}/bin">
      <fileset dir="src/bin" />
    </copy>
    <fixcrlf srcdir="${jasper.build}/bin" includes="*.sh" eol="lf"/>
    <fixcrlf srcdir="${jasper.build}/bin" includes="*.bat" eol="crlf"/>
    <chmod perm="+x" file="${jasper.build}/bin/jasper.sh"/>
    <chmod perm="+x" file="${jasper.build}/bin/jspc.sh"/>

    <!-- Common Extensions -->
    <copy todir="${jasper.build}/jasper" file="${copy.crimson.jar}"/>
    <copy todir="${jasper.build}/jasper" file="${copy.jaxp.jar}"/>

  </target>


  <!-- ================= BUILD: Compile Server Components ================= -->
  <target name="build-main" depends="build-static">

    <!-- Compile internal server components -->
    <javac srcdir="src/share" destdir="${jasper.build}/classes"
           debug="${compile.debug}" deprecation="${compile.deprecation}"
           optimize="${compile.optimize}"
           excludes="**/CVS/**">
      <classpath refid="jasper.classpath" />
    </javac>
</project>

Best Practices

Best Practices (Variables)

Use variables for varying elements:

Collaboration

Mailing Lists

VCS Notifications

Example Notification

Date: Sat, 19 Aug 2006 08:24:01 +0000 (UTC)
Subject: cvs commit: src/usr.bin/pkill Makefile
X-FreeBSD-CVS-Branch: HEAD

yar         2006-08-19 08:24:01 UTC

  FreeBSD src repository

  Modified files:
    usr.bin/pkill        Makefile
  Log:
  Install pkill(1), aka pgrep(1), to /bin so that rc scripts
  can use this small and nifty utility.  Create compatibility
  symlinks from /usr/bin for the time being to avoid breaking
  custom scripts relying on the hardcoded path to the utility.

  Idea by:        des
  Discussed with: brooks (in cvs-src and cvs-all)

  Revision  Changes    Path
  1.6       +5 -0      src/usr.bin/pkill/Makefile

Setting up CVS Notifications

Example:
#!/bin/sh

(
        id -P |
        awk -F: '{
                print $1 " (" gensub(",.*", "", "", $8) ")\t" strftime("%F %R:%S %z (%Z)")
        }
        END {
                print "\nRepository: '"$2"'\n"
        }'
        echo "Directory: $1"
        egrep -v '^In directory|^Update of'
) | mail -s "[$2] cvs commit $1" $3

Documentation is Ubiquitous

Wikis

Advantages of Wikis for storing documentation. The MediaWiki web page

Things to put on a wiki

Wiki Best Practices

Issue Tracking

Issue Reports

Track bugs according to:

Example: Bugzilla

Bugzilla screen dump

Severity of a Bug

Blocker Blocks development or testing work (e.g. a build)
Critical Crashes, loss of data, severe memory leak
Major major functionality problem
Minor Minor functionality problem, or easy to work around
Trivial Cosmetic problem
Enhancement Request for enhancement

An Issue's Lifecycle

A bug's lifecycle

Resolution Options

Example: Releasing

Before a release.

Bug Tracking Best Practices

Code Manipulation

Typical Tasks

Regular Expressions

Regular Expression Symbols

^Beginning of a line
$End of a line
.Any character
Expression?The expression zero or one times
Expression*The expression zero or more times
Expression+The expression one or more times
Expression{n}The expression n times
Expression{n,}The expression at least n times
Expression{n,m}The expression at least n but no more than m times
Expression1|Expression2 The expression1 or the expression2
(Expression) The expression within the brackets
\1 \2 ... \n The content of the nth bracket

Character Classes

[abc]One of a, b, or c
[a-z]A letter from a to z
[^abc]Any letter appart from a, b, and c.
\t The character tab
\n The character newline
\r The character carriage return
\a The character alert
\f The character form feed
\e The character escape
\cx The character control-x (a-z)
\d Digit
\D Non-digit
\s Space
\S Non-space

The Editor as a Code Browser

Code Searching with grep

Locating File Differences

Using the Compiler

Compiler Warning Messages

(Depending on the language, some of the above may be errors)

The Compiler as a Code-Reading Tool

Assembly Can be Useful

Read symbolic code to

Code Browsers

Code browsers typicall offer the following facilities:

Code Browsers in OO

In OO languages given a class you can find:

Refactoring

(Live demo in Eclipse.)

Beautifiers

For printing use a pretty-printer, like listings (LaTeX), vgrind (troff).

Cdecl: Decoding C Declarations

Example:
void (*signal(int sig, void (*func)(int)))(int);

declare signal as function that expects (sig as int, func as pointer to
function that expects (int) returning void) returning pointer to function
that expects (int) returning void;

Inspection and Testing

Static Verification

Examples: Characteristics:

Identified Issues

Some FindBugs Issues

(FindBugs reports more than 200 issues.)

A FindBugs Run

A FindBugs run

GCC Best Practices

C Compilation Example

main(char *argv[])
{
        int a, b, c;

        a = b;
        printf("%g\n", a);
}
Plain compile:
$ gcc t.c
$
Compile with warnings:
$ gcc -O4 -Wall -Werror t.c
cc1: warnings being treated as errors
t.c:9: warning: return-type defaults to `int'
t.c:9: warning: first argument of `main' should be `int'
t.c:9: warning: `main' takes only zero or two arguments
t.c: In function `main':
t.c:13: warning: implicit declaration of function `printf'
t.c:13: warning: double format, different type arg (arg 2)
t.c:10: warning: unused variable `c'
t.c:14: warning: control reaches end of non-void function
t.c:10: warning: `b' might be used uninitialized in this function

Lint Best Practices

Tracing Tools

InterfaceTool
Operating Systemstrace
Libraryltrace
Networktcpdump
Resource Snapshotlsof

Using Tracing Tools

[sl]trace Tips and Tricks

Example: System Call Tracing

Which shared libraries is dot loading?
$ strace dot </dev/null 2>&1 | fgrep .so | fgrep -v ENOENT
open("/etc/ld.so.cache", O_RDONLY)      = 3
open("/usr/lib/libfreetype.so.6", O_RDONLY) = 3
open("/usr/lib/libpng.so.2", O_RDONLY)  = 3
open("/usr/lib/libjpeg.so.62", O_RDONLY) = 3
open("/usr/lib/libz.so.1", O_RDONLY)    = 3
open("/lib/libm.so.6", O_RDONLY)        = 3
open("/lib/libc.so.6", O_RDONLY)        = 3

Example: Library Call Tracing

How does the whoami command obtain its data?
$ ltrace whoami
[...]
geteuid()                                         = 1000
getpwuid(1000, 0x40013678, 0xbffffcac, 0x08048cff, 0x4012ee48) = 0x401310f0
puts("dds"dds
)                                       = 4
exit(0 <unfinished ...>

Unit Testing

JUnit Example

Test Class and Fields

public class RationalTest {
    private Rational r12;
    private Rational r13;
    private Rational r56;
}

Initialization Code

    @Before public void setUp() {
        r12 = new Rational(12);
        r13 = new Rational(13);
        r56 = new Rational(56);
    }

A Test Method

    @Test public void simpleAdd() {
        Rational result = r12.add(r13);
        assertTrue(result.equals(r56));
    }

Run the Class's Test Methods

    public static void main (String... args) {
        junit.textui.TestRunner.run(RationalTest.class);
    }

Textual Regression Testing

Example: Testing the Sort Program

#!/bin/sh
FILES=`cd in; echo *`

# Prime test data
if [ "$1" = "-p" ] ; then
        for in $FILES ; do
                sort in/$i >old/$i
        done
fi

# Compare old with new result
for in $FILES ; do
        sort in/$i >new/$i
        if diff old/$i new/$i ; then
                echo "OK $i"
        else
                echo "FAIL $i"
                exit 1
        fi
done

Test Coverage in C/C++ Code

To investigate test coverage, you can use basic block profiling. Example:
 83.33% of 650 source lines executed in file hilbert.c

Performance Measurement

Program States

Also

Measuring Workload

Workload and Tools

Profile r >>u+s s >u u ≈ r
Characterization I/O-bound kernel-bound CPU-bound
Tools Disk, net, VM stats, packet dumps System call tracing Function profiling, basic block counting

System Monitoring Tools

I/O
iostat (under *BSD), vmstat (Linux)
Memory
vmstat, free (Linux)
Network
netstat
Example: virtual memory statistics while executing the find command
$ vmstat 1
   procs                      memory    swap          io     system         cpu
 r  b  w   swpd   free   buff  cache  si  so    bi    bo   in    cs  us  sy  id
 1  0  0      0  52296   3476  50092   0   0   340     0  189   190   0   6  94
 0  1  0      0  51736   3588  50428   0   0   448     0  214   243   0   5  95
 1  0  0      0  51072   3716  50724   0   0   424     0  210   218   0   5  95
 0  1  0      0  50596   3848  50968   0   0   376     0  196   204   0   4  96
 1  0  0      0  49952   3976  51304   0   0   464     0  220   247   0   6  94
 0  1  0      0  49556   4068  51512   0   0   300     0  177   172   2   2  96
 1  0  0      0  49024   4132  51816   0   0   368     0  196   195   0   7  93
 1  0  0      0  48228   4200  52416   0   0   668     0  270   307   0   9  91
 1  0  0      0  47668   4352  52712   0   0   448     0  215   227   0   5  95
 1  0  0      0  47048   4412  53092   0   0   440     0  213   244   1   5  94
 0  1  0      0  44912   4668  54080   0   0   432     0  211   225   0   4  96

Profiling System Calls

Example:
$ strace -c find . -name test
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 66.06    0.367503         584       629           getdents64
 26.31    0.146389          80      1826           lstat64
  2.27    0.012621          40       313           fcntl64
  1.83    0.010168          31       326        10 open
  1.78    0.009894          16       625           chdir
  1.23    0.006846          22       316           fstat64
[...]

Function Profiling

Profiling C/C++ Code with Gprof

A Flat Profile

Flat profile:

Each sample counts as 0.01 seconds.
  %   cumulative   self              self     total
 time   seconds   seconds    calls  ms/call  ms/call  name
  6.35      0.33     0.33                             _Unwind_SjLj_Register
  5.77      0.63     0.30 10192020     0.00     0.00  __gnu_norm::__deque_buf_size(unsigned int)
  1.54      1.53     0.08       10     8.00   118.33  parse_parse()
  1.35      1.60     0.07  5096343     0.00     0.00  operator==(Tokid, Tokid)

A Call Graph Profile

index % time    self  children    called     name
                                  10             Pdtoken::process_pragma() <cycle 1> [360]
[4]     22.8    0.08    1.10      10         parse_parse() <cycle 1> [4]
                0.00    0.42    8348/17593       Token::unify(Token const&, Token const&) [5]
                0.00    0.26    4328/4328        Type::declare() [28]
                0.00    0.22    3511/3511        completed_typedef(Type) [33]
                0.00    0.03    3529/3540        Block::enter() [220]
                0.00    0.02    7402/27543       obj_lookup(std::string const&) [94]
                0.00    0.02  812361/834736      YYSTYPE::operator=(YYSTYPE const&) [324]
                0.01    0.01   85359/295237      Type::~Type() <cycle 3> [429]
                0.00    0.02    1690/1690        Call::register_call(Token const&, Id const*) [331]
                0.00    0.02   11362/11362       Type::set_abstract(Type) <cycle 4> [581]

Profiling Java Code with EJP

A Java Program Profile

An EJP profile of a Java program

Basic Block Counting in C/C++ Code

To investigate algorithms count the number of times each line is executed. Example:
           main(int argc, char *argv[])
           {
      1            int i, j, k;
      1            int a = 0;

     11            for (i = 0; i < 10; i++)
    110                    for (j = 0; j < 10; j++)
   1100                            for (k = 0; k < 10; k++)
   1000                                    a += i + j + k;
      1    }

Architectural Inefficiencies

Architectural Profiling Tools

Processor event monitoring
Oprofile (http://oprofile.sourceforge.net/) (Linux)
Locality optimizations
SLO: Suggestions for Locality Optimizations (http://slo.sourceforge.net/)
Events that Oprofile can analyze on a Core 2 Intel CPU.

Memory Performance

Memory as important as CPU cycles Again, we need to profile

Memory Profiling C/C++ Code with Valgrind

Example: sed under valgrind

echo ':abcdefgh: : :' |
valgrind  --tool=massif ./sed -f TEST/hanoi.sed
Valgrind's output

Documentation and Visualization

Declarative Text Processing

DocBook Details

Best Practices

Documentation from Source Code

Javadoc Example

/**
 * Constructs a newly allocated {@code Integer} object that
 * represents the specified {@code int} value.
 *
 * @param   value   the value to be represented by the
 *                  {@code Integer} object.
 */
public Integer(int value) {
    this.value = value;
}

Automation Example: C++ Code

void
workdb_schema(Sql *db, ostream &of)
{
    cout <<
        // BEGIN AUTOSCHEMA
        "CREATE TABLE STRINGS("         // Strings in the code
        "FID INTEGER,"                  // File key (references FILES)
        "FOFFSET INTEGER,"              // Offset within the file
        "STRING " << db->varchar() << ","   // The string, including its delimiters
        "PRIMARY KEY(FID, FOFFSET)"
        ");\n"

        "CREATE TABLE LINEPOS("         // Line number offsets within each file
        "FID INTEGER,"                  // File key (references FILES)
        "FOFFSET INTEGER,"              // Offset within the file
        "LNUM INTEGER,"                 // Line number (starts at 1)
        "PRIMARY KEY(FID, FOFFSET)"
        ");\n"

        "CREATE TABLE FCALLS("          // Function calls
        "SOURCEID INTEGER, "            // Calling function identifier key (references FUNCTIONS)
        "DESTID INTEGER"                // Called function identifier key (references FUNCTIONS)
        ");\n"
        // ...
        // END AUTOSCHEMA
        "";
}

Automation Example: Processing Script

print 'The following sections describe the
schema of the database created through the SQL backend.';
while (<>) {
    if (/BEGIN AUTOSCHEMA/../END AUTOSCHEMA/) {
        if (/CREATE TABLE (\w+)\(.*\/\/ (.*)/) {
            print qq{
<h2>Table $1</h2>
<p>
$2.
</p>
<table border = "1">
<tr> <th>Field name</th> <th>Field type</th> <th>Value description</th> </tr>
            };
        } elsif (/^\s*\"(\w+).*\/\/ (.*)/) {
            $name = $1;
            $description = $2;
            $type = 'BOOLEAN' if (/booltype/);
            $type = 'CHARACTER VARYING' if (/varchar/);
            print "
<tr><td>$name</td><td>$type</td><td>$description</td></tr>
";
        } elsif (/\"\)\;\\n\"/) {
            print "</table>\n";
        }
    }
}

Automation Example: Documentation Page

The following sections describe the schema of the database created through the SQL backend.

Table STRINGS

Strings in the code.

Field name Field type Value description
FIDINTEGERFile key (references FILES)
FOFFSETINTEGEROffset within the file
STRINGCHARACTER VARYINGThe string, including its delimiters

Table LINEPOS

Line number offsets within each file.

Field name Field type Value description
FIDINTEGERFile key (references FILES)
FOFFSETINTEGEROffset within the file
LNUMINTEGERLine number (starts at 1)

Table PROJECTS

Project details.

Field name Field type Value description
PIDINTEGERUnique project key
NAMECHARACTER VARYINGProject name

Table FCALLS

Function calls.

Field name Field type Value description
SOURCEIDINTEGERCalling function identifier key (references FUNCTIONS)
DESTIDINTEGERCalled function identifier key (references FUNCTIONS)

Graph and Diagram Types

Declarative Drawing Tools

UMLGraph Class Diagram

class Person {
        String Name;
}

class Employee extends Person {}

class Client extends Person {}
A UMLGraph Class Diagram

Detailed Class Diagram

A more complex class diagram
// Author:  Vadim Nasardinov
// Version: $Id: ceg-mv.xml,v 1.1 2005/11/23 22:21:22 dds Exp $

import java.util.List;
import java.util.Map;

/**
 * @assoc "1..1" - "0..n" Adapter
 * @assoc "" - "0..n" ObjectType
 * @assoc "" - "0..n" ObjectMap
 * @assoc "" - "0..n" Table
 * @assoc "" - "0..n" DataOperation
 **/
class Root {
    private Map m_adapters;
    private List m_types;
    private List m_maps;
    private List m_tables;
    private List m_ops;

    public Adapter getAdapter(Class klass) {}
}

class Adapter {
    public Root getRoot();
}

abstract class Element {
    Root getRoot() {}
}

class ObjectType extends Element {}

/**
 * @has "1..1" - "1..1" ObjectType
 **/
class ObjectMap extends Element {
    private ObjectType m_type;
}

class Table extends Element {}

class DataOperation extends Element {}

UMLGraph Sequence Diagram

# Define the objects
object(O,"o:Toolkit");
placeholder_object(P);
step();

# Activation and messages
active(O);
message(O,O,"callbackLoop()");
create_message(O,P,"p:Peer");
message(O,P,"handleExpose()");
active(P);
return_message(P,O,"");
inactive(P);
destroy_message(O,P);
inactive(O);

# Complete the lifeline of O
step();
complete(O);
A sequence diagram

Directory Hierarchies with dot

(Generated with a 50-line Perl script) A directory hierarchy

Plotting Test Coverage: GNU Plot Script

#
# $Id: testcoverage.gpl 1.3 2005/10/13 18:57:00 dds Exp $
#
set ylabel 'Branch test coverage %'
set xlabel 'Test case number'
set ytics 10
set y2tics 10
set mytics
set nomxtics
set terminal png medium enhanced
set output 'testbranch.png'
plot [] [0:100] 'testbranch.dat' using 1:3 title "Executed branches" with lines,\
'testbranch.dat' using 1:5 title "Fully tested branches" with lines

Plotting Test Coverage: Result

Branch test coverage analysis

Memory Fragmentation Example

(Postscript generated by a Perl script and a custom new operator.) Memory fragmentation map

Stack Usage Example

(GNU Plot data generated by a custom function prologue.) Stack usage diagram

Map Example

(Generated by mining data from the CVS repository.) Developer contributions around the world

Tool Building

Implementation Options

Choosing an Implementation

A Simple Grep Program in Java ...

/*
 * Globally match regular expression and print
 * Modelled after the Unix command with the same name
 * D. Spinellis
 */

import java.util.regex.*;
import java.io.*;

class Grep {
    public static void main(String args[]) {
        if (args.length != 2) {
            System.err.println("Usage: Grep pattern file");
            System.exit(1);
        }

        Pattern cre = null;        // Compiled RE
        try {
            cre = Pattern.compile(args[0]);
        } catch (PatternSyntaxException e) {
            System.err.println("Invalid RE syntax: " + e.getDescription());
            System.exit(1);
        }

        BufferedReader in = null;
        try {
            in = new BufferedReader(new InputStreamReader(
                 new FileInputStream(args[1])));
        } catch (FileNotFoundException e) {
            System.err.println("Unable to open file " +
                args[1] + ": " + e.getMessage());
            System.exit(1);
        }

        try {
            String s;
            while ((s = in.readLine()) != null) {
                Matcher m = cre.matcher(s);
                if (m.find())
                    System.out.println(s);
            }
        } catch (Exception e) {
            System.err.println("Error reading line: " + e.getMessage());
            System.exit(1);
        }
    }
}

... And its Equivalent in Perl

#!/usr/bin/perl -n
BEGIN {$pat = shift;}
print if (/$pat/);

Advice

Example: Signature Survey

Example of a signature survey