Add GraphProperties and property caching
This commit is contained in:
@ -25,7 +25,7 @@ export is_exit_node
|
||||
export parents
|
||||
export children
|
||||
export compute
|
||||
export graph_properties
|
||||
export get_properties
|
||||
export get_exit_node
|
||||
export is_valid
|
||||
|
||||
@ -55,6 +55,8 @@ export bytes_to_human_readable
|
||||
import Base.length
|
||||
import Base.show
|
||||
import Base.==
|
||||
import Base.+
|
||||
import Base.-
|
||||
import Base.in
|
||||
import Base.copy
|
||||
import Base.isempty
|
||||
@ -66,6 +68,7 @@ import Base.collect
|
||||
include("task/type.jl")
|
||||
include("node/type.jl")
|
||||
include("diff/type.jl")
|
||||
include("properties/type.jl")
|
||||
include("operation/type.jl")
|
||||
include("graph/type.jl")
|
||||
|
||||
@ -96,6 +99,9 @@ include("operation/get.jl")
|
||||
include("operation/print.jl")
|
||||
include("operation/validate.jl")
|
||||
|
||||
include("properties/create.jl")
|
||||
include("properties/utility.jl")
|
||||
|
||||
include("task/create.jl")
|
||||
include("task/compare.jl")
|
||||
include("task/print.jl")
|
||||
|
@ -58,12 +58,12 @@ function show(io::IO, graph::DAG)
|
||||
end
|
||||
println(io)
|
||||
println(io, " Edges: ", noEdges)
|
||||
properties = graph_properties(graph)
|
||||
println(io, " Total Compute Effort: ", properties.compute_effort)
|
||||
properties = get_properties(graph)
|
||||
println(io, " Total Compute Effort: ", properties.computeEffort)
|
||||
println(io, " Total Data Transfer: ", properties.data)
|
||||
return println(
|
||||
io,
|
||||
" Total Compute Intensity: ",
|
||||
properties.compute_intensity,
|
||||
properties.computeIntensity,
|
||||
)
|
||||
end
|
||||
|
@ -1,31 +1,17 @@
|
||||
"""
|
||||
graph_properties(graph::DAG)
|
||||
get_properties(graph::DAG)
|
||||
|
||||
Return the graph's properties, a named tuple with fields `.data`, `.compute_effort`, `.compute_intensity`, `.nodes` (number of nodes) and `.edges` (number of edges).
|
||||
Return the graph's [`GraphProperties`](@ref).
|
||||
"""
|
||||
function graph_properties(graph::DAG)
|
||||
function get_properties(graph::DAG)
|
||||
# make sure the graph is fully generated
|
||||
apply_all!(graph)
|
||||
|
||||
d = 0
|
||||
ce = 0
|
||||
ed = 0
|
||||
for node in graph.nodes
|
||||
d += data(node.task) * length(node.parents)
|
||||
ce += compute_effort(node.task)
|
||||
ed += length(node.parents)
|
||||
if (graph.properties.computeEffort == 0.0)
|
||||
graph.properties = GraphProperties(graph)
|
||||
end
|
||||
|
||||
ci = ce / d
|
||||
|
||||
result = (
|
||||
data = d,
|
||||
compute_effort = ce,
|
||||
compute_intensity = ci,
|
||||
nodes = length(graph.nodes),
|
||||
edges = ed,
|
||||
)
|
||||
return result
|
||||
return graph.properties
|
||||
end
|
||||
|
||||
"""
|
||||
|
@ -41,6 +41,9 @@ mutable struct DAG
|
||||
# "snapshot" system: keep track of added/removed nodes/edges since last snapshot
|
||||
# these are muted in insert_node! etc.
|
||||
diff::Diff
|
||||
|
||||
# the cached properties of the DAG
|
||||
properties::GraphProperties
|
||||
end
|
||||
|
||||
"""
|
||||
@ -69,5 +72,6 @@ function DAG()
|
||||
PossibleOperations(),
|
||||
Set{Node}(),
|
||||
Diff(),
|
||||
GraphProperties(),
|
||||
)
|
||||
end
|
||||
|
@ -195,6 +195,14 @@ function parse_abc(filename::String, verbose::Bool = false)
|
||||
#put all nodes into dirty nodes set
|
||||
graph.dirtyNodes = copy(graph.nodes)
|
||||
|
||||
if (verbose)
|
||||
println("Generating the graph's properties")
|
||||
end
|
||||
graph.properties = GraphProperties(graph)
|
||||
|
||||
if (verbose)
|
||||
println("Done")
|
||||
end
|
||||
# don't actually need to read the edges
|
||||
return graph
|
||||
end
|
||||
|
@ -1,3 +1,43 @@
|
||||
|
||||
DataTaskNode(t::AbstractDataTask) = DataTaskNode(
|
||||
t,
|
||||
Vector{Node}(),
|
||||
Vector{Node}(),
|
||||
UUIDs.uuid1(rng[threadid()]),
|
||||
missing,
|
||||
missing,
|
||||
missing,
|
||||
)
|
||||
ComputeTaskNode(t::AbstractComputeTask) = ComputeTaskNode(
|
||||
t,
|
||||
Vector{Node}(),
|
||||
Vector{Node}(),
|
||||
UUIDs.uuid1(rng[threadid()]),
|
||||
missing,
|
||||
missing,
|
||||
Vector{NodeFusion}(),
|
||||
)
|
||||
|
||||
copy(m::Missing) = missing
|
||||
copy(n::ComputeTaskNode) = ComputeTaskNode(
|
||||
copy(n.task),
|
||||
copy(n.parents),
|
||||
copy(n.children),
|
||||
UUIDs.uuid1(rng[threadid()]),
|
||||
copy(n.nodeReduction),
|
||||
copy(n.nodeSplit),
|
||||
copy(n.nodeFusions),
|
||||
)
|
||||
copy(n::DataTaskNode) = DataTaskNode(
|
||||
copy(n.task),
|
||||
copy(n.parents),
|
||||
copy(n.children),
|
||||
UUIDs.uuid1(rng[threadid()]),
|
||||
copy(n.nodeReduction),
|
||||
copy(n.nodeSplit),
|
||||
copy(n.nodeFusion),
|
||||
)
|
||||
|
||||
"""
|
||||
make_node(t::AbstractTask)
|
||||
|
||||
|
@ -12,6 +12,18 @@ Return whether this node is an exit node of its graph, i.e., it has no parents.
|
||||
"""
|
||||
is_exit_node(node::Node) = length(node.parents) == 0
|
||||
|
||||
"""
|
||||
data(edge::Edge)
|
||||
|
||||
Return the data transfered by this edge, i.e., 0 if the child is a [`ComputeTaskNode`](@ref), otherwise the child's `data()`.
|
||||
"""
|
||||
function data(edge::Edge)
|
||||
if typeof(edge.edge[1]) <: DataTaskNode
|
||||
return data(edge.edge[1].task)
|
||||
end
|
||||
return 0.0
|
||||
end
|
||||
|
||||
"""
|
||||
children(node::Node)
|
||||
|
||||
|
@ -81,25 +81,6 @@ mutable struct ComputeTaskNode <: Node
|
||||
nodeFusions::Vector{Operation}
|
||||
end
|
||||
|
||||
DataTaskNode(t::AbstractDataTask) = DataTaskNode(
|
||||
t,
|
||||
Vector{Node}(),
|
||||
Vector{Node}(),
|
||||
UUIDs.uuid1(rng[threadid()]),
|
||||
missing,
|
||||
missing,
|
||||
missing,
|
||||
)
|
||||
ComputeTaskNode(t::AbstractComputeTask) = ComputeTaskNode(
|
||||
t,
|
||||
Vector{Node}(),
|
||||
Vector{Node}(),
|
||||
UUIDs.uuid1(rng[threadid()]),
|
||||
missing,
|
||||
missing,
|
||||
Vector{NodeFusion}(),
|
||||
)
|
||||
|
||||
"""
|
||||
Edge
|
||||
|
||||
@ -116,23 +97,3 @@ struct Edge
|
||||
Tuple{ComputeTaskNode, DataTaskNode},
|
||||
}
|
||||
end
|
||||
|
||||
copy(m::Missing) = missing
|
||||
copy(n::ComputeTaskNode) = ComputeTaskNode(
|
||||
copy(n.task),
|
||||
copy(n.parents),
|
||||
copy(n.children),
|
||||
UUIDs.uuid1(rng[threadid()]),
|
||||
copy(n.nodeReduction),
|
||||
copy(n.nodeSplit),
|
||||
copy(n.nodeFusions),
|
||||
)
|
||||
copy(n::DataTaskNode) = DataTaskNode(
|
||||
copy(n.task),
|
||||
copy(n.parents),
|
||||
copy(n.children),
|
||||
UUIDs.uuid1(rng[threadid()]),
|
||||
copy(n.nodeReduction),
|
||||
copy(n.nodeSplit),
|
||||
copy(n.nodeFusion),
|
||||
)
|
||||
|
@ -40,6 +40,9 @@ function apply_operation!(graph::DAG, operation::NodeFusion)
|
||||
operation.input[2],
|
||||
operation.input[3],
|
||||
)
|
||||
|
||||
graph.properties += GraphProperties(diff)
|
||||
|
||||
return AppliedNodeFusion(operation, diff)
|
||||
end
|
||||
|
||||
@ -52,6 +55,9 @@ Return an [`AppliedNodeReduction`](@ref) object generated from the graph's [`Dif
|
||||
"""
|
||||
function apply_operation!(graph::DAG, operation::NodeReduction)
|
||||
diff = node_reduction!(graph, operation.input)
|
||||
|
||||
graph.properties += GraphProperties(diff)
|
||||
|
||||
return AppliedNodeReduction(operation, diff)
|
||||
end
|
||||
|
||||
@ -64,6 +70,9 @@ Return an [`AppliedNodeSplit`](@ref) object generated from the graph's [`Diff`](
|
||||
"""
|
||||
function apply_operation!(graph::DAG, operation::NodeSplit)
|
||||
diff = node_split!(graph, operation.input)
|
||||
|
||||
graph.properties += GraphProperties(diff)
|
||||
|
||||
return AppliedNodeSplit(operation, diff)
|
||||
end
|
||||
|
||||
@ -127,6 +136,9 @@ function revert_diff!(graph::DAG, diff::Diff)
|
||||
for edge in diff.removedEdges
|
||||
insert_edge!(graph, edge.edge[1], edge.edge[2], false)
|
||||
end
|
||||
|
||||
graph.properties -= GraphProperties(diff)
|
||||
|
||||
return nothing
|
||||
end
|
||||
|
||||
|
73
src/properties/create.jl
Normal file
73
src/properties/create.jl
Normal file
@ -0,0 +1,73 @@
|
||||
"""
|
||||
GraphProperties()
|
||||
|
||||
Create an empty [`GraphProperties`](@ref) object.
|
||||
"""
|
||||
function GraphProperties()
|
||||
return (
|
||||
data = 0.0,
|
||||
computeEffort = 0.0,
|
||||
computeIntensity = 0.0,
|
||||
cost = 0.0,
|
||||
noNodes = 0,
|
||||
noEdges = 0,
|
||||
)::GraphProperties
|
||||
end
|
||||
|
||||
"""
|
||||
GraphProperties(graph::DAG)
|
||||
|
||||
Calculate the graph's properties and return the constructed [`GraphProperties`](@ref) object.
|
||||
"""
|
||||
function GraphProperties(graph::DAG)
|
||||
# make sure the graph is fully generated
|
||||
apply_all!(graph)
|
||||
|
||||
d = 0.0
|
||||
ce = 0.0
|
||||
ed = 0
|
||||
for node in graph.nodes
|
||||
d += data(node.task) * length(node.parents)
|
||||
ce += compute_effort(node.task)
|
||||
ed += length(node.parents)
|
||||
end
|
||||
|
||||
return (
|
||||
data = d,
|
||||
computeEffort = ce,
|
||||
computeIntensity = (d == 0) ? 0.0 : ce / d,
|
||||
cost = 0.0, # TODO
|
||||
noNodes = length(graph.nodes),
|
||||
noEdges = ed,
|
||||
)::GraphProperties
|
||||
end
|
||||
|
||||
"""
|
||||
GraphProperties(diff::Diff)
|
||||
|
||||
Create the graph properties difference from a given [`Diff`](@ref).
|
||||
The graph's properties after applying the [`Diff`](@ref) will be `get_properties(graph) + GraphProperties(diff)`.
|
||||
For reverting a diff, it's `get_properties(graph) - GraphProperties(diff)`.
|
||||
"""
|
||||
function GraphProperties(diff::Diff)
|
||||
d = 0.0
|
||||
ce = 0.0
|
||||
c = 0.0 # TODO
|
||||
|
||||
ce =
|
||||
reduce(+, compute_effort(n.task) for n in diff.addedNodes; init = 0.0) -
|
||||
reduce(+, compute_effort(n.task) for n in diff.removedNodes; init = 0.0)
|
||||
|
||||
d =
|
||||
reduce(+, data(e) for e in diff.addedEdges; init = 0.0) -
|
||||
reduce(+, data(e) for e in diff.removedEdges; init = 0.0)
|
||||
|
||||
return (
|
||||
data = d,
|
||||
computeEffort = ce,
|
||||
computeIntensity = (d == 0) ? 0.0 : ce / d,
|
||||
cost = c,
|
||||
noNodes = length(diff.addedNodes) - length(diff.removedNodes),
|
||||
noEdges = length(diff.addedEdges) - length(diff.removedEdges),
|
||||
)::GraphProperties
|
||||
end
|
17
src/properties/type.jl
Normal file
17
src/properties/type.jl
Normal file
@ -0,0 +1,17 @@
|
||||
"""
|
||||
GraphProperties
|
||||
|
||||
Representation of a [`DAG`](@ref)'s properties.
|
||||
|
||||
# Fields:
|
||||
`.data`: The total data transfer.\\
|
||||
`.computeEffort`: The total compute effort.\\
|
||||
`.computeIntensity`: The compute intensity, will always equal `.computeEffort / .data`.\\
|
||||
`.cost`: The estimated cost.\\
|
||||
`.noNodes`: Number of [`Node`](@ref)s.\\
|
||||
`.noEdges`: Number of [`Edge`](@ref)s.
|
||||
"""
|
||||
const GraphProperties = NamedTuple{
|
||||
(:data, :computeEffort, :computeIntensity, :cost, :noNodes, :noEdges),
|
||||
Tuple{Float64, Float64, Float64, Float64, Int, Int},
|
||||
}
|
58
src/properties/utility.jl
Normal file
58
src/properties/utility.jl
Normal file
@ -0,0 +1,58 @@
|
||||
"""
|
||||
-(prop1::GraphProperties, prop2::GraphProperties)
|
||||
|
||||
Subtract `prop1` from `prop2` and return the result as a new [`GraphProperties`](@ref).
|
||||
Also take care to keep consistent compute intensity.
|
||||
"""
|
||||
function -(prop1::GraphProperties, prop2::GraphProperties)
|
||||
return (
|
||||
data = prop1.data - prop2.data,
|
||||
computeEffort = prop1.computeEffort - prop2.computeEffort,
|
||||
computeIntensity = if (prop1.data - prop2.data == 0)
|
||||
0.0
|
||||
else
|
||||
(prop1.computeEffort - prop2.computeEffort) /
|
||||
(prop1.data - prop2.data)
|
||||
end,
|
||||
cost = prop1.cost - prop2.cost,
|
||||
noNodes = prop1.noNodes - prop2.noNodes,
|
||||
noEdges = prop1.noEdges - prop2.noEdges,
|
||||
)::GraphProperties
|
||||
end
|
||||
|
||||
"""
|
||||
+(prop1::GraphProperties, prop2::GraphProperties)
|
||||
|
||||
Add `prop1` and `prop2` and return the result as a new [`GraphProperties`](@ref).
|
||||
Also take care to keep consistent compute intensity.
|
||||
"""
|
||||
function +(prop1::GraphProperties, prop2::GraphProperties)
|
||||
return (
|
||||
data = prop1.data + prop2.data,
|
||||
computeEffort = prop1.computeEffort + prop2.computeEffort,
|
||||
computeIntensity = if (prop1.data + prop2.data == 0)
|
||||
0.0
|
||||
else
|
||||
(prop1.computeEffort + prop2.computeEffort) /
|
||||
(prop1.data + prop2.data)
|
||||
end,
|
||||
cost = prop1.cost + prop2.cost,
|
||||
noNodes = prop1.noNodes + prop2.noNodes,
|
||||
noEdges = prop1.noEdges + prop2.noEdges,
|
||||
)::GraphProperties
|
||||
end
|
||||
|
||||
"""
|
||||
-(prop::GraphProperties)
|
||||
|
||||
Unary negation of the graph properties. `.computeIntensity` will not be negated because `.data` and `.computeEffort` both are.
|
||||
"""
|
||||
function -(prop::GraphProperties)
|
||||
return (
|
||||
data = -prop.data,
|
||||
computeEffort = -prop.computeEffort,
|
||||
computeIntensity = prop.computeIntensity, # no negation here!
|
||||
noNodes = -prop.noNodes,
|
||||
noEdges = -prop.noEdges,
|
||||
)::GraphProperties
|
||||
end
|
Reference in New Issue
Block a user