detect possibly evil tasks and do the right thing if a possibly evil execution patter...
authorjjenista <jjenista>
Fri, 8 Apr 2011 22:38:01 +0000 (22:38 +0000)
committerjjenista <jjenista>
Fri, 8 Apr 2011 22:38:01 +0000 (22:38 +0000)
Robust/src/Analysis/Disjoint/ProcessStateMachines.java
Robust/src/Analysis/Disjoint/SMFEState.java
Robust/src/Analysis/Disjoint/StateMachineForEffects.java
Robust/src/IR/Flat/RuntimeConflictResolver.java

index cc87d8289085e897322ea978dcfc877e753fbe59..0008324b862935499b813e0b26118900ea99ff21 100644 (file)
@@ -22,6 +22,7 @@ public class ProcessStateMachines {
     computeConflictEffects();
     prune();
     merge();
+    protectAgainstEvilTasks();
   }
 
   private void merge() {
@@ -305,4 +306,41 @@ public class ProcessStateMachines {
       }
     }
   }
+
+
+  private void protectAgainstEvilTasks() {
+    for( Pair<FlatNode, TempDescriptor> machinepair: bsm.getAllMachineNames() ) {
+      StateMachineForEffects sm = bsm.getStateMachine( machinepair );
+      protectAgainstEvilTasks( sm );
+    }
+  }
+
+  private void protectAgainstEvilTasks( StateMachineForEffects sm ) {
+    // first identify the set of <Alloc, Field> pairs for which this
+    // traverser will both read and write, remember the read effect
+    Set<Effect> allocAndFieldRW = new HashSet<Effect>();
+    for( Pair<Alloc, FieldDescriptor> af: sm.effectsMap.keySet() ) {
+      Integer effectType = sm.effectsMap.get( af );
+      if( (effectType & Effect.read)  != 0 &&
+          (effectType & Effect.write) != 0
+          ) {
+        allocAndFieldRW.add( new Effect( af.getFirst(),
+                                         Effect.read,
+                                         af.getSecond()
+                                         )
+                             );
+      }
+    }
+
+    // next check the state machine: if an effect that initiates
+    // a transition is in the allocAndFieldRW set, then mark it
+    // as... POSSIBLY EVIL!!!!!
+    for( SMFEState state: sm.getStates() ) {
+      for( Effect effect: state.getTransitionEffects() ) {
+        if( allocAndFieldRW.contains( effect ) ) {
+          sm.addPossiblyEvilEffect( effect );
+        }
+      }
+    }
+  }
 }
\ No newline at end of file
index 9f3857af4cc9016df01f6372f7945982b1fd442b..d08811ed4132f45c2d2e5b09f087959c1b7b92ec 100644 (file)
@@ -101,7 +101,7 @@ public class SMFEState {
     return conflicts;
   }
   
-  public Set<Effect> getTransistionEffects() {
+  public Set<Effect> getTransitionEffects() {
     return this.e2states.keySet();
   }
 
index c8655883769b4dd4d012d4b7fd8829d7326290a7..111273750e8da3d1531e5fe98905ab5905140c86 100644 (file)
@@ -31,11 +31,23 @@ public class StateMachineForEffects {
   protected FlatNode fn;
   protected int id=0;
 
+  // We have a situation in which a task can start executing
+  // and "evil-ly" destroy the paths to all the objects it will
+  // access as it goes along.  If this is the case, a traverser
+  // should know which effects these are, and if the traverser
+  // is ever running and detects that the task is also running,
+  // it should not continue (and therefore hold up any tasks that
+  // might come later, because now we might never be able to find
+  // the effects that should block later tasks).  Should be rare!
+  protected Set<Effect> possiblyEvilEffects;
+
+
   public StateMachineForEffects( FlatNode fnInitial ) {
     fn2state = new Hashtable<FlatNode, SMFEState>();
     effectsMap = new HashMap<Pair<Alloc, FieldDescriptor>, Integer>();
     initialState = getState( startNode );
     this.fn=fnInitial;
+    possiblyEvilEffects = new HashSet<Effect>();
   }
 
   public Set<SMFEState> getStates() {
@@ -110,6 +122,16 @@ public class StateMachineForEffects {
     return 0;
   }
 
+
+  public void addPossiblyEvilEffect( Effect e ) {
+    possiblyEvilEffects.add( e );
+  }
+
+  public Set<Effect> getPossiblyEvilEffects() {
+    return possiblyEvilEffects;
+  }
+
+
   public void writeAsDOT( String graphName ) {
     graphName = graphName.replaceAll( "[\\W]", "" );
 
index 9b580b4d7a9a095072d794067195b60172c46a1a..96c2a536b8bf6272ad0da4a32adcf03e775c2e30 100644 (file)
@@ -186,7 +186,7 @@ public class RuntimeConflictResolver {
          cFile.println("  if(traverserState=="+state.getID()+") {");
        }
         
-        printAllocChecksInsideState(state, taskOrStallSite, var, "ptr", 0, weakID);
+        printAllocChecksInsideState(smfe, state, taskOrStallSite, var, "ptr", 0, weakID);
         
        cFile.println("      break;");
       }
@@ -225,7 +225,7 @@ public class RuntimeConflictResolver {
     cFile.flush();
   }
   
-  public void printAllocChecksInsideState(SMFEState state, FlatNode fn, TempDescriptor tmp, String prefix, int depth, int weakID) {
+  public void printAllocChecksInsideState(StateMachineForEffects smfe, SMFEState state, FlatNode fn, TempDescriptor tmp, String prefix, int depth, int weakID) {
     EffectsTable et = new EffectsTable(state);
     boolean needswitch=et.getAllAllocs().size()>1;
     if (needswitch) {
@@ -239,7 +239,7 @@ public class RuntimeConflictResolver {
       } else {
        cFile.println("     if("+prefix+"->"+allocSite+"=="+a.getUniqueAllocSiteID()+") {");
       }
-      addChecker(a, fn, tmp, state, et, prefix, depth, weakID);
+      addChecker(smfe, a, fn, tmp, state, et, prefix, depth, weakID);
       if (needswitch) {
        cFile.println("       }");
        cFile.println("       break;");
@@ -252,7 +252,7 @@ public class RuntimeConflictResolver {
     cFile.println("      }");
   }
   
-  public void addChecker(Alloc a, FlatNode fn, TempDescriptor tmp, SMFEState state, EffectsTable et, String prefix, int depth, int weakID) {
+  public void addChecker(StateMachineForEffects smfe, Alloc a, FlatNode fn, TempDescriptor tmp, SMFEState state, EffectsTable et, String prefix, int depth, int weakID) {
     if (depth>30) {
       System.out.println(fn+"  "+state+" "+state.toStringDOT());
     }
@@ -275,7 +275,18 @@ public class RuntimeConflictResolver {
            cFile.println("  for(i = 0; i<((struct ArrayObject *) " + prefix + " )->___length___; i++ ) {");
            first=false;
          }
-         printRefSwitch(fn, tmp, pdepth, childPtr, currPtr, state.transitionsTo(e), weakID);
+         printRefSwitch(smfe, fn, tmp, pdepth, childPtr, currPtr, state.transitionsTo(e), weakID);
+
+          // only if we are traversing for a new task, not a stall site
+          if( (fn instanceof FlatSESEEnterNode) &&
+              smfe.getPossiblyEvilEffects().contains( e ) ) {
+
+            FlatSESEEnterNode evilTask = (FlatSESEEnterNode)fn;
+            
+            detectPossiblyEvilExecution( evilTask,
+                                         evilTask.getInVarsForDynamicCoarseConflictResolution().indexOf( tmp )
+                                         );
+          }
        }
       }
       if (!first)
@@ -288,13 +299,24 @@ public class RuntimeConflictResolver {
       for(Effect e: et.getEffects(a)) {
        if (!state.transitionsTo(e).isEmpty()) {
          String childPtr = "((struct "+a.getType().getSafeSymbol()+" *)"+prefix +")->" + e.getField().getSafeSymbol();
-         printRefSwitch(fn, tmp, pdepth, childPtr, currPtr, state.transitionsTo(e), weakID);
+         printRefSwitch(smfe, fn, tmp, pdepth, childPtr, currPtr, state.transitionsTo(e), weakID);
+
+          // only if we are traversing for a new task, not a stall site
+          if( (fn instanceof FlatSESEEnterNode) &&
+              smfe.getPossiblyEvilEffects().contains( e ) ) {
+
+            FlatSESEEnterNode evilTask = (FlatSESEEnterNode)fn;
+            
+            detectPossiblyEvilExecution( evilTask,
+                                         evilTask.getInVarsForDynamicCoarseConflictResolution().indexOf( tmp )
+                                         );
+          }
        }
       }
     }
   }
 
-  private void printRefSwitch(FlatNode fn, TempDescriptor tmp, int pdepth, String childPtr, String currPtr, Set<SMFEState> transitions, int weakID) {    
+  private void printRefSwitch(StateMachineForEffects smfe, FlatNode fn, TempDescriptor tmp, int pdepth, String childPtr, String currPtr, Set<SMFEState> transitions, int weakID) {    
     
     for(SMFEState tr: transitions) {
       if(tr.getRefCount() == 1) {       //in-lineable case
@@ -302,7 +324,7 @@ public class RuntimeConflictResolver {
        cFile.println("    "+currPtr+"= (struct ___Object___ * ) " + childPtr + ";");
        cFile.println("    if (" + currPtr + " != NULL) { ");
        
-       printAllocChecksInsideState(tr, fn, tmp, currPtr, pdepth+1, weakID);
+       printAllocChecksInsideState(smfe, tr, fn, tmp, currPtr, pdepth+1, weakID);
         
        cFile.println("    }"); //break for internal switch and if
       } else {                          //non-inlineable cases
@@ -345,6 +367,36 @@ public class RuntimeConflictResolver {
     }
   }
 
+
+  private void detectPossiblyEvilExecution( FlatSESEEnterNode possiblyEvilTask,
+                                            int               rcrRecordIndex 
+                                            ) {
+    // We have a situation in which a task can start executing and
+    // "evil-ly" destroy the paths to some objects it will access as
+    // it goes along.  If this is the case, a traverser should not
+    // continue and instead intentionally hold up any tasks that might
+    // come later, because now we might never be able to find the
+    // effects that should block later tasks.  This should be rare!
+    cFile.append("// a possibly evil task has been detected!\n");
+    cFile.append("BARRIER();\n");
+    cFile.append("if( unlikely( record->common.unresolvedDependencies == 0 &&");
+    cFile.append(              "BARRIER() &&");
+    cFile.append(              "record->common.doneExecuting == FALSE ) ) {\n");
+    cFile.append("  // first abort this traversal, doesn't matter what the flag is because\n");
+    cFile.append("  // the traverser is not going to clear the task, it's already running...\n");
+    cFile.append("  int flag = LOCKXCHG32( &(record->rcrRecords["+rcrRecordIndex+"].flag), 0 );\n");
+    cFile.append("  \n");
+    cFile.append("  // just wait for the the task to retire...\n");
+    cFile.append("  while( record->common.doneExecuting == FALSE ) {\n");
+    cFile.append("    BARRIER();\n");
+    cFile.append("  }\n");
+    cFile.append("  \n");
+    cFile.append("  // and now its safe to release the traverser to clear other tasks\n");
+    cFile.append("  return;\n");
+    cFile.append("}\n");
+  }
+
+
   private void setupOutputFiles(String buildir) throws FileNotFoundException {
     cFile = new CodePrinter(new File(buildir + "RuntimeConflictResolver" + ".c"));
     headerFile = new CodePrinter(new File(buildir + "RuntimeConflictResolver" + ".h"));