操作
機能 #2418
完了ECからRTCコールバック呼び出しを参照からサーバントにすることで効率化する
n-ando さんが12年以上前に追加. 12年以上前に更新.
ステータス:
終了
優先度:
通常
担当者:
-
対象バージョン:
-
開始日:
2012/05/07
期日:
進捗率:
100%
予定工数:
説明
現在のECはRTCをCORBA Object referenceで保持しているが、これをサーバントに変換した上でコールバックを呼び出すように変更する。
こうすることで、onExecuteなど呼び出し時間が重要になるコールバック関数においてパフォーマンスを向上させる。
ファイル
120419_newEC.zip (1.5 MB) 120419_newEC.zip | n-ando, 2012/05/07 11:19 |
n-ando さんが12年以上前に更新
実験¶
以下のコードを実行してみる。
interface Hoge { void munya(in string msg, in short val); };
// // CORBA performance test program // Noriaki Ando, 2012.4.18 // // This program compare between CORBA servant (implementation) // operation call and CORBA object reference operation call. // // 1. Servant newed from Hoge_impl // 2. Object reference obtained by _this() // 3. Object reference from stringfied IOR // 4. Servant obtained from object reference by reference_to_servant // // Servant. // 0[sec], 3571[usec] // Object reference from _this(). // 0[sec], 150894[usec] // Created object from string IOR. // 0[sec], 143678[usec] // Servant obtained from reference_to_servant. // 0[sec], 3543[usec] // ORB termianted. // // Servant : 3.571 ns // Obj ref : 150.894 ns // IOR ref : 143.678 ns // Servant2: 3.543 ns // obj ref is 42 times slower than servant // #include <omniORB4/CORBA.h> #include <sys/time.h> #include <iostream> #include <pthread.h> #include "hoge.hh" CORBA::ORB_var orb; class Hoge_impl : public virtual POA_Hoge { public: virtual void munya(const char* msg, ::CORBA::Short val) { // std::cout << msg << std::endl; return; } }; void* orb_run(void* arg) { std::cout << "orb started" << std::endl; orb->run(); return NULL; } #define USEC_PAR_SEC 1000000 timeval subtime(timeval start, timeval end) { timeval ret; if (end.tv_usec < start.tv_usec) { ret.tv_usec = end.tv_usec + USEC_PAR_SEC - start.tv_usec; ret.tv_sec = end.tv_sec - 1 - start.tv_sec; return ret; } ret.tv_usec = end.tv_usec - start.tv_usec; ret.tv_sec = end.tv_sec - start.tv_sec; return ret; } int main(int argc, char** argv) { orb = CORBA::ORB_init(argc, argv); CORBA::Object_var obj = orb->resolve_initial_references((char*)"RootPOA"); PortableServer::POA_var poa = PortableServer::POA::_narrow(obj); PortableServer::POAManager_var poamgr = poa->the_POAManager(); poamgr->activate(); // pthread_t thread_handle; // pthread_attr_t thread_attr; // pthread_create(&thread_handle, NULL, orb_run, (void *) NULL); Hoge_impl* hoge_servant = new Hoge_impl(); CORBA::Object_var hoge_obj = hoge_servant->_this(); Hoge_var hoge_var = Hoge::_narrow(hoge_obj); std::string ior; ior = orb->object_to_string(hoge_var); std::cout << ior << std::endl; CORBA::Object_var newobj = orb->string_to_object(ior.c_str()); Hoge_var newhoge = Hoge::_narrow(newobj); Hoge_impl* newservant = dynamic_cast<Hoge_impl*>(poa->reference_to_servant(hoge_var)); timeval start, end, result; gettimeofday(&start, NULL); for (int i(0); i < 1000000; ++i) { hoge_servant->munya("hoge", 1000); } gettimeofday(&end, NULL); result = subtime(start, end); std::cout << "Servant." << std::endl; std::cout << result.tv_sec << "[sec], "; std::cout << result.tv_usec << "[usec]" << std::endl; gettimeofday(&start, NULL); for (int i(0); i < 1000000; ++i) { hoge_var->munya("hoge", 1000); } gettimeofday(&end, NULL); result = subtime(start, end); std::cout << "Object reference from _this()." << std::endl; std::cout << result.tv_sec << "[sec], "; std::cout << result.tv_usec << "[usec]" << std::endl; gettimeofday(&start, NULL); for (int i(0); i < 1000000; ++i) { newhoge->munya("hoge", 1000); } gettimeofday(&end, NULL); result = subtime(start, end); std::cout << "Created object from string IOR." << std::endl; std::cout << result.tv_sec << "[sec], "; std::cout << result.tv_usec << "[usec]" << std::endl; gettimeofday(&start, NULL); for (int i(0); i < 1000000; ++i) { newservant->munya("hoge", 1000); } gettimeofday(&end, NULL); result = subtime(start, end); std::cout << "Servant obtained from reference_to_servant." << std::endl; std::cout << result.tv_sec << "[sec], "; std::cout << result.tv_usec << "[usec]" << std::endl; // orb->shutdown(true); // pthread_join(thread_handle, NULL); // std::cout << "ORB termianted." << std::endl; return 0; }
all: hoge OBJS = hogeSK.o hoge_impl.o CFLAGS = -I. LIBS = -lomniORB4 -lomnithread hoge: $(OBJS) g++ -o hoge $(OBJS) $(LIBS) hogeSK.o: hogeSK.cc g++ $(CFLAGS) -c -o hogeSK.o hogeSK.cc hoge_impl.o: hoge_impl.cpp g++ $(CFLAGS) -c -o hoge_impl.o hoge_impl.cpp hogeSK.cc: hoge.idl omniidl -bcxx hoge.idl clean: rm -rf *.o hogeSK.cc hoge.hh hoge core *~
結果¶
Servant | 3.571 ns | インスタンス化直後のサーバントへのポインタ経由呼び出し |
Obj ref | 150.894 ns | _this()で取得したオブジェクトリファレンス経由の呼び出し |
IOR ref | 143.678 ns | IOR文字列化後再度オブジェクト参照化したもの |
Servant2 | 3.543 ns | IOR->オブジェクト参照->reference_to_servantで取得したサーバントのポインタ |
大体40倍くらい違う。
n-ando さんが12年以上前に更新
RTObjectStateMachineを以下のように変更することで、オブジェクトリファレンス呼び出しをサーバント呼び出しにした。
Index: RTObjectStateMachine.cpp =================================================================== --- RTObjectStateMachine.cpp (revision 2330) +++ RTObjectStateMachine.cpp (working copy) @@ -17,6 +17,8 @@ */ #include <rtm/RTObjectStateMachine.h> +#include <rtm/Manager.h> +#include <rtm/RTObject.h> #include <iostream> #include <stdio.h> @@ -27,7 +29,8 @@ : m_id(id), m_rtobj(RTC::LightweightRTObject::_duplicate(comp)), m_sm(NUM_OF_LIFECYCLESTATE), - m_ca(false), m_dfc(false), m_fsm(false), m_mode(false) + m_ca(false), m_dfc(false), m_fsm(false), m_mode(false), + m_rtobjPtr(NULL), m_measure(false) { m_caVar = RTC::ComponentAction::_nil(); m_dfcVar = RTC::DataFlowComponentAction::_nil(); @@ -155,7 +158,11 @@ setComponentAction(const RTC::LightweightRTObject_ptr comp) { m_caVar = RTC::ComponentAction::_narrow(comp); - if (!CORBA::is_nil(m_caVar)) { m_ca = true; } + if (CORBA::is_nil(m_caVar)) { return; } + m_ca = true; + PortableServer::POA_ptr poa = RTC::Manager::instance().getPOA(); + m_rtobjPtr = + dynamic_cast<RTC::RTObject_impl*>(poa->reference_to_servant(comp)); } void RTObjectStateMachine:: @@ -182,16 +189,40 @@ // RTC::ComponentAction operations void RTObjectStateMachine::onStartup(void) { + // call Servant + if (m_rtobjPtr != NULL) + { + m_rtobjPtr->on_startup(m_id); + return; + } + // call Object reference if (!m_ca) { return; } m_caVar->on_startup(m_id); } void RTObjectStateMachine::onShutdown(void) { + // call Servant + if (m_rtobjPtr != NULL) + { + m_rtobjPtr->on_shutdown(m_id); + return; + } + // call Object reference if (!m_ca) { return; } m_caVar->on_shutdown(m_id); } void RTObjectStateMachine::onActivated(const ExecContextStates& st) { + // call Servant + if (m_rtobjPtr != NULL) + { + if (m_rtobjPtr->on_activated(m_id) != RTC::RTC_OK) + { + m_sm.goTo(RTC::ERROR_STATE); + } + return; + } + // call Object reference if (!m_ca) { return; } if (m_caVar->on_activated(m_id) != RTC::RTC_OK) { @@ -203,24 +234,55 @@ void RTObjectStateMachine::onDeactivated(const ExecContextStates& st) { + // call Servant + if (m_rtobjPtr != NULL) + { + m_rtobjPtr->on_deactivated(m_id); + return; + } + // call Object reference if (!m_ca) { return; } m_caVar->on_deactivated(m_id); } void RTObjectStateMachine::onAborting(const ExecContextStates& st) { + // call Servant + if (m_rtobjPtr != NULL) + { + m_rtobjPtr->on_aborting(m_id); + return; + } + // call Object reference if (!m_ca) { return; } - m_caVar->on_error(m_id); + m_caVar->on_aborting(m_id); } void RTObjectStateMachine::onError(const ExecContextStates& st) { + // call Servant + if (m_rtobjPtr != NULL) + { + m_rtobjPtr->on_error(m_id); + return; + } + // call Object reference if (!m_ca) { return; } m_caVar->on_error(m_id); } void RTObjectStateMachine::onReset(const ExecContextStates& st) { + // call Servant + if (m_rtobjPtr != NULL) + { + if (m_rtobjPtr->on_reset(m_id) != RTC::RTC_OK) + { + m_sm.goTo(RTC::ERROR_STATE); + } + return; + } + // call Object reference if (!m_ca) { return; } if (m_caVar->on_reset(m_id) != RTC::RTC_OK) { @@ -233,9 +295,58 @@ // RTC::DataflowComponentAction void RTObjectStateMachine::onExecute(const ExecContextStates& st) { + static int count; + double max_interval, min_interval, mean_interval, stddev; + // call Servant + if (m_rtobjPtr != NULL) + { + if (m_measure) { m_svtMeasure.tick(); } + if (m_rtobjPtr->on_execute(m_id) != RTC::RTC_OK) + { + m_sm.goTo(RTC::ERROR_STATE); + } + if (m_measure) + { + m_svtMeasure.tack(); + if (count > 1000) + { + count = 0; + m_svtMeasure.getStatistics(max_interval, min_interval, + mean_interval, stddev); + std::cout << "[servant] "; + std::cout << " max: " << max_interval; + std::cout << " min: " << min_interval; + std::cout << " mean: " << mean_interval; + std::cout << " stddev: " << stddev; + std::cout << std::endl; + } + ++count; + } + return; + } + // call Object reference if (!m_dfc) { return; } - if (m_dfcVar->on_execute(m_id) != RTC::RTC_OK) + if (m_measure) { m_refMeasure.tick(); } + RTC::ReturnCode_t ret = m_dfcVar->on_execute(m_id); + if (m_measure) { + m_refMeasure.tack(); + if (count > 1000) + { + count = 0; + m_refMeasure.getStatistics(max_interval, min_interval, + mean_interval, stddev); + std::cout << "[objref] "; + std::cout << " max: " << max_interval; + std::cout << " min: " << min_interval; + std::cout << " mean: " << mean_interval; + std::cout << " stddev: " << stddev; + std::cout << std::endl; + } + ++count; + } + if (ret != RTC::RTC_OK) + { m_sm.goTo(RTC::ERROR_STATE); return; } @@ -244,6 +355,16 @@ void RTObjectStateMachine::onStateUpdate(const ExecContextStates& st) { + // call Servant + if (m_rtobjPtr != NULL) + { + if (m_rtobjPtr->on_state_update(m_id) != RTC::RTC_OK) + { + m_sm.goTo(RTC::ERROR_STATE); + } + return; + } + // call Object reference if (!m_dfc) { return; } if (m_dfcVar->on_state_update(m_id) != RTC::RTC_OK) { @@ -255,6 +376,16 @@ void RTObjectStateMachine::onRateChanged(void) { + // call Servant + if (m_rtobjPtr != NULL) + { + if (m_rtobjPtr->on_rate_changed(m_id) != RTC::RTC_OK) + { + m_sm.goTo(RTC::ERROR_STATE); + } + return; + } + // call Object reference if (!m_dfc) { return; } if (m_dfcVar->on_rate_changed(m_id) != RTC::RTC_OK) {
n-ando さんが12年以上前に更新
- ステータス を 新規 から 解決 に変更
- 進捗率 を 0 から 100 に変更
以下の条件で実験を行った。
- ConfigSampleComp
- EC: nowait
- 表示なしに変更
- log: NO, loglevel: NORMAL
- 1000回ごとに統計
objref | 17us |
servant | 2.5us |
7倍くらい早くなったが、素のCORBA呼び出しの測定を行った前回の実験(40倍)に比べると、それほど変化がない。
また、呼び出し速度自体も、素のCORBAの場合、100nsオーダーだったか、今回はusオーダーであり、呼び出し時間も長い。
計測方法の問題のようなので、ひとまずECの改良自体は終了。
操作