zyxwvu
Using Weaves for Software Construction and Analysis
Michael M. Gorlick and Rami R. Razouk*
The Aerospace Corporation
P.O. Box 92957, Los Angeles, CA 90009
Abstract
cessive version is a testbed for investigating questions
of functionality, user response and acceptance, performance, and cost. Continuous, low-overhead monitoring, whether for debugging, performance analysis, or
human factors engineering, is always available.
One abstract way to view a software system (a view
commonly used as a design aid) is as a network of
components that communicate via messages. However,
high communication costs and the overhead of heavyweight parallel processes make the implementation of
this idealized view comparatively expensive. The goal
of using weaves is to reduce these expenses to the point
where the abstract view can be implemented directly.
For example, one application area that is conveniently characterized in this manner is satellite telemetry processing. Most satellites transmit a continuous,
nonstop stream of information to earth. This telemetry
stream contains payload sensor readings, measurements
of the power output of solar arrays, operating tempera
tures, electrical load, and command responses. Figure 1
illustrates a typical functional data flow for processing satellite-payload sensor readings whose interpretation depends upon the orientation of the satellite. The
labeled boxes denote active functional elements, and
the labeled arrows denote medium- to large-grain data
flows from one functional element to another. These
systems are characterized by a rich variety of data and
the fact that individual functional elements can be successively decomposed into primitive, well-defined actions on streams of data.
The ground stations that process these telemetry
streams can be large, complicated systems requiring
substantial computational resources; not surprisingly,
designing, implementing, debugging, and performancetuning these software systems is notoriously difficult.
These systems are distinguished by several features:
e They are extremely long-lived. It can take from 5 to
10 years to design, build, and launch a single satellite.
The accompanying ground stations may be in place for
decades and may need to accommodate multiple ver-
Weaves are networks of concurrently executing tool fragments that communicate by passing objects. Intended as an
engineering medium for systems characterized by streams
of data, weaves occupy a computational niche midway between heavyweight parallel processes and fine-grain dataflow. Weaves are distinguished from other data flow styles
by their emphasis on instrumentation, continuous observability, and dynamic rearrangement: (1) Basic low-overhead
instrumentation is inserted automatically. (2 )Executing
weaves can be observed at any time by means of sophisticated analysis agents, without degrading the performance
of the weave. (3) Weaves can be dynamically snipped and
spliced without interrupting the data flow; this permits
novel forms of experimentation and analysis.
Weaves execute efficiently on a broad spectrum of architectures and offer numerous opportunities for parallel execution. Also, it is possible to synthesize nontrivial weaves
automatically from libraries of components. We discuss the
architectural features of weaves, their implementation, and
their use in a variety of applications.
Keywords: data flow, incremental development, objectoriented, parallel execution, performance analysis, software
instrumentation, streams, threads
1 Introduction
One of the central problems of software engineering
concerns the economical development of software systems that perform satisfactorily. To deal with this
problem we propose to use weaves, software organizations based on the low-overhead transmission of objects; weaves combine rapid incremental development
with ongoing performance analysis and debugging.
Rapid incremental development provides a continuous development sequence in which each development
step is a small, easily understood change to, or extension of, the previous version of a system. Each suc-
zyxwvutsr
zyxwvut
zyxwvutsrqpon
zyxwvutsrqpon
*This work was supported by the Aerospace Sponsored Research Program.
23
CH2982-7/91/0000/0023$01.OO
(9
1991 IEEE
Recommended by: Richard Kemmerer
zyxwvu
T
Izyxwvutsrqpo
1
TelemetrvSatellite
1-1
Sensor
R e a d i W - P I
Filtering
Star Sightings
Filtered
Sensor
Readincs,
Satellite
Orientation
Orientation
Oriented
Sensor
Readings
/
Estimation
Figure 1: A Typical Functional Data Flow for Telemetry Processing
tended (“grown”) without disturbing the behavior of
the tool fragments already in place. A weave can be
refined by replacing a sink with a subweave. More generally, one subweave replaces another transparently if
it respects the connectivity of the original. By systematically replacing tool fragments and subweaves with
more refined versions, one can grow a complete weave,
beginning with trivial tool fragments that mimic the
behaviors of the final components. Entire subweaves
can be attached anywhere within a running weave without disturbing the integrity of the original weave.
Continuous low-overhead monitoring and observation. All weave components contain inexpensive instrumentation that can be left in place for the life of the
system. This basic instrumentation is provided automatically, whereas specialized instrumentation can be
transparently introduced into a weave at any time. Instruments and monitors that are application-specific
can be easily derived, making “performance debugging”
as natural and commonplace as functional debugging.
Weaves can be observed at any time, without the need
to make special provisions beforehand, and can be monitored at varying levels of detail.
Concurrent communication. Weaves are graphs
assembled from tool fragments, where the arcs of the
graph serialize communication and synchronization and
the data objects flowing through the weave serialize access. Tool fragments are written in commonly available
deterministic languages, without regard to the issues of
communication and synchronization. Considerable attention has been devoted to reducing the overhead of
object passing. Object copying is the exception rather
than the rule, and in most cases data-object transfer is
by reference.
Numerous opportunities for parallelism. Weaves
are designed to take advantage of commonly available
parallel architectures such as shared-memory multipro-
sions of the same satellite.
T h e y are eztremely large. Even modest systems
contain over 100,000 lines of code. The largest examples contain in excess of 1,000,000 lines of code. Furthermore, history and evolution usually leave most systems with a legacy of two or more distinctly different
programming languages.
They must process large volumes of data in real or
near-real t i m e . The telemetry transmission rates alone
can strain the processing capacity of the most powerful
processors available. The telemetry data may require
sophisticated and extensive conditioning or processing
before they are suitable for use by applications.
They are opaque. It is nearly impossible, given the
structure of these systems and their operational constraints, to instrument them once they are in place.
For the sake of performance, all of the debugging aids
have been optimized away. Even if such aids were still
in place, determining where to look to resolve a performance problem or track down a bug remains a significant challenge.
They undergo constant change. For example, a
satellite may spontaneously exhibit anomalous behavior as a consequence of unforeseen environmental conditions or hardware degradation. These behaviors often require that bizarre “special cases” be inserted into
the software. Furthermore, older satellites are often
adapted to new missions that require additional software support. In some cases, existing telemetry may
be exploited in a new way.
In an effort to improve radically the software engineering practices for these ground systems, we have
turned to weaves - networks of tool fragments that
communicate by passing objects. Weaves are structured to permit, throughout the entire system lifecycle,
the following:
Continuous incremental change. Weaves are ex-
zyxwvutsrqp
zyxwvutsrq
zyxwv
24
zyxwvutsrq
zyxwvutsrqpon
zyxwvutsrqpo
zyxwvu
zyxwvuts
Figure 2: A Trivial Weave
cessors. When suitably split, weaves can execute efficiently on nonuniform-memorymachines or distributed
architectures.
0 Continuous scaling. A tool fragment in a weave
may itself be an encapsulation of an entire subweave.
Weaves scale hierarchically in a manner consistent with
modern software engineering practices.
This paper is divided into four sections. Section 2
contains a discussion of weaves and their constituent
components, and Section 3 describes how weaves are
assembled. Section 4 examines the mechanisms for
monitoring and analyzing weaves. Finally, Section 5
describes our initial experience and outlines our future
plans.
2
Figure 3: Snapshot of a Weave
Weaves are designed to exploit a computational niche
that lies midway between the large-grain filters introduced by Unix processes and pipes [l]and the fine-grain
computations of classical data flow [2]. The computational model employed by weaves is medium-grain,
non-blocking data flow with finite buffering, first-infirst-out stream access, and multiple readers and writers. Each individual stream datum is an object with
encapsulated state, class membership, inheritance, and
exported methods. Weaves are intended for situations
that are characterized by such streams of data, for example, message switching and telemetry processing.
Although weaves share some of the features of Unix
filters (composed of processes and pipes), they differ
significantly in several respects:
Weave tool granularity is finer. A Unix tool, appearing as a component in a filter chain, is usually much
larger than a single procedure. While many Unix tools
adhere to the maxim “do one thing very well,” they
are often composed of multiple routines that cannot be
easily decomposed into separate tools.
0 Weave process granularity is finer. Unix tools run
as heavyweight processes, with significant setup and
switching times. However, the tool fragments in weaves
execute as threads, which have much lower setup and
switching times. This reduction in process granularity increases the opportunities for parallelism on multiprocessor architectures, particularly on uniform sharedmemory machines.
0 Weaves permit multiway communication.
Even
though some versions of Unix implement “named
pipes,” no shell in common use permits anything other
than linear filter chains. A weave may be an arbitrary
multigraph that permits “many-to-many” communica-
Weaves
Weaves are interconnected networks of tool fragments,
wherein data objects serve as the coin of information
exchange. A tool fragment is a small software component, on the order of a procedure, that performs
a single, well-defined function. Tool fragments consume objects as inputs and produce objects as outputs.
Each tool fragment executes as an independent thread,
a lightweight concurrent process that shares memory
with others of its kind. Objects are transmitted from
one tool fragment to another via ports attached to
queues. Ports connect tool fragments to queues, which
in turn buffer and synchronize communication among
tool fragments. Formally, weaves are bipartite, directed
multigraphs. Figure 2 is a trivial example of such a
graph.
The objects flowing through a weave, and the ports
and queues through which they travel, are passive.
Only the tool fragments are active, accepting objects
from ports, invoking the methods implemented by
the objects, performing tool-specific computations, and
passing objects downstream.
We have implemented in C++ a prototype environment for constructing, executing, and observing
weaves. The weave and its components, tool fragments,
ports, and queues are all objects, as are the data passing through the weave. A “snapshot” of a small running
weave is shown in Figure 3.
zyxwvutsr
25
zyxwvuts
zyxwvut
zyxwvutsrq
zyxwvutsrqp
zyxwvutsr
zyxwvutsrq
work. Thus the overhead of an object moving through
the weave is amortized to a greater degree than is the
corresponding overhead of classical data flow.
The same datum m a y be processed simultaneously
at diflerent points an the weave. In classical data flow,
a datum never experiences a side effect; instead, a copy
is produced. Weaves permit side effects and the same
object may be referenced simultaneously by multiple
tool fragments. Because synchronization and conflict
resolution are the responsibility of the object itself, the
implementor of the tool fragment is freed from such
concerns. Each tool fragment is written as though it
had sole access to the object; this makes each fragment
easier to implement and comprehend than an alternate
formulation where concurrency must be managed by
the programmer. Finally, since all objects (except those
representing primitive data) are denoted by reference,
moving an object through a weave is inexpensive.
Each tool fragment m a y retain state. Since each
tool fragment is an arbitrary deterministic program, it
may retain state. Local state, combined with the conditional consumption or production of objects, permits
tremendous flexibility in a fragment’s communication.
Weaves and the Stream Machine [9] share the same
level of processing granularity; however, they manage
streams in significantly different ways. In the Stream
Machine the streams retain complete history, all stream
values are copied, writing is always nonblocking, and
each stream is restricted to a single writer (with possibly multiple readers). Stream reads may block, and
readers can request future values, blocking until they
arrrive. The stream data values are restricted to simple
fundamental data types, integer, real, character, and
the like. Finally, the stream machine is modeled on
multiple separate processes, each with its own distinct
memory space.
With weaves, streams do not retain history, stream
data values (with the exception of simple primitive data
types) are passed from place to place by reference (except where they cross memory space or machine boundaries), both reading and writing are nonblocking, and
each stream is permitted multiple readers and writers.
No reader may request future values, and data values
are arbitrary objects. Finally, weaves are explicitly designed to exploit multiple threads that share a single
memory space.
In passing we note that TDFL, the Task-level Data
Flow Language [lo], also supports coarse-grained data
flow and a level of task granularity equivalent to that
of weaves. However, TDFL adheres strictly to the semantics of classical data flow.
tion among tool fragments.
Weave streams are structured. Unix pipes reduce
communication to the lowest common denominator streams of uninterpreted bytes. On the other hand, tool
fragments in weaves communicate by using streams of
objects, which in a shared-memory tasking model are
as efficient as byte streams. Since each object can encapsulate a large amount of data and many procedural
interpretations, the effective bandwidth of an object
stream is much higher than that of a flat byte stream.
In classical data flow the unit of execution is a single machine instruction, and the data flowing through
the network consist of simple machine-level values. Instructions execute only when all of their operands have
arrived. While this scheme is conceptually attractive,
its overhead is prohibitive. Despite resembling classical data-flow graphs, weaves differ from them in many
ways as follows:
Weaves are indifferent t o ihe composition of the
tool fragments. Tool fragments may be derived from
various languages and programming models. In this
respect, weaves are an integrative glue for disparate
serial codes, in the spirit of the Program Composition Notation [3, 41 or Durra [5, 61. In fact, the
Durra application-specification language could be easily adapted, with minor modifications, to describe
weaves, which themselves can be regarded as a lowerlevel implementation medium.
Weave tool granularity is larger. Weave tool fragments execute from hundreds t o thousands of instructions for each set of input objects. This level of execution granularity is well-suited to shared-memory multiprocessors and operating systems that support threads
such as Mach [7] or Synthesis [SI.
Weave tool-fragment scheduling i s not data driven.
In the classical data-flow model, instructions are
blocked until all of their operands have arrived. Weaves
do not enforce this restriction, but rather encourage
fragments to exploit their input latency to perform useful computation. Tool fragment scheduling can be optimized in various ways to take advantage of the processing demands of the fragment and the arrival patterns
of its inputs.
e Weave data granularity is larger. Data flow typically deals with either primitive elements such as integers and booleans or simple uniform structures (arrays)
of these primitive elements. In contrast, weaves process
objects whose internal structure may be quite complex
and whose methods represent substantial computation.
At each stage in a weave, more effective work is accomplished than in an equivalent classical data-flow net-
26
I
Quew
zyxwvutsrqponm
I
zyx
zyxwvutsrq
zyxw
zyxwvutsrq
zyxwvuts
Figure 4: Port and Queue Transport Service
Figure 5: A Specialized Transport Service
Weaves are primarily designed to foster the smooth,
incremental construction of observable systems. The
basic instrumentation for weaves must be so inexpensive and ubiquitous that no one would go to the bother
of removing it. Additionally, it must be possible to
include, at one’s discretion, more powerful (but potentially more expensive) mechanisms for observation.
Observation, besides being cheap, should also be effortless; that is, it should be automatic without requiring
additional work. Below we discuss the techniques used
to achieve these goals.
not prevent A from being connected to B. In this case,
specialized ports, subclasses of the general port class,
implement the necessary type coercion as a “valueadded” layer over the basic transport service. This
concept is illustrated in Figure 5 .
The transport service can also be used to resolve differences in representation (for example, transforming
arrays stored in column-major order into row-major
order). More generally, issues involving data translation across machine boundaries can be resolved at the
transport service level transparently, between tool fragments executing on different processor architectures.
The same principles can be applied to object transmission across machine boundaries, where the transport
service can send an object transparently by transmitting only its internal state and reconstituting it on the
receiving end (similarly, Durra [5] uses queues to implement data translation across host boundaries).
Ports are also responsible for the atomicity of transfers of data objects to and from queues. Once a tool
fragment “sends” through a write port to a queue, delivery to the queue is guaranteed. Conversely, a data
object remains in a queue until transfer to a tool fragment via a read port is guaranteed. A data object can
be in only one of two places at any one time - inside
a tool fragment or a queue.
This atomicity makes it possible to rearrange the
network dynamically without disturbing the flow of
data objects. Figure 6 illustrates this procedure, where
tool fragments A and C are connected via a singleproducer/single-consumer queue, & I . A’s write port
and C’s read port are detached from & I . Any data
objects in transit are either already in the queue or
waiting in the ports. Tool fragment B is inserted between fragments A and C by reconnecting the write
port leading from A to a queue Q2,which feeds B instead. B’s write port, in turn, is attached to the queue
feeding C. This reweaving is transparent to A , B , and
C, since they all communicate blindly.
2.1
Ports and Queues
Ports and queues are a blind, type-indifferent, twolayer transport service. No tool fragment using this
service can discover the source (or destination) of the
data objects it receives (or sends). Ports implement the
wrapping and unwrapping of data objects by means of
envelopes. Queues are finite buffers of envelopes. Envelopes are wrappers that hide the type of the underlying data object. This arrangement is illustrated in
Figure 4.
Blindness and type indifference increase the flexibility of interconnectivity. Since with weaves all communication is blind, tool fragments exhibit location transparency; that is, the actions of a tool fragment are independent of its location in the network. Each of these
properties helps to ensure that a weave remains malleable irrespective of its size. (Note that Unix tools also
exhibit location transparency.)
Since the transport mechanism is type-indifferent , it
is easy to construct specialized transport services that
reflect the type coercions common to many programming languages. This increases the degree of tool fragment “plug compatibility,’’ since intercommunicating
fragments need not be strictly type-compatible. For
example, the fact that tool fragment A produces only
integers and tool fragment B consumes only floats does
zyxwvut
zyxwvutsrqp
27
zyxw
zyxwvutsrqp
signed to a fragment for the lifetime of that fragment.
IAl-
Figure 6: Splicing a Tool Fragment into a Weave
All tool fragments implement a minimal set of control
methods. S t a r t initiates the execution of the fragment.
Suspend halts the fragment in a timely manner, leaving
it in a safe state from which it may be transparently
continued. Resume is the converse of Suspend. The
functional behavior of a resumed tool fragment is identical to that of a fragment that was never suspended in
the first place. Sleep suspends the tool fragment for a
minimum delay (given in milliseconds). Abort immediately halts the fragment but does not leave it in a
state from which it may be safely restarted; Abort is
the control action of last resort.
zyxwvutsrq
The transport service also separates the specification of communication from that of synchronization.
Queues are distinguished by the producer/consumer relationships they support: 1 / 1 , l / n , m / l , or m / n . Ports
are blind to the producer/consumer relationship supported by the queue to which they are attached. Consequently, the synchronization of multiple readers or
writers is the responsibility of the queue; this permits
efficient implementations that cater to special cases.
For each producer/consumer relationship, a queue subclass is defined that exploits optimistic synchronization
[8] to implement efficiently those queue operations that
minimize locking.
All queues are finite and all sends or receives on ports
are nonblocking. For example, if a queue is full then a
send on a port connected to that queue will fail and an
error code is returned to the tool fragment undertaking
the send. Each port supplies a Wait method (an implementation of some port-specific waiting policy) that
will temporarily suspend the fragment. The tool fragment may wait or exploit the stream latency to perform
other computations. If the fragment chooses to wait, it
is free to reattempt the transmission; however, there is
no guarantee that the condition that caused the transmission failure has been resolved. For example, a tool
fragment can achieve the effect of a blocking send by repeatedly Waiting after each unsuccessful send. Blocking receives are constructed in an analogous fashion.
2.2
Tool Fragments and Threads
Tool fragments are the active agents in weaves. Each
tool fragment is composed of a routine, a vector of arguments, and a thread that executes the tool fragment.
The routine is the working part of the tool fragment;
it is responsible for processing incoming data objects
and producing outgoing data objects. The argument
vector is divided, by convention, into three subvectors.
The first i arguments are those arguments that are not
ports. The next j arguments are read ports. Finally,
the last k arguments are write ports. The thread is as
There are two major families of tool fragments. The
first is designed to support the incorporation of foreign
routines (written in common sequential programming
languages) into weaves. In this case the routine is insulated from all of the details of sending or receiving
data objects through ports. When the tool fragment
is created, a mapping is given that specifies the rela,
tionship between the argument vector of the fragment
and the parameters of the routine. When inserted into
a weave, the instance waits for data objects to arrive
at the read ports. After all of the inputs have arrived,
the routine is invoked with its parameters, which are
extracted as specified by the argument mapping. The
return value and output parameters of the routine are
transshipped by the tool fragment through its output
ports. All of the weave-related activity is invisible to
the routine in a manner similar to that of TDFL [lo];
that is, the routine is called whenever a full set of input
data objects have arrived. All of the control methods
are implemented by the fragment on behalf of the foreign routine. As a simple metric this family maintains
a count of the number of times the foreign routine is
invoked. This measure is treated as a rough indicator
of the total work performed by the fragment.
The second family is designed for tool fragments that
were implemented from scratch as weave components.
Here no effort is made to insulate the routine from the
weave. In this family the routine is invoked just once
upon tool fragment S t a r t . It is the routine’s responsibility to unpack the argument vector, collect objects
from read ports, process the objects, and then pass
them on to write ports. In addition, the routine must
respond to control requests. For example, in this family a Suspend only sets a boolean flag indicating that
a suspend request is outstanding. The routine is obligated to check the flag regularly, as well as to suspend
itself in a clean manner suitable for resumption.
zyxwvutsrq
zyxwvutsr
3
Weaving
zyxwv
mediates all of the environment services, including the
instrumentation of programs, data collection, analysis, and presentation. The weaves constructed by the
Gauge weaver are composed of small tools interconnected by data streams. Although the Gauge d a t a
flow networks resemble weaves in the abstract, they
are substantially different in detail and execution. Every action within Gauge is eventually translated into a
relationship between inputs and desired outputs. The
weaver must stitch together a weave that consumes the
inputs, produces the desired outputs, and satisfies the
relationship. The individual tools comprising the weave
are described in terms of their input/output behavior.
Each tool is characterized according to the types of its
inputs and outputs and the properties they have. Some
tools can be used in a variety of ways. There is one description for each of the possible tool applications, so
that the same tool might be mentioned repeatedly in a
related series of descriptions.
The weaver works backwards from the goal outputs,
by locating tools that can produce the desired outputs and satisfy the required input/output relationships. The inputs of these tools become the new goal
outputs, and the weaver recursively tries to satisfy the
new requirements by connecting the outputs of each
newly discovered tool to the corresponding inputs of
the consuming tool. Weaving terminates when all of
the original inputs are being used as inputs to some
tool in the weave and all relationships are satisfied. As
a heuristic, if there are several weaves that fully satisfy the constraints, then the smallest weave is selected.
If there are still several satisfactory weaves remaining,
then the first weave that was constructed is selected.
The Gauge weaving was done “on the fly” for every
significant action.
Contrary to our intuition, the cost of the dynamic
weaving was insignificant (< 1%) in comparison to the
total cost of executing the resulting weave. Furthermore, the use of the weaver had an important beneficial
effect on the internal organization of Gauge. It was possible to make significant changes to Gauge by simply
modifying the tool descriptions to reflect the addition
of new tools or changes to existing tools. We would
typically breadboard services by adding new tool descriptions (without bothering to implement the tools)
and then request the weaver to create a weave to satisfy the service but not execute the weave. To satisfy
the input requirements of new tools, in many cases the
weaver was able to exploit existing tools in unanticipated ways, even at times making the weave smaller
than those we had constructed by hand.
One can assemble weaves in a variety of ways: manually, using a specification language to specifying individual software components and their interconnections;
interactively, by using a graphical editor to sketch the
weave, selecting its components from libraries of components; or automatically, by leaving the details of component selection and interconnection to the discretion
of an automated agent, a weaver. All of these different methods of assembly, ranging from “hand-coded”
to fully automatic, could be intermixed. For example,
during rapid prototyping a system architect could direct the weaver to assemble subweaves automatically,
using the graphical weave editor afterwards to connect
the pieces. During system implementation, critical portions of a weave could be manually optimized by means
of the specification language and then stored in the
weave library for later use. Finally, during system test
and integration, the test team could use the graphical
weave editor to insert a test instrument into a specific
communication path, to verify that a system requirement is satisfied.
Graphical dataflow editors have appeared in a number of other contexts, and we will not discuss these editors here. The IDeA design environment [ll], TDFL
[lo], PegaSys [12], and VERDI [13] allow a user to
sketch a data flow task interactively, while the environment performs the clerical tasks of maintaining network
consistency, recording designs, and performing a variety of design checks. Several commercial products for
scientific visualization, such as ConMan [14] or AVS
[15], also have data flow editors for constructing largegrain data-flow graphs, where each node in the graph
executes as a separate heavyweight process.
In the current implementation, weaves are objects
and their methods constitute a simple assembly language for specifying weaves. In contrast, a weaver frees
users to state their requirements in terms of high-level
goals. A weaver then selects and interconnects software
components that satisfy these goals. A similar planning
component has been implemented in the IDeA environment [ll]. We have been experimenting with weavers
since early 1988 and have used one as the central orga
nizing agent in a large, complex performance-analysis
environment called Gauge [16]. We describe the role
of the weaver in Gauge and then briefly outline how
we intend to deal with the scaling issues that a large,
robust weaver faces.
Gauge is an environment for the performance analysis of logic programs. The weaver embedded in Gauge
zy
zyxwvuts
zyxw
zyx
29
zyxwvuts
In other words, the weaver acted as an integrative
glue for Gauge, so that new tools or services could be
added without concern for the details of interconnection or integration. The implementor of a tool was
largely relieved of the burden of worrying about how
the tool fit into the rest of Gauge (while still adhering
to the data protocol conventions of inter-tool communication). Instead, the problem of providing new services was narrowed to local concerns, the construction
of a single tool for performing a well-defined processing
task.
Gauge’s tool descriptions covered from 50 to 80 tools
and the largest weaves the Gauge weaver ever produced
contained from 15 to 20 tools. Encouraged by the
Gauge experience, we are now investigating techniques
for scaling weavers to produce weaves containing 50
to 100 tool fragments selected from repositories containing thousands of tool fragment descriptions. We
expect the weaver t o be used in concert with graphical
weave editors and hand-assembled weaves. However,
even in this limited role, weavers, backed by adequate
tool-fragment libraries, may improve the productivity
of software engineers. Finally, systems containing an
embedded dynamic weaver will probably be the exception, and we expect that most systems will be woven
statically and then assembled.
Our second-generation weaver will be based on
the paradigm of partial-order programming [17,
181. Partial-order programming expresses computa
tion declaratively, as statements of ordering. Each
partial-order program specifies a domain D of values
with partial order E; a set B 2 D of objects; and
a set of ordering constraints C of the form U C ‘U,
where U , ’ U E B. A semantics for a partial-order program is an assignment of values in D to each object B
such that all constraints in C are satisfied. A partialorder programming problem is a statement of the form
“minimize g subject to P,” where g E B is a specific
object and P is a partial-order program as described
above. A solution of a partial-order programming problem is a semantics for P that minimizes g. There may
be many, one, or no solutions.
It is profitable to view specifications of the properties and functional behaviors of tool fragments as s y s
tems of constraints over partial orders, and a weave as
the solution to a partial-order programming problem.
Partial orders are powerful organizing mechanisms in
knowledge representation. Ordering underlies type hierarchies, generalization or abstraction, composition,
aggregation, and causal relationships. Tool fragments
will be described by constraints that delimit their lo-
cation in a multidimensional universe of partial orders.
This application of partial-order programming is a generalization of the domain characteristics of IDeA [ll]
and of the concept of facets [19] for cataloging reusable
software components.
In addition, there is a duality between weaves and
partial-order programs, where tool fragments are equivalent to systems of constraints over partial orders, and
interconnections among tool fragments are equivalent
to common variables shared by separate systems of constraints. In this view, constructing a weave is equivalent to growing a system of constraints from a fixed pool
(library) of subsystems of constraints, so that the system (weave) always remains consistent. This approach
will permit the concise description of tool fragments,
and algorithms for resolving partial-order programming
problems can be directly applied to generating weaves.
zyxwvutsrqpo
4
Analysis of Weaves
The structure of weaves aids us in understanding their
dynamic behavior; this understanding is achieved by
capturing and analyzing information produced by the
weave itself. In this section we discuss the mechanisms
for controlling weaves and capturing information, after
which we turn to their use in analysis.
The principal mechanisms for the analysis of weaves
are the following:
0 Self-metric tool fragments. In weaves, permanent
low-overhead instrumentation is the norm. The authors of tool fragments embed inexpensive instrumentation in their software [ZO] and provide access methods
(exploited by observers, described below) with which to
extract the needed information.
0 Instruments. Instruments are specialized tool fragments whose sole purpose is to collect, transparently,
information about the objects flowing through them.
Inserted into a weave, instruments monitor objects that
appear at the interfaces between tool fragments. Instruments are therefore limited by the granularity of
the tool fragments; the finer the granularity, the more
information that can be captured.
0 Observers. Observers collect information from instruments, queues, and tool fragments and perform
analyses. The separation of observation from data capture permits us to build low-overhead instruments that
can be left in place permanently, while we are free to
construct observers with varying precisions and costs.
0 Actors. Actors, the agents for regulating tool fragments and queues, provide the control needed to per-
zyxwvut
zyxwvutsrq
zyxwvutsrqp
zyxwvutsrqp
zyxwvutsr
zyxwvuts
30
zyxwvut
zyxw
zyxwvuts
zyxwvutsrq
zyxw
the weave.
form experiments or make observations.
We explore each of these mechanisms in detail below.
4.2
4.1
Self-Metric Tool Fragments
Instruments
Instruments are additional tool fragments whose sole
purpose is to monitor data object flow at some flow
boundary. Instruments must adhere to flow transparency; that is, they may inspect, but not modify, the
objects passing through them. In other words, they
are side-effect-free with respect to these data objects.
Consequently, instruments form a subclass of tool fragments whose behavior is quite simple: they receive objects from read ports, perform simple counting or classification functions, and then send the objects on to
write ports. Figure 7 shows a simple weave composed
of two tool fragments with an instrument interposed
(transparently) between them.
Often the author of a tool fragment can anticipate that
some metric will be useful in analyzing weaves containing that fragment. Software that contains embedded instrumentation is called self-metric [20]. Typically
only the simplest and cheapest of mechanisms are used,
such as boolean flags or counters. Despite their obvious
limitations, these measures can be sufficient to obtain
sophisticated analytical results [21]. Each tool fragment supplies access methods for retrieving the data
collected by these flags and counters. Since tool fragments are objects, the class hierarchy of tool fragments
can be used to define families of tools that provide the
same functionality but with varying degrees of instrumentation. For example, all tool fragments inherit a
method that reports whether the tool fragment is active
or suspended. Various tools elaborate this by reporting
on intermediate transitions.
This instrumentation is not limited to tool fragments. Queues are also self-metric. Functional families of queues provide information at varying levels of
detail. The base queue class supplies a method that
reports the number of objects enqueued in a queue.
More-specialized classes, by calculating the size of each
waiting object, report the total amount of data enqueued. Other queue classes supply methods that report on the types or average waiting time of the objects
being transported.
Since each tool fragment runs as an independent
thread and concurrently updates its state or sends and
receives data objects, access contention over embedded
measures can arise. The contention is of the singlewriter, multiple-reader variety; a tool fragment updates
the state information, but many external observers may
read it. Because we tolerate imprecision, locking is
unnecessary. For example, acquiring the length of a
queue does not interfere with reading or writing that
queue, since no observer requires that the exact length
be known. Sacrificing precision is an important means
of reducing the overhead associated with instrumentation. Observers must also tolerate inconsistency, since
tool fragments, instruments and the like may update
state variables asynchronously during their inspection
by an observer. Consequently, conservative observers
may be limited in the accuracy of their analyses. Users
are free to substitute more accurate observers at the
price of higher overheads and greater interference with
@
@ myweave
Figure 7: Example Weave
The simplest example of an instrument is the genericobject flow meter, which counts the total number of
objects that have passed through it. It receives encapsulated objects (envelopes), increments a counter, and
sends the objects on again. By deliberately ignoring the
contents of the envelopes, flow meters monitor streams
without incurring the overhead caused by the repeated
decapsulation and encapsulation of data objects.
A more-sophisticated instrument classifies the objects according to their types. Within the instrument,
each object type has an associated counter. As each
data object is received, its type is examined, the appropriate counter is incremented, and the object is passed
on. Processing is limited to reading the type informa
tion written on an envelope, but without opening the
envelope.
These two examples illustrate how a hierarchy of increasingly specialized instruments can be built. The
most general instruments are oblivious to object types;
they can therefore be inserted in weaves at any level and
remain unchanged as object types become more refined.
This generality is particularly useful as weaves are successively refined by the replacement of tool fragments
31
zyxwvutsr
zyxwvutsrqp
zyxwvutsr
with subweaves. Although more-specialized instruments provide more type-specific information about the
objects they monitor, they are limited accordingly in
their general utility. Tradeoffs among the generality,
utility, and cost of instrumentation are readily supported by the mechanisms outlined above.
4.3
per second is sufficient for weave debugging and coarse
performance analysis.
0bservers
The instruments discussed above are only collection
mechanisms- they do not analyze or display the information in any way. This partitioning of responsibility
ensures that instrumentation overhead does not significantly interfere with the performance of a weave. Observers are agents whose sole purpose is to analyze and
present the measures collected by instruments, queues,
and self-metric tool fragments. Three considerations
dictate the overhead imposed by an observer: the frequency of measure collection, the complexity of the
analysis function, and the presentation of the analysis.
A variety of mechanisms exist for triggering observations, with each mechanism supporting a different
frequency of collection and therefore representing some
tradeoff between cost and precision. Here precision
means information that is consistent with the internal state of tool fragments and queues. An observation
that is triggered every time the state of a tool fragment
changes can introduce significant overhead but be capable of yielding very precise information. Conversely,
an observation that is triggered externally by a sampler enjoys a lower overhead but may be less precise.
The separation of the observers from instruments, and
the provision of a triggering mechanism for observations, allow us to implement analysis tools that have
a full range of precisions and overheads. Users choose
the precision appropriate to their needs and pay the
corresponding price in overhead.
To illustrate the importance of this separation, consider an observer that monitors queue length. If updates are posted to an observer every time an item is
added to or removed from the queue, the observer will
always have information consistent with the state of the
queue. However, with message-passing rates on the order of thousands of messages per second, the overhead
is prohibitive. Instead, if the same observations are
triggered only periodically, the overhead is small but
inconsistencies may arise. Often we overestimate the
amount of precision required; that is, we worry needlessly about the effects of inconsistencies. For example,
contrary to intuition, in our experience a “queue-length
observer” that samples queue lengths only a few times
Figure 8: Counts and a Histogram
The uppermost display in Figure 8 is the output of
an observer that periodically samples the count maintained by a generic flow-meter instrument and updates
a display window. The lower display shows a more sophisticated observer that displays counts of data object
types and a simple histogram of their distribution.
Figure 9: Animation of a Weave
Our most sophisticated observer is one that animates
weaves. The animator constructs a representation of a
weave as a network of tool fragments and queues. Figure 9 is a snapshot of the output of the animator. Each
tool fragment, watched by its own tool observer, is represented by a labeled rectangle. Each queue, watched
by its own queue observer, is represented by an openended box. The numbers at the upper left and upper
right corners of each queue icon are the queue’s capacity and occupancy, respectively. The shaded portion of
a queue icon is a histogram of its relative occupancy.
The weave animator periodically triggers observations
32
zy
5
by each tool and queue observer. After interrogating
the status of the corresponding tool, each tool observer
updates its display of tool status. Similarly, queue
observers update their queue icons after interrogating
their queues. Although the individual actions of the
animator and its component observers are very simple, the resulting animation is a complex and very useful debugging tool. Our experience in building weaves
indicates that simple visualization tools can help one
quickly identify subtle flaws that might otherwise go
undetected.
4.4
Experience and Future Work
We constructed a prototype implementation in C++,
running on a Sun 3 under Unix, of the facilities described in the previous sections. The threads were implemented as a C++ layering over the Sun Lightweight
Process Library [22]. The graphics facilities used by observers and actors were built on top of Interviews [23],
an object-oriented widget set implemented in C++ to
run on X Windows.
A number of tool fragments have been implemented
for processing satellite telemetry. A variety of instruments and observers have also been implemented;
these are roughly split equally between those generic
to weaves and those specific to the satellite telemetry domain. The animator has been used extensively
as a debugging and performance analysis tool. We
have constructed several dozen weaves, each dealing
with some aspect of telemetry processing. The performance of weave message passing is about 6,000 objects/second, and their throughput is high enough that
they have been used for the nontrivial filtering of satellite telemetry, delivering data rates in excess of 100
kilobits/second.
Our initial experience has been so favorable that we
are attempting to engineer a ten-fold increase in the
performance and size of weaves. We recently ported the
thread package to Mach, whose kernel-level support for
threads should dramatically improve the performance
of weaves. Preliminary experiments show that weaves
with over 100 threads perform adequately. In contrast, the prototypes described above have been limited to 10-20 threads. The full Mach implementation
of weaves will be demonstrated in mid-1991.
We plan to use weaves to build a collection of tools
for the temporal analysis of extremely large (gigabyte)
event-trace streams. Simultaneously, a separate project
will be underway to use weaves as the foundation for an
engineering workbench for the development and exploration of alternative satellite telemetry-processing algorithms. Other avenues of investigation include the
re-engineering of aging software into weaves, and astrodynamical modeling using weaves. Our research will
concentrate on the specification of tool fragments and
weaves as partial-order programs, the development of
a weaver based on partial-order programming, the automated performance analysis of weaves, and the improved visualization of weaves and instruments.
In summary, weaves are interesting in several respects:
they use the object as the fundamental unit of ex-
zyxwvutsrq
zyxwvutsrqp
Actors
The analysis and debugging of weaves requires some
level of control over the execution of the weave. Actors regulate weaves by translating high-level control
requests into low-level control commands to individual
tool fragments and queues. Control is partitioned in a
manner analogous to that of observers. Tool fragments
and queues are responsible for implementing low-level
control, while issues of presentation and interaction are
the responsibility of the actor. For example, the base
class of tool fragments defines methods that guarantee
a minimal level of control, that is, suspension and reactivation. The weave animator discussed above (see
Figure 9) contains one actor for every tool fragment
in the weave. The state of each tool fragment is managed by its actor and is presented as an icon - the
idle and running figures, denoting suspended and active states, respectively. Clicking on a running (or idle)
figure causes the tool fragment to be suspended (or resumed) by the actor.
Weaves employ specialized tool fragments, known
as “border crossings,” for debugging, and specialized
actors, known as “border guards,” for controlling the
crossings. Each border-crossing tool fragment holds a
data object for inspection until the user signals that it
may pass on. A generic border crossing can determine
the class and size of the data object, and, for a number of primitive classes, can even extract the value of
the data object. The generic border guard can display
each of the properties extracted by the crossing and
control the passage of objects through the crossing.
Specialized crossings and guards can be constructed
for application-specificdata objects. Like instruments,
border crossings can be left in place at critical junctions for the lifetime of the weave. This partitioning
of responsibility and expense allows users to use sophisticated debugging tools without incurring excessive
overhead.
zyxwvuts
zyxwvuts
zyxwvuts
33
zyxwvutsr
zyxwvutsrqp
zyxwvutsrq
change in a data flow network;
0 they extensively use lightweight processes to implement large networks of cooperating tools;
0 they systematically exploit tool fragment boundaries as the natural sites for measurement and instrumentation;
0 they ubiquitously distribute low-overhead instrumentation that is so inexpensive it can be left in place
over the lifetime of the system;
0 they provide for the transparent, dynamic rearrangement of the network for the insertion of instruments or subweaves;
0 they permit debugging and analysis at all points
during system development, up to and including the
deployment of a production weave;
0 they can be partly synthesized automatically from
high-level specifications; and
0 they have the potential for parallel execution, on either shared-memory multiprocessors or distributed architectures.
To our knowledge the combined application of these
advantages to the systematic construction of streamoriented systems is novel. Over the next several years
we intend to make a substantial research investment in
weaves and their supporting technologies.
[8] H. Massalin and C. Pu, “Threads and input/output in the
Synthesis kernel,” in Proceedings of the Twelfth ACM Symposium on Operating System Principles, pp. 191-201,Dec.
1989. SIGOS Operating Systems Review, 23(5).
[9] P. Barth, S. Guthery, and D. Barstow, “The stream machine: A data flow architecture for real-time applications,”
in Proceedings 8th International Conference on Software
Engineering, pp. 103-110,IEEE Computer Society Press,
Aug. 1985.
[lo] P. A. Suhler, J. Biswas, K. M. Korner, and J. C. Browne,
IITDFL: A task-level dataflow language,” Joumal of Distributed and Parallel PTogramming, vol. 9, pp. 103-115,
June 1990.
[ll]
ings 11th International Conference on Software Engineering, pp. 23-32,IEEE Computer Society Press, May 1989.
[12] M. Moriconi and D. F. Hare, “The PegaSys system: Three
papers,” Computer Science Laboratory Report 145,SRI International, Menlo Park, CA 94025-3493,Sept. 1985.
[13] V. Y. Shen, C. Richter, M. L. Graf, and J. A. Brumfield,
“Verdi: A visual environment for designing distributed systems,” Joumal of Distributed and Parallel Programming,
vol. 9,pp. 128-137,June 1990.
[14]P. E. Haeberli, “ConMan: A visual programming language for interactive graphics,’’ Computer Graphics, vol. 2 2 ,
pp. 103-111,Aug. 1988.
[15] C. Upson et al., “The application visualization system,”
IEEE Computer Graphics and Applications, vol. 9,pp. 3042,July 1989.
zyxwvutsrqpon
zyxwvutsrqp
zyxwvutsrqpo
zyxwvutsrqpo
zyxwvutsrqpo
[16] M. M. Gorlick and C. F. Kesselman, “Gauge: A workbench
for the performance analysis of logic programs,” in Logic
Programming: Proceedings of the Fifth International Conference (R. A. Kowalski and K. A. Bowen, eds.), pp. 548561,MIT Press, Aug. 1988.
References
[l] D. Ritchie and K. Thompson, “The UNIX time-sharingsystem,” The Bell System Technical Joumal, vol. 57,pp. 19051930,July-August 1978.
(21
M.D. Lubars, “The IDeA design environment,” in Proceed-
[17] D. S. Parker, “Partial order programming,” Tech. Rep.
CSD-870067,Computer Science Department, University of
California, Los Angeles, Dec. 1987.
R. M. Karp and R. E. Miller, “Properties of a model for
parallel computation: Determinacy, termination, queuing;,”
SIAM Journal of Applied Mathematics, vol. 14,pp. 13901411,Nov. 1966.
[18] D. S. Parker, “Partial order programming,” in Proceedings
of Sixteenth Annual A C M SIGACT-SIGPLAN Symposium
on Principles of Programming Language#, pp. 1-7, ACM
Press, Jan. 1989.
K. M. Chandy and S. Taylor, “The composition of parallel
programs,” in Proceedings of the 1989 International Conference on Supercomputing, Nov. 1989.
[19] R. Preito-Diaz and P. Freeman, “Classifying software for
reusability,” IEEE Software, vol. 4,pp. 6-16, Jan. 1987.
K. M. Chandy and S. Taylor, “Examplesin program composition,” in Beauty is Our Business - A Birthday Salute t o
E. W . Dijkatra (W. Feijen e t al., eds.), pp. 94-101,SpringerVerlag, 1990.
[20] L. Stuck, “Automatic generation of self-metric software,”in
Proceedings 1979 IEEE Symposium on Computer Software
Reliability, pp. 94-100, 1973.
M. Barbacci and J. Wing, “A language for distributed applications,” in Proceedings of the 1990 International Conference on Computer Languages, IEEE Computer Society,
Mar. 1990.
[21] M. M. Gorlick and C. F. Kesselman, “Timing Prolog p r s
grams without clocks,“ in Proceedings 1987 Symposium on
Logic Programming, pp. 426-432,IEEE Computer Society
Press, 1987.
M. Barbacci,
D. Doubleday, and C. Weinstock, ”Application-levelprogramming,” in Proceedings of
the 10th International Conference on Distributed Computing Systems, pp. 458-465, IEEE Computer Society, May
1990.
[22] Sun Microsystems, Lightweight Processes Library, Nov.
1987. Sun Release 4.0.
[23] M. A. Linton, P. R. Calder, and J. M. Vlissides, “The design
and implementation of Interviews,” in Proceedings of the
USENIX C++ Workshop, (Sante Fe, New Mexico), Nov.
1987.
D. L. Black, “Scheduling support for concurrency and parallelism in the Mach operating system,” IEEE Computer,
vol. 23,pp. 3543,May 1990.
34