[Company Logo Image]    

Home Feedback Contents Search

4.16 Redundant SW
4.1 Structure 4.2 Compiling 4.3 Example 4.4 Socket 4.5 OOP 4.6 Competing 4.7 Optimization 4.8 Connector 4.9 Merging 4.10 Emulation 4.11 Ordered Calls 4.12 Last-Only 4.13 Group Inputs 4.14 Complex Sys. 4.15 Prior Art... 4.16 Redundant SW 4.17 Visual SW 

Back Home Up Next

4.16 Application in Redundant Software Design

Universal method of redundant software design is completely missing from prior-art software programming systems and methods in spite of tremendous need for it in many critical areas of computer/microcontroller application. Software/computer redundancy, if done at all, is still done in custom way for each application. For a single processor-system it would not make much sense to do such a thing any other way than by replicating the processor hardware as well and thus implementing the redundancy mostly in hardware made to run the same software twice. This is a crude solution and only applicable to relatively small number of applications. Situation is totally different in a system with an array of processors. Different parts of the array could work on the same problem in order to make sure that the solution is arrived at or that it is absolutely accurate. Accuracy could be determined by comparing results of different paths working on the same problem. Such redundant design would have application far beyond mission-critical systems. Among many other things, redundant software would greatly decrease cost and energy consumption of electronic hardware. Due to complete lack of universal redundant programming methodologies, decisive majority of the software makes infallibility and error-free operation of the computer hardware the key underlying principle. To make this principle true for most practical purposes, quality norms of the computer hardware manufacturing need to be extremely high. This, of course, costs money. Suppose our computer quality norms allow some program to have one chance in a million to yield incorrect result due to hardware failure (very low expectation). In most cases, increasing quality norms to allow only one failure chance in 10 million would double the cost of the hardware at the least. Suppose that we instead double the hardware cost by simply replicating the same quality hardware to run the same software twice. The probability of such redundant software paths failing both at the same time would be one chance in million squared. This means that the same cost resulted in a million-fold quality of calculation improvement.

 

collect void DoneA(Array& A)

             DoneB(Array& B)  

// Code to compare A and B

};

 

struct PrimesR  

   detach void CalculateOne ( int iPrime, Array& Results,

                              detach (*Out)(Array&)

                            )

       {  // ...

          // Prime checking code like on Fig 26A

          if ( Results.Fill(i,isPrime) )

             Out(Results);

       };

   

   detach void PrimesR      ( int N,

                              detach (*Out)(Array&)

                            )

       {  return;

          Array Results(N);

             for ( int i=0; i<N/2; ++i )

                CalculateOne(i,Results,Out);

       };      

};

 

void StartRoutine()

PrimesR Pr1(1000,DoneA);

   PrimesR Pr2(1000,DoneB);

};

FIG. 27: Redundancy example of prime number calculation performed on two paths

 Using the mechanisms of the stress-flow it is extremely easy to implement redundant software design. Suppose we need to implement the Primes example from FIG. 26A by running it through two duplicate paths. The modification needed to Primes code itself requires changes where results of these two paths merge together. This can be easily done with stress-flow with already explained collector mechanisms as shown on FIG. 27. The collector mechanism merges reports of completion DoneA and DoneB. When both of these entry points of the routine are called, the code inside the routine is run which in this case allows checking if both results arrived at are correct by comparing A and B arrays. Rather than duplicating the code for prime calculation with one of them calling DoneA and another DoneB, the proper label to call is passed as parameter. Please note that the parameter declaration uses detach as parameter designator. Keyword “collect” even if implemented (it does not have to be – as explained before), should be a special case of detach, thus allowing this code. Another way to handle it could use the “connector” inside Primes object.   

 

collect void Done(Array& A)[2]

{ // Code to compare A[0] and A[1]

};

 

void StartRoutine()  

PrimesR Pr1(1000,Done[0]);

   PrimesR Pr2(1000,Done[1]);

};

FIG. 27A: Syntax modification to code from FIG. 27

To make writing such code slightly easier, especially if more than two such merged paths are needed, the compiler implementing stress-flow can allow declaring multiple collector paths of the same layout to be declared as an array, rather than list with separate labels. This is shown on FIG. 27A. To refer to specific entry point or parameters of specific entry point, array indexing will naturally be used (example Done[1] or A[1]).

 

firstof void DoneA(Array& A)

             DoneB(Array& B)  

{  if ( DoneA )

      //---

};

 

void StartRoutine()  

PrimesR Pr1(1000,!!Done[0]);

   PrimesR Pr2(1000,!!Done[1]);

};

FIG. 27B: Code for prime number calculations with different type of redundancy

The method of redundancy shown so far calculates the same problem through two or more paths and then reports all results at the same point. Another method of redundancy could require calculating the same problem through two or more paths and then reporting the first result arrived at and ignoring the next ones. The underlying mechanisms of stress-flow can easily support such schemes which can be implemented at the cost of another keyword as shown on FIG. 27B. To identify which path arrived at the solution, the name of the entry label can be tested as boolean expression inside the routine, which was the method already introduced with the “nodef” stress-flow atoms. Starting of the redundant calculation in this routine may be done as before, or the calls can be made into “ordered” by using the “!!”operator before passing them to the routine calculating primes as shown on FIG. 27B. Due to the way the ordered operator reserves places in final collector queue, this scheme can be easily utilized for marking the other paths going to the “firstof” collector as no longer necessary and possibly killing them after the first one makes it through. This can be done by means of another definition modifier – for example “cancelrest.”

Complete implementation of the scheme where late comer calls to “cancelrest” collector can be canceled must involve means to cancel these calling tasks gracefully, which means allowing them to process their destructor functions and properly de-allocate all objects. Destructor functions are object-oriented programming concepts allowing programmers to define actions that take place when an object of a given type goes out of scope. This means that if some object is declared on stack the compiler inserts destructor calls automatically as part of sequence of instructions executed after all user programmed actions in the routine end. Canceling the late comers would therefore mean forcing the makers of the late calls to jump to their destructor sequences at the end of their code. A mechanism such as this is far easier to implement than say “try-catch” constructs of the object-oriented languages, but due to inherent true multi-tasking of stress-flow become extremely powerful tools.

 

firstof void Done(Array& A)[2]

             UserKilled()

{  if ( UserKilled )

      //---

   if ( Done[0] )

      //---

};

FIG. 27C: Syntax modification to code from FIG. 27B

It still will make perfect sense to use the indexed entry label scheme with this method. Please note that a fully capable compiler implementing stress-flow should allow defining several indexed entry points together with non-indexed ones, as show on FIG. 27C where an additional entry point is used to report a special case of user canceling the calculation.

 

connector firstof void Done(Array& A)[2]

                       UserKilled();

FIG. 27D: Mechanisms from previous FIGs used with collector construct

 

socket void Done(Array& A)[2];

 

void StartRoutine(Array& Result)  

{  bool success=false;

   do

   {  PrimesR Pr1(1000,Done[0]);

      PrimesR Pr2(1000,Done[1]);

   

      socket void Done(Array& A)[2]

      {  if ( A[0]==A[1] )

         {  success=true;

            Result=A;

         };

      };     

   }  while ( !success );

};

FIG. 27E: Mechanisms from previous FIGs used with socket construct

The underlying elementary mechanisms of stress-flow do not prevent multi-label collectors of any described type to be used as basis for a connector, as shown on FIG. 27D or basis for a socket construct as shown on FIG. 27E. This last example shows how stress-flow can be used to create massively parallel and redundant calculation of primes. The whole routine can be called from a parallelism unaware regular command-flow routine which will get results back when both redundant paths come up with the same results.

Back Home Up Next
Send mail to info@stressflow.com with questions or comments.
Copyright © 2005-2010. All Rights Reserved. Patents Pending in Multiple Jurisdictions.
First published 03/29/06. Last modified: 06/25/10