Exemple #1
0
def greedy(wrkld, spd, pwrusg, idle, idleusg, pwrcap, plcy):
    """Greedly schedules tasks according to a certain policy (no transitions while executing a task)

    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
    plcy: function that receives wrkld, spd, pwrusg and two triples (i1,j1,k1) and (i2,j2,k2) and returns True
    if and only if (i1,j1,k1) < (i2,j2,k2) in the policy used to greedly allocate the task
    (i.e., triple (i1,j1,k1) is preferred over (i2,j2,k2))
    --> plcy may assume that it will receive triples that don't yield zero speed

    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].config is a list of machine configurations
    -- for every machine j,
    -- trn[t].config[j] is the 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
    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
    """

    tasks = len(spd)
    machines = len(spd[0])
    configs = len(spd[0][0])

    order = [None] * machines
    trn = []
    run = [None] * machines

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

    possib = [(i,j,k)
              for i in range(tasks)
              for j in range(machines)
              for k in range(configs)
              if pwrusg[i][j][k] <= pwrcap and spd[i][j][k] > 0 #exclude violating configs and zero speeds
          ]
    possib.sort(key=less2key(lambda t1,t2: plcy(wrkld,spd,pwrusg,t1,t2), tuple))
    
    taskcompleted = [False] * tasks
    events = [(0, #time
               0)]#machine that became free (first value is irrelevant)
    currentconfigs = [idle[j] for j in range(machines)]
    currentpwrusgs = [idleusg[j] for j in range(machines)]
    currenttotalpwrusg = sum(currentpwrusgs)
    currentfree = [True] * machines
    numberoffree = machines
    
    while True: #Equivalent to while len(events) != 0 here
        (time, becamefree) = heapq.heappop(events)
        # currentfree update block
        if time != 0: #to exclude first iteration
            while True:
                currentfree[becamefree] = True
                numberoffree += 1
                currenttotalpwrusg += idleusg[becamefree] - currentpwrusgs[becamefree]
                currentpwrusgs[becamefree] = idleusg[becamefree]
                currentconfigs[becamefree] = idle[becamefree]
                if len(events) == 0 or events[0][0] != time:
                    break
                #next event has the same time (i.e., more machines may have become free at time)
                becamefree = heapq.heappop(events)[1]
        # End currentfree update block

        psbind = 0 #since deletion in list possib is involved, we must do it like this
        while numberoffree:
            while psbind < len(possib):
                i,j,k = possib[psbind]
                if taskcompleted[i]: # task is completed: can be removed from possibilities
                    del possib[psbind]
                    continue # avoid incrementing index psbind
                if currentfree[j] and currenttotalpwrusg - currentpwrusgs[j] + pwrusg[i][j][k] <= pwrcap:
                    break # found best valid triple!
                psbind += 1
            else: # (while's else) cannot run any more tasks at this time
                if numberoffree < machines:
                    #at least one occupied machine, wait for it to finish
                    #(that is leave the while loop skipping the "Run task block")
                    break
                #no occupied machine: either we are done or there is no solution
                if False in taskcompleted: #some task is left: no solution
                    raise no_solution
                for j in range(machines):# Fix run for machines that never ran any task
                    if len(order[j]) == 0:
                        run[j] = []
                trn.append(stateTran(time,currentconfigs))#add final transition to idle states at the end
                return (order,trn,run) #RETURN IS HERE!!

            # Run i on j with config k block
            taskcompleted[i] = True
            del possib[psbind]
            order[j].append(i)
            currenttotalpwrusg += pwrusg[i][j][k] - currentpwrusgs[j] 
            currentconfigs[j] = k
            currentpwrusgs[j] = pwrusg[i][j][k]
            #transition left to be updated after all tasks of this time are processed

            completiontime = time + float(wrkld[i]) / spd[i][j][k] #speed guaranteed to be non-zero
            run[j].append(completiontime)
            heapq.heappush(events,(completiontime,j)) #machine j will become free at time completiontime

            currentfree[j] = False
            numberoffree -= 1
            # End of run i on j with config k block

        #update transition of this time
        trn.append(stateTran(time,currentconfigs[:])) #the slicing is to generate a copy
Exemple #2
0
def getRealTransitionsFromPseudo(trn, run, finaltrnconfig=None):
    """Computes the transitions into real system states from transitions into pseudo system states and
    assignment/completion times (does not check for correctness of the solution)

    Arguments:
    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 (k1,...,km), where m is the number of machines,
    -- trn[t].configcoeff[k1,...,km] is the coefficient of real system configuration (k1,...,km) in the
       pseudo system configuration to which machine j has transitioned
    run: describes when each task runs on each machine (see getAssignmentCompletionRealTransitionsFromPseudo)
    -- for every machine j, and every t in len(order[j])
    -- task order[j][t] runs on machine j from time run[j][t] to time run[j][t+1]

    finaltrnconfig: list of machine configurations to be put at the end
    (or None (default), which is equivalent to [0]*machines)
    --- for every machine j,
    --- finaltrnconfig[j] is the configuration to which machine j has transitioned
    (this is typically the list of idle configurations)

    Returns: a list of real state transitions realtrn, where
    - realtrn: is the list of real state transitions
    -- for every t in range(len(realtrn)),
    -- realtrn[t].time is the time of transition t
    -- realtrn[t].config is a list of machine configurations
    --- for every machine j,
    --- realtrn[t].config[j] is the configuration to which machine j has transitioned
    """

    events = []
    realtrn = []
    machines = len(run)
    nconfigs = len(trn[0].configcoeff) # number of configurations

    if finaltrnconfig == None:
        finaltrnconfig = [0]*machines

    for j in range(machines):
        if run[j]:
            for t in range(1,len(run[j])):
                events.append((run[j][t],j,t))

    for t in range(1,len(trn)):
        events.append((trn[t].time,machines,t)) # we put the transitions with a dummy marker on second coordinate

    events.sort()
    lasttime = trn[0].time
    psdnow = [(trn[0].configcoeff[sysconf], list(sysconf))
              for sysconf in itertools.product(range(nconfigs), repeat=machines)# iterator for system configs
              if trn[0].configcoeff[sysconf] != 0] # first pseudo system state

    for (time,j,t) in events:
        if lasttime < time:
            difftime = time - lasttime
            splittime = lasttime
            for (p,sysconf) in psdnow:
                realtrn.append(stateTran(splittime,sysconf))
                splittime += p * difftime
            lasttime = time
        if j == machines: # it is a pseudo system state transition
            psdnow = [(trn[t].configcoeff[sysconf], list(sysconf))
                      for sysconf in itertools.product(range(nconfigs), repeat=machines)# iter for system configs
                      if trn[t].configcoeff[sysconf] != 0]
    #The part below normalizes the solution by putting a final state transition at the end
    realtrn.append(stateTran(lasttime,finaltrnconfig))
    return realtrn
Exemple #3
0
def halfHeartedGreedy(wrkld, spd, pwrusg, idle, idleusg, pwrcap, plcies, makecopy=True, reorder=True):
    """Greedly schedules tasks according to a certain policy (allows transitions while executing a task)

    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
    plcies: list of functions that receive wrkld, spd, pwrusg and two triples (i1,j1,k1) and (i2,j2,k2) and return 
    True if and only if (i1,j1,k1) < (i2,j2,k2) in the policy used to greedly allocate the task
    (i.e., triple (i1,j1,k1) is preferred over (i2,j2,k2))
    --> plcy may assume that it will receive triples that don't yield zero speed
    makecopy: boolean, if True, algorithm does not change any of its parameters (see Data races)
    reorder: reorder triples (task, machine, configuration) after each task completion (needed if policy is to
    use workload left instead of initial workload of tasks)

    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].config is a list of machine configurations
    -- for every machine j,
    -- trn[t].config[j] is the 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
    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
    plcies non-empty

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

    if makecopy:
        wrkld = wrkld[:]

    tasks = len(spd)
    machines = len(spd[0])
    configs = len(spd[0][0])

    order = [None] * machines
    trn = []
    run = [None] * machines

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

    nplcies = len(plcies)
    possibs = [None] * nplcies
    possibs[0] = [(i,j,k)
                  for i in range(tasks)
                  for j in range(machines)
                  for k in range(configs)
                  if pwrusg[i][j][k] <= pwrcap and spd[i][j][k] > 0 #exclude violating configs and zero speeds
              ]
    keys = [None] * nplcies

    for p in range(1,nplcies):
        possibs[p] = possibs[0][:] #make copy
        keys[p]=less2key(lambda t1,t2: plcies[p](wrkld,spd,pwrusg,t1,t2), tuple)
        possibs[p].sort(key=keys[p])
    
    taskstatus = [0] * tasks #0: waiting, 1: running, 2: completed
    events = [(0, #time
               0)]#machine that became free (first value is irrelevant)

    idletotalpwrusg = sum(idleusg)
    currentrunning = [None] * machines
    time = 0

    #The below will be true in the first iteration, but do not need to be initialized here:
    #currentconfigs = [idle[j] for j in range(machines)]
    #currentpwrusgs = [idleusg[j] for j in range(machines)]
    #currentfree = [True] * machines
    #numberoffree = machines
    #currenttotalpwrusg = idletotalpwrusg
    
    while True: #Equivalent to while len(events) != 0 here
        prevtime = time
        time = events[0][0]
        # taskstatus update block
        if prevtime != time: #to exclude first iteration
            # determine the minimum completion time
            for (t,mc) in events:
                if t < time:
                    time = t
            # consider tasks that finish at time time completed
            for (t,machinecompleted) in events:
                if t == time:
                    taskstatus[currentrunning[machinecompleted]] = 2 #completed
                    run[machinecompleted].append(time)
                    currentrunning[machinecompleted] = None
        # End taskstatus update block

        # wrkld update block
        deltat = time - prevtime
        for j in range(machines):
            if currentrunning[j] != None:
                wrkld[currentrunning[j]] -= spd[currentrunning[j]][j][currentconfigs[j]] * deltat
        # End wrkld update block

        # Falsely transition every occupied machine to idle state (so that the algorithm can choose new configs)
        currentconfigs = [idle[j] for j in range(machines)]
        currentpwrusgs = [idleusg[j] for j in range(machines)]
        currenttotalpwrusg = idletotalpwrusg
        currentcompletiontimes = [None] * machines

        someOccupied = False
        for p in range(nplcies):
            # Since wrklds might have been updated, we may need to sort the triples again
            if (reorder):
                possibs[p].sort(key=keys[p])

            psbind = 0 #since deletion in list possibs[p] is involved, we must do it like this
            numberofnotconsidered = machines
            currentnotconsidered = [True] * machines
            while numberofnotconsidered:
                while psbind < len(possibs[p]):
                    i,j,k = possibs[p][psbind]
                    if taskstatus[i] == 2: # task is completed: can be removed from possibilities
                        del possibs[p][psbind]
                        continue # avoid incrementing index psbind
                    if (currentnotconsidered[j] and
                        ((currentrunning[j] == None and taskstatus[i] == 0) or currentrunning[j] == i) and
                        currenttotalpwrusg - currentpwrusgs[j] + pwrusg[i][j][k] <= pwrcap):
                        break # found best valid triple!
                    psbind += 1
                else: # (while's else) cannot run any more tasks at this time
                    if p+1 < nplcies or someOccupied:
                        #we are not finished deciding or there is at least one occupied machine
                        #(that is leave the while loop skipping the "Run task block")
                        break
                    #no occupied machine: either we are done or there is no solution
                    if 0 in taskstatus: #some task is left: no solution
                        raise no_solution
                    for j in range(machines):# Fix run for machines that never ran any task
                        if len(order[j]) == 0:
                            run[j] = []
                    trn.append(stateTran(time,currentconfigs))#add final transition to idle states at the end
                    return (order,trn,run) #RETURN IS HERE!!

                # Consider running i on j with config k block
                taskstatus[i] = 1 #running
                if currentrunning[j] == None:
                    order[j].append(i)
                currentrunning[j] = i
                currenttotalpwrusg += pwrusg[i][j][k] - currentpwrusgs[j] 
                currentconfigs[j] = k
                currentpwrusgs[j] = pwrusg[i][j][k]
                #transition left to be updated after all tasks of this time are processed

                completiontime = time + float(wrkld[i]) / spd[i][j][k] #speed guaranteed to be non-zero
                #if we don't change our mind, machine j will become free at time completiontime:
                currentcompletiontimes[j] = completiontime

                someOccupied = True
                currentnotconsidered[j] = False
                numberofnotconsidered -= 1
                # End of consider running i on j with config k block

        #out of for: commit to decision and update transition of this time
        events = [(currentcompletiontimes[j],j) for j in range(machines) if currentcompletiontimes[j] != None]
        trn.append(stateTran(time,currentconfigs[:])) #the slicing is to generate a copy
#!/usr/bin/python
#-*- coding: utf-8 -*-

from commonclasses import stateTran, pseudoStateTran
from numpy import array

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]]])),