/// <summary> /// Inserts conditions into the schedule given by the operations list at their earliest possible position /// todo: set/map operations are potentially expensive, they shouldn't be insertes asap, but depending an weight, /// derived from statistics over set/map size for graph elements, quiet well known for anonymous rule sets /// </summary> private static void InsertConditionsIntoSchedule(PatternCondition[] conditions, List <SearchOperation> operations, bool lazyNegativeIndependentConditionEvaluation) { // get needed (in order to evaluate it) elements of each condition Dictionary <String, object>[] neededElements = new Dictionary <String, object> [conditions.Length]; for (int i = 0; i < conditions.Length; ++i) { neededElements[i] = new Dictionary <string, object>(); for (int j = 0; j < conditions[i].NeededNodeNames.Length; ++j) { String neededNodeName = conditions[i].NeededNodeNames[j]; PatternNode neededNode = conditions[i].NeededNodes[j]; neededElements[i][neededNodeName] = neededNode; } for (int j = 0; j < conditions[i].NeededEdgeNames.Length; ++j) { String neededEdgeName = conditions[i].NeededEdgeNames[j]; PatternEdge neededEdge = conditions[i].NeededEdges[j]; neededElements[i][neededEdgeName] = neededEdge; } for (int j = 0; j < conditions[i].NeededVariableNames.Length; ++j) { String neededVariableName = conditions[i].NeededVariableNames[j]; PatternVariable neededVariable = conditions[i].NeededVariables[j]; neededElements[i][neededVariableName] = neededVariable; } } // iterate over all conditions for (int i = 0; i < conditions.Length; ++i) { int j; float costToEnd = 0; // find leftmost place in scheduled search plan for current condition // by search from end of schedule forward until the first element the condition is dependent on is found for (j = operations.Count - 1; j >= 0; --j) { SearchOperation op = operations[j]; if (op.Type == SearchOperationType.Condition || op.Type == SearchOperationType.NegativePattern || op.Type == SearchOperationType.IndependentPattern || op.Type == SearchOperationType.DefToBeYieldedTo) { continue; } if (lazyNegativeIndependentConditionEvaluation) { break; } if (op.Type == SearchOperationType.AssignVar) { if (neededElements[i].ContainsKey(((PatternVariable)op.Element).Name)) { costToEnd = op.CostToEnd; break; } continue; } if (neededElements[i].ContainsKey(((SearchPlanNode)op.Element).PatternElement.Name)) { costToEnd = op.CostToEnd; break; } } operations.Insert(j + 1, new SearchOperation(SearchOperationType.Condition, conditions[i], null, costToEnd)); } }
/// <summary> /// Inserts inlined variable assignments into the schedule given by the operations list at their earliest possible position /// </summary> private static void InsertInlinedVariableAssignmentsIntoSchedule(PatternGraph patternGraph, List <SearchOperation> operations) { // compute the number of inlined parameter variables int numInlinedParameterVariables = 0; foreach (PatternVariable var in patternGraph.variablesPlusInlined) { if (var.AssignmentSource != null && patternGraph.WasInlinedHere(var.originalSubpatternEmbedding)) { ++numInlinedParameterVariables; } } if (numInlinedParameterVariables == 0) { return; } // get the inlined parameter variables and the elements needed in order to compute their defining expression Dictionary <String, PatternElement>[] neededElements = new Dictionary <String, PatternElement> [numInlinedParameterVariables]; PatternVariable[] inlinedParameterVariables = new PatternVariable[numInlinedParameterVariables]; int curInlParamVar = 0; foreach (PatternVariable var in patternGraph.variablesPlusInlined) { if (var.AssignmentSource == null) { continue; } if (!patternGraph.WasInlinedHere(var.originalSubpatternEmbedding)) { continue; } neededElements[curInlParamVar] = new Dictionary <string, PatternElement>(); for (int i = 0; i < var.AssignmentDependencies.neededNodeNames.Length; ++i) { String neededNodeName = var.AssignmentDependencies.neededNodeNames[i]; PatternNode neededNode = var.AssignmentDependencies.neededNodes[i]; neededElements[curInlParamVar][neededNodeName] = neededNode; } for (int i = 0; i < var.AssignmentDependencies.neededEdgeNames.Length; ++i) { String neededEdgeName = var.AssignmentDependencies.neededEdgeNames[i]; PatternEdge neededEdge = var.AssignmentDependencies.neededEdges[i]; neededElements[curInlParamVar][neededEdgeName] = neededEdge; } inlinedParameterVariables[curInlParamVar] = var; ++curInlParamVar; } // iterate over all inlined parameter variables for (int i = 0; i < inlinedParameterVariables.Length; ++i) { int j; float costToEnd = 0; // find leftmost place in scheduled search plan for current assignment // by search from end of schedule forward until the first element the expression assigned is dependent on is found for (j = operations.Count - 1; j >= 0; --j) { SearchOperation op = operations[j]; if (op.Type == SearchOperationType.Condition || op.Type == SearchOperationType.Assign || op.Type == SearchOperationType.AssignVar || op.Type == SearchOperationType.NegativePattern || op.Type == SearchOperationType.IndependentPattern || op.Type == SearchOperationType.DefToBeYieldedTo) { continue; } if (neededElements[i].ContainsKey(((SearchPlanNode)op.Element).PatternElement.Name)) { costToEnd = op.CostToEnd; break; } } SearchOperation so = new SearchOperation(SearchOperationType.AssignVar, inlinedParameterVariables[i], null, costToEnd); so.Expression = inlinedParameterVariables[i].AssignmentSource; operations.Insert(j + 1, so); } }
/// <summary> /// Parallelize the scheduled search plan to the branching factor, /// splitting it at the first loop into a header part and a body part /// </summary> public static void ParallelizeHeadBody(LGSPRulePattern rulePattern) { Debug.Assert(rulePattern.patternGraph.schedulesIncludingNegativesAndIndependents.Length == 1); ScheduledSearchPlan ssp = rulePattern.patternGraph.schedulesIncludingNegativesAndIndependents[0]; int indexToSplitAt = 0; for (int i = 0; i < ssp.Operations.Length; ++i) { SearchOperation so = ssp.Operations[i]; if (so.Type == SearchOperationType.Lookup || so.Type == SearchOperationType.Incident || so.Type == SearchOperationType.Incoming || so.Type == SearchOperationType.Outgoing || so.Type == SearchOperationType.PickFromStorage || so.Type == SearchOperationType.PickFromStorageDependent || so.Type == SearchOperationType.PickFromIndex || so.Type == SearchOperationType.PickFromIndexDependent) { indexToSplitAt = i; break; } } rulePattern.patternGraph.parallelizedSchedule = new ScheduledSearchPlan[2]; List <SearchOperation> headOperations = new List <SearchOperation>(); List <SearchOperation> bodyOperations = new List <SearchOperation>(); for (int i = 0; i < rulePattern.Inputs.Length; ++i) { if (rulePattern.Inputs[i] is VarType) // those don't appear in the schedule, they are only extracted into the search program { VarType varType = (VarType)rulePattern.Inputs[i]; String varName = rulePattern.InputNames[i]; PatternVariable dummy = new PatternVariable(varType, varName, varName, i, false, null); headOperations.Add(new SearchOperation(SearchOperationType.WriteParallelPresetVar, dummy, null, 0)); bodyOperations.Add(new SearchOperation(SearchOperationType.ParallelPresetVar, dummy, null, 0)); } } for (int i = 0; i < ssp.Operations.Length; ++i) { SearchOperation so = ssp.Operations[i]; if (i < indexToSplitAt) { SearchOperation clone = (SearchOperation)so.Clone(); clone.Isomorphy.Parallel = true; clone.Isomorphy.LockForAllThreads = true; headOperations.Add(clone); switch (so.Type) { // the target binding looping operations can't appear in the header, so we don't treat them here // the non-target binding operations are completely handled by just adding them, happended already above // the target binding non-looping operations are handled below, // by parallel preset writing in the header and reading in the body // with exception of def, its declaration and initializion is just re-executed in the body // some presets can't appear in an action header, they are thus not taken care of case SearchOperationType.ActionPreset: case SearchOperationType.MapWithStorage: case SearchOperationType.MapWithStorageDependent: case SearchOperationType.Cast: case SearchOperationType.Assign: case SearchOperationType.Identity: case SearchOperationType.ImplicitSource: case SearchOperationType.ImplicitTarget: case SearchOperationType.Implicit: headOperations.Add(new SearchOperation(SearchOperationType.WriteParallelPreset, (SearchPlanNode)so.Element, so.SourceSPNode, 0)); bodyOperations.Add(new SearchOperation(SearchOperationType.ParallelPreset, (SearchPlanNode)so.Element, so.SourceSPNode, 0)); break; case SearchOperationType.AssignVar: headOperations.Add(new SearchOperation(SearchOperationType.WriteParallelPresetVar, (PatternVariable)so.Element, so.SourceSPNode, 0)); bodyOperations.Add(new SearchOperation(SearchOperationType.ParallelPresetVar, (PatternVariable)so.Element, so.SourceSPNode, 0)); break; case SearchOperationType.DefToBeYieldedTo: bodyOperations.Add((SearchOperation)so.Clone()); break; } } else if (i == indexToSplitAt) { SearchOperation cloneHead; SearchOperation cloneBody; switch (so.Type) { case SearchOperationType.Lookup: cloneHead = (SearchOperation)so.Clone(SearchOperationType.SetupParallelLookup); cloneBody = (SearchOperation)so.Clone(SearchOperationType.ParallelLookup); break; case SearchOperationType.Incident: cloneHead = (SearchOperation)so.Clone(SearchOperationType.SetupParallelIncident); cloneBody = (SearchOperation)so.Clone(SearchOperationType.ParallelIncident); break; case SearchOperationType.Incoming: cloneHead = (SearchOperation)so.Clone(SearchOperationType.SetupParallelIncoming); cloneBody = (SearchOperation)so.Clone(SearchOperationType.ParallelIncoming); break; case SearchOperationType.Outgoing: cloneHead = (SearchOperation)so.Clone(SearchOperationType.SetupParallelOutgoing); cloneBody = (SearchOperation)so.Clone(SearchOperationType.ParallelOutgoing); break; case SearchOperationType.PickFromStorage: cloneHead = (SearchOperation)so.Clone(SearchOperationType.SetupParallelPickFromStorage); cloneBody = (SearchOperation)so.Clone(SearchOperationType.ParallelPickFromStorage); break; case SearchOperationType.PickFromStorageDependent: cloneHead = (SearchOperation)so.Clone(SearchOperationType.SetupParallelPickFromStorageDependent); cloneBody = (SearchOperation)so.Clone(SearchOperationType.ParallelPickFromStorageDependent); break; case SearchOperationType.PickFromIndex: cloneHead = (SearchOperation)so.Clone(SearchOperationType.SetupParallelPickFromIndex); cloneBody = (SearchOperation)so.Clone(SearchOperationType.ParallelPickFromIndex); break; case SearchOperationType.PickFromIndexDependent: cloneHead = (SearchOperation)so.Clone(SearchOperationType.SetupParallelPickFromIndexDependent); cloneBody = (SearchOperation)so.Clone(SearchOperationType.ParallelPickFromIndexDependent); break; default: // failure, operation at this index cannot be parallelized/parallelization not supported cloneHead = null; cloneBody = null; break; } headOperations.Add(cloneHead); cloneBody.Isomorphy.Parallel = true; bodyOperations.Add(cloneBody); } else { SearchOperation clone = (SearchOperation)so.Clone(); clone.Isomorphy.Parallel = true; bodyOperations.Add(clone); if (clone.Element is PatternCondition) { SetNeedForParallelizedVersion((clone.Element as PatternCondition).ConditionExpression); } } } ScheduledSearchPlan headSsp = new ScheduledSearchPlan( rulePattern.patternGraph, headOperations.ToArray(), headOperations.Count > 0 ? headOperations[0].CostToEnd : 0); rulePattern.patternGraph.parallelizedSchedule[0] = headSsp; ScheduledSearchPlan bodySsp = new ScheduledSearchPlan( rulePattern.patternGraph, bodyOperations.ToArray(), bodyOperations.Count > 0 ? bodyOperations[0].CostToEnd : 0); rulePattern.patternGraph.parallelizedSchedule[1] = bodySsp; ParallelizeNegativeIndependent(bodySsp); ParallelizeAlternativeIterated(rulePattern.patternGraph); ParallelizeYielding(rulePattern.patternGraph); }