utility.getChildNextPhase(child);
utility.getChildPhase(child, nPhase);
    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++)                {                    while (preJoinBuffers[nChild]                        - joinerOverallPop[nChild]                        + childOverallPush[nChild]                        < 0)                    {                        StreamInterface child = getHierarchicalChild(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]++;                    }                }            }            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);                }            }            // okay, now I know how many times I need to run the            // splitter, children and the joiner.  just run them :)            {                PhasingSchedule phase = new PhasingSchedule(this);                // first run the splitter:                for (; splitterPhases > 0; splitterPhases--)                {                    // get the appropriate flow                    SplitFlow flow = utility.getNextSplitSteadyPhaseFlow();                    // update the buffers (add data)                    int nChild;                    for (nChild = 0; nChild < getNumChildren(); nChild++)                    {                        postSplitBuffers[nChild]                            += flow.getPushWeight(nChild);                    }                    // add the phase to the schedule and                     // advance the phase counter                    phase.appendPhase(utility.getNextSplitSteadyPhase());                    utility.advanceSplitSchedule();                    // note that I've just executed a splitter init phase                    splitExecs--;                }                // now run the children                {                    int nChild;                    for (nChild = 0; nChild < getNumChildren(); nChild++)                    {                        StreamInterface child = getHierarchicalChild(nChild);                        for (;                            phaseChildrenExecs[nChild] > 0;                            phaseChildrenExecs[nChild]--)                        {                            // get the phase and check that I've enough                             // peek data in the buffer to run it                            PhasingSchedule childPhase =                                utility.getChildNextPhase(child);                            ASSERT(                                postSplitBuffers[nChild]                                    >= childPhase.getOverallPeek());                            // update the buffers                            postSplitBuffers[nChild]                                -= childPhase.getOverallPop();                            preJoinBuffers[nChild]                                += childPhase.getOverallPush();                            // add the phase to the schedule                            // and advance the phase counter                            phase.appendPhase(childPhase);                            utility.advanceChildSchedule(child);                            // note that I've just executed a child                             // init phase                            childrenExecs[nChild]--;                        }                    }                }                // and finally run the joiner                for (; joinerPhases > 0; joinerPhases--)                {                    // get the appropriate flow                    JoinFlow flow = utility.getNextJoinSteadyPhaseFlow();                    // update the buffers (add data)                    int nChild;                    for (nChild = 0; nChild < getNumChildren(); nChild++)                    {                        preJoinBuffers[nChild] -= flow.getPopWeight(nChild);                        ASSERT(preJoinBuffers[nChild] >= 0);                    }                    // add the phase to the schedule and                     // advance the phase counter                    phase.appendPhase(utility.getNextJoinSteadyPhase());                    utility.advanceJoinSchedule();                    // note that I've just executed a joiner init phase                    joinExecs--;                }                utility.addSchedulePhase(phase);            }        }        // now execute all the components (other than the join, which        // is done initializing) until they're guaranteed to have been        // initialized        {            PhasingSchedule phase = new PhasingSchedule(this);            // first run the splitter:            for (; splitExecs > 0; splitExecs--)            {                // get the appropriate flow                SplitFlow flow = utility.getNextSplitSteadyPhaseFlow();                // update the buffers (add data)                int nChild;                for (nChild = 0; nChild < getNumChildren(); nChild++)                {                    postSplitBuffers[nChild] += flow.getPushWeight(nChild);                }                // add the phase to the schedule and                 // advance the phase counter                phase.appendPhase(utility.getNextSplitSteadyPhase());                utility.advanceSplitSchedule();            }            // now run the children            {                int nChild;                for (nChild = 0; nChild < getNumChildren(); nChild++)                {                    StreamInterface child = getHierarchicalChild(nChild);                    for (;                        childrenExecs[nChild] > 0;                        childrenExecs[nChild]--)                    {                        // get the phase and check that I've enough                         // peek data in the buffer to run it                        PhasingSchedule childPhase =                            utility.getChildNextPhase(child);                        ASSERT(                            postSplitBuffers[nChild]                                >= childPhase.getOverallPeek());                        // update the buffers                        postSplitBuffers[nChild]                            -= childPhase.getOverallPop();                        preJoinBuffers[nChild] += childPhase.getOverallPush();                        // add the phase to the schedule                        // and advance the phase counter                        phase.appendPhase(childPhase);                        utility.advanceChildSchedule(child);                    }                }            }            // add the phase to the init schedule, if necessary            if (phase.getNumPhases() != 0)            {                utility.addSchedulePhase(phase);            }        }    }