First release of the solver component
Change-Id: Ie016703ce389b97a849ba7c0a56abad89885b5b2
This commit is contained in:
parent
c83d0dedd5
commit
e730917516
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
__pycache__/
|
__pycache__/
|
||||||
.nox/
|
.nox/
|
||||||
|
*.d
|
||||||
|
/SolverComponent
|
||||||
|
@ -161,8 +161,11 @@ void AMPLSolver::SolveProblem(
|
|||||||
// objective functions as 'dropped'. Note that this is experimental code
|
// objective functions as 'dropped'. Note that this is experimental code
|
||||||
// as the multi-objective possibilities in AMPL are not well documented.
|
// as the multi-objective possibilities in AMPL are not well documented.
|
||||||
|
|
||||||
|
std::string
|
||||||
|
OptimisationGoal = TheContext.at( Solver::ObjectiveFunctionLabel );
|
||||||
|
|
||||||
for( auto TheObjective : ProblemDefinition.getObjectives() )
|
for( auto TheObjective : ProblemDefinition.getObjectives() )
|
||||||
if( TheObjective.name() == TheContext.at( Solver::ObjectiveFunctionLabel ) )
|
if( TheObjective.name() == OptimisationGoal )
|
||||||
TheObjective.restore();
|
TheObjective.restore();
|
||||||
else
|
else
|
||||||
TheObjective.drop();
|
TheObjective.drop();
|
||||||
|
2
Bin/.gitignore
vendored
Normal file
2
Bin/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.d
|
||||||
|
*.o
|
@ -87,6 +87,12 @@ void MetricUpdater::AddMetricSubscription( const MetricTopic & TheMetrics,
|
|||||||
// The sender address will contain the metric topic, but this will contain the
|
// The sender address will contain the metric topic, but this will contain the
|
||||||
// generic metric prediction root string, and this string must be removed
|
// generic metric prediction root string, and this string must be removed
|
||||||
// before the metric name can be updated.
|
// before the metric name can be updated.
|
||||||
|
//
|
||||||
|
// Note that the map's [] operator cannot be used to look up the topic in the
|
||||||
|
// current map because it assumes the implicit creation of non-existing keys,
|
||||||
|
// which means that an empty metric value record should be constructed first
|
||||||
|
// and then used. To modify the existing record, the 'at' function must be
|
||||||
|
// used.
|
||||||
|
|
||||||
void MetricUpdater::UpdateMetricValue(
|
void MetricUpdater::UpdateMetricValue(
|
||||||
const MetricValueUpdate & TheMetricValue, const Address TheMetricTopic)
|
const MetricValueUpdate & TheMetricValue, const Address TheMetricTopic)
|
||||||
@ -96,8 +102,8 @@ void MetricUpdater::UpdateMetricValue(
|
|||||||
|
|
||||||
if( MetricValues.contains( TheTopic ) )
|
if( MetricValues.contains( TheTopic ) )
|
||||||
{
|
{
|
||||||
MetricValues[ TheTopic ].Value = TheMetricValue[ NebulOuS::ValueLabel ];
|
MetricValues.at( TheTopic ).Value = TheMetricValue[ NebulOuS::ValueLabel ];
|
||||||
|
|
||||||
ValidityTime = std::max( ValidityTime,
|
ValidityTime = std::max( ValidityTime,
|
||||||
TheMetricValue[ NebulOuS::TimePoint ].get< Solver::TimePointType >() );
|
TheMetricValue[ NebulOuS::TimePoint ].get< Solver::TimePointType >() );
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ private:
|
|||||||
const std::string OptimisationName;
|
const std::string OptimisationName;
|
||||||
JSON Value;
|
JSON Value;
|
||||||
|
|
||||||
MetricValueRecord( const std::string & TheName, JSON InitialValue )
|
MetricValueRecord( const std::string & TheName, const JSON InitialValue )
|
||||||
: OptimisationName( TheName ), Value( InitialValue )
|
: OptimisationName( TheName ), Value( InitialValue )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -46,16 +46,10 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
|
|||||||
// Standard headers
|
// Standard headers
|
||||||
|
|
||||||
#include <string> // For standard strings
|
#include <string> // For standard strings
|
||||||
// #include <memory> // For smart pointers
|
|
||||||
#include <source_location> // Making informative error messages
|
#include <source_location> // Making informative error messages
|
||||||
#include <sstream> // To format error messages
|
#include <sstream> // To format error messages
|
||||||
#include <stdexcept> // standard exceptions
|
#include <stdexcept> // standard exceptions
|
||||||
#include <filesystem> // Access to the file system
|
#include <filesystem> // Access to the file system
|
||||||
// #include <initializer_list> // To unpack variable arguments
|
|
||||||
// #include <concepts> // To constrain types
|
|
||||||
// #include <vector> // To store subscribed topics
|
|
||||||
// #include <thread> // To sleep while waiting for termination
|
|
||||||
// #include <chrono> // To have a concept of fime
|
|
||||||
|
|
||||||
// Theron++ headers
|
// Theron++ headers
|
||||||
|
|
||||||
@ -89,10 +83,9 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
|
|||||||
|
|
||||||
/*==============================================================================
|
/*==============================================================================
|
||||||
|
|
||||||
Main file
|
Main
|
||||||
|
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
//
|
|
||||||
|
|
||||||
int main( int NumberOfCLIOptions, char ** CLIOptionStrings )
|
int main( int NumberOfCLIOptions, char ** CLIOptionStrings )
|
||||||
{
|
{
|
||||||
@ -201,12 +194,19 @@ int main( int NumberOfCLIOptions, char ** CLIOptionStrings )
|
|||||||
// a parameter to the constructor of the Metric Updater so the latter actor
|
// a parameter to the constructor of the Metric Updater so the latter actor
|
||||||
// knows where to send application execution contexts whenever a new solution
|
// knows where to send application execution contexts whenever a new solution
|
||||||
// is requested by the SLO Violation Detector through the Optimzer Controller.
|
// is requested by the SLO Violation Detector through the Optimzer Controller.
|
||||||
|
// Then follows the number of solvers to use in the solver pool and the root
|
||||||
|
// name of the solvers. This root name string will be extended with _n where n
|
||||||
|
// where n is a sequence number from 1.As all solvers are of the same type
|
||||||
|
// given by the template parameter (here AMPLSolver), they are assumed to need
|
||||||
|
// the same set of constructor arguments and the constructor arguments follow
|
||||||
|
// the root solver name.
|
||||||
|
|
||||||
NebulOuS::SolverManager< NebulOuS::AMPLSolver >
|
NebulOuS::SolverManager< NebulOuS::AMPLSolver >
|
||||||
WorkloadMabager( "WorkloadManager",
|
WorkloadMabager( "WorkloadManager",
|
||||||
std::string( NebulOuS::Solver::Solution::MessageIdentifier ),
|
std::string( NebulOuS::Solver::Solution::MessageIdentifier ),
|
||||||
std::string( NebulOuS::Solver::ApplicationExecutionContext::MessageIdentifier ),
|
std::string( NebulOuS::Solver::ApplicationExecutionContext::MessageIdentifier ),
|
||||||
"AMPLSolver", ampl::Environment( TheAMPLDirectory.native() ), ModelDirectory );
|
1, "AMPLSolver",
|
||||||
|
ampl::Environment( TheAMPLDirectory.native() ), ModelDirectory );
|
||||||
|
|
||||||
NebulOuS::MetricUpdater
|
NebulOuS::MetricUpdater
|
||||||
ContextMabager( "MetricUpdater", WorkloadMabager.GetAddress() );
|
ContextMabager( "MetricUpdater", WorkloadMabager.GetAddress() );
|
||||||
|
@ -49,11 +49,13 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
|
|||||||
#include <list> // Pool of local solvers
|
#include <list> // Pool of local solvers
|
||||||
#include <ranges> // Range based views
|
#include <ranges> // Range based views
|
||||||
#include <algorithm> // Standard algorithms
|
#include <algorithm> // Standard algorithms
|
||||||
|
#include <iterator> // For inserters
|
||||||
#include <sstream> // For nice error messages
|
#include <sstream> // For nice error messages
|
||||||
#include <stdexcept> // Standard exceptions
|
#include <stdexcept> // Standard exceptions
|
||||||
#include <source_location> // Error location reporting
|
#include <source_location> // Error location reporting
|
||||||
#include <condition_variable> // Execution stop management
|
#include <condition_variable> // Execution stop management
|
||||||
#include <mutex> // Lock the condtion variable
|
#include <mutex> // Lock the condtion variable
|
||||||
|
#include <tuple> // For constructing solvers
|
||||||
|
|
||||||
// Other packages
|
// Other packages
|
||||||
|
|
||||||
@ -143,7 +145,7 @@ private:
|
|||||||
if( !PassiveSolvers.empty() && !ContextExecutionQueue.empty() )
|
if( !PassiveSolvers.empty() && !ContextExecutionQueue.empty() )
|
||||||
{
|
{
|
||||||
for( const auto & [ SolverAddress, ContextElement ] :
|
for( const auto & [ SolverAddress, ContextElement ] :
|
||||||
ranges::views::zip( PassiveSolvers, ContextExecutionQueue ) )
|
std::ranges::views::zip( PassiveSolvers, ContextExecutionQueue ) )
|
||||||
Send( Contexts.at( ContextElement.second ), SolverAddress );
|
Send( Contexts.at( ContextElement.second ), SolverAddress );
|
||||||
|
|
||||||
// The number of contexts dispatched must equal the minimum of the
|
// The number of contexts dispatched must equal the minimum of the
|
||||||
@ -156,13 +158,15 @@ private:
|
|||||||
|
|
||||||
std::ranges::move(
|
std::ranges::move(
|
||||||
std::ranges::subrange( PassiveSolvers.begin(),
|
std::ranges::subrange( PassiveSolvers.begin(),
|
||||||
PassiveSolvers.begin() + DispatchedContexts ),
|
std::ranges::next( PassiveSolvers.begin(), DispatchedContexts,
|
||||||
std::inserter( ActiveSolvers ) );
|
PassiveSolvers.end() ) ),
|
||||||
|
std::inserter( ActiveSolvers, ActiveSolvers.end() ) );
|
||||||
|
|
||||||
// Then the dispatched context identifiers are removed from queue
|
// Then the dispatched context identifiers are removed from queue
|
||||||
|
|
||||||
ContextExecutionQueue.erase( ContextExecutionQueue.begin(),
|
ContextExecutionQueue.erase( ContextExecutionQueue.begin(),
|
||||||
ContextExecutionQueue.begin() + DispatchedContexts );
|
std::ranges::next( ContextExecutionQueue.begin(), DispatchedContexts,
|
||||||
|
ContextExecutionQueue.end() ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +220,7 @@ private:
|
|||||||
// contexts, if any.
|
// contexts, if any.
|
||||||
|
|
||||||
void PublishSolution( const Solver::Solution & TheSolution,
|
void PublishSolution( const Solver::Solution & TheSolution,
|
||||||
const Addres TheSolver )
|
const Address TheSolver )
|
||||||
{
|
{
|
||||||
Send( TheSolution, SolutionReceiver );
|
Send( TheSolution, SolutionReceiver );
|
||||||
PassiveSolvers.insert( ActiveSolvers.extract( TheSolver ) );
|
PassiveSolvers.insert( ActiveSolvers.extract( TheSolver ) );
|
||||||
@ -243,10 +247,13 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
template< typename ...SolverArgTypes >
|
||||||
SolverManager( const std::string & TheActorName,
|
SolverManager( const std::string & TheActorName,
|
||||||
const Theron::AMQ::TopicName & SolutionTopic,
|
const Theron::AMQ::TopicName & SolutionTopic,
|
||||||
const Theron::AMQ::TopicName & ContextPublisherTopic,
|
const Theron::AMQ::TopicName & ContextPublisherTopic,
|
||||||
const auto & ...SolverArguments )
|
const unsigned int NumberOfSolvers,
|
||||||
|
const std::string SolverRootName,
|
||||||
|
SolverArgTypes && ...SolverArguments )
|
||||||
: Actor( TheActorName ),
|
: Actor( TheActorName ),
|
||||||
StandardFallbackHandler( Actor::GetAddress().AsString() ),
|
StandardFallbackHandler( Actor::GetAddress().AsString() ),
|
||||||
NetworkingActor( Actor::GetAddress().AsString() ),
|
NetworkingActor( Actor::GetAddress().AsString() ),
|
||||||
@ -256,10 +263,22 @@ public:
|
|||||||
Contexts(), ContextExecutionQueue()
|
Contexts(), ContextExecutionQueue()
|
||||||
{
|
{
|
||||||
// The solvers are created by expanding the arguments for the solvers
|
// The solvers are created by expanding the arguments for the solvers
|
||||||
// one by one creating new elements in the solver pool
|
// one by one creating new elements in the solver pool. The solvers
|
||||||
|
// will be named with a sequence number from 1 and up added to the
|
||||||
|
// root solver name, e.g., if the root name is "MySolver" the solvers
|
||||||
|
// will have names "MySolver_1", "MySolver_2",... and so forth. Since
|
||||||
|
// all solvers are of the same type they should take the same arguments
|
||||||
|
// and so the given arguments are just fowarded to each solver constructor.
|
||||||
|
|
||||||
( SolverPool.emplace_back( std::forward( SolverArguments ) ), ... );
|
for( unsigned int i = 1; i <= NumberOfSolvers; i++ )
|
||||||
|
{
|
||||||
|
std::ostringstream TheSolverName;
|
||||||
|
|
||||||
|
TheSolverName << SolverRootName << "_" << i;
|
||||||
|
SolverPool.emplace_back( TheSolverName.str(),
|
||||||
|
std::forward< SolverArgTypes >(SolverArguments)... );
|
||||||
|
}
|
||||||
|
|
||||||
// If the solvers were successfully created, their addresses are recorded as
|
// If the solvers were successfully created, their addresses are recorded as
|
||||||
// passive servers, and a publisher is made for the solution channel, and
|
// passive servers, and a publisher is made for the solution channel, and
|
||||||
// optionally, a subscritpion is made for the alternative context publisher
|
// optionally, a subscritpion is made for the alternative context publisher
|
||||||
@ -268,8 +287,9 @@ public:
|
|||||||
|
|
||||||
if( !SolverPool.empty() )
|
if( !SolverPool.empty() )
|
||||||
{
|
{
|
||||||
std::ranges::transform( ServerPool, std::inserter( PassiveSolvers ),
|
std::ranges::transform( SolverPool,
|
||||||
[](const SolverType & TheSolver){ return TheSolver.GetAddress(); } );
|
std::inserter( PassiveSolvers, PassiveSolvers.end() ),
|
||||||
|
[](const SolverType & TheSolver){ return TheSolver.GetAddress(); } );
|
||||||
|
|
||||||
Send( Theron::AMQ::NetworkLayer::TopicSubscription(
|
Send( Theron::AMQ::NetworkLayer::TopicSubscription(
|
||||||
Theron::AMQ::NetworkLayer::TopicSubscription::Action::Publisher,
|
Theron::AMQ::NetworkLayer::TopicSubscription::Action::Publisher,
|
||||||
|
43
makefile
43
makefile
@ -22,6 +22,17 @@ RM = rm -f
|
|||||||
|
|
||||||
THERON = /home/GHo/Documents/Code/Theron++
|
THERON = /home/GHo/Documents/Code/Theron++
|
||||||
|
|
||||||
|
# Location of the AMPL API directory
|
||||||
|
|
||||||
|
AMPL_INCLUDE = /opt/AMPL/amplapi/include
|
||||||
|
|
||||||
|
# The solver component uses the CxxOpts class for parsing the command line
|
||||||
|
# options since it is header only and lighter than the Options library of
|
||||||
|
# boost, which seems to have lost the most recent C++ features. The CxxOpts
|
||||||
|
# library can be cloned from https://github.com/jarro2783/cxxopts
|
||||||
|
|
||||||
|
CxxOpts_DIR = /home/GHo/Documents/Code/CxxOpts/include
|
||||||
|
|
||||||
# Optimisation -O3 is the highest level of optimisation and should be used
|
# Optimisation -O3 is the highest level of optimisation and should be used
|
||||||
# with production code. -Og is the code optimising and offering debugging
|
# with production code. -Og is the code optimising and offering debugging
|
||||||
# transparency and should be use while the code is under development
|
# transparency and should be use while the code is under development
|
||||||
@ -40,7 +51,8 @@ DEPENDENCY_FLAGS = -MMD -MP
|
|||||||
# Options
|
# Options
|
||||||
|
|
||||||
GENERAL_OPTIONS = -Wall -std=c++23 -ggdb -D_DEBUG
|
GENERAL_OPTIONS = -Wall -std=c++23 -ggdb -D_DEBUG
|
||||||
INCLUDE_DIRECTORIES = -I. -I/usr/include -I$(THERON)
|
INCLUDE_DIRECTORIES = -I. -I/usr/include -I$(THERON) -I$(AMPL_INCLUDE) \
|
||||||
|
-I$(CxxOpts_DIR)
|
||||||
|
|
||||||
CXXFLAGS = $(GENERAL_OPTIONS) $(INCLUDE_DIRECTORIES) $(DEPENDENCY_FLAGS) \
|
CXXFLAGS = $(GENERAL_OPTIONS) $(INCLUDE_DIRECTORIES) $(DEPENDENCY_FLAGS) \
|
||||||
$(OPTIMISATION_FLAG)
|
$(OPTIMISATION_FLAG)
|
||||||
@ -55,7 +67,7 @@ CXXFLAGS = $(GENERAL_OPTIONS) $(INCLUDE_DIRECTORIES) $(DEPENDENCY_FLAGS) \
|
|||||||
|
|
||||||
CFLAGS = $(DEPENDENCY_FLAGS) $(OPTIMISATION_FLAG) $(GENERAL_OPTIONS)
|
CFLAGS = $(DEPENDENCY_FLAGS) $(OPTIMISATION_FLAG) $(GENERAL_OPTIONS)
|
||||||
LDFLAGS = -fuse-ld=gold -ggdb -D_DEBUG -pthread -l$(THERON)/Theron++.a \
|
LDFLAGS = -fuse-ld=gold -ggdb -D_DEBUG -pthread -l$(THERON)/Theron++.a \
|
||||||
-lqpid-proton-cpp
|
-lqpid-proton-cpp -l/opt/AMPL/amplapi/lib/libampl.so
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Theron library
|
# Theron library
|
||||||
@ -82,29 +94,34 @@ OBJECTS_DIR = Bin
|
|||||||
# Listing the actors' source files and expected object files
|
# Listing the actors' source files and expected object files
|
||||||
|
|
||||||
SOLVER_SOURCE = $(wildcard *.cpp)
|
SOLVER_SOURCE = $(wildcard *.cpp)
|
||||||
SOLVER_OBJECTS = $(addprefix $(OBJECTS_DIR)/, $(SOLVER_SOURCE:.cpp=.o)
|
SOLVER_OBJECTS = $(addprefix $(OBJECTS_DIR)/, $(SOLVER_SOURCE:.cpp=.o) )
|
||||||
|
|
||||||
# Since all source files are in the same directory as the make file and the
|
# Since all source files are in the same directory as the make file and the
|
||||||
# component's objective file, they can be built by a general rule
|
# component's objective file, they can be built by a general rule
|
||||||
|
|
||||||
$(OBJECTS_DIR)/%.o : %.cpp
|
$(OBJECTS_DIR)/%.o : %.cpp
|
||||||
$(CXX) $(CXXFLAGS) $< -o $@ $(INCLUDE_DIRECTORIES)
|
$(CXX) $(CXXFLAGS) -c $< -o $@ $(INCLUDE_DIRECTORIES)
|
||||||
|
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
# Solver component
|
# Solver component
|
||||||
#------------------------------------------------------------------------------
|
#------------------------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# The solver component uses the CxxOpts class for parsing the command line
|
|
||||||
# options since it is header only and lighter than the Options library of
|
|
||||||
# boost, which seems to have lost the most recent C++ features. The CxxOpts
|
|
||||||
# library can be cloned from https://github.com/jarro2783/cxxopts
|
|
||||||
|
|
||||||
CxxOpts_DIR = /home/GHo/Documents/Code/CxxOpts/include
|
|
||||||
|
|
||||||
# The only real target is to build the solver component whenever some of
|
# The only real target is to build the solver component whenever some of
|
||||||
# the object files or the solver actors.
|
# the object files or the solver actors.
|
||||||
|
|
||||||
SolverComponent: SolverComponent.cpp $(SOLVER_OBJECTS) $(THERON)/Theron++.a
|
SolverComponent: $(SOLVER_OBJECTS) $(THERON)/Theron++.a
|
||||||
$(CXX) SolverComponent.cpp -o SolverComponent $(CXXFLAGS) \
|
$(CXX) -o SolverComponent $(CXXFLAGS) $(SOLVER_OBJECTS) $(LDFLAGS)
|
||||||
-I$(CxxOpts_DIR) $(LDFLAGS)
|
|
||||||
|
|
||||||
|
# There is also a standard target to clean the automatically generated build
|
||||||
|
# files
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) $(OBJECTS_DIR)/*.o $(OBJECTS_DIR)/*.d
|
||||||
|
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
# Dependencies
|
||||||
|
#------------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
|
||||||
|
-include $(SOLVER_OBJECTS:.o=.d)
|
Loading…
Reference in New Issue
Block a user