/*
* Измерение производительности SObjectizer-а при помощи теста chameneos.
*
* Изменение в версии 4.4.0-beta6: для того, чтобы гарантировать, что
* a_meeting_place_t не прозевает сообщение msg_creature_inside при
* начале своей работы, хамелеоны создаются в виде дочерней кооперации
* в a_meeting_place_t.evt_start.
*/
#include <iostream>
#include <vector>
#include <ace/OS.h>
#include <ace/Time_Value.h>
#include <so_4/rt/h/rt.hpp>
#include <so_4/api/h/api.hpp>
#include <so_4/disp/one_thread/h/pub.hpp>
#include <so_4/timer_thread/simple/h/pub.hpp>
#include <test/bench/time_value_msec_helper.hpp>
typedef int color_t;
const color_t blue = 1;
const color_t red = 2;
const color_t yellow = 3;
const color_t fadded = 4;
const int creatures_count = 4;
//
// a_meeting_place_t
//
class a_meeting_place_t
: public so_4::rt::agent_t
{
typedef so_4::rt::agent_t base_type_t;
public :
a_meeting_place_t(
const std::string & name,
int meetings )
: base_type_t( name )
, m_remaining_meetings( meetings )
{}
virtual const char *
so_query_type() const;
struct msg_creature_inside
{
const so_4::rt::agent_t * m_who;
color_t m_color;
msg_creature_inside()
: m_who( 0 )
, m_color( fadded )
{}
msg_creature_inside(
const so_4::rt::agent_t * who,
color_t color )
: m_who( who )
, m_color( color )
{}
static bool check( const msg_creature_inside * msg )
{
return ( 0 != msg && 0 != msg->m_who );
}
};
struct msg_meet_completed
{
color_t m_other;
msg_meet_completed()
: m_other( fadded )
{}
msg_meet_completed(
color_t color )
: m_other( color )
{}
static bool check( const msg_meet_completed * msg )
{
return ( 0 != msg );
}
};
struct msg_creature_report
{
const so_4::rt::agent_t * m_who;
int m_meetings_count;
msg_creature_report()
: m_who( 0 )
, m_meetings_count( 0 )
{}
msg_creature_report(
const so_4::rt::agent_t * who,
int meetings_count )
: m_who( who )
, m_meetings_count( meetings_count )
{}
static bool check( const msg_creature_inside * msg )
{
return ( 0 != msg && 0 != msg->m_who );
}
};
virtual void
so_on_subscription();
void
evt_start();
void
evt_first_in(
const msg_creature_inside & cmd );
void
evt_second_in(
const msg_creature_inside & cmd );
void
evt_creature_in_when_no_meetings_left(
const msg_creature_inside & cmd );
void
evt_creature_report(
const msg_creature_report & cmd );
private :
int m_remaining_meetings;
msg_creature_inside m_first_in;
typedef std::vector< msg_creature_report > reports_vector_t;
reports_vector_t m_reports;
ACE_Time_Value m_start_time;
};
//
// a_creature_t
//
class a_creature_t
: public so_4::rt::agent_t
{
typedef so_4::rt::agent_t base_type_t;
public :
a_creature_t(
const std::string & name,
const std::string & meeting_place_name,
color_t color )
: base_type_t( name )
, m_meeting_place_name( meeting_place_name )
, m_color( color )
, m_creatures_met( 0 )
{}
virtual const char *
so_query_type() const;
virtual void
so_on_subscription();
void
evt_start();
void
evt_meet_completed(
const a_meeting_place_t::msg_meet_completed & cmd );
private :
const std::string m_meeting_place_name;
color_t m_color;
int m_creatures_met;
};
//
// a_meeting_place_t implementation
//
SOL4_CLASS_START( a_meeting_place_t )
SOL4_MSG_START(
msg_creature_inside,
a_meeting_place_t::msg_creature_inside )
SOL4_MSG_CHECKER( a_meeting_place_t::msg_creature_inside::check )
SOL4_MSG_FINISH()
SOL4_MSG_START(
msg_meet_completed,
a_meeting_place_t::msg_meet_completed )
SOL4_MSG_CHECKER( a_meeting_place_t::msg_meet_completed::check )
SOL4_MSG_FINISH()
SOL4_MSG_START(
msg_creature_report,
a_meeting_place_t::msg_creature_report )
SOL4_MSG_CHECKER( a_meeting_place_t::msg_creature_report::check )
SOL4_MSG_FINISH()
SOL4_EVENT( evt_start )
SOL4_EVENT_STC( evt_first_in,
a_meeting_place_t::msg_creature_inside )
SOL4_EVENT_STC( evt_second_in,
a_meeting_place_t::msg_creature_inside )
SOL4_EVENT_STC( evt_creature_in_when_no_meetings_left,
a_meeting_place_t::msg_creature_inside )
SOL4_EVENT_STC( evt_creature_report,
a_meeting_place_t::msg_creature_report )
SOL4_STATE_START( st_initial )
SOL4_STATE_EVENT( evt_start )
SOL4_STATE_FINISH()
SOL4_STATE_START( st_empty )
SOL4_STATE_EVENT( evt_first_in )
SOL4_STATE_FINISH()
SOL4_STATE_START( st_first_in )
SOL4_STATE_EVENT( evt_second_in )
SOL4_STATE_FINISH()
SOL4_STATE_START( st_no_meetings_left )
SOL4_STATE_EVENT( evt_creature_in_when_no_meetings_left )
SOL4_STATE_EVENT( evt_creature_report )
SOL4_STATE_FINISH()
SOL4_CLASS_FINISH()
void
a_meeting_place_t::so_on_subscription()
{
so_subscribe(
"evt_start",
so_4::rt::sobjectizer_agent_name(),
"msg_start",
1 );
so_subscribe( "evt_first_in", "msg_creature_inside" );
so_subscribe( "evt_second_in", "msg_creature_inside" );
so_subscribe( "evt_creature_in_when_no_meetings_left",
"msg_creature_inside" );
so_subscribe( "evt_creature_report", "msg_creature_report" );
}
void
a_meeting_place_t::evt_start()
{
m_start_time = ACE_OS::gettimeofday();
so_change_state( "st_empty" );
// Теперь можно создавать дочерних хамелеонов.
so_4::rt::agent_t * agents[] = {
new a_creature_t( "a_first", so_query_name(), blue )
, new a_creature_t( "a_second", so_query_name(), yellow )
, new a_creature_t( "a_third", so_query_name(), red )
, new a_creature_t( "a_forth", so_query_name(), blue )
};
so_4::rt::dyn_agent_coop_t * chameneos_coop =
new so_4::rt::dyn_agent_coop_t(
"chameneos",
agents,
sizeof(agents) / sizeof(agents[0]) );
chameneos_coop->set_parent_coop_name( so_query_coop()->query_name() );
so_4::rt::dyn_agent_coop_helper_t chameneos_coop_registrator(
chameneos_coop );
}
void
a_meeting_place_t::evt_first_in(
const msg_creature_inside & cmd )
{
m_first_in = cmd;
so_change_state( "st_first_in" );
}
inline void
send_msg_meet_completed(
const so_4::rt::agent_t & meetplace,
const so_4::rt::agent_t & receiver,
color_t color )
{
so_4::api::send_msg_safely(
meetplace.so_query_name(),
"msg_meet_completed",
new a_meeting_place_t::msg_meet_completed( color ),
receiver.so_query_name() );
}
void
a_meeting_place_t::evt_second_in(
const msg_creature_inside & cmd )
{
send_msg_meet_completed( *this, *m_first_in.m_who, cmd.m_color );
send_msg_meet_completed( *this, *cmd.m_who, m_first_in.m_color );
so_change_state(
( --m_remaining_meetings > 0 ) ?
"st_empty" : "st_no_meetings_left" );
}
void
a_meeting_place_t::evt_creature_in_when_no_meetings_left(
const msg_creature_inside & cmd )
{
send_msg_meet_completed( *this, *cmd.m_who, fadded );
}
void
a_meeting_place_t::evt_creature_report(
const msg_creature_report & cmd )
{
m_reports.push_back( cmd );
if( creatures_count == m_reports.size() )
{
ACE_Time_Value finish_time = ACE_OS::gettimeofday();
int total = 0;
for( reports_vector_t::iterator it = m_reports.begin(),
it_end = m_reports.end();
it != it_end;
++it )
{
std::cout << "creature: '" << it->m_who->so_query_name()
<< "' met: " << it->m_meetings_count << std::endl;
total += it->m_meetings_count;
}
std::cout << "Total: " << total << std::endl;
double work_time =
( milliseconds( finish_time ) -
milliseconds( m_start_time ) ) / 1000.0;
long total_messages = total * 4;
std::cout << "Time: " << work_time << " sec" << std::endl;
std::cout << "Throughput: "
<< total_messages / work_time << " msgs/sec" << std::endl;
so_4::api::send_msg(
so_4::rt::sobjectizer_agent_name(),
"msg_normal_shutdown" );
}
}
//
// a_creature_t implementation
//
SOL4_CLASS_START( a_creature_t )
SOL4_EVENT( evt_start )
SOL4_EVENT_STC( evt_meet_completed,
a_meeting_place_t::msg_meet_completed )
SOL4_STATE_START( st_normal )
SOL4_STATE_EVENT( evt_start )
SOL4_STATE_EVENT( evt_meet_completed )
SOL4_STATE_FINISH()
SOL4_CLASS_FINISH()
void
a_creature_t::so_on_subscription()
{
so_subscribe(
"evt_start",
so_4::rt::sobjectizer_agent_name(),
"msg_start" );
so_subscribe(
"evt_meet_completed",
m_meeting_place_name,
"msg_meet_completed" );
}
inline void
send_msg_creature_inside(
const std::string & meeting_place_name,
const so_4::rt::agent_t & who,
color_t color )
{
so_4::api::send_msg_safely(
meeting_place_name,
"msg_creature_inside",
new a_meeting_place_t::msg_creature_inside( &who, color ) );
}
void
a_creature_t::evt_start()
{
send_msg_creature_inside( m_meeting_place_name, *this, m_color );
}
void
a_creature_t::evt_meet_completed(
const a_meeting_place_t::msg_meet_completed & cmd )
{
if( fadded != cmd.m_other )
{
++m_creatures_met;
switch( m_color )
{
case blue :
m_color = ( cmd.m_other == red ? yellow : red );
break;
case red :
m_color = ( cmd.m_other == blue ? yellow : blue );
break;
case yellow :
m_color = ( cmd.m_other == blue ? red : blue );
}
send_msg_creature_inside( m_meeting_place_name, *this, m_color );
}
else
{
m_color = fadded;
so_4::api::send_msg_safely(
m_meeting_place_name,
"msg_creature_report",
new a_meeting_place_t::msg_creature_report(
this,
m_creatures_met ) );
}
}
int main( int argc, char **argv )
{
const int default_meeting_count = 100;
int meeting_count = argc == 2 ?
ACE_OS::atoi( argv[ 1 ] ) :
default_meeting_count;
a_meeting_place_t meeting_place( "a_meeting_place", meeting_count );
so_4::rt::agent_coop_t coop( meeting_place );
so_4::ret_code_t rc = so_4::api::start(
so_4::disp::one_thread::create_disp(
so_4::timer_thread::simple::create_timer_thread(),
so_4::auto_destroy_timer ),
so_4::auto_destroy_disp,
&coop );
if( rc )
std::cerr << "SObjectizer start error: " << rc << std::endl;
return int( rc );
}