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__/
|
||||
.nox/
|
||||
*.d
|
||||
/SolverComponent
|
||||
|
@ -161,8 +161,11 @@ void AMPLSolver::SolveProblem(
|
||||
// objective functions as 'dropped'. Note that this is experimental code
|
||||
// as the multi-objective possibilities in AMPL are not well documented.
|
||||
|
||||
std::string
|
||||
OptimisationGoal = TheContext.at( Solver::ObjectiveFunctionLabel );
|
||||
|
||||
for( auto TheObjective : ProblemDefinition.getObjectives() )
|
||||
if( TheObjective.name() == TheContext.at( Solver::ObjectiveFunctionLabel ) )
|
||||
if( TheObjective.name() == OptimisationGoal )
|
||||
TheObjective.restore();
|
||||
else
|
||||
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
|
||||
// generic metric prediction root string, and this string must be removed
|
||||
// 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(
|
||||
const MetricValueUpdate & TheMetricValue, const Address TheMetricTopic)
|
||||
@ -96,8 +102,8 @@ void MetricUpdater::UpdateMetricValue(
|
||||
|
||||
if( MetricValues.contains( TheTopic ) )
|
||||
{
|
||||
MetricValues[ TheTopic ].Value = TheMetricValue[ NebulOuS::ValueLabel ];
|
||||
|
||||
MetricValues.at( TheTopic ).Value = TheMetricValue[ NebulOuS::ValueLabel ];
|
||||
|
||||
ValidityTime = std::max( ValidityTime,
|
||||
TheMetricValue[ NebulOuS::TimePoint ].get< Solver::TimePointType >() );
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ private:
|
||||
const std::string OptimisationName;
|
||||
JSON Value;
|
||||
|
||||
MetricValueRecord( const std::string & TheName, JSON InitialValue )
|
||||
MetricValueRecord( const std::string & TheName, const JSON InitialValue )
|
||||
: OptimisationName( TheName ), Value( InitialValue )
|
||||
{}
|
||||
|
||||
|
@ -46,16 +46,10 @@ License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
|
||||
// Standard headers
|
||||
|
||||
#include <string> // For standard strings
|
||||
// #include <memory> // For smart pointers
|
||||
#include <source_location> // Making informative error messages
|
||||
#include <sstream> // To format error messages
|
||||
#include <stdexcept> // standard exceptions
|
||||
#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
|
||||
|
||||
@ -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 )
|
||||
{
|
||||
@ -201,12 +194,19 @@ int main( int NumberOfCLIOptions, char ** CLIOptionStrings )
|
||||
// a parameter to the constructor of the Metric Updater so the latter actor
|
||||
// knows where to send application execution contexts whenever a new solution
|
||||
// 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 >
|
||||
WorkloadMabager( "WorkloadManager",
|
||||
std::string( NebulOuS::Solver::Solution::MessageIdentifier ),
|
||||
std::string( NebulOuS::Solver::ApplicationExecutionContext::MessageIdentifier ),
|
||||
"AMPLSolver", ampl::Environment( TheAMPLDirectory.native() ), ModelDirectory );
|
||||
1, "AMPLSolver",
|
||||
ampl::Environment( TheAMPLDirectory.native() ), ModelDirectory );
|
||||
|
||||
NebulOuS::MetricUpdater
|
||||
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 <ranges> // Range based views
|
||||
#include <algorithm> // Standard algorithms
|
||||
#include <iterator> // For inserters
|
||||
#include <sstream> // For nice error messages
|
||||
#include <stdexcept> // Standard exceptions
|
||||
#include <source_location> // Error location reporting
|
||||
#include <condition_variable> // Execution stop management
|
||||
#include <mutex> // Lock the condtion variable
|
||||
#include <tuple> // For constructing solvers
|
||||
|
||||
// Other packages
|
||||
|
||||
@ -143,7 +145,7 @@ private:
|
||||
if( !PassiveSolvers.empty() && !ContextExecutionQueue.empty() )
|
||||
{
|
||||
for( const auto & [ SolverAddress, ContextElement ] :
|
||||
ranges::views::zip( PassiveSolvers, ContextExecutionQueue ) )
|
||||
std::ranges::views::zip( PassiveSolvers, ContextExecutionQueue ) )
|
||||
Send( Contexts.at( ContextElement.second ), SolverAddress );
|
||||
|
||||
// The number of contexts dispatched must equal the minimum of the
|
||||
@ -156,13 +158,15 @@ private:
|
||||
|
||||
std::ranges::move(
|
||||
std::ranges::subrange( PassiveSolvers.begin(),
|
||||
PassiveSolvers.begin() + DispatchedContexts ),
|
||||
std::inserter( ActiveSolvers ) );
|
||||
std::ranges::next( PassiveSolvers.begin(), DispatchedContexts,
|
||||
PassiveSolvers.end() ) ),
|
||||
std::inserter( ActiveSolvers, ActiveSolvers.end() ) );
|
||||
|
||||
// Then the dispatched context identifiers are removed from queue
|
||||
|
||||
ContextExecutionQueue.erase( ContextExecutionQueue.begin(),
|
||||
ContextExecutionQueue.begin() + DispatchedContexts );
|
||||
std::ranges::next( ContextExecutionQueue.begin(), DispatchedContexts,
|
||||
ContextExecutionQueue.end() ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,7 +220,7 @@ private:
|
||||
// contexts, if any.
|
||||
|
||||
void PublishSolution( const Solver::Solution & TheSolution,
|
||||
const Addres TheSolver )
|
||||
const Address TheSolver )
|
||||
{
|
||||
Send( TheSolution, SolutionReceiver );
|
||||
PassiveSolvers.insert( ActiveSolvers.extract( TheSolver ) );
|
||||
@ -243,10 +247,13 @@ private:
|
||||
|
||||
public:
|
||||
|
||||
template< typename ...SolverArgTypes >
|
||||
SolverManager( const std::string & TheActorName,
|
||||
const Theron::AMQ::TopicName & SolutionTopic,
|
||||
const Theron::AMQ::TopicName & ContextPublisherTopic,
|
||||
const auto & ...SolverArguments )
|
||||
const Theron::AMQ::TopicName & SolutionTopic,
|
||||
const Theron::AMQ::TopicName & ContextPublisherTopic,
|
||||
const unsigned int NumberOfSolvers,
|
||||
const std::string SolverRootName,
|
||||
SolverArgTypes && ...SolverArguments )
|
||||
: Actor( TheActorName ),
|
||||
StandardFallbackHandler( Actor::GetAddress().AsString() ),
|
||||
NetworkingActor( Actor::GetAddress().AsString() ),
|
||||
@ -256,10 +263,22 @@ public:
|
||||
Contexts(), ContextExecutionQueue()
|
||||
{
|
||||
// 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
|
||||
// passive servers, and a publisher is made for the solution channel, and
|
||||
// optionally, a subscritpion is made for the alternative context publisher
|
||||
@ -268,8 +287,9 @@ public:
|
||||
|
||||
if( !SolverPool.empty() )
|
||||
{
|
||||
std::ranges::transform( ServerPool, std::inserter( PassiveSolvers ),
|
||||
[](const SolverType & TheSolver){ return TheSolver.GetAddress(); } );
|
||||
std::ranges::transform( SolverPool,
|
||||
std::inserter( PassiveSolvers, PassiveSolvers.end() ),
|
||||
[](const SolverType & TheSolver){ return TheSolver.GetAddress(); } );
|
||||
|
||||
Send( Theron::AMQ::NetworkLayer::TopicSubscription(
|
||||
Theron::AMQ::NetworkLayer::TopicSubscription::Action::Publisher,
|
||||
|
43
makefile
43
makefile
@ -22,6 +22,17 @@ RM = rm -f
|
||||
|
||||
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
|
||||
# with production code. -Og is the code optimising and offering debugging
|
||||
# transparency and should be use while the code is under development
|
||||
@ -40,7 +51,8 @@ DEPENDENCY_FLAGS = -MMD -MP
|
||||
# Options
|
||||
|
||||
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) \
|
||||
$(OPTIMISATION_FLAG)
|
||||
@ -55,7 +67,7 @@ CXXFLAGS = $(GENERAL_OPTIONS) $(INCLUDE_DIRECTORIES) $(DEPENDENCY_FLAGS) \
|
||||
|
||||
CFLAGS = $(DEPENDENCY_FLAGS) $(OPTIMISATION_FLAG) $(GENERAL_OPTIONS)
|
||||
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
|
||||
@ -82,29 +94,34 @@ OBJECTS_DIR = Bin
|
||||
# Listing the actors' source files and expected object files
|
||||
|
||||
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
|
||||
# component's objective file, they can be built by a general rule
|
||||
|
||||
$(OBJECTS_DIR)/%.o : %.cpp
|
||||
$(CXX) $(CXXFLAGS) $< -o $@ $(INCLUDE_DIRECTORIES)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@ $(INCLUDE_DIRECTORIES)
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# 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 object files or the solver actors.
|
||||
|
||||
SolverComponent: SolverComponent.cpp $(SOLVER_OBJECTS) $(THERON)/Theron++.a
|
||||
$(CXX) SolverComponent.cpp -o SolverComponent $(CXXFLAGS) \
|
||||
-I$(CxxOpts_DIR) $(LDFLAGS)
|
||||
SolverComponent: $(SOLVER_OBJECTS) $(THERON)/Theron++.a
|
||||
$(CXX) -o SolverComponent $(CXXFLAGS) $(SOLVER_OBJECTS) $(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