[comp.sys.apollo] DSEE Benefits / Converting to DSEE

bobr@zeus.TEK.COM (Robert Reed) (06/23/87)

In article <3596c60e.b0a1@apollo.uucp> nazgul@apollo.UUCP (Kee Hinckley) writes:

        DSEE manages binaries.  This means that if I'm working on one part of
    a system, and someone else is working on another, we can share binaries.
    DSEE keeps track of what binaries have been built using what compiler
    options.  The model description tells it which options are critical and
    which are not, so it knows whether or not you can use the result of
    someone elses build.  This is very nice on large projects when multiple
    people are working on different branches of a few files, but need to
    share the rest.  Furthermore you can tell DSEE whether or not the tools
    are critical, so if you get a new compiler, or translator or whatever
    tool you are using, DSEE will know whether it should recompile
    everything.

We could certainly reduce our disk requirements by sharing common binaries
and/or source files.  It's never been a problem for us, though.  Each of us
on the design team has a 1-2 MB directory containing private copies of all
the sources and objects, and our make dependency graph connects the sources
to a common RCS directory.  We have the option of including updated sources
for a particular make or not, which allows us to isolate ourselves from the
changes of others.  I would be concerned with a system that uses common
binaries which did not provide this isolation.  If a member of the team
releases a change which involves several binaries, one or more of which I am
also making changes to, is there some way to automatically prevent the
incorporation of the rest of the binaries involved in this change?  

For example, if a system consists of modules a, b and c, suppose someone
else has checked out b and c when I proceed to check out b.  I begin to make
and test changes to b, but suddenly a new version of b and c are released to
the world.  If these foreign changes to b and c are dependent on one
another, is DSEE flexible enough not to include the new object for c in my
subsequent builds of the system?  My guess is that since I have not checked
out c, I would get the common version, which may mean that my bind will fail
(if for example, my version of b had a vestigial external reference,
formerly resolved by c).

Management of binaries may be a very economic feature, but there are
pitfalls (which DSEE may handle adequately).  I know that private working
directories with Make/RCS can do the right thing.  I am curious whether DSEE
can do the same.  This is not meant as a challenge, just a plea for
information.

        DSEE can automatically perform actions when something happens (such as
    the replacement of an item).  So you can tell it to watch a file for you
    and tell you when it changes.

Change notification is certainly a useful service in a multi-person project.
We handle change notification by requiring a release note whenever any set
of files is returned to the common directory.  This gives an opportunity for
the developer to summarize the changes as well as give notice of them.  The
release note is mailed to each of the developers, to be examined at their
leasure.  I expect that DSEE uses a similar mechanism.  Though I rarely have
need for an explicit notice on the release of a particular file, I'll not
deny that it may have some use.  Providing a server for that purpose does
seem a bit of overkill (I am assuming that this function is handled by the
DSEE server), so I hope the server has more purpose than simple notification.

        DSEE supports threads.  These allow you to tell DSEE what versions of
    what files to use when you build, and what options to use on what files
    (either specifically or by wildcard).

    Threads allow you to do things like (as I just did now) tell DSEE that I
    want a different version of a header file and have it promptly know that
    as a result it has to recompile five other programs that depend on that
    file.

This appears to provide some features not available in Make.  I would have
to get a better description of them to acertain that.  I've felt for a long
time that the option selection features of Make are underpowered.  Regarding
the specific example, I would probably never use such a "thread."  We keep
two (actually more) versions of our program around, one with no debug and
one with debug in every module.  This avoids the hassle of chasing down a
bug, only to find that the path leads through a module which does not have
the debug symbol tables loaded.

        DSEE supports multiple builders.  For instance I have a version of
    the ICON programming language under DSEE.  It consists of 4 libraries
    (insert files, translator, linker, runtime) under control of a single
    dsee model.  There are about 80 files in all.  I'll start off a rebuild
    of everything right now and see how long it takes.  This will take a
    little longer than a normal build, since it purges the old builds in the
    process, but it should still give you and idea of the advantage.

I don't understand what you mean by "multiple builders."  Is it something
different from multiple Make targets?  You say that this should give us an
idea of the advantage.  I'm having trouble understanding what it is that
this gives an advantage over.  Are you comparing multiple builders versus a
single builder under DSEE?  Or, are you comparing features of DSEE and Make?
-- 
Robert Reed, Tektronix CAE Systems Division, bobr@zeus.TEK

Erstad@HI-MULTICS.ARPA (06/24/87)

This is mostly response to Robert Reed's comments regarding DSEE and
software development.  Two things should probably be made clear.  First,
I have no direct experience with RCS and will not make a direct
comparison based on what little I know.  Second, I am not trying to say
anyone "should" need any of the DSEE capability.  What I am saying is
that it has proved useful in our environment.  I'm not out to sell
anyone on anything.

Shared binaries save us LOTS of disk space.  I did a rough estimate
based on our common binaries and the number of people which would/might
be replicating them and at a minimum our disk space requirements would
increase by 100 MB.  Even though we have 7+ Gig, this is a lot to us.
This also saves a lot of build time when new releases are made.

There are several ways to isolate a development effort from unwanted
changes.  One is to use a command which will identify all the current
versions of source modules at the start of an effort.  In one's thread,
a statement of the form

   [dave_wants_these_versions]

will automatically use only those versions.  In general, I don't bother
since we tend not to make non-upward compatible changes (in theory at
least...)

Threads are very useful if, for reasons beyond your control, you are
forced to field multiple versions of code either temporarily or
permanently.  To date, we have never wanted to provide build control we
have not been able to do within DSEE.  The naming capability mentioned
earlier is one example of a useful capability of threads.  After
performing a build which is to be released, a command like

   NAME VERSION build_name  this_build_went_to_freds_group

allows me to readily rebuild the same build by using a meaningful name.
Additionally, I can use all of these items EXCEPT grab one module from a
different version, and so forth.  Multiple lines of descent are also
supported by the threads.

The multiple builder capability refers to having multiple nodes compile
in parallel.  This hasn't been released to me yet, so I can't comment on
the implementation, but for us this is a nice-to-have rather than a
critical item.  I can see where it is useful for sites with millions of
lines of code (like Apollo) rather than 100s of thousands of lines (like
us)

Dave Erstad

Honeywell SSED

nazgul@apollo.uucp (Kee Hinckley) (06/25/87)

In article <1907@zeus.TEK.COM> bobr@zeus.UUCP (Robert Reed) writes:
> to a common RCS directory.  We have the option of including updated sources
> for a particular make or not, which allows us to isolate ourselves from the
> changes of others.  I would be concerned with a system that uses common
> binaries which did not provide this isolation.  If a member of the team
> releases a change which involves several binaries, one or more of which I am
> also making changes to, is there some way to automatically prevent the
> incorporation of the rest of the binaries involved in this change?  
> 
> For example, if a system consists of modules a, b and c, suppose someone
> else has checked out b and c when I proceed to check out b.  I begin to make
> and test changes to b, but suddenly a new version of b and c are released to
> the world.  If these foreign changes to b and c are dependent on one
> another, is DSEE flexible enough not to include the new object for c in my
> subsequent builds of the system?  My guess is that since I have not checked
> out c, I would get the common version, which may mean that my bind will fail
> (if for example, my version of b had a vestigial external reference,
> formerly resolved by c).

Good question.  I'm having a little trouble explaining things today, so
bear with me, this is probably a bit longer than it need be.

Presumably you checked out B by making a branch off the mainline (since
the other person already had the mainline reserved).  (Alternatively of course
they may have made the branch and you have the mainline, it doesn't really
make any difference to this issue.)

In your thread you can specify any number of constraints.  The default is
simply to take any reserved files it finds in the current directory, and
then to take the most recent version of the common stuff.  If this is the
case then you won't run into any problems until someone changes something
in the mainline that you depended on.  In the case you describe if the new
versions of B and C are off on a branch then you don't have to worry, you'll
never see the binaries.  On the other hand if they are in the mainline (or
have been merged back into it) you could have problems.

The way to avoid this problem is to specify in your thread what version of
the common files you want to use.  I think this is probably best explained
by an example:

Here's what exists now (bracketed items are version numbers):
        a[1]    -> named SR9.2
        a[2]    -> named SR9.5

        b[1]    -> named SR9.2 and SR9.5

        c[1]
        c[2]    -> named SR9.2
        c[3]
        c[4]
        c[5]    -> named SR9.5

Now, P1 and P2 or both doing development based on SR9.5.  So your threads look
like this (we try and make sure that everyone working on a project uses the
same base thread so we know exactly what's going into the things we release):
    -for ?*.c -reserved -use -g
    -reserved
    -for ?*.c -use -O
    [sr9.5] -when_exists
    []

Read in order that says that:
o   All reserved C files are compiled with "-g".
o   Any other files that are reserved are also used.  (If we took out these
    two lines then we wouldn't use any reserved versions at all, useful when
    you want to make a pure release without including the stuff you are
    currently working on.)
o   All non-reserved files are compiled with "-O".
o   If there's a non-reserved file that has a version named "SR9.5", use that one.
o   Otherwise take the most recent version of the it.

Okay, now P1 reserves file "b" and file "c" from the mainline to do some work.

P2 comes along and wants to make a change to file "b".  Since it's already
reserved P2 has to create a branch, let's call it "/P2".

Now P1 replaces file "b" and file "c" with changes that are incompatible to
what P2 is doing.  As it happens P1 names these versions, but it doesn't really
matter for our purposes.  Now the state looks like this (ignoring file "a").
        b[1]    -> named SR9.2 and SR9.5
        b[2]    -> named SR9.6_BL1

        c[1]
        c[2]    -> named SR9.2
        c[3]
        c[4]
        c[5]    -> named SR9.5
        c[6]    -> named SR9.6_BL1

If P2's thread hadn't had the line "[SR9.5] -when_exists" then P2 would now
be getting the most recent version of "c" and would be in trouble.  However
as it stands P2 will continue getting version 5 (SR9.5) of "c" and will still be
getting the reserved copy of "b".  So everyone's happy.

Now let's take the scenario a little further.  P2 decides to check "b" back
in, but not to merge it into the mainline yet since it still needs some testing.
Now the state of "b" looks something like:
        b[1]    -> named SR9.2 and SR9.5
            b/P2
        b[2]    -> named SR9.6_BL1

Now if P2 wants to specify that in P2's compiles that branch is always used,
the thread has to be changed to look like:
    -for ?*.c -reserved -use -g
    -reserved
    -for ?*.c -use -O
    /P2 -when_exists
    [sr9.5] -when_exists
    []

Note that because of the order the "/P2" branch will be used whenever their
might be a conflict between "/P2" and "[sr9.5]".  And all throughout this
there will still be no confusion between the binaries.  In fact, since
DSEE knows what compile options were used, it won't even confuse binaries
that have different compile options, so if you specified that all non-reserved
binaries were also compiled with "-g" you would only get those common binaries
which had been compiled with that option.


> Change notification is certainly a useful service in a multi-person project.
...
> deny that it may have some use.  Providing a server for that purpose does
> seem a bit of overkill (I am assuming that this function is handled by the
> DSEE server), so I hope the server has more purpose than simple notification.

I had to run off and ask about this one.  Basically there are two kinds of
monitors.  One executes arbitrary commands when you perform a specified action 
(e.g. send mail to everyone telling them that a file has been checked in).  The
other adds "tasks" to a "task-list".  I'm not going to go into any detail on
that, since I've never used it.  The basic idea is that you can set up a task
list of things to do, and the act of checking a file in or some similar
action can be made to trigger a task which will remind you of what you have
to do next.  As it turns out neither of these use a server, both are executed
by DSEE at the time you perform the action.  (You can also specify whether
a monitor is to be executed for everyone, just for you, or just for everyone
else.  And obviously there are protections concerning *who* can create monitors.)

> I don't understand what you mean by "multiple builders."  Is it something

Sorry, I should have explained the terminology.  

A "builder" is the machine ("node") on which the compile ("build") actually takes
place.  What DSEE allows you to do is give it a list of up to 20 different
machines which can be used to build things.  Since DSEE has a clear idea of
who depends on what, it knows which things can be built in parallel and which
must wait for the results of some other build.  It then spawns off each 
task to a different machine.  Two things make this even more useful.  

First of all it checks the load on the machine and won't use it unless it's 
relatively idle.  That way you seldom notice that someone is using your machine 
for a build.  Occasionally you will notice if you start something while a build 
is underway, but DSEE checks for activity before each individual build, so once 
the current task is done it won't come back until your node is idle again.

Secondly it allows you to specify a reference pathname which the "/" directory
will resolve to.  In other words, if my model makes references to tools in
"/bin" and sources in "/usr/nazgul/src" I don't have to worry about whether
the tools are the same on other machines, or whether the pathname (or link)
"/usr/nazgul/src" exists on the remote machine.  As far as the remote process
is concerned the directory structure looks like my machine.  That means I
don't have to specify absolute network pathnames anywhere and then worry about
what happens if I change the name of my machine or move the sources somewhere
else.

All of this is done automatically, so long as you somewhere tell DSEE what
machines to use.  For instance, here's the line from my dsee startup file.

set builder -reference //morgul //anarres //morgul //faerie //caruso //northpeak //marvin

That tells it that the reference machine (to which "/" will refer) is mine
("//morgul") and that when doing builds it should look for CPU time on "//anarres",
then my node, and then the others, so on down the line.  (Actually, looking at
this I just realized that I only have 6 builders listed, I think I'm going to
go hunt down some more fast machines. :-)

....

And THAT is more than enough about DSEE for now.  Hope it helps.

                                                    Kee Hinckley
                                                    User Environment
-- 
UUCP: {mit-erl,yale,uw-beaver}!apollo!nazgul  ARPA: apollo!nazgul@eddie.mit.edu
I'm not sure which upsets me more; that people are so unwilling to accept
responsibility for their own actions, or that they are so eager to regulate 
everyone else's.

mishkin@apollo.uucp (Nathaniel Mishkin) (06/26/87)

I think Kee's message did a fine job of explaining the subtleties of
DSEE.  One important point about sources and binaries is getting lost
in the noise though:  DSEE users always deal with sources and source
specifications, not binaries.  DSEE completely manages binaries (and
assuming the user hasn't lied about the relationships among the pieces
of his system, DSEE doesn't ever get confused about what binaries
correspond to what sources and options.)  The DSEE user does not say
"use these binaries", s/he says "I want the thing that results from using
such-and-such versions of sources".  "such-and-such versions of sources"
is a function of the "thread" (described in Kee's message) and the "system
model", a block-structured description of the relationships among sources
and results of compilations.  A sample model fragment:

    aggregate ls =
        depends_result
            element ls.c =
                depends_source
                    sort.h;
                end;
        
            element sort.c =
                depends_source
                    sort.h;
                end;
        end;

This says that there's an aggregate (read "program") "ls", the building
of which depends on the result of building "ls.c" and "sort.c", and that
both "ls.c" and "sort.c" depend on the source (i.e. textually) of "sort.h".
(Note: there more to the model than I've shown.) The model says nothing
about particular versions or binaries.

When a user asks to build "ls", the model plus the user's current thread
yields a tree-structured description (analogous to the model tree
structure, with the addition of particular version numbers for every
source element) of what the user wants.  DSEE then searches its "binary
pool" (a directory that the user never looks at where DSEE keeps binaries;
binaries are tagged with the tree-structured description that describes what
source versions were used to build the binaries).  If it finds matching
entries in the pool, it just uses them; if it doesn't, it creates them
(by running the correct "translate" rule from the model).
-- 
                    -- Nat Mishkin
                       Apollo Computer Inc.
                       Chelmsford, MA
                       {wanginst,yale,mit-eddie}!apollo!mishkin

bobr@zeus.TEK.COM (Robert Reed) (06/30/87)

Thanks for the exposition about DSEE, Kee.  It's clear that DSEE can handle
the source parallax problem I previously described.  I still like the system
we have with Make and RCS better.  We buy convenience, and pay for it with
disk space.

From your explanation, I see that the difference between the two systems is
that where we have an implicit selection of version by choosing which
source/object pair is sitting in our individual development directory, the
canonical approach in DSEE is to maintain an explicit enumeration of all the
versions which comprise a particular "build" of the system.  Where we just
copy a new source file into our development directory, the DSEE approach is
to edit the "thread" to redefine the configuration through explicitly named
releases of system components.

Not being a DSEE user, I can only speculate on how well this works, but if
you have a complicated system with many (say a hundred) source files and
many (say more than 5) developers, either the threads must get quite
complicated or a lot of time is spent assigning new version numbers to the
tops of trunks of all the components.  Do you find either of these fit your
operating environment, and do either of them pose a problem?  Do you have
any mechanism which automatically updates your thread to adjust the build
for:

    1) Sealing your particular set of versions to prevent such side effects
	as have been described,

    2) Incorporating changes made by other developers, performing source
	level merges where necessary, while preserving your changes as
	nonreleased reservations to prevent possibly buggy development code
	from reaching other developers,

    3) Release your private changes to the world, making your next build be
	strictly "top of trunk".

I suspect such a utility should be possible, though it would probably
require a lot of global version number assigment to manage the bookkeeping.
All these functions are of course quite easy using our existing system.

We do pay other penalties for our approach.  Since we have separate copies
of binaries, we get a lot of duplication in compilation.  Include file
changes can propogate a lot of identical and unnecessary build steps.  Most
people have cheater scripts that do a simple compile and link for making
small changes to the system, and periodically these scripts must be updated
to reflect the new set of components and compile time options required to
build the system.

    Basically there are two kinds of monitors.  One executes arbitrary
    commands when you perform a specified action (e.g. send mail to everyone
    telling them that a file has been checked in).  The other adds "tasks"
    to a "task-list".  I'm not going to go into any detail on that, since
    I've never used it.  The basic idea is that you can set up a task list
    of things to do, and the act of checking a file in or some similar
    action can be made to trigger a task which will remind you of what you
    have to do next.  As it turns out neither of these use a server, both
    are executed by DSEE at the time you perform the action.

Okay, so the server is not used for notification.  I've heard that DSEE does
have a server.  Why?  What functions DOES it perform?

    A "builder" is the machine ("node") on which the compile ("build")
    actually takes place.  What DSEE allows you to do is give it a list of
    up to 20 different machines which can be used to build things.  Since
    DSEE has a clear idea of who depends on what, it knows which things can
    be built in parallel and which must wait for the results of some other
    build.  It then spawns off each task to a different machine.

I've been intrigued with this sort of facility since I first heard it
described a year or more ago.  A friend who works at Sequent described their
"parallel Make" which takes (mostly) a standard makefile and performs the
same function.  Unfortunately, we have no such facility here.  (As Apollo
migrates towards a more UNIX-like SR10, it would be great if they built a
similar function into the Make they provide :-)
-- 
Robert Reed, Tektronix CAE Systems Division, bobr@zeus.TEK

joelm@apollo.uucp (Joel Margolese) (07/01/87)

In article <1938@zeus.TEK.COM> bobr@zeus.UUCP (Robert Reed) writes:
>    From your explanation, I see that the difference between the two systems is
>    that where we have an implicit selection of version by choosing which
>    source/object pair is sitting in our individual development directory, the
>    canonical approach in DSEE is to maintain an explicit enumeration of all the
>    versions which comprise a particular "build" of the system.  Where we just
>    copy a new source file into our development directory, the DSEE approach is
>    to edit the "thread" to redefine the configuration through explicitly named
>    releases of system components.

You only need to edit a thread when you want rebuild a particular version
of something or select (and lock) the versions that you use.  The "default"
thread is:
 -reserved
 []
Which means, any element that I have reserved or the most recent version of
all other elements.  Therefore, whenever any source files are replaced,
(or "put back into your development directory") they will be picked up.  Since
that behaviour is what most people (around here anyways) seem to want most
of the time, it just works.
 
If you are working on a specific project, the project may have a thread
such as:
-reserved
/sr9.5 -when_exists
[sr9.5] -when_exists
[sr9.0]
 
Which says: give me the latest version of anything on a branch names /sr9.5,
or give me a version named [sr9.5], which is a fixed name, or just give
me the version that was used in sr9.0.  The selection is done by first match.
 
i.e.
       element foo[1]       bar[1]                   fred[1]
               foo[2]       bar[2]->bar/sr9.5[1]     fred[2][sr9.5]
               foo[3][sr9.0]          bar/sr9.5[2]
                            bar[3]       
 
For element foo we select version 3, for bar we select bar/sr9.5[2]
and for fred we select version 2.
 
Note that I never change my thread again for the life of the project, nor
do I have to know what versions change or have to maintain separate
development directories.                

>Not being a DSEE user, I can only speculate on how well this works, but if
>you have a complicated system with many (say a hundred) source files and
>many (say more than 5) developers, either the threads must get quite
>
>    1) Sealing your particular set of versions to prevent such side effects
>	as have been described,

We periodically take make baselevels.  To do this an administrator will 
take a snapshot by building the object (assuming that it is tested, stable
whatever) and creating a release.  The release contains a description of
what versions were used to build the object and all of its subcomponents.
(It can contain more, but that is all we bother to save.)  Note that
we do NOT snapshot binaries.  All you need is the description of how
to build anything and the binaries are regenerable if they happen to get
flushed out of the pools.  If the baselevel is used as a reference point,
the binaries stick around, if not, say as the baselevel ages and becomes
obsolete, the binaries get flushed out of the pool automatically.  Therefore
the cost of a baselevel (release) is very low.  (a few disk blocks.)
To build off of such a baselevel the thread just needs to say:
  -reserved     (if you want this)
   foo!/release/pathname -versions



>    2) Incorporating changes made by other developers, performing source
>	level merges where necessary, while preserving your changes as
>	nonreleased reservations to prevent possibly buggy development code
>	from reaching other developers,
>
DSEE also provides quite a good 3 way merge system, (vastly improved: i.e. now
usable) at version 3.0) that does source level merges.  It does not work that
well if the changes are *really* extensive, but for routine changes, it
generally does the whole merge automatically.  (And usually gets it right!)
Because of the history files, DSEE can see the common ancestor and the two
changed files and figure out which file changed what.  It only asks for your
help if both versions changed the same code, then you get to pick which version
you like better, or edit it yourself.  It also keeps track of what has
been merged, so that if you change 30 modules you can say something like:
 show elements -missing -merge -with foobar
The changes are not replaced until the developer issues a replace command.  This
is useful for several developpers who want to stay in sync.

>    3) Release your private changes to the world, making your next build be
>	strictly "top of trunk".
>                           
Answered above, I think.

>All these functions are of course quite easy using our existing system.

Our experience here (which does not necessarily apply everywhere) was it was
no easier for just doing mainline development under dsee, but once you
started doing anything in parallel, or wanted to experiment with versions
DSEE became invaluable.  It is the old story: You don't miss it until you've
tried it and lost it.

>
>We do pay other penalties for our approach.  Since we have separate copies
>of binaries, we get a lot of duplication in compilation.  Include file
>changes can propogate a lot of identical and unnecessary build steps.  Most
>people have cheater scripts that do a simple compile and link for making
>small changes to the system, and periodically these scripts must be updated
>to reflect the new set of components and compile time options required to
>build the system.
 
This sounds like much more work that we do to keep track of the correct thread,
and a lot more error prone.  DSEE also gives us the ability to look at a
build in a DSEE pool and determine exactly what versions of each file were
used so that we can have a high degree of confidence in what we've built.
DSEE also allows you to declare "equivalences", it means saying: I've just
changed foo.ins.pas, and there are 72 modules that depend on it.  But I
know that that only 3 need to be rebuilt.  For all the others, assume
that foo.ins.pas[3] is equivelent to foo.ins.pas[2].  Specifing that is
not very hard, DSEE will prompt you for everything.

>
>    Basically there are two kinds of monitors.  One executes arbitrary
>    commands when you perform a specified action (e.g. send mail to everyone
>    telling them that a file has been checked in).  The other adds "tasks"
>    to a "task-list".  I'm not going to go into any detail on that, since
>    have to do next.  As it turns out neither of these use a server, both
>    are executed by DSEE at the time you perform the action.
>
>Okay, so the server is not used for notification.  I've heard that DSEE does
>have a server.  Why?  What functions DOES it perform?

DSEE does not (in general) have a server.  There is a d3m server which runs
on nodes that have DSEE libraries, d3m is the database manager.  DSEE also uses
the alarm_server (which runs on most nodes anyways) as a way of sending some
notifications.  (One of the possible monitor actions is to send an alarm to
somone that some element has been modified or whatever.)  DSEE itself can run
as a server and will then accept input via mailboxes.  This of course works
across the network the same as on individual nodes.  This allows you to
design a custom interface or a set of shell level commands or whatever
to communicate with DSEE.  Most DSEE functions are also available via a
released (*some* things get released! :-)) set of calls to the dseelib
global library, so you could write your own server if you really want to.


I am not a DSEE developper, just a heavy user who likes to tell people about
neato things they can do by moving up to newer tools.  (Ok, so I'm biased,
why not?)
 
                                                      Joel
-- 
Joel Margolese          UUCP:      ...{attunix,uw-beaver,decvax!wanginst}!apollo!joelm
Apollo Computer         ARPA:     apollo!joelm@eddie.mit.edu
                        INTERNET: joelm@apollo.com

bobr@zeus.TEK.COM (Robert Reed) (07/02/87)

In article <35cd8d38.86ca@apollo.uucp> joelm@apollo.UUCP (Joel Margolese) writes:

    > versions which comprise a particular "build" of the system.  Where we just
    > copy a new source file into our development directory, the DSEE approach is
    > to edit the "thread" to redefine the configuration through explicitly named
    > releases of system components.

    You only need to edit a thread when you want rebuild a particular
    version of something or select (and lock) the versions that you use.
    The "default" thread is:
     -reserved
     []

    Which means, any element that I have reserved or the most recent version
    of all other elements.  Therefore, whenever any source files are
    replaced, (or "put back into your development directory") they will be
    picked up.  Since that behaviour is what most people (around here
    anyways) seem to want most of the time, it just works.

This simplified approach of course breaks the scheme that Kee so carefully
outlined to isolate simultaneous source modifiers from partial release side
effects, and so it doesn't answer the question I was posing.


    > 1) Sealing your particular set of versions to prevent such side effects
    >    as have been described,

    We periodically take make baselevels.  To do this an administrator will
    take a snapshot by building the object (assuming that it is tested,
    stable whatever) and creating a release.

Perhaps I failed to explain myself adequately.  Perhaps you failed to read
the discourse between Kee and myself.  In any case, I don't believe you
understand my questions.  The members of our engineering group have
interchangable responsibilities for code and so operate in an environment
where it is desirable to allow multiple simultaneous reservations for
sources.  One of the side effects of such an environment is a sort of update
parallax error, where the simple priority scheme you outline for determining
which version to use just won't work.

    > 2) Incorporating changes made by other developers, performing source
    >	level merges where necessary, while preserving your changes as
    >	nonreleased reservations to prevent possibly buggy development code
    >	from reaching other developers,

    DSEE also provides quite a good 3 way merge system, (vastly improved:
    i.e. now usable) at version 3.0) that does source level merges.  It does
    not work that well if the changes are *really* extensive, but for
    routine changes, it generally does the whole merge automatically.  (And
    usually gets it right!) Because of the history files, DSEE can see the
    common ancestor and the two changed files and figure out which file
    changed what.  It only asks for your help if both versions changed the
    same code, then you get to pick which version you like better, or edit
    it yourself.  It also keeps track of what has been merged, so that if
    you change 30 modules you can say something like:

     show elements -missing -merge -with foobar

    The changes are not replaced until the developer issues a replace
    command.  This is useful for several developers who want to stay in
    sync.

These seem on par with the facilities available through RCS.

    > We do pay other penalties for our approach. ...

    This sounds like much more work that we do to keep track of the correct
    thread, and a lot more error prone.  DSEE also gives us the ability to
    look at a build in a DSEE pool and determine exactly what versions of
    each file were used so that we can have a high degree of confidence in
    what we've built.  DSEE also allows you to declare "equivalences", it
    means saying: I've just changed foo.ins.pas, and there are 72 modules
    that depend on it.  But I know that that only 3 need to be rebuilt.  For
    all the others, assume that foo.ins.pas[3] is equivelent to
    foo.ins.pas[2].  Specifing that is not very hard, DSEE will prompt you
    for everything.

No, there is very little work involved since the list of linker modules
changes very infrequently these days, and when it does, there is a file
which always has the proper list, so editing involves deleting the old list
and incorporating a new one.  I do that once every couple of months.  The
equivalency notion of DSEE sounds intriguing.  Do such equivalencies ever
get obsoleted?  Are they easy to keep track of?  Are they based on analysis
or hunch?

This has been a great discussion.  Unfortunately (or fortunately), I'm going
on vacation for a couple of weeks, and so will have to drop out now.  See
you when I get back.
-- 
Robert Reed, Tektronix CAE Systems Division, bobr@zeus.TEK

billj@zaphod.UUCP (07/04/87)

Although I've read the published papers on DSEE, and seen it demoed in
toy situations, I still have some uncertainty about the system's
capabilities.  Though the questions below deal with more demanding
situations, they are not intended as potshots, just requests for
information on DSEE's current practical limits.  All the situations
below, BTW, are everyday real-life concerns in our own environment.

- is there support for maintaining, as Bob Reed mentioned, parallel
  systems of derived objects, say one with debugging turned on and one
  not?  Or will most of the binaries have to be recreated on each build
  as the pool cache capacity is reached?

- in the above environment, what support is there for variant
  implementations of the same module?  Must the elements be named
  differently, and the system model preprocessed, to avoid conflict, or
  can they be distinguished automatically in the directory structure?

- can a bug-fix or feature branch to several elements be treated
  (e.g. named or merged) globally, or must the operations be repeated
  for each element affected?

- can a system be composed of subsystems each maintained in its own
  directory structure, or must there be a single system model (with
  absolute pathnames) for the whole?

The next few questions deal with evolutionary systems where not only
the module code, but the module structure itself may change over time.

- the extracts quoted from system models indicate that include
  dependencies must be specified manually.  I understand that there is
  a make_model program to determine these automatically when the model
  is first written, but has there been any support added to generate
  them dynamically at build time?

- if the structure of the system is changed at some point in a way
  which significantly affects the system model, will subsequent
  modifications to earlier configurations see the new or old model?

My thanks to the long-suffering correspondents at Apollo for any
answers they can provide.
-- 
Bill Jones, Develcon Electronics, 856 51 St E, Saskatoon S7K 5C7 Canada
uucp:  ...ihnp4!sask!zaphod!billj               phone:  +1 306 931 1504

oj@apollo.UUCP (07/07/87)

In article <1745@zaphod.UUCP> billj@zaphod.UUCP (Bill Jones) asked
a bunch of questions about DSEE.  I'm another Apollo in-house DSEE
user, and fan, but I'm not a DSEE developer.  Here are my answers
to Bill's questions (which I've trimmed a bit):

>- is there support for maintaining parallel
>  systems of derived objects...? Or will most of the binaries
>  have to be recreated on each build
>  as the pool cache capacity is reached?

Parallel systems are supported.  Different pools can
be used for different variants(like debugging on and off).
Options (typically, compiler options like CPU variants, debugging,
optimization) can be specified as either
 -- "critical" meaning if the binary pool doesn't contain an
               an object that was made with the option, DSEE will
               remake it with the option.
 -- "noncritical" meaning that DSEE will accept the same source
                  file, but compiled with a different options.
(Note that all dependencies, including insert files, can be
critical or noncritical.)
"Pool capacity" means three things:
  (1) disk storage capacity--limited by the disk a pool is on;
      however, pools can be split among disks and nodes.
  (2) a -limit option to set the number of versions of a derived object
      that are retained in a pool.  
  (3) an -age option to specify the number of hours that  a  derived 
      object  version  must  have  been  sitting in the pool to be a
      candidate for purging.  We keep this just large enough to give
      us a chance to actually use the objects.

>- what support is there for variant
>  implementations of the same module?

Variant implementations are kept on branches in the source library.
For example, I might do the following:
   DSEE>  set library /gpr/src                  #to access the GPR source library
   DSEE>  create branch sixteen text.pas        #to make the branch "sixteen" for text
            .... edit....
   DSEE> replace text.pas/sixteen               #check in my branch
   DSEE> create branch kanji text.pas/sixteen   #make a branch off a branch
            .... edit....
   DSEE> replace text.pas/sixteen/kanji         #check in my kanji branch

>  Must the elements be named
>  differently...?

No, not really.  Once I create and check in my kanji branch, I can
read it using the path name /gpr/src/text.pas/sixteen/kanji 

>  and the system model preprocessed...?

No need to "preprocess" the system model explicitly.  The configuration
thread settings can be used to select which branch or version of each module
get compiled when DSEE does a build.  For example, one might use this
configuration thread:

    -reserved
    -for vector.pas -use_options -opt 2
    -for '?* @ gpr' /sixteen/kanji -when_exists
    -for '?* @ gpr' /sixteen       -when_exists
    [sr9.6]                        -when_exists
    []

This means: 1.  Use my reserved version of any module if I have one.
                In this case a module is either a source or header
                (insert) file.   Compilations run under DSEE automatically
                locate the thread-selected versions and branches of header files.
            2.  Compile vector.pas with "-opt 2"
            3.  Use the /sixteen/kanji branch for any module for which
                that branch exists.
            4.  Use the /sixteen branch for any module for which that exists.
            5.  Use the version named sr9.6 for all modules that have such
                a version name.
            6.  For all other modules, just use the latest stuff.

>  can they be distinguished automatically in the directory structure?

Yes.

>- can a bug-fix or feature branch to several elements be treated
>  (e.g. named or merged) globally, or must the operations be repeated
>  for each element affected?

I'm not sure whether branches can be created or merged globally.  The branch and
configuration thread system is flexible enough that there's no need to 
take branches of "everything," so I've never tried it.
Version names can be applied either globally or module-by-module.

>- can a system be composed of subsystems each maintained in its own
>  directory structure?

Yes.  This is standard practice here.  A system model can refer to several
DSEE source library areas.

>  Must there be a single system model (with
>  absolute pathnames) for the whole?

You can have as many system models as you like.  However, we
ordinarily use just one for each major component, and maintain it as a DSEE element, with
branches and version names.
As for absolute pathnames, what we do is create a standard set of links in the root
directory of each developer's node.  For example, here are some of the links in the root
structure of my node:

dl               "//id/dl"
dm               "//guess/what/dm"
gmr              "//ice/cream/gmr"
gpr              "//tribble/gpr"
gsr              "//ice/cream/gsr"
os               "//os/os"
uet              "//guess/what/uet"
us               "//us/us"
x10              "//morgul/x"

Most (not all) of these directories have a "src" and a "ins" DSEE structure under them.
Thus, I (and everybody else) can find the gpr file text.pas by using the path name
/gpr/src/text.pas ... this resolves, through my link to //tribble/gpr/src/text.pas .

Things do change...
Once in a while, somebody sends around mail saying, for example
     "/dm" is moving from //ice/cream to //guess/what .
At the same time, they do a copy_tree ($ cpt or % cp -r) of the DSEE structures
to the new node / volume, and put a symbolic link in place of the old structure.
Thus, until developers make the change, they traverse an extra symbolic link.

So yes, you need absolute pathnames for multiple libraries, but using links
mitigates the problem.

>The next few questions deal with evolutionary systems where not only
>the module code, but the module structure itself may change over time.
>- the extracts quoted from system models indicate that include
>  dependencies must be specified manually.  I understand that there is
>  a make_model program to determine these automatically when the model
>  is first written, but has there been any support added to generate
>  them dynamically at build time?

Not that I know of...  but builds do succeed, with a DSEE warning message
when you omit a dependency.  I use this feature to "debug" my system
model.  Here's a transcript from a DSEE session showing this.

Completed "gsr_vector.pas" on //VERMONT (6BAD)
Build gsr_vector.pas!6-Jul-1987.22:34:02
?(DSEE/Streams Manager) Element "//us/us/ins/gpr.ins.pas" was read but was not declared as an Element dependency.
?(DSEE/Streams Manager) Element "//us/us/sys/ins/gpr.ins.pas" was read but was not declared as an Element dependency.
No errors, no warnings, Pascal Rev 7.2891

>- if the structure of the system is changed at some point in a way
>  which significantly affects the system model, will subsequent
>  modifications to earlier configurations see the new or old model?

Models can be placed on branches, and snapshotted as part of
the release-creation process, so the answer is that modifications
see the appropriate model.

>My thanks to the long-suffering correspondents at Apollo for any
>answers they can provide.

Thank you for reading this far.  This turned out to be sort of long.

Ollie Jones.  Apollo Computer.   I'm responsible for my own statements
                                 and misstatements.  My knowlege of DSEE
                                 comes through (a) using it and (b) reading
                                 the published manuals.

joelm@apollo.UUCP (07/07/87)

In article <1745@zaphod.UUCP> billj@zaphod.UUCP (Bill Jones) writes:
>
>- is there support for maintaining, as Bob Reed mentioned, parallel
>  systems of derived objects, say one with debugging turned on and one
>  not?  Or will most of the binaries have to be recreated on each build
>  as the pool cache capacity is reached?

The whole point of the caching scheme is to maintain prallel systems of
derived objects.  Remember, DSEE views the world from the source point of
view.  It decides (forgive me some anthropomorphisms) what sources and
translator options are necessary and then tries to find a build in the
pools that matches the requested versions and options.  You can specify
some options as "critical" to the build, i.e. debugging information,
or as "non-critical" i.e. produce a map file.  If the pools are not
configured with enough depth (i.e. number of builds of each object)
then you can of course thrash, but that is a problem that is easily
solved and one that we almost never encounter.  The pool can be reconfigured
at any time.


>- in the above environment, what support is there for variant
>  implementations of the same module?  Must the elements be named
>  differently, and the system model preprocessed, to avoid conflict, or
>  can they be distinguished automatically in the directory structure?

There is only one "element".  In fact, it is an extensible streams
object.  (From the Open Systems Toolkit.)  So that the directory structure
appears to be consistant, that is to say the elements and all the
varients (branches) appear to exist.  The reality is that they are created
on the fly by the streams manager when they are requested.  This operation
is surprisingly quick.  One of my favorite demos is to open random versions
of case-history objects and show that it is about as fast as opening
plain ascii.  For example the library "src" contains element "pgm.c".
"pgm.c"  pgm.c could have several lines-of-descent (variations) going on
at once.  Each could be refered to by its branch name.  I.e. pgm.c/bug_fix
pgm.c/risky_changes, pgm.c/add_debug_statments.  Note that no special
version is necessary to compile it with debug information.  That is an
option that is specified at build time.
  
>
>- can a bug-fix or feature branch to several elements be treated
>  (e.g. named or merged) globally, or must the operations be repeated
>  for each element affected?

Each element must be merged independently.  I don't think that I would
trust any merge system that did the merging w/o my supervision.  Most
of the merge work is automatic, so very little intervention is required,
provided your changes on the branch do not conflict with changes on
the main-line of descent.  All elements (branches or main_line) can be
named globally.  Nameing is pretty flexible, you can name specific
versions or just say: name all versions used in this build.

>
>- can a system be composed of subsystems each maintained in its own
>  directory structure, or must there be a single system model (with
>  absolute pathnames) for the whole?
>
The directory structure is independent of the models.  All "elements"
(progams, modules, insert files etc...) live in libraries.  Any system
model can refer to any library, and more then one system model can
refer to the same library.  Generally, you would group your sources
logically in similar libraries, i.e. src modules, insert files etc...
and then create a model to build what you need.  You can use smaller
models to build subcomponents, and then include them (literally with
a %include statement) in a larger model that incorporates many
smaller models.  Most of the time though, it is simpler just to make
one large model.  You can at build time specify which subcomponents
to build.  i.e. build foo.pas, build foo.system (which includes foo.pas)
or just "build" which builds everything in the model.  (Or finds 
appropriate builds in the pools.)

>- the extracts quoted from system models indicate that include
>  dependencies must be specified manually.  I understand that there is
>  a make_model program to determine these automatically when the model
>  is first written, but has there been any support added to generate
>  them dynamically at build time?

There is *sigh* no such support.  Though, you will get a warning if
your program reads a DSEE library element that was not declared.  In
general it is not a great idea to include non-DSEE elements.  It works
just fine, but you lose all of the history information.  Make_model
still needs a bit of work.

>
>- if the structure of the system is changed at some point in a way
>  which significantly affects the system model, will subsequent
>  modifications to earlier configurations see the new or old model?

Part of specifying which versions go into a build is specifying
a version of the model to use.  (Models are generally DSEE library
elements themselves.)  So, if you want to build an older version of
your modules, you would use and older version of the model.


>Bill Jones, Develcon Electronics, 856 51 St E, Saskatoon S7K 5C7 Canada
>uucp:  ...ihnp4!sask!zaphod!billj               phone:  +1 306 931 1504
 
                                             Joel


-- 
Joel Margolese          UUCP:      ...{attunix,uw-beaver,decvax!wanginst}!apollo!joelm
Apollo Computer         ARPA:     apollo!joelm@eddie.mit.edu
                        INTERNET: joelm@apollo.com