-
Notifications
You must be signed in to change notification settings - Fork 29
Reduce memory usage of sample-level result accumulators #109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,8 @@ abstract type ResultSpec end | |
|
|
||
| abstract type ResultAccumulator{R<:ResultSpec} end | ||
|
|
||
| issamplebased(::ResultSpec) = false | ||
|
|
||
| abstract type Result{ | ||
| N, # Number of timesteps simulated | ||
| L, # Length of each simulation timestep | ||
|
|
@@ -182,6 +184,20 @@ include("StorageEnergySamples.jl") | |
| include("GeneratorStorageEnergySamples.jl") | ||
| include("DemandResponseEnergySamples.jl") | ||
|
|
||
| issamplebased(::ShortfallSamples) = true | ||
| issamplebased(::DemandResponseShortfallSamples) = true | ||
| issamplebased(::SurplusSamples) = true | ||
| issamplebased(::FlowSamples) = true | ||
| issamplebased(::UtilizationSamples) = true | ||
| issamplebased(::StorageEnergySamples) = true | ||
| issamplebased(::GeneratorStorageEnergySamples) = true | ||
| issamplebased(::DemandResponseEnergySamples) = true | ||
| issamplebased(::GeneratorAvailability) = true | ||
| issamplebased(::StorageAvailability) = true | ||
| issamplebased(::GeneratorStorageAvailability) = true | ||
| issamplebased(::DemandResponseAvailability) = true | ||
| issamplebased(::LineAvailability) = true | ||
|
|
||
| function resultchannel( | ||
| results::T, threads::Int | ||
| ) where T <: Tuple{Vararg{ResultSpec}} | ||
|
|
@@ -194,18 +210,57 @@ end | |
| merge!(xs::T, ys::T) where T <: Tuple{Vararg{ResultAccumulator}} = | ||
| foreach(merge!, xs, ys) | ||
|
|
||
| function copy_sample_partition!( | ||
| x::A, | ||
| y::A, | ||
| sampleids::UnitRange{Int}, | ||
| ) where {A<:ResultAccumulator} | ||
|
|
||
| field = fieldnames(A)[1] | ||
| xarr = getfield(x, field) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this leads to some performance issues. Have you tested this on very high sample results? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If only grabbing the 1st filed is correct (I don't thnk it is), repalcing with this could work: `function copy_sample_partition!( end` This explicitly tells the complier the field and the type of the field you want to grab. |
||
| yarr = getfield(y, field) | ||
|
|
||
| @views xarr[:, :, sampleids] .= yarr | ||
| return | ||
| end | ||
|
|
||
| function finalize( | ||
| results::Channel{<:Tuple{Vararg{ResultAccumulator}}}, | ||
| results::Channel, | ||
| system::SystemModel{N,L,T,P,E}, | ||
| threads::Int | ||
| threads::Int, | ||
| nsamples::Int, | ||
| resultspecs::Tuple{Vararg{ResultSpec}}, | ||
| ) where {N,L,T,P,E} | ||
|
|
||
| total_result = take!(results) | ||
| first_recorders, first_sampleids = take!(results) | ||
|
|
||
| if threads == 1 && first_sampleids == 1:nsamples | ||
| close(results) | ||
| return finalize.(first_recorders, system) | ||
| end | ||
|
|
||
| total_result = map(resultspecs, first_recorders) do spec, recorder | ||
| issamplebased(spec) ? accumulator(system, nsamples, spec) : recorder | ||
| end | ||
|
|
||
| for i in eachindex(total_result) | ||
| if issamplebased(resultspecs[i]) | ||
| copy_sample_partition!(total_result[i], first_recorders[i], first_sampleids) | ||
| end | ||
| end | ||
|
|
||
| for _ in 2:threads | ||
| thread_result = take!(results) | ||
| merge!(total_result, thread_result) | ||
| thread_recorders, sampleids = take!(results) | ||
|
|
||
| for i in eachindex(total_result) | ||
| if issamplebased(resultspecs[i]) | ||
| copy_sample_partition!(total_result[i], thread_recorders[i], sampleids) | ||
| else | ||
| merge!(total_result[i], thread_recorders[i]) | ||
| end | ||
| end | ||
| end | ||
|
|
||
| close(results) | ||
|
|
||
| return finalize.(total_result, system) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it worth it to just do this the other way round, so you don't have to define this for all the non sample ResultSpec s?