trick/trick_source/sim_services/Executive/Executive_shutdown.cpp
Hong Chen 9076a3e88f
1592 send hs run stats improvement (#1604)
* Added system CPU time and initialization system CPU time and added user wording for existing CPU time to distinguish it from system CPU time used for trick run summary.

* Updated the order of a couple of times of shutdown messages printed on screen and sim/cpu time ratio to both user and system cpu time.

* Minor change for lining up the shutdown message.
2023-10-31 10:20:17 -05:00

143 lines
5.2 KiB
C++

/*
PURPOSE: (Graceful Simulation termination with timing data output.)
PROGRAMMERS:
(((Robert W. Bailey) (LinCom) (Feb 1991) (v1.0) (Initial Release.))
((Robert W. Bailey) (LinCom) (April 1992) (--) (Realtime clock))
((Scott Killingsworth) (LinCom) (September 1997) (--) (Issue #1016)))
*/
#include <stdlib.h>
#include <fcntl.h>
#include <iomanip>
#include <iostream>
#include <sys/resource.h>
#include "trick/Executive.hh"
#include "trick/ExecutiveException.hh"
#include "trick/message_proto.h"
#include "trick/message_type.h"
#include "trick/release.h"
#include "trick/SysThread.hh"
/**
@design
-# Set the mode to Exit.
Requirement [@ref r_exec_mode_3]
-# Wait for asynchronous or AMF threads to complete if the user has specified to do so
-# The scheduler calls shutdown jobs
Requirement [@ref r_exec_discrete_4]
-# If an exception is caught during calling the shutdown jobs the exception is ignored as we are already terminating.
-# The scheduler prints a simulation shutdown message
-# The scheduler kills all child threads
-# Return the exception_return value. (Set to 0 if no exception thrown.)
*/
int Trick::Executive::shutdown() {
double sim_elapsed_time;
double cpu_time;
double user_cpu_time, kernal_cpu_time;
double sim_to_cpu;
unsigned int ii;
int process_id = 0 ;
struct rusage cpu_usage_buf ;
double sim_mem;
SIM_MODE prev_mode = mode ;
/* Set mode to ExitMode. */
mode = ExitMode;
/* If we made it past initialization */
if ( prev_mode != Initialization ) {
/* Wait for asynchronous threads to complete if the user has specified to wait. */
for (ii = 1; ii < threads.size() ; ii++) {
if ( (threads[ii]->process_type == Trick::PROCESS_TYPE_ASYNC_CHILD || threads[ii]->process_type == Trick::PROCESS_TYPE_AMF_CHILD) && threads[ii]->shutdown_wait_async ) {
message_publish(MSG_INFO, "Waiting for asynchronous or AMF thread %d to finish\n", ii ) ;
while (threads[ii]->child_complete == false) {
RELEASE_1();
}
}
}
}
try {
/* Call the shutdown jobs. */
if (initialization_complete == true) {
shutdown_queue.reset_curr_index() ;
while ( (curr_job = shutdown_queue.get_next_job()) != NULL ) {
curr_job->call() ;
}
}
} catch (Trick::ExecutiveException & ex ) {
/* Handle exception type Trick::ExecutiveException. Set the file name and error message.
Return the exception return code. */
except_return = ex.ret_code ;
except_file += std::string(" then exception caught in ") + ex.file ;
except_message += std::string(" then exception Message: ") + ex.message ;
}
Trick::SysThread::ensureAllShutdown();
getrusage(RUSAGE_SELF, &cpu_usage_buf);
cpu_time = ((double) cpu_usage_buf.ru_utime.tv_sec) + ((double) cpu_usage_buf.ru_utime.tv_usec / 1000000.0);
/* Get memory usage in MB for the calling process. Note that ru_maxrss returns long value in bytes on Mac and kilobytes on Linux. */
#if __APPLE__
sim_mem = (double)cpu_usage_buf.ru_maxrss / (1024 * 1024);
#else
sim_mem = (double)cpu_usage_buf.ru_maxrss / 1024;
#endif
/* Calculate simulation elapsed sim time and actual cpu time */
sim_elapsed_time = get_sim_time() - sim_start;
user_cpu_time = cpu_time - user_cpu_start;
/* */
cpu_time = ((double) cpu_usage_buf.ru_stime.tv_sec) + ((double) cpu_usage_buf.ru_stime.tv_usec / 1000000.0);
kernal_cpu_time = cpu_time - kernal_cpu_start;
if ((user_cpu_time + kernal_cpu_time) <= 1e-6) {
sim_to_cpu = 1e8;
} else {
sim_to_cpu = sim_elapsed_time / (user_cpu_time + kernal_cpu_time);
}
/* Print a shutdown message. */
message_publish(MSG_NORMAL , "\n"
"SIMULATION TERMINATED IN\n"
" PROCESS: %d\n"
" ROUTINE: %s\n"
" DIAGNOSTIC: %s\n\n"
" SIMULATION START TIME: %12.3f\n"
" SIMULATION STOP TIME: %12.3f\n"
" SIMULATION ELAPSED TIME: %12.3f\n"
" USER CPU TIME USED: %12.3f\n"
" SYSTEM CPU TIME USED: %12.3f\n"
" SIMULATION / CPU TIME: %12.3f\n"
" INITIALIZATION USER CPU TIME: %12.3f\n"
" INITIALIZATION SYSTEM CPU TIME: %12.3f\n"
" SIMULATION RAM USAGE: %12.3fMB\n"
" (External program RAM usage not included!)\n",
process_id, except_file.c_str(), except_message.c_str(),
sim_start, get_sim_time(), sim_elapsed_time,
user_cpu_time, kernal_cpu_time, sim_to_cpu,
user_cpu_init, kernal_cpu_init, sim_mem) ;
/* Kill all threads. */
for (ii = 1; ii < threads.size() ; ii++) {
if ( threads[ii]->running ) {
pthread_cancel(threads[ii]->get_pthread_id()) ;
}
#if ! ( __APPLE__ || __CYGWIN__ || __Lynx__ )
// Even Linux is hanging on this call right now... hmmm.
//pthread_join(threads[ii]->thread_id, (void **) NULL);
#endif
}
/* Return the exception_return value. This defaults to 0 if no exceptions were thrown. */
return(except_return) ;
}