First release
- Added build script and AMPL license file - Fixed merge errors for the makefile - Extended the makefile header - Added initial AMQ message topics - Tested remote build - Removed AMPL license file - Validated build script - Accepting the metric definition message from the EMS Change-Id: I2c7c661d1006ff5a29f2d4ea77859036072c821b
This commit is contained in:
parent
9ac035a6b9
commit
03f0b88138
@ -7,6 +7,9 @@
|
|||||||
# minimal installation of the latest Fedora version. The intent is to load
|
# minimal installation of the latest Fedora version. The intent is to load
|
||||||
# all dependencies in a constructive way.
|
# all dependencies in a constructive way.
|
||||||
#
|
#
|
||||||
|
# Note that this is intended to be executed in a build machine that already
|
||||||
|
# has the solver code installed in the directory where the script is running.
|
||||||
|
#
|
||||||
# Author and Copyright: Geir Horn, University of Oslo
|
# Author and Copyright: Geir Horn, University of Oslo
|
||||||
# Contact: Geir.Horn@mn.uio.no
|
# Contact: Geir.Horn@mn.uio.no
|
||||||
# License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
|
# License: MPL2.0 (https://www.mozilla.org/en-US/MPL/2.0/)
|
||||||
@ -16,7 +19,7 @@
|
|||||||
# as root on the machine - put 'sudo' in front if the build user is not root.
|
# as root on the machine - put 'sudo' in front if the build user is not root.
|
||||||
|
|
||||||
dnf --assumeyes install gcc-c++ make git boost boost-devel ccache \
|
dnf --assumeyes install gcc-c++ make git boost boost-devel ccache \
|
||||||
qpid-proton-cpp* jsoncpp-devel coin-or-Couenne wget
|
qpid-proton-cpp* json* coin-or-Couenne wget
|
||||||
|
|
||||||
# Cloning the open source dependencies
|
# Cloning the open source dependencies
|
||||||
|
|
||||||
@ -24,9 +27,9 @@ git clone https://github.com/jarro2783/cxxopts.git CxxOpts
|
|||||||
git clone https://github.com/GeirHo/TheronPlusPlus.git Theron++
|
git clone https://github.com/GeirHo/TheronPlusPlus.git Theron++
|
||||||
mkdir Theron++/Bin
|
mkdir Theron++/Bin
|
||||||
|
|
||||||
# Clone the solver component
|
# Clone the solver component (if it is not in this build directory already)
|
||||||
|
|
||||||
git clone https://opendev.org/nebulous/optimiser-solver.git Solver
|
#git clone https://opendev.org/nebulous/optimiser-solver.git Solver
|
||||||
|
|
||||||
# Installing the AMPL library
|
# Installing the AMPL library
|
||||||
|
|
||||||
@ -34,11 +37,19 @@ wget https://portal.ampl.com/external/?url=\
|
|||||||
https://portal.ampl.com/dl/amplce/ampl.linux64.tgz -O ampl.linux64.tgz
|
https://portal.ampl.com/dl/amplce/ampl.linux64.tgz -O ampl.linux64.tgz
|
||||||
tar --file=ampl.linux64.tgz --extract
|
tar --file=ampl.linux64.tgz --extract
|
||||||
mv ampl.linux-intel64 AMPL
|
mv ampl.linux-intel64 AMPL
|
||||||
rm ampl.linux64.tgz
|
|
||||||
#cp ampl.lic AMPL
|
#cp ampl.lic AMPL
|
||||||
|
|
||||||
# Building the solver component
|
# Buildirm ampl.linux64.tgzng the solver component
|
||||||
|
# Note: use this make command if the solver is installed in a
|
||||||
|
# subdirectory.
|
||||||
|
|
||||||
make -C Solver SolverComponent -e THERON=../Theron++ \
|
#make -C Solver SolverComponent -e THERON=../Theron++ \
|
||||||
AMPL_INCLUDE=../AMPL/amplapi/include AMPL_LIB=../AMPL/amplapi/lib \
|
#AMPL_INCLUDE=../AMPL/amplapi/include AMPL_LIB=../AMPL/amplapi/lib \
|
||||||
CxxOpts_DIR=../CxxOpts/include
|
#CxxOpts_DIR=../CxxOpts/include
|
||||||
|
|
||||||
|
# Use this script if the solver is already in the current directory
|
||||||
|
|
||||||
|
make SolverComponent -e THERON=./Theron++ \
|
||||||
|
AMPL_INCLUDE=./AMPL/amplapi/include AMPL_LIB=./AMPL/amplapi/lib \
|
||||||
|
CxxOpts_DIR=./CxxOpts/include
|
||||||
|
@ -41,17 +41,22 @@ namespace NebulOuS
|
|||||||
void MetricUpdater::AddMetricSubscription( const MetricTopic & TheMetrics,
|
void MetricUpdater::AddMetricSubscription( const MetricTopic & TheMetrics,
|
||||||
const Address OptimiserController )
|
const Address OptimiserController )
|
||||||
{
|
{
|
||||||
if( TheMetrics.is_object() )
|
if( TheMetrics.is_object() &&
|
||||||
for( const auto & [MetricName, TopicName] : TheMetrics.items() )
|
TheMetrics.at( NebulOuS::MetricList ).is_object() )
|
||||||
{
|
{
|
||||||
auto [ MetricRecord, NewMetric ] = MetricValues.try_emplace(
|
JSON MetricList = TheMetrics.at( NebulOuS::MetricList );
|
||||||
TopicName, MetricName, JSON() );
|
|
||||||
|
|
||||||
if( NewMetric )
|
for( const JSON MetricDefinition : MetricList.items() )
|
||||||
Send( Theron::AMQ::NetworkLayer::TopicSubscription(
|
{
|
||||||
Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
|
auto [ MetricRecord, NewMetric ] = MetricValues.try_emplace(
|
||||||
TopicName ),
|
MetricDefinition.at( NebulOuS::MetricName ), JSON() );
|
||||||
Theron::AMQ::Network::GetAddress( Theron::Network::Layer::Session) );
|
|
||||||
|
if( NewMetric )
|
||||||
|
Send( Theron::AMQ::NetworkLayer::TopicSubscription(
|
||||||
|
Theron::AMQ::NetworkLayer::TopicSubscription::Action::Subscription,
|
||||||
|
MetricRecord->first ),
|
||||||
|
Theron::AMQ::Network::GetAddress( Theron::Network::Layer::Session) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -62,7 +67,7 @@ void MetricUpdater::AddMetricSubscription( const MetricTopic & TheMetrics,
|
|||||||
<< "in function " << Location.function_name() <<"] "
|
<< "in function " << Location.function_name() <<"] "
|
||||||
<< "The message to define a new metric subscription is given as "
|
<< "The message to define a new metric subscription is given as "
|
||||||
<< std::endl << TheMetrics.dump(2) << std::endl
|
<< std::endl << TheMetrics.dump(2) << std::endl
|
||||||
<< "this is not a JSON object!";
|
<< "this is not as expected!";
|
||||||
|
|
||||||
throw std::invalid_argument( ErrorMessage.str() );
|
throw std::invalid_argument( ErrorMessage.str() );
|
||||||
}
|
}
|
||||||
@ -98,11 +103,12 @@ void MetricUpdater::UpdateMetricValue(
|
|||||||
const MetricValueUpdate & TheMetricValue, const Address TheMetricTopic)
|
const MetricValueUpdate & TheMetricValue, const Address TheMetricTopic)
|
||||||
{
|
{
|
||||||
Theron::AMQ::TopicName TheTopic
|
Theron::AMQ::TopicName TheTopic
|
||||||
= TheMetricTopic.AsString().erase(0, MetricValueRootString.size() );
|
= TheMetricTopic.AsString().erase( 0,
|
||||||
|
NebulOuS::MetricValueRootString.size() );
|
||||||
|
|
||||||
if( MetricValues.contains( TheTopic ) )
|
if( MetricValues.contains( TheTopic ) )
|
||||||
{
|
{
|
||||||
MetricValues.at( TheTopic ).Value = TheMetricValue[ NebulOuS::ValueLabel ];
|
MetricValues.at( TheTopic ) = TheMetricValue[ NebulOuS::ValueLabel ];
|
||||||
|
|
||||||
ValidityTime = std::max( ValidityTime,
|
ValidityTime = std::max( ValidityTime,
|
||||||
TheMetricValue[ NebulOuS::TimePoint ].get< Solver::TimePointType >() );
|
TheMetricValue[ NebulOuS::TimePoint ].get< Solver::TimePointType >() );
|
||||||
@ -135,10 +141,9 @@ void MetricUpdater::SLOViolationHandler(
|
|||||||
|
|
||||||
Solver::MetricValueType TheApplicationExecutionContext;
|
Solver::MetricValueType TheApplicationExecutionContext;
|
||||||
|
|
||||||
for( const auto & [_, MetricRecord ] : MetricValues )
|
for( const auto & [ MetricName, MetricValue ] : MetricValues )
|
||||||
if( !MetricRecord.Value.is_null() )
|
if( !MetricValue.is_null() )
|
||||||
TheApplicationExecutionContext.emplace( MetricRecord.OptimisationName,
|
TheApplicationExecutionContext.emplace( MetricName, MetricValue );
|
||||||
MetricRecord.Value );
|
|
||||||
|
|
||||||
// The application context can then be sent to the solution manager
|
// The application context can then be sent to the solution manager
|
||||||
// using the corresponding message, and the time stamp of the severity
|
// using the corresponding message, and the time stamp of the severity
|
||||||
|
@ -88,7 +88,15 @@ constexpr std::string_view TimePoint = "predictionTime";
|
|||||||
// defined next.
|
// defined next.
|
||||||
|
|
||||||
constexpr std::string_view MetricSubscriptions
|
constexpr std::string_view MetricSubscriptions
|
||||||
= "eu.nebulouscloud.optimiser.solver.metrics";
|
= "eu.nebulouscloud.monitoring.metric_lists";
|
||||||
|
|
||||||
|
// The JSON message attribute for the list of metrics is another JSON object
|
||||||
|
// stored under the following key, see the Event type III defined in
|
||||||
|
// https://158.39.75.54/projects/nebulous-collaboration-hub/wiki/slo-severity-based-violation-detector
|
||||||
|
// where the name of the metric is defined under as sub-key.
|
||||||
|
|
||||||
|
constexpr std::string_view MetricList = "metric_list";
|
||||||
|
constexpr std::string_view MetricName = "name";
|
||||||
|
|
||||||
// The metric value messages will be published on different topics and to
|
// The metric value messages will be published on different topics and to
|
||||||
// check if an inbound message is from a metric value topic, it is necessary
|
// check if an inbound message is from a metric value topic, it is necessary
|
||||||
@ -154,33 +162,11 @@ private:
|
|||||||
// --------------------------------------------------------------------------
|
// --------------------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// The metric values are stored essentially as a JSON values where the
|
// The metric values are stored essentially as a JSON values where the
|
||||||
// attributes are the metric names and the values are JSON values because
|
// attributes are the metric names and the values are JSON values. It is
|
||||||
// they are polymorphic with respect to different variable types, and as
|
// assumed that same metric name is used both for the optimisation model
|
||||||
// they arrive as JSON values this avoids converting the values on input and
|
// and for the metric topic.
|
||||||
// output. The metric optimisation name is just a string.
|
|
||||||
|
|
||||||
class MetricValueRecord
|
std::unordered_map< Theron::AMQ::TopicName, JSON > MetricValues;
|
||||||
{
|
|
||||||
public:
|
|
||||||
const std::string OptimisationName;
|
|
||||||
JSON Value;
|
|
||||||
|
|
||||||
MetricValueRecord( const std::string & TheName, const JSON InitialValue )
|
|
||||||
: OptimisationName( TheName ), Value( InitialValue )
|
|
||||||
{}
|
|
||||||
|
|
||||||
MetricValueRecord( const MetricValueRecord & Other )
|
|
||||||
: OptimisationName( Other.OptimisationName ), Value( Other.Value )
|
|
||||||
{}
|
|
||||||
|
|
||||||
MetricValueRecord() = delete;
|
|
||||||
~MetricValueRecord() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
// This value record is used in the map where the subscribed topic name is
|
|
||||||
// the key so that values can quickly be updated when messages arrives.
|
|
||||||
|
|
||||||
std::unordered_map< Theron::AMQ::TopicName, MetricValueRecord > MetricValues;
|
|
||||||
|
|
||||||
// The metric values should ideally be forecasted for the same future time
|
// The metric values should ideally be forecasted for the same future time
|
||||||
// point, but this may not be assured, and as such a zero-order hold is
|
// point, but this may not be assured, and as such a zero-order hold is
|
||||||
|
Loading…
x
Reference in New Issue
Block a user