All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opalj.fpcf.seq.TasksManager.scala Maven / Gradle / Ivy

The newest version!
/* BSD 2-Clause License - see OPAL/LICENSE for details. */
package org.opalj
package fpcf
package seq

import java.util.ArrayDeque
import java.util.PriorityQueue

import scala.collection.mutable

trait TasksManager {

    /**
     * Just a hint from the property store to the tasks manager that some
     * computations related to entities are done directly by the property store.
     */
    def processing(e: Entity): Unit = {}

    def push(task: QualifiedTask): Unit

    // Please recall that the store can be queried for the current dependers, because
    // the push is done before the set of dependers is potentially deleted in an update.
    //
    // To get the "bottomness", you can use:
    // val bottomness =
    // if (eps.hasUBP && eps.ub.isOrderedProperty)
    //  eps.ub.asOrderedProperty.bottomness
    // else
    //  OrderedProperty.DefaultBottomness
    def push(
        task:                              QualifiedTask,
        taskEPK:                           SomeEPK,
        updatedEOptionP:                   SomeEOptionP, // the current eOptionP to which the task is related
        updatedEOptionPDependees:          Iterable[SomeEOptionP], // the dependees of the eOptionP
        currentDependersOfUpdatedEOptionP: Iterable[SomeEPK]
    ): Unit

    def pollAndExecute(): Unit

    def isEmpty: Boolean

    def size: Int
}

/**
 * Processes the task that was added last first.
 */
private[seq] final class LIFOTasksManager extends TasksManager {

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)
    private[this] val tasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)

    override def push(task: QualifiedTask): Unit = {
        this.initialTasks.addFirst(task)
    }

    override def push(
        task:             QualifiedTask,
        taskEPK:          SomeEPK,
        eOptionP:         SomeEOptionP,
        dependees:        Iterable[SomeEOptionP],
        currentDependers: Iterable[SomeEPK]
    ): Unit = {
        this.tasks.addFirst(task)
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null)
            t()
        else
            this.tasks.pollFirst()()
    }

    override def isEmpty: Boolean = this.initialTasks.isEmpty && this.tasks.isEmpty

    override def size: Int = this.initialTasks.size + this.tasks.size

    override def toString: String = "LIFOTasksManager"
}

/**
 * Processes the tasks that are scheduled for the longest time first.
 */
private[seq] final class FIFOTasksManager extends TasksManager {

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)
    private[this] val tasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)

    override def push(task: QualifiedTask): Unit = {
        this.initialTasks.addLast(task)
    }

    override def push(
        task:             QualifiedTask,
        taskEPK:          SomeEPK,
        eOptionPs:        SomeEOptionP,
        dependees:        Iterable[SomeEOptionP],
        currentDependers: Iterable[SomeEPK]
    ): Unit = {
        this.tasks.addLast(task)
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null)
            t()
        else
            this.tasks.pollFirst()()
    }

    override def isEmpty: Boolean = this.initialTasks.isEmpty && this.tasks.isEmpty

    override def size: Int = this.initialTasks.size + this.tasks.size

    override def toString: String = "FIFOTasksManager"
}

private class WeightedQualifiedTask(
        val task:   QualifiedTask,
        val weight: Int
) extends Comparable[WeightedQualifiedTask] {
    def compareTo(other: WeightedQualifiedTask) = this.weight - other.weight
}

private class WeightedExtendedQualifiedTask(
        val task:    QualifiedTask,
        val taskEPK: SomeEPK,
        val weight:  Int
) extends Comparable[WeightedQualifiedTask] {
    def compareTo(other: WeightedQualifiedTask) = this.weight - other.weight
}

private class ExtendedQualifiedTask(
        val task:    QualifiedTask,
        val taskEPK: SomeEPK
)

trait PropertyStoreDependentTasksManager extends TasksManager {

    protected[this] var ps: PKESequentialPropertyStore = null

    private[seq] def setSeqPropertyStore(ps: PKESequentialPropertyStore): Unit = {
        if (this.ps != null)
            throw new IllegalStateException(s"property store is already set: ${this.ps}")

        this.ps = ps
    }

}

/**
 * Schedules tasks that have many depender and dependee relations last.
 */
private[seq] final class ManyDirectDependenciesLastTasksManager
    extends PropertyStoreDependentTasksManager {

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)
    private[this] val tasks: PriorityQueue[WeightedQualifiedTask] = new PriorityQueue(50000)

    override def push(task: QualifiedTask): Unit = {
        this.initialTasks.addFirst(task)
    }

    override def push(
        task:             QualifiedTask,
        taskEPK:          SomeEPK,
        eOptionP:         SomeEOptionP,
        dependees:        Iterable[SomeEOptionP],
        currentDependers: Iterable[SomeEPK]
    ): Unit = {
        val weight = Math.max(1, dependees.size) * Math.max(1, currentDependers.size)
        this.tasks.add(new WeightedQualifiedTask(task, weight))
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null)
            t()
        else
            this.tasks.poll().task()
    }

    override def isEmpty: Boolean = this.initialTasks.isEmpty && this.tasks.isEmpty

    override def size: Int = this.initialTasks.size + this.tasks.size

    override def toString: String = "ManyDirectDependenciesLastTasksManager"
}

/**
 * Schedules tasks that have many depender and dependee relations first.
 */
private[seq] final class ManyDirectDependenciesFirstTasksManager
    extends PropertyStoreDependentTasksManager {

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)
    private[this] val tasks: PriorityQueue[WeightedQualifiedTask] = new PriorityQueue(50000)

    override def push(task: QualifiedTask): Unit = {
        this.initialTasks.addFirst(task)
    }

    override def push(
        task:             QualifiedTask,
        taskEPK:          SomeEPK,
        eOptionP:         SomeEOptionP,
        dependees:        Iterable[SomeEOptionP],
        currentDependers: Iterable[SomeEPK]
    ): Unit = {
        val weight = -(Math.max(1, dependees.size) * Math.max(1, currentDependers.size))
        this.tasks.add(new WeightedQualifiedTask(task, weight))
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null)
            t()
        else
            this.tasks.poll().task()
    }

    override def isEmpty: Boolean = this.initialTasks.isEmpty && this.tasks.isEmpty

    override def size: Int = this.initialTasks.size + this.tasks.size

    override def toString: String = "ManyDirectDependenciesFirstTasksManager"
}

private[seq] final class ManyDirectDependersLastTasksManager
    extends PropertyStoreDependentTasksManager {

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)
    private[this] val tasks: PriorityQueue[WeightedQualifiedTask] = new PriorityQueue(50000)

    override def push(task: QualifiedTask): Unit = {
        this.initialTasks.addFirst(task)
    }

    override def push(
        task:             QualifiedTask,
        taskEPK:          SomeEPK,
        eOptionP:         SomeEOptionP,
        dependees:        Iterable[SomeEOptionP],
        currentDependers: Iterable[SomeEPK]
    ): Unit = {
        this.tasks.add(new WeightedQualifiedTask(task, currentDependers.size))
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null)
            t()
        else
            this.tasks.poll().task()
    }

    override def isEmpty: Boolean = this.initialTasks.isEmpty && this.tasks.isEmpty

    override def size: Int = this.initialTasks.size + this.tasks.size

    override def toString: String = "ManyDirectDependersLastTasksManager"
}

private[seq] final class ManyDirectDependersFirstTasksManager
    extends PropertyStoreDependentTasksManager {

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)
    private[this] val tasks: PriorityQueue[WeightedQualifiedTask] = new PriorityQueue(50000)

    override def push(task: QualifiedTask): Unit = {
        this.initialTasks.addFirst(task)
    }

    override def push(
        task:             QualifiedTask,
        taskEPK:          SomeEPK,
        eOptionP:         SomeEOptionP,
        dependees:        Iterable[SomeEOptionP],
        currentDependers: Iterable[SomeEPK]
    ): Unit = {
        this.tasks.add(new WeightedQualifiedTask(task, -(currentDependers.size)))
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null)
            t()
        else
            this.tasks.poll().task()
    }

    override def isEmpty: Boolean = this.initialTasks.isEmpty && this.tasks.isEmpty

    override def size: Int = this.initialTasks.size + this.tasks.size

    override def toString: String = "ManyDirectDependersFirstTasksManager"
}

private[seq] final class ManyDependeesOfDirectDependersLastTasksManager
    extends PropertyStoreDependentTasksManager {

    // The following insights were gained by running the IFDS taint analysis:
    // Note: What really didn't work was to delay tasks that have no dependers at the time
    //       the task is registered.

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(32768)
    private[this] val tasks: PriorityQueue[WeightedQualifiedTask] = new PriorityQueue(32768)

    override def push(task: QualifiedTask): Unit = {
        task match {
            case _: HandleResultTask[_, _] => this.initialTasks.addFirst(task)
            case _                         => this.initialTasks.addLast(task)
        }
    }

    override def push(
        task:                              QualifiedTask,
        taskEPK:                           SomeEPK,
        updatedEOptionP:                   SomeEOptionP,
        updatedEOptionPDependees:          Iterable[SomeEOptionP],
        currentDependersOfUpdatedEOptionP: Iterable[SomeEPK]
    ): Unit = {
        if (task.isTriggeredByFinalProperty && ps.dependeesCount(taskEPK) == 1) {
            task()
        } else {
            var weight = 0
            currentDependersOfUpdatedEOptionP foreach { epk => weight += ps.dependeesCount(epk) }
            val wt = new WeightedQualifiedTask(task, weight)
            this.tasks.add(wt)
        }
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null) {
            t()
            return ;
        }

        val wt = this.tasks.poll()
        wt.task()
    }

    override def isEmpty: Boolean = initialTasks.isEmpty && tasks.isEmpty // && delayedTasks.isEmpty

    override def size: Int = initialTasks.size + tasks.size // + delayedTasks.size

    override def toString: String = "ManyDependeesOfDirectDependersLastTasksManager"
}

private[seq] final class ManyDependeesOfDirectDependersFirstTasksManager
    extends PropertyStoreDependentTasksManager {

    // The following insights were gained by running the IFDS taint analysis:
    // Note: What really didn't work was to delay tasks that have no dependers at the time
    //       the task is registered.

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(32768)
    private[this] val tasks: PriorityQueue[WeightedQualifiedTask] = new PriorityQueue(32768)

    override def push(task: QualifiedTask): Unit = {
        task match {
            case _: HandleResultTask[_, _] => this.initialTasks.addFirst(task)
            case _                         => this.initialTasks.addLast(task)
        }
    }

    override def push(
        task:                              QualifiedTask,
        taskEPK:                           SomeEPK,
        updatedEOptionP:                   SomeEOptionP,
        updatedEOptionPDependees:          Iterable[SomeEOptionP],
        currentDependersOfUpdatedEOptionP: Iterable[SomeEPK]
    ): Unit = {
        if (task.isTriggeredByFinalProperty && ps.dependeesCount(taskEPK) == 1) {
            task()
        } else {
            var weight = 0
            currentDependersOfUpdatedEOptionP foreach { epk => weight += ps.dependeesCount(epk) }
            val wt = new WeightedQualifiedTask(task, -weight)
            this.tasks.add(wt)
        }
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null) {
            t()
            return ;
        }

        val wt = this.tasks.poll()
        //if (wt ne null) {
        wt.task()
        //    return ;
        // }

        // this.delayedTasks.poll().task()
    }

    override def isEmpty: Boolean = initialTasks.isEmpty && tasks.isEmpty // && delayedTasks.isEmpty

    override def size: Int = initialTasks.size + tasks.size // + delayedTasks.size

    override def toString: String = "ManyDependeesOfDirectDependersFirstTasksManager"
}

private[seq] final class ManyDependeesAndDependersOfDirectDependersLastTasksManager
    extends PropertyStoreDependentTasksManager {

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)
    private[this] val tasks: PriorityQueue[WeightedQualifiedTask] = new PriorityQueue(50000)

    override def push(task: QualifiedTask): Unit = {
        this.initialTasks.addFirst(task)
    }

    override def push(
        task:             QualifiedTask,
        taskEPK:          SomeEPK,
        eOptionP:         SomeEOptionP,
        dependees:        Iterable[SomeEOptionP],
        currentDependers: Iterable[SomeEPK]
    ): Unit = {
        var weight = 0
        currentDependers foreach { epk =>
            weight += ps.dependeesCount(epk) + ps.dependersCount(epk)
        }
        this.tasks.add(new WeightedQualifiedTask(task, weight))
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null)
            t()
        else
            this.tasks.poll().task()
    }

    override def isEmpty: Boolean = this.initialTasks.isEmpty && this.tasks.isEmpty

    override def size: Int = this.initialTasks.size + this.tasks.size

    override def toString: String = "ManyDependeesAndDependersOfDirectDependersLastTasksManager"
}

private[seq] final class ManyDependeesAndDependersOfDirectDependersFirstTasksManager
    extends PropertyStoreDependentTasksManager {

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)
    private[this] val tasks: PriorityQueue[WeightedQualifiedTask] = new PriorityQueue(50000)

    override def push(task: QualifiedTask): Unit = {
        this.initialTasks.addFirst(task)
    }

    override def push(
        task:             QualifiedTask,
        taskEPK:          SomeEPK,
        eOptionP:         SomeEOptionP,
        dependees:        Iterable[SomeEOptionP],
        currentDependers: Iterable[SomeEPK]
    ): Unit = {
        var weight = 0
        currentDependers foreach { epk =>
            weight -= ps.dependeesCount(epk) + ps.dependersCount(epk)
        }
        this.tasks.add(new WeightedQualifiedTask(task, weight))
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null)
            t()
        else
            this.tasks.poll().task()
    }

    override def isEmpty: Boolean = this.initialTasks.isEmpty && this.tasks.isEmpty

    override def size: Int = this.initialTasks.size + this.tasks.size

    override def toString: String = "ManyDependeesAndDependersOfDirectDependersFirstTasksManager"
}

private[seq] final class AllDependeesTasksManager(
        final val forward:           Boolean = true,
        final val manyDependeesLast: Boolean = true
) extends PropertyStoreDependentTasksManager {

    private[this] val initialTasks: ArrayDeque[QualifiedTask] = new ArrayDeque(50000)
    private[this] val tasks: PriorityQueue[WeightedQualifiedTask] = new PriorityQueue(50000)

    override def push(task: QualifiedTask): Unit = {
        this.initialTasks.addFirst(task)
    }

    private[this] def computeForwardWeight(dependees: Iterable[SomeEOptionP]): Int = {
        val allDependees = mutable.HashSet.empty[SomeEPK]
        var newDependees = dependees.map(_.toEPK).toList
        while (newDependees.nonEmpty) {
            val nextDependee = newDependees.head
            newDependees = newDependees.tail
            val nextDependeeEPK = nextDependee
            allDependees += nextDependeeEPK
            ps.dependees(nextDependeeEPK) foreach { nextNextDependee =>
                val nextNextDependeeEPK = nextNextDependee.toEPK
                if (allDependees.add(nextNextDependeeEPK)) {
                    newDependees ::= nextNextDependeeEPK
                }
            }
        }
        allDependees.size
    }

    private[this] def computeBackwardWeight(currentDependers: Iterable[SomeEPK]): Int = {
        var weight = 0
        val allDependers = mutable.HashSet.empty[SomeEPK]
        var newDependers = currentDependers.toList
        while (newDependers.nonEmpty) {
            val nextDepender = newDependers.head
            newDependers = newDependers.tail
            allDependers += nextDepender
            ps.dependers(nextDepender) foreach { nextNextDepender =>
                if (allDependers.add(nextNextDepender)) {
                    newDependers ::= nextNextDepender
                    weight += ps.dependeesCount(nextNextDepender)
                }
            }
        }
        weight
    }

    override def push(
        task:             QualifiedTask,
        taskEPK:          SomeEPK,
        eOptionP:         SomeEOptionP,
        dependees:        Iterable[SomeEOptionP],
        currentDependers: Iterable[SomeEPK]
    ): Unit = {
        var weight =
            if (forward) {
                computeForwardWeight(dependees)
            } else {
                computeBackwardWeight(currentDependers)
            }
        if (!manyDependeesLast) weight = -weight
        //println("Weight: "+weight+"   -     Tasks:"+size)
        this.tasks.add(new WeightedQualifiedTask(task, weight))
    }

    override def pollAndExecute(): Unit = {
        val t = this.initialTasks.pollFirst()
        if (t ne null)
            t()
        else
            this.tasks.poll().task()
    }

    override def isEmpty: Boolean = this.initialTasks.isEmpty && this.tasks.isEmpty

    override def size: Int = this.initialTasks.size + this.tasks.size

    override def toString: String = {
        s"AllDependeesTasksManager(forward=$forward,manyDependeesLast=$manyDependeesLast)"
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy