+ splitterOverallPush[nChild]
+ childSplitterPush
    public void computeMinLatencySchedule(        SJSchedulingUtility utility,        int splitExecs,        int joinExecs,        int childrenExecs[],        int postSplitBuffers[],        int preJoinBuffers[])    {        // first pull all the data out of the split-join        // that needs to go (drain the join)        while (joinExecs > 0)        {            int splitterPhases = 0;            int joinerPhases = 0;            int phaseChildrenExecs[] = new int[getNumChildren()];            int joinerOverallPop[] = new int[getNumChildren()];            // compute how many times I need to execute the joiner            // before I get some output - this will be my phase            {                JoinFlow joinFlow;                do                {                    joinFlow = utility.getJoinSteadyPhaseFlow(joinerPhases);                    joinerPhases++;                    int nChild;                    for (nChild = 0; nChild < getNumChildren(); nChild++)                    {                        joinerOverallPop[nChild]                            += joinFlow.getPopWeight(nChild);                    }                }                while (joinFlow.getPushWeight() == 0);            }            int childOverallPeek[] = new int[getNumChildren()];            int childOverallPop[] = new int[getNumChildren()];            int childOverallPush[] = new int[getNumChildren()];            // figure out how many times to execute all the children            // to provide input for the joiner            {                int nChild;                for (nChild = 0; nChild < getNumChildren(); nChild++)                {                    StreamInterface child = getHierarchicalChild(nChild);                    while (preJoinBuffers[nChild]                        - joinerOverallPop[nChild]                        + childOverallPush[nChild]                        < 0)                    {                        PhasingSchedule childPhase =                            utility.getChildPhase(                                child,                                phaseChildrenExecs[nChild]);                        childOverallPeek[nChild] =                            MAX(                                childOverallPeek[nChild],                                childOverallPop[nChild]                                    + childPhase.getOverallPeek());                        childOverallPop[nChild] += childPhase.getOverallPop();                        childOverallPush[nChild] += childPhase.getOverallPush();                        phaseChildrenExecs[nChild]++;                    }                }            }            int splitterOverallPush[] = new int[getNumChildren()];            // figure out how many times to execute the splitter to            // supply enough data for all the children to go            {                int nChild;                for (nChild = 0; nChild < getNumChildren(); nChild++)                {                    int childSplitterPhases = 0;                    while (postSplitBuffers[nChild]                        + splitterOverallPush[nChild]                        - childOverallPeek[nChild]                        < 0)                    {                        SplitFlow splitFlow =                            utility.getSplitSteadyPhaseFlow(                                childSplitterPhases);                        childSplitterPhases++;                        splitterOverallPush[nChild]                            += splitFlow.getPushWeight(nChild);                    }                    splitterPhases = MAX(splitterPhases, childSplitterPhases);                }            }            // push the data available in the splitjoin down as much            // as possible:            {                // execute the children as much as possible given                // how much data they've been given by the splitter                {                    for (int nChild = 0; nChild < getNumChildren(); nChild++)                    {                        StreamInterface child = getHierarchicalChild(nChild);                        while (postSplitBuffers[nChild]                            + splitterOverallPush[nChild]                            - childOverallPop[nChild]                            >= utility                                .getChildPhase(                                    child,                                    phaseChildrenExecs[nChild])                                .getOverallPeek()                            && phaseChildrenExecs[nChild] < childrenExecs[nChild])                        {                            PhasingSchedule childPhase =                                utility.getChildPhase(                                    child,                                    phaseChildrenExecs[nChild]);                            childOverallPeek[nChild] =                                MAX(                                    childOverallPeek[nChild],                                    childOverallPop[nChild]                                        + childPhase.getOverallPeek());                            childOverallPop[nChild]                                += childPhase.getOverallPop();                            childOverallPush[nChild]                                += childPhase.getOverallPush();                            phaseChildrenExecs[nChild]++;                        }                    }                }                // and execute the joiner as much as possible, given                // the data available for it in the channels                joiner_push_data : while (joinExecs > joinerPhases)                {                    JoinFlow joinFlow;                    joinFlow = utility.getJoinSteadyPhaseFlow(joinerPhases);                    int nChild;                    for (nChild = 0; nChild < getNumChildren(); nChild++)                    {                        if (joinFlow.getPopWeight(nChild)                            > preJoinBuffers[nChild]                                + childOverallPush[nChild]                                - joinerOverallPop[nChild])                            break joiner_push_data;                    }                    for (nChild = 0; nChild < getNumChildren(); nChild++)                    {                        joinerOverallPop[nChild]                            += joinFlow.getPopWeight(nChild);                    }                    joinerPhases++;                }            }            // okay, now I know how many times I need to run the            // splitter, children and the joiner.  just run them :)            {                // get the phase                PhasingSchedule phase =                    utility.createPhase(                        splitterPhases,                        phaseChildrenExecs,                        joinerPhases,                        postSplitBuffers,                        preJoinBuffers);                // and adjust counters of execution:                splitExecs -= splitterPhases;                for (int nChild = 0; nChild < getNumChildren(); nChild++)                {                    childrenExecs[nChild] -= phaseChildrenExecs[nChild];                }                joinExecs -= joinerPhases;                utility.addSchedulePhase(phase);            }        }        // now execute all the components (other than the join, which        // is done initializing) until they're guaranteed to have been        // initialized        {            // create the phase            PhasingSchedule phase =                utility.createPhase(                    splitExecs,                    childrenExecs,                    0,                    postSplitBuffers,                    preJoinBuffers);            // add it to the init schedule, if necessary            if (phase.getNumPhases() != 0)            {                utility.addSchedulePhase(phase);            }        }    }