VX/FPT - Record/Replay (Hamlet)

VX/FPT instruments the user's code to capture and to replay:

For example, the subroutine:

     SUBROUTINE GET_VISCOSITY_TABLE
C
      COMMON /VTAB/ VISCOSITY(1000)
C
      OPEN(7,FILE='VISCOSITY.DAT',ACCESS='DIRECT',STATUS='OLD')
      DO I=1,1000
         READ(7,REC=I,ERR=200)VISCOSITY(I)
      ENDDO
      WRITE(1,100)
100   FORMAT (/,'Viscosity table read successfully')
      CLOSE (7)
      RETURN
C
200   WRITE(1,300)
300   FORMAT (/,'Error reading viscosity table - aborting')
      STOP
C
      END

is modified by VX/FPT to read:

     SUBROUTINE GET_VISCOSITY_TABLE
C
      INCLUDE 'rr_cmn.fpi'
C
      COMMON /VTAB/VISCOSITY(1000)
C
      IF (.NOT. REPLAY_IO(1,7)) THEN
         OPEN (7,FILE='VISCOSITY.DAT',ACCESS='DIRECT',STATUS='OLD')
      ENDIF
      DO I=1,1000
         IF (REPLAY_IO(2,7)) THEN
            READ (RR_LUN_FOR_REPLAY,*)RR_IOSTAT
            READ (RR_LUN_FOR_REPLAY,*)VISCOSITY(I)
         ELSE
            READ (7,REC=I,IOSTAT=RR_IOSTAT)VISCOSITY(I)
         ENDIF
         IF (RR_INPUT_RECORD_F) THEN
            WRITE (RR_LUN_TO_RECORD_INPUT,*)RR_IOSTAT
            WRITE (RR_LUN_TO_RECORD_INPUT,*)VISCOSITY(I)
         ENDIF
         IF (RR_IOSTAT .NE. 0) THEN
            GOTO 200
         ENDIF
      ENDDO
      IF (.NOT. REPLAY_IO(3,1)) THEN
         WRITE (1,100)
      ENDIF
      IF (RR_OUTPUT_RECORD_F) THEN
         WRITE (RR_LUN_TO_RECORD_OUTPUT,100)
      ENDIF
100   FORMAT (/,'Viscosity table read successfully')
      IF (.NOT. REPLAY_IO(4,7)) THEN
         CLOSE (7)
      ENDIF
      RETURN
C
200   CONTINUE
      IF (.NOT. REPLAY_IO(5,1)) THEN
         WRITE (1,300)
      ENDIF
      IF (RR_OUTPUT_RECORD_F) THEN
         WRITE (RR_LUN_TO_RECORD_OUTPUT,300)
      ENDIF
300   FORMAT (/,'Error reading viscosity table - aborting')
      STOP
C
      END

The Changes VX/FPT Has Made

VX/FPT has inserted an INCLUDE statement for declaration of the variables used to control record and replay.

     INCLUDE 'rr_cmn.fpi'

The control variables, RR_LUN_FOR_REPLAY, RR_OUTPUT_RECORD_F etc. are in COMMON blocks. The file also contains declarations of the control functions such as REPLAY_IO(N,UNIT). This function determines whether the unit is being replayed or not.

The OPEN statement has been enclosed in a test to find whether or not the unit, in this case unit 7, is being replayed.

     IF (.NOT. REPLAY_IO(1,7)) THEN
         OPEN (7,FILE='VISCOSITY.DAT',ACCESS='DIRECT',STATUS='OLD')
      ENDIF

If unit 7 is replayed from the captured data, we don't need to open the file. This means that the original files don't need to be present when the code is first tested.

The read of the viscosity array has been enclosed in a test.

        IF (REPLAY_IO(2,7)) THEN
            READ (RR_LUN_FOR_REPLAY,*)RR_IOSTAT
            READ (RR_LUN_FOR_REPLAY,*)VISCOSITY(I)
         ELSE
            READ (7,REC=I,IOSTAT=RR_IOSTAT)VISCOSITY(I)
         ENDIF

If unit 7 is being replayed, VISCOSITY(I) is read from the replay file. If not, the original READ statement is executed.

VX/FPT inserts code to capture the values from the viscosity file.

        IF (RR_INPUT_RECORD_F) THEN
            WRITE (RR_LUN_TO_RECORD_INPUT,*)RR_IOSTAT
            WRITE (RR_LUN_TO_RECORD_INPUT,*)VISCOSITY(I)
         ENDIF

The original READ statement had an END= destination. This has been replaced by capturing the IOSTAT value in the READ. The IOSTAT is replayed to the variable RR_IOSTAT and this is used to control jumping to the error destination by the statements:

        IF (RR_IOSTAT .NE. 0) THEN
            GOTO 200
         ENDIF

RR_IOSTAT is also replayed from the recorded file, so that the recording behaves in exactly the same way as the original code.

The WRITE statement to unit 1 is modified in a similar way. Once again, the statement is enclosed in a test, and is not executed if unit 1 is being replayed. The file does not need to exist during the initial stages of testing.

     IF (.NOT. REPLAY_IO(3,1)) THEN
         WRITE (1,100)
      ENDIF
      IF (RR_OUTPUT_RECORD_F) THEN
         WRITE (RR_LUN_TO_RECORD_OUTPUT,100)
      ENDIF
100   FORMAT (/,'Viscosity table read successfully')

Note that VX/FPT captures the outputs from the program as well as the inputs. In a migration project, the outputs may be compared on the old and new hosts as a diagnostic tool.

 

The Extent of the Changes

VX/FPT has re-written so much of this small subroutine that it is almost unrecognisable. This is not typical. It has happened because the subroutine contains almost nothing but I/O statements. Usually, the record/replay process makes very few changes to a large program.

 

A Shared Memory Location

Many programs have interfaces which are shared memory locations. These may also be instrumented for record and replay. In the code fragment below, VISBUFR is part of a memory block shared between a simulation program and the visual scene generator.

C     Only the visual system knows where the ground is
      RADAR_ALT=-RVISBUF(3)

To instrument this interface, we need to tell VX/FPT that the memory is shared. This is done by annotating a declaration of VISBUFR. The annotation doesn't need to be in the main code body. It can be written in a small template file which is used only by VX/FPT. The annotation would be, for example:

     COMMON /VISBUF/ RVISBUF(20),IVISBUF(200)
C%    Record/replay interface:: RVISBUF

The comment beginning C% has special meaning to VX/FPT.

VX/FPT then modifies the original statement to read:

C     Only the visual system knows where the ground is
C     RADAR_ALT=-RVISBUF(3)
      IF (REPLAY_INTERFACE(1,'RVISBUF')) THEN
         READ (RR_LUN_FOR_REPLAY,*)RVISBUF_TMP(3)
      ELSE
         RVISBUF_TMP(3)=RVISBUF(3)
      ENDIF
      IF (RR_INPUT_RECORD_F) THEN
         WRITE (RR_LUN_TO_RECORD_INPUT,*)RVISBUF_TMP(3)
      ENDIF
      RADAR_ALT=-RVISBUF_TMP(3)

The original statement is commented-out. Note how replay of the specific interface is controlled by the logical function REPLAY_INTERFACE(N,NAME).

VX/FPT has added a new array, RVISBUF_TMP to the code. This has the same bounds and type as the original array RVISBUF and is declared wherever it is needed.

 

A Sub-Program Interface

Programs may communicate with external devices or other programs through sub-program arguments. To instrument these interfaces, VX/FPT requires a declaration that the sub-program is an interface, and needs either the code of the sub-program, or a template which indicates the INTENT of the arguments - whether they are inputs, outputs or both. Templates may be written in small files outside the main body of the code, which are processed only by VX/FPT. For example:

C     Template for MACRO routine TO_RADALT
C%    Record/replay interface TO_RADALT
      SUBROUTINE TO_RADALT(V,IADD,IE)
C%    INTENT (IN) :: V
C%    INTENT (IN) :: IADD
C%    INTENT (OUT) :: IE
      END

A call to TO_RADALT, for example:

     CALL TO_RADALT(RADAR_ALT,23,ISTAT)

is instrumented to read:

     IF (REPLAY_INTERFACE(2,'TO_RADALT')) THEN
         READ (RR_LUN_FOR_REPLAY,*)ISTAT
      ELSE
         CALL TO_RADALT(RADAR_ALT,23,ISTAT)
      ENDIF
      IF (RR_INPUT_RECORD_F) THEN
         WRITE (RR_LUN_TO_RECORD_INPUT,*)ISTAT
      ENDIF
      IF (RR_OUTPUT_RECORD_F) THEN
         WRITE (RR_LUN_TO_RECORD_OUTPUT,*)RADAR_ALT,23
      ENDIF

 

VX/FPT Reference Manual

For a more complete description of the record/replay process, and of some of the special cases which arise, please see the VX/FPT Reference Manual.

Back to the VX/FPT home page