Пример #1
0
def linearProgram(wrkld,
                  spd,
                  pwrusg,
                  idle,
                  idleusg,
                  pwrcap,
                  makecopy=True,
                  epsilon=1e-9):
    """Schedules according to linear program

    Arguments:
    wrkld: list of workloads of each task
    spd: list of speeds of configurations states
    - for every task i, every machine j, and every configuration k,
    - spd[i][j][k] is the speed of task i in machine j while in configuration k
    pwrusg: list of power usages of configuration states
    - for every task i, every machine j, and every configuration k,
    - pwrusg[i][j][k] is the power usage of task i in machine j while in configuration k
    idle: list of idle configuration states
    - for every machine j
    - idle[j] is the idle configuration of machine j (i.e., the state with less power usage)
    idleusg: list of power usages of idle configuration states
    - for every machine j
    - idleusg[j] is the power usage of the idle configuration of machine j when no task is running
    pwrcap: power limit of the system
    makecopy: boolean, if True, algorithm does not change any of its parameters (see Data races)
    epsilon: precision for zero comparison


    Returns: A triple (order, trn, run)
    order: list of orderings of tasks on machines
    - for every machine j,
    - order[j] is a list [i1, ..., ik] that describes the tasks that will be run on machine j and their order
    trn: list of state transitions
    - for every t in range(len(trn)),
    - trn[t].time is the time of transition t
    - trn[t].configcoeff is an numpy.array of machine configurations
    -- for every system configuration (l1,...,lm), where m is the number of machines,
    -- trn[t].configcoeff[l1,...,lm] is the coefficient of real system configuration (l1,...,lm) in the
       pseudo system configuration to which machine j has transitioned
    run: list of completion times of tasks
    - for every machine j, and every t in len(order[j])
    - task order[j] runs on machine j from time run[j][t] to time run[j][t+1]

    Exceptions raised:
    - no_solution if pwrcap cannot be satisfied

    Assumptions:
    Compatibility of sizes
    Non-negative values
    Non-zero tasks, machines and configurations
    Non-zero workloads
    Idle state usages are less than when tasks are being run
    Every task i on idle state idle[j] has same usage pwrusg[i][j][idle[j]] as idleusg[j]
    Every task on an idle state has speed zero

    Data races: 
    If makecopy = False, then
    - wrkld is modified
    """

    tasks = len(spd)
    machines = len(spd[0])
    nconfigs = len(spd[0][1])

    if makecopy:
        wrkld = wrkld[:]

    order = [None] * machines
    run = [None] * machines
    trn = []
    for j in range(machines):
        order[j] = []
        run[j] = [0]

    initialtime = 0
    thisalloc = [i for i in range(tasks) if i < machines
                 ] + [None] * (machines - tasks)
    nexttask = machines

    while True:
        # (order of the) variables of the linear program:
        # nconfigs ** machines variables (p_{sysconf}), one for each system configuration sysconf
        # objective variable (y): inverse of the maximum time (maxtime) of completion (y will be maximized)

        nsysconfigs = nconfigs**machines
        objective = [0] * nsysconfigs + [-1]

        #Restrictions of the form a.x <= b
        upperboundedrestr = []  #list of a's
        upperboundedrhs = []  #list of b's

        #Restriction: each allocated task must have its workload completed:
        # The restriction is:
        # \sum_{sysconf} p_{sysconf} spd_{sysconf} * maxtime >= wrkld[task]
        # But we use (since y = 1 / maxtime):
        # - \sum_{sysconf} p_{sysconf} spd_{sysconf} + wrkld[task] * y <= 0
        for j in range(machines):
            if thisalloc[j] != None:  #machine has an allocated task
                upperboundedrestr.append([
                    -spd[thisalloc[j]][j][sysconf[j]]
                    for sysconf in itertools.product(range(nconfigs),
                                                     repeat=machines)
                ] + [wrkld[thisalloc[j]]])  #y
                upperboundedrhs.append(0)  #right-hand side

        #Restriction: coefficients of system configuration sum to 1
        equalityrestrs = [[1] * nsysconfigs + [0]]  #y
        equalityrhs = [1]  #right-hand side

        bounds = [None] * (nsysconfigs + 1)
        for var in range(nsysconfigs + 1):
            bounds[var] = (0, None)  #all variables are non-negative

        #Restriction): every sysconf that consumes more than powercap cannot be used:
        #p_{sysconf} = 0 for every sysconf with \sum_j pwrusg[task][machine][sysconf[j]] > pwrcap
        #put as the sum of such p_{sysconf} equals 0
        restr = [0] * (nsysconfigs + 1)
        for index, sysconf in enumerate(
                itertools.product(range(nconfigs), repeat=machines)):
            thispwrusg = 0
            for j in range(machines):
                if thisalloc[j] != None:  #machine has an allocated task
                    thispwrusg += pwrusg[thisalloc[j]][j][sysconf[j]]
                elif sysconf[j] == idle[
                        j]:  #machine does not have allocated task: it should idle
                    thispwrusg += idleusg[j]
                else:  #machine does not have allocated task but is not idle: forbid system configuration
                    thispwrusg += pwrcap + 1
                    break
            if thispwrusg > pwrcap:
                restr[index] = 1  #force coefficient to be zero
        equalityrestrs.append(restr)
        equalityrhs.append(0)

        #Solve linear program
        LPresult = scipy.optimize.linprog(c=objective,
                                          A_ub=upperboundedrestr,
                                          b_ub=upperboundedrhs,
                                          A_eq=equalityrestrs,
                                          b_eq=equalityrhs)

        if LPresult.nit == 1:
            raise iteration_limit
        if LPresult.nit == 2:
            raise commonclasses.no_solution
        if LPresult.nit == 3:
            raise unboundedLP  #This should never be raised if the workloads are non-zero

        #Compute task effective speeds and completion times
        effectivespeeds = [None] * machines
        completiontimes = [None] * machines
        mincompletiontime = 2.0 / LPresult.x[
            -1]  #= 2/y = 2*maxtime (the 2 is to avoid precision errors)
        for j in range(machines):
            if thisalloc[j] != None:  #machine had an allocated task
                effectivespeeds[j] = 0
                for index, sysconf in enumerate(
                        itertools.product(range(nconfigs), repeat=machines)):
                    effectivespeeds[j] += LPresult.x[index] * spd[
                        thisalloc[j]][j][sysconf[j]]
                completiontimes[j] = float(
                    wrkld[thisalloc[j]]) / effectivespeeds[j]
                if mincompletiontime > completiontimes[j]:
                    mincompletiontime = completiontimes[j]

        finished = True  #boolean that will indicate all tasks have been completed
        #Every task completed in time mincompletiontime is deemed completed
        #All other tasks will be rescheduled (with updated workloads)
        for j in range(machines):
            if thisalloc[j] != None:
                if completiontimes[j] <= mincompletiontime + epsilon:
                    order[j].append(thisalloc[j])
                    run[j].append(initialtime + completiontimes[j])
                    if nexttask < tasks:
                        finished = False
                        thisalloc[j] = nexttask
                        nexttask += 1
                    else:
                        thisalloc[j] = None
                else:  #machine had an allocated task that took more than mincompletiontime
                    wrkld[
                        thisalloc[j]] -= mincompletiontime * effectivespeeds[j]

        #Add transition at time initialtime to pseudo state given by LP solution
        p = numpy.empty([nconfigs] * machines)  #empty array
        for index, sysconf in enumerate(
                itertools.product(range(nconfigs), repeat=machines)):
            p[sysconf] = LPresult.x[index]
        trn.append(commonclasses.pseudoStateTran(initialtime, p))

        if finished:
            for j in range(machines):
                if thisalloc[
                        j] != None:  #machine had an allocated task that took more than mincompletiontime
                    order[j].append(thisalloc[j])
                    run[j].append(initialtime + completiontimes[j])
                elif len(
                        run[j]
                ) == 1:  #machine was never used, remove initial run time
                    run[j] = []
            #Add final transition to idle states
            p = numpy.full([nconfigs] * machines, 0)  #array filled with 0s
            p[tuple(idle)] = 1
            trn.append(
                commonclasses.pseudoStateTran(
                    initialtime + 1.0 / LPresult.x[-1], p))
            return (order, trn, run)  #RETURN IS HERE!!!

        initialtime = mincompletiontime  #go to time mincompletiontime
Пример #2
0
def linearProgram(wrkld, spd, pwrusg, idle, idleusg, pwrcap, makecopy=True, epsilon=1e-9):
    """Schedules according to linear program

    Arguments:
    wrkld: list of workloads of each task
    spd: list of speeds of configurations states
    - for every task i, every machine j, and every configuration k,
    - spd[i][j][k] is the speed of task i in machine j while in configuration k
    pwrusg: list of power usages of configuration states
    - for every task i, every machine j, and every configuration k,
    - pwrusg[i][j][k] is the power usage of task i in machine j while in configuration k
    idle: list of idle configuration states
    - for every machine j
    - idle[j] is the idle configuration of machine j (i.e., the state with less power usage)
    idleusg: list of power usages of idle configuration states
    - for every machine j
    - idleusg[j] is the power usage of the idle configuration of machine j when no task is running
    pwrcap: power limit of the system
    makecopy: boolean, if True, algorithm does not change any of its parameters (see Data races)
    epsilon: precision for zero comparison


    Returns: A triple (order, trn, run)
    order: list of orderings of tasks on machines
    - for every machine j,
    - order[j] is a list [i1, ..., ik] that describes the tasks that will be run on machine j and their order
    trn: list of state transitions
    - for every t in range(len(trn)),
    - trn[t].time is the time of transition t
    - trn[t].configcoeff is an numpy.array of machine configurations
    -- for every system configuration (l1,...,lm), where m is the number of machines,
    -- trn[t].configcoeff[l1,...,lm] is the coefficient of real system configuration (l1,...,lm) in the
       pseudo system configuration to which machine j has transitioned
    run: list of completion times of tasks
    - for every machine j, and every t in len(order[j])
    - task order[j] runs on machine j from time run[j][t] to time run[j][t+1]

    Exceptions raised:
    - no_solution if pwrcap cannot be satisfied

    Assumptions:
    Compatibility of sizes
    Non-negative values
    Non-zero tasks, machines and configurations
    Non-zero workloads
    Idle state usages are less than when tasks are being run
    Every task i on idle state idle[j] has same usage pwrusg[i][j][idle[j]] as idleusg[j]
    Every task on an idle state has speed zero

    Data races: 
    If makecopy = False, then
    - wrkld is modified
    """

    tasks = len(spd)
    machines = len(spd[0])
    nconfigs = len(spd[0][1])

    if makecopy:
        wrkld = wrkld[:]

    order = [None] * machines
    run = [None] * machines
    trn = []
    for j in range(machines):
        order[j] = []
        run[j] = [0]

    initialtime = 0
    thisalloc = [i for i in range(tasks) if i < machines] + [None] * (machines - tasks)
    nexttask = machines

    while True:
        # (order of the) variables of the linear program:
        # nconfigs ** machines variables (p_{sysconf}), one for each system configuration sysconf
        # objective variable (y): inverse of the maximum time (maxtime) of completion (y will be maximized)

        nsysconfigs = nconfigs ** machines
        objective = [0] * nsysconfigs + [-1]

        #Restrictions of the form a.x <= b
        upperboundedrestr = [] #list of a's
        upperboundedrhs = [] #list of b's

        #Restriction: each allocated task must have its workload completed:
        # The restriction is:
        # \sum_{sysconf} p_{sysconf} spd_{sysconf} * maxtime >= wrkld[task]
        # But we use (since y = 1 / maxtime):
        # - \sum_{sysconf} p_{sysconf} spd_{sysconf} + wrkld[task] * y <= 0
        for j in range(machines):
            if thisalloc[j] != None: #machine has an allocated task
                upperboundedrestr.append([-spd[thisalloc[j]][j][sysconf[j]]
                                          for sysconf in itertools.product(range(nconfigs), repeat=machines)]
                                         + [wrkld[thisalloc[j]]])#y
                upperboundedrhs.append(0)#right-hand side

        #Restriction: coefficients of system configuration sum to 1
        equalityrestrs = [[1] * nsysconfigs
                         + [0]]#y
        equalityrhs = [1]#right-hand side

        bounds = [None] * (nsysconfigs + 1)
        for var in range(nsysconfigs + 1):
            bounds[var] = (0,None)#all variables are non-negative

        #Restriction): every sysconf that consumes more than powercap cannot be used:
        #p_{sysconf} = 0 for every sysconf with \sum_j pwrusg[task][machine][sysconf[j]] > pwrcap
        #put as the sum of such p_{sysconf} equals 0
        restr = [0] * (nsysconfigs + 1)
        for index,sysconf in enumerate(itertools.product(range(nconfigs), repeat=machines)):
            thispwrusg = 0
            for j in range(machines):
                if thisalloc[j] != None: #machine has an allocated task
                    thispwrusg += pwrusg[thisalloc[j]][j][sysconf[j]]
                elif sysconf[j] == idle[j]: #machine does not have allocated task: it should idle
                    thispwrusg += idleusg[j]
                else: #machine does not have allocated task but is not idle: forbid system configuration
                    thispwrusg += pwrcap + 1
                    break
            if thispwrusg > pwrcap:
                restr[index] = 1#force coefficient to be zero
        equalityrestrs.append(restr)
        equalityrhs.append(0)
        
        #Solve linear program
        LPresult = scipy.optimize.linprog(c=objective,
                                          A_ub=upperboundedrestr,
                                          b_ub=upperboundedrhs,
                                          A_eq=equalityrestrs,
                                          b_eq=equalityrhs)

        if LPresult.nit == 1:
            raise iteration_limit
        if LPresult.nit == 2:
            raise commonclasses.no_solution
        if LPresult.nit == 3:
            raise unboundedLP #This should never be raised if the workloads are non-zero

        #Compute task effective speeds and completion times
        effectivespeeds = [None] * machines
        completiontimes = [None] * machines
        mincompletiontime = 2.0/LPresult.x[-1] #= 2/y = 2*maxtime (the 2 is to avoid precision errors)
        for j in range(machines):
            if thisalloc[j] != None: #machine had an allocated task
                effectivespeeds[j] = 0
                for index,sysconf in enumerate(itertools.product(range(nconfigs), repeat=machines)):
                    effectivespeeds[j] += LPresult.x[index] * spd[thisalloc[j]][j][sysconf[j]]
                completiontimes[j] = float(wrkld[thisalloc[j]]) / effectivespeeds[j]
                if mincompletiontime > completiontimes[j]:
                    mincompletiontime = completiontimes[j]

        finished = True #boolean that will indicate all tasks have been completed
        #Every task completed in time mincompletiontime is deemed completed
        #All other tasks will be rescheduled (with updated workloads)
        for j in range(machines):
            if thisalloc[j] != None:
                if completiontimes[j] <= mincompletiontime + epsilon:
                    order[j].append(thisalloc[j])
                    run[j].append(initialtime + completiontimes[j])
                    if nexttask < tasks:
                        finished = False
                        thisalloc[j] = nexttask
                        nexttask += 1
                    else:
                        thisalloc[j] = None
                else: #machine had an allocated task that took more than mincompletiontime
                    wrkld[thisalloc[j]] -= mincompletiontime * effectivespeeds[j]

        #Add transition at time initialtime to pseudo state given by LP solution
        p = numpy.empty([nconfigs]*machines) #empty array
        for index,sysconf in enumerate(itertools.product(range(nconfigs), repeat=machines)):
            p[sysconf] = LPresult.x[index]
        trn.append(commonclasses.pseudoStateTran(initialtime, p))

        if finished:
            for j in range(machines):
                if thisalloc[j] != None: #machine had an allocated task that took more than mincompletiontime
                    order[j].append(thisalloc[j])
                    run[j].append(initialtime + completiontimes[j])
                elif len(run[j]) == 1: #machine was never used, remove initial run time
                    run[j] = []
            #Add final transition to idle states
            p = numpy.full([nconfigs]*machines,0) #array filled with 0s
            p[tuple(idle)] = 1
            trn.append(commonclasses.pseudoStateTran(initialtime + 1.0/LPresult.x[-1], p))
            return (order,trn,run) #RETURN IS HERE!!!

        initialtime = mincompletiontime #go to time mincompletiontime
Пример #3
0
workload = [10] * 6
speed = [[[1, 2, 3]] * 3] * 6

order = [[0,1],
         [2,3],
         [4,5]]

realtransitions = [stateTran(0,[0,0,0]),
                   stateTran(2,[1,2,0]),
                   stateTran(5,[2,0,1]),
                   stateTran(7,[2,2,2]),
                   stateTran(10,[1,1,1])]
pseudotransitions = [
    pseudoStateTran(0,array([
        [[1,0,0],[0,0,0],[0,0,0]],
        [[0,0,0],[0,0,0],[0,0,0]],
        [[0,0,0],[0,0,0],[0,0,0]]])),
    pseudoStateTran(2,array([
        [[1.0/2,0,1.0/2],[0,0,0],[0,0,0]],
        [[0,0,0],[0,0,0],[0,0,0]],
        [[0,0,0],[0,0,0],[0,0,0]]])),
    pseudoStateTran(5,array([
        [[1.0/4,0,1.0/4],[0,0,0],[1.0/4,0,1.0/4]],
        [[0,0,0],[0,0,0],[0,0,0]],
        [[0,0,0],[0,0,0],[0,0,0]]])),
    pseudoStateTran(11,array([
        [[0,0,0],[0,0,0],[0,0,0]],
        [[0,0,0],[0,0,0],[0,0,0]],
        [[0,0,0],[0,0,0],[0,0,1]]]))
]