//Command to create a new action using a model job (or reset an existing action job), num is index starting at 0. int Trick::IPPythonEvent::action_job(int num, std::string jobname, std::string comment) { /** @par Detailed Design: */ /** @li Find the job for the jobname string and pass it to action() */ JobData *job = exec_get_job(jobname.c_str(),1); /** @li Emit an error if specified jobname does not exist. */ if (job==NULL) { message_publish(MSG_WARNING, "Event action job %s not found. No action was added.\n", jobname.c_str()) ; } else { if (! job->job_class_name.compare("malfunction")) { // enable it if it's a malf job because they are not in any queue job->disabled = false; } action(num, jobname, comment, job, 3 ); } return(0); }
/** @details -# If the #delimiter is not empty and not a comma then set the file extension to ".txt" -# Else set the file extension to ".csv" -# Allocate enough memory to hold #record_size of records in memory -# Open the log file -# Return an error if the open failed. -# Write out the title line of the log file. The title line includes the names of recorded variables and the units of measurement separated by the #delimiter -# Declare the recording group to the memory manager so that the group can be checkpointed and restored */ int Trick::DRAscii::format_specific_init() { unsigned int jj ; /* Store log information in csv/txt file */ if ( ! delimiter.empty() && delimiter.compare(",") != 0 ) { file_name.append(".txt"); } else { file_name.append(".csv"); } /* Calculate a "worst case" for space used for 1 record. */ writer_buff = (char *)calloc(1 , record_size * rec_buffer.size()) ; /* This loop touches all of the memory locations in the allocation forcing the system to actually do the allocation */ for ( jj= 0 ; jj < record_size * rec_buffer.size() ; jj += 1024 ) { writer_buff[jj] = 1 ; } writer_buff[record_size * rec_buffer.size() - 1] = 1 ; out_stream.open(file_name.c_str(), std::fstream::out | std::fstream::app ) ; if ( !out_stream || !out_stream.good() ) { message_publish(MSG_ERROR, "Can't open Data Record file %s.\n", file_name.c_str()) ; record = false ; return -1 ; } // Write out the title line of the recording file /* Start with the 1st item in the buffer which should be "sys.exec.out.time" */ out_stream << rec_buffer[0]->ref->reference ; if ( rec_buffer[0]->ref->attr->units != NULL ) { out_stream << " {" << rec_buffer[0]->ref->attr->units << "}" ; } /* Write out specified recorded parameters */ for (jj = 1; jj < rec_buffer.size() ; jj++) { out_stream << delimiter << rec_buffer[jj]->ref->reference ; if ( rec_buffer[jj]->ref->attr->units != NULL ) { out_stream << " {" << rec_buffer[jj]->ref->attr->units << "}" ; } } out_stream << std::endl ; return(0) ; }
//Command to create a new condition and set its input string (or reset an existing condition string), num is index starting at 0. int Trick::IPPythonEvent::condition(int num, std::string str, std::string comment, REF2* ref, JobData* job) { /** @par Detailed Design: */ if (num == condition_count) { /** @li Add a new condition when num is sequential, i.e. it is equal to condition_count */ condition_count++; if (condition_count == 1) { condition_list = (Trick::condition_t **)TMM_declare_var_s("Trick::condition_t*[1]"); } else { condition_list = (Trick::condition_t **)TMM_resize_array_1d_a(condition_list, condition_count); } condition_list[num] = (Trick::condition_t *)TMM_declare_var_s("Trick::condition_t"); condition_list[num]->fired_count = 0; condition_list[num]->fired_time = -1.0; } if ((num >=0) && (num < condition_count)) { /** @li This is either a new condition or user is changing the condition. */ /** @li Initialize condition variables - default as enabled. */ condition_list[num]->ref = ref ; condition_list[num]->job = job ; condition_list[num]->enabled = true; condition_list[num]->hold = false; condition_list[num]->fired = false; if (ref != NULL) { condition_list[num]->cond_type = 1; } else if (job != NULL) { condition_list[num]->cond_type = 2; } else condition_list[num]->cond_type = 0; condition_list[num]->str = str; // comment is for display in mtv, if not supplied create a comment containing up to 50 characters of cond string if (comment.empty()) { condition_list[num]->comment = str.substr(0,50); } else { condition_list[num]->comment = comment; } // dummy must contain max conditions used in any event so it can replace any event in mtv when deleted } else { /** @li Emit an error if specified index num is not sequential. */ message_publish(MSG_WARNING, "Event condition not added: condition number %d is not sequential.\n", num) ; } return(0); }
/** @par Detailed Design: */ Trick::MonteRun *Trick::MonteCarlo::get_next_dispatch() { /** <ul><li> While there are remaining runs: */ while (!runs.empty()) { MonteRun *curr_run = runs.front(); /** <li> If it is in range, return it. </ul>*/ if (in_range(curr_run)) { return curr_run; /** <li> Otherwise, run the pre run jobs and dequeue it. */ } else { if (verbosity >= ALL) { message_publish(MSG_WARNING, "Monte [Master] Run %d is out of range and has been skipped.\n", curr_run->id) ; } prepare_run(curr_run); } } return NULL; }
/*! * @brief Print the ball position. * * @job_class{ scheduled } * * @return Always returns 0. * @param [in] sim_time Simulation elapsed time. * @param [in] exec_data Executive control date. * @param [in] state Ball EOM state parameters. */ int ball_print( double sim_time, BallExec * exec_data, BallState * state ) { if (! exec_data->print_off) { #ifdef TRICK_VER message_publish( 0, "time = %8.2f , position = %12.6f , %12.6f\n", sim_time, state->position[0], state->position[1]); #else printf( "time = %8.2f , position = %12.6f , %12.6f\n", sim_time, state->position[0], state->position[1]); #endif } return( 0 ); }
int Trick::SlaveInfo::write_master_chkpnt_name(std::string full_path_name) { /** @par Detailed Design: */ /** @li If the slave is an active synchronization partner (activated == true) */ if ( activated == true ) { /** @li write the checkpoint dir/filename to the slave */ if (full_path_name.length() > sizeof(chkpnt_name)-1) { message_publish(MSG_ERROR, "Master could not send checkpoint name to slave because name too long (max = %d).\n", sizeof(chkpnt_name)) ; chkpnt_name[0] = MS_ERROR_NAME; // send error character } else { strcpy(chkpnt_name, full_path_name.c_str()); } connection->write_name(chkpnt_name, sizeof(chkpnt_name)) ; } return(0) ; }
/** @details -# Test if the incoming data record group name has been used. -# If true return an error. -# Set the group buffering type to the incoming type -# Add the group to the executive. */ int Trick::DataRecordDispatcher::add_group(Trick::DataRecordGroup * in_group, Trick::DR_Buffering buffering) { unsigned int ii ; for ( ii = 0 ; ii < groups.size() ; ii++ ) { if ( !groups[ii]->group_name.compare(in_group->group_name) ) { message_publish(MSG_ERROR, "Data Record group with duplicate name %s.\n", in_group->group_name.c_str()) ; return -1 ; } } if ( buffering != Trick::DR_Not_Specified ) { in_group->set_buffer_type(buffering) ; } exec_add_sim_object(in_group , (char *)in_group->name.c_str()) ; return 0 ; }
void Trick::MonteCarlo::initialize_slave(Trick::MonteSlave* slave_to_init) { std::stringstream ss; if (slave_to_init->remote_shell_args.empty()) { slave_to_init->remote_shell_args = ""; } std::string buffer; /** <li> If this is a custom slave dispatch: add the #custom_pre_text. */ if (custom_slave_dispatch) { buffer = custom_pre_text; /** <li> Otherwise add the default pre text. */ } else { default_slave_dispatch_pre_text(slave_to_init, buffer) ; } if (!slave_to_init->S_main_name.compare("")) { slave_to_init->S_main_name = "./S_main_${TRICK_HOST_CPU}.exe"; } /** <li> Append the S_main executable and slave-specific arguments. */ ss << slave_to_init->S_main_name << " " << command_line_args_get_input_file() << " --monte_host " << machine_name << " --monte_sync_port " << listen_device.port << " --monte_data_port " << data_listen_device.port << " --monte_client_id " << slave_to_init->id << " -O " << run_directory; buffer += ss.str(); /** <li> if this is a custom slave dispatch, append the #custom_post_text. */ if (custom_slave_dispatch) { buffer += custom_post_text; } else { buffer += std::string("' &"); } if (verbosity >= INFORMATIONAL) { message_publish(MSG_INFO, "Monte: Spawning Slave %s:%d :\n%s\n", slave_to_init->machine_name.c_str(), slave_to_init->id, buffer.c_str()) ; } /** <li> Set the slave's state to INITIALIZING. */ slave_to_init->state = MonteSlave::INITIALIZING; /** <li> Make the system call to execute the shell. */ system(buffer.c_str()); }
//Command to create a new action and set its input string (or reset an existing action string), num is index starting at 0. int Trick::IPPythonEvent::action(int num, std::string str, std::string comment, JobData *job, int act_type) { /** @par Detailed Design: */ if (num == action_count) { /** @li Add a new action when num is sequential, i.e. it is equal to action_count */ action_count++; if (action_count == 1) { action_list = (Trick::action_t **)TMM_declare_var_s("Trick::action_t*[1]"); } else { action_list = (Trick::action_t **)TMM_resize_array_1d_a(action_list, action_count); } action_list[num] = (Trick::action_t *)TMM_declare_var_s("Trick::action_t"); action_list[num]->ran_count = 0; action_list[num]->ran_time = -1.0; } if ((num >=0) && (num < action_count)) { /** @li This is either a new action or user is changing the action. */ /** @li Initialize action variables - default as enabled. */ action_list[num]->job = job ; action_list[num]->act_type = act_type ; action_list[num]->enabled = true; action_list[num]->ran = false; action_list[num]->str = str; // comment is for display in mtv, if not supplied create a comment containing up to 50 characters of act string if (comment.empty()) { action_list[num]->comment = str.substr(0,50); } else { action_list[num]->comment = comment; } // dummy must contain max actions used in any event so it can replace any event in mtv when deleted #if 0 if (num == ip->dummy_event.action_count) { ip->dummy_event.action(num, "XXX_DELETED_ACT"); } #endif } else { /** @li Emit an error if specified index num is not sequential. */ message_publish(MSG_WARNING, "Event action not added: action number %d is not sequential.\n", num) ; } return(0); }
int Trick::DataRecordGroup::write_header() { unsigned int jj ; std::string header_name ; std::fstream out_stream ; /*! create the header file used by the GUIs */ header_name = output_dir + "/log_" + group_name + ".header" ; out_stream.open(header_name.c_str(), std::fstream::out ) ; if ( ! out_stream || ! out_stream.good() ) { #ifndef _DMTCP message_publish(MSG_ERROR, "Can't open Data Record file %s.\n", header_name.c_str()) ; #endif return -1; } /* Header file first line is created in format specific header */ out_stream << "log_" << group_name ; format_specific_header(out_stream) ; /* Output the file name, variable size, units, and variable name * to the rest of recorded data header file. * (e.g. file_name C_type units sim_name) * Note: "sys.exec.out.time" should be the first variable in the buffer. */ for (jj = 0; jj < rec_buffer.size() ; jj++) { /*! recording single data item */ out_stream << "log_" << group_name << "\t" << type_string(rec_buffer[jj]->ref->attr->type, rec_buffer[jj]->ref->attr->size) << "\t" << std::setw(6)<<rec_buffer[jj]->ref->attr->units << "\t" << rec_buffer[jj]->ref->reference << std::endl ; } // Send all unwritten characters in the buffer to its output/file. out_stream.flush() ; out_stream.close() ; return(0) ; }
int Trick::Executive::freeze(double in_time) { long long new_time ; new_time = (long long)(in_time * time_tic_value) ; if (new_time > time_tics ) { freeze_times.push(new_time) ; if ( new_time < freeze_job->next_tics ) { freeze_job->next_tics = new_time ; } //std::cout << "\033[33mSET FREEZE TIME " << in_time << " " << new_time << "\033[0m" << std::endl ; } else { message_publish(MSG_ERROR, "Freeze time specified in the past. specified %f, current_time %f\n", in_time , get_sim_time()) ; } return(0) ; }
/** @par Detailed Design: */ void Trick::MonteCarlo::resolve_run(MonteSlave& slave, MonteRun::ExitStatus exit_status) { if (exit_status != MonteRun::COMPLETE) { failed_runs.push_back(slave.current_run); } /** <li> Update the bookkeeping. */ struct timeval time_val; gettimeofday(&time_val, NULL); slave.current_run->end_time = time_val.tv_sec + (double)time_val.tv_usec / 1000000; slave.current_run->exit_status = exit_status; ++slave.num_results; slave.cpu_time += slave.current_run->end_time - slave.current_run->start_time; ++num_results; if (verbosity >= ALL) { message_publish(MSG_INFO, "Monte [Master] Run %d has been resolved as: %d.\n",slave.current_run->id, exit_status) ; } }
int Trick::Master::checkpoint() { /** @par Detailed Design: */ /** @li If chkpnt_dump_auto, tell slave to dump a checkpoint */ unsigned int ii ; // do not tell slave to dump if this is a pre_init, post_init, or end checkpoint // those are handled with flags sent to slave in init() if ((exec_get_mode() == Initialization) || (exec_get_mode() == ExitMode)) { return(0); } if (enabled) { // Use 2 loops to read all slave status before writing any status out. for ( ii = 0 ; ii < slaves.size() ; ii++ ) { slaves[ii]->read_slave_status() ; } SIM_COMMAND save_command = exec_get_exec_command() ; std::string full_path_name = checkpoint_get_output_file(); for ( ii = 0 ; ii < slaves.size() ; ii++ ) { if (slaves[ii]->chkpnt_dump_auto) { if (slaves[ii]->chkpnt_binary) { if (slaves[ii]->slave_type == "dmtcp") { exec_set_exec_command((SIM_COMMAND)MS_ChkpntDumpBinCmd) ; slaves[ii]->write_master_status() ; slaves[ii]->write_master_chkpnt_name(full_path_name) ; exec_set_exec_command(save_command) ; } else { message_publish(MSG_ERROR, "Slave is not running under dmtcp control so it cannot dump binary checkpoint.\n") ; slaves[ii]->write_master_status() ; } } else { // ascii exec_set_exec_command((SIM_COMMAND)MS_ChkpntDumpAsciiCmd) ; slaves[ii]->write_master_status() ; slaves[ii]->write_master_chkpnt_name(full_path_name) ; exec_set_exec_command(save_command) ; } } else { // no auto dump slaves[ii]->write_master_status() ; } } } return(0) ; }
int Trick::DataRecordGroup::add_change_variable( std::string in_name ) { REF2 * ref2 ; ref2 = ref_attributes((char *)in_name.c_str()) ; if ( ref2 == NULL || ref2->attr == NULL ) { message_publish(MSG_WARNING, "Could not find Data Record change variable %s.\n", in_name.c_str()) ; return(-1) ; } Trick::DataRecordBuffer * new_var = new Trick::DataRecordBuffer ; new_var->ref = ref2 ; new_var->buffer = (char *)malloc(ref2->attr->size) ; new_var->last_value = NULL ; memcpy(new_var->buffer , ref2->address , ref2->attr->size) ; change_buffer.push_back(new_var) ; return(0) ; }
// MEMBER FUNCTION void* Trick::MemoryManager:: declare_extern_var(void* address, const char* alloc_definition) { void* res_address = NULL; ADefParseContext* context = NULL; std::stringstream alloc_decl_sstream; /** @par Design Details: This function is implemented using the following algorithm: */ alloc_decl_sstream << alloc_definition; /** @li Create a parse context. */ context = new ADefParseContext( &alloc_decl_sstream); /** @li Call ADEF_parse to parse the declaration. */ if (context != NULL) { if ( ADEF_parse( context) == 0) { /** @li Call the general form of declare_extern_var. */ res_address = declare_extern_var( address, context->type, context->user_type_name, context->n_stars, context->var_name, context->n_cdims, context->cdims); /** @li Delete the parse context. */ delete( context); } else { message_publish(MSG_ERROR, "Memory Manager: Invalid declaration \"%s\".\n", alloc_definition) ; } } /** @li Return the address. */ return ( res_address); }
/* @details -# If the user specified an address and port -# disconnect the current listen port -# initialize listen port to new address and port -# else print message of current port number of listen device */ int Trick::JSONVariableServer::restart() { int ret ; if ( user_port_requested ) { printf("user_port_requested set %d", port) ; tc_disconnect(&listen_dev) ; ret = tc_init_with_connection_info(&listen_dev, AF_INET, SOCK_STREAM, source_address.c_str(), port) ; if (ret != TC_SUCCESS) { message_publish(MSG_ERROR, "ERROR: Could not establish listen port %d for Variable Server. Aborting.\n", port); return (-1); } } else { struct sockaddr_in s_in; int s_in_size = sizeof(s_in) ; getsockname( listen_dev.socket , (struct sockaddr *)&s_in, (socklen_t *)&s_in_size) ; printf("restart JSON variable server message port = %d\n" , ntohs(s_in.sin_port)) ; port = listen_dev.port = ntohs(s_in.sin_port); } return 0 ; }
std::string Trick::ClassicCheckPointAgent::get_var_name( void* addr, ATTRIBUTES* A, void* struct_addr, std::string name, ATTRIBUTES** left_type) { char *ret; std::string var_name; var_name = name; ret = getCompositeSubReference( addr, left_type, struct_addr, A); if (ret != NULL) { var_name += ret; free(ret); } else { std::stringstream ss; ss << "Checkpoint Agent ERROR: Unable to create a subreference of variable \"" << name << "\"." << std::endl; message_publish(MSG_ERROR, ss.str().c_str() ); } return (var_name); }
int STLCheckpoint::speak() { //message_publish(1,"Quack!\n") ; //message_publish(1,"double_vector: %f %f %f\n", double_vector[0], double_vector[1], double_vector[2]) ; //message_publish(1,"vector_vector_double[1]: %f %f %f\n", // vector_vector_double[1][0], vector_vector_double[1][1], vector_vector_double[1][2]) ; //message_publish(1,"vector_vector_vector_double[4][2]: %f %f %f\n", // vector_vector_vector_double[4][2][0], vector_vector_vector_double[4][2][1], vector_vector_vector_double[4][2][2]) ; //message_publish(1,"string_vector[0]: %s\n", string_vector[0].c_str()) ; //message_publish(1,"map_int_vector_int[1][1] = %d\n", map_int_vector_int[1][1]) ; //message_publish(1,"gcd = %d\n", gcd[std::pair<int, int >(24,30)]) ; //message_publish(1,"common_multiples = %d\n", common_multiples[std::pair<int, int >(3,5)][1]) ; //message_publish(1,"common_multiples = %d\n", common_multiples[std::pair<int, int >(3,5)][1]) ; //message_publish(1,"int_pair_int_int.second.second = %d\n", int_pair_int_int.second.second) ; //message_publish(1,"pair_int_int_int.first.second = %d\n", pair_int_int_int.first.second) ; //message_publish(1,"pair_pair_pair.second.first = %d\n", pair_pair_pair.second.first) ; //message_publish(1,"int_queue.front = %d\n", int_queue.front()) ; //message_publish(1,"int_priority_queue.top = %d\n", int_priority_queue.top()) ; //message_publish(1,"uint_stack.top = %d\n", uint_stack.top()) ; //message_publish(1,"queue_vector_int.front()[3] = %d\n", queue_vector_int.front()[3]) ; //message_publish(1,"priority_queue_vector_int.top()[2] = %d\n", priority_queue_vector_int.top()[2]) ; message_publish(1,"stack_vector_int.top()[1] = %d\n", stack_vector_int.top()[1]) ; return 0 ; }
int Trick::Master::preload_checkpoint() { /** @par Detailed Design: */ /** @li If chkpnt_load_auto, tell slave to load a checkpoint */ unsigned int ii ; if (enabled) { // Use 2 loops to read all slave status before writing any status out. for ( ii = 0 ; ii < slaves.size() ; ii++ ) { slaves[ii]->read_slave_status() ; } SIM_COMMAND save_command = exec_get_exec_command() ; std::string full_path_name = checkpoint_get_load_file(); for ( ii = 0 ; ii < slaves.size() ; ii++ ) { if (slaves[ii]->chkpnt_load_auto) { if (slaves[ii]->chkpnt_binary) { if (slaves[ii]->slave_type == "dmtcp") { exec_set_exec_command((SIM_COMMAND)MS_ChkpntLoadBinCmd) ; slaves[ii]->write_master_status() ; slaves[ii]->write_master_chkpnt_name(full_path_name) ; exec_set_exec_command(save_command) ; } else { message_publish(MSG_ERROR, "Slave is not running under dmtcp control so it cannot load binary checkpoint.\n") ; slaves[ii]->write_master_status() ; } } else { // ascii exec_set_exec_command((SIM_COMMAND)MS_ChkpntLoadAsciiCmd) ; slaves[ii]->write_master_status() ; slaves[ii]->write_master_chkpnt_name(full_path_name) ; exec_set_exec_command(save_command) ; } } else { // no auto load slaves[ii]->write_master_status() ; } } } return(0) ; }
int Trick::VariableServerThread::var_units(std::string var_name, std::string units_name) { unsigned int ii ; for ( ii = 0 ; ii < vars.size() ; ii++ ) { if ( ! std::string(vars[ii]->ref->reference).compare(var_name) ) { if (!units_name.compare("xx")) { vars[ii]->ref->units = strdup(vars[ii]->ref->attr->units); } else { Unit orig_units(vars[ii]->ref->attr->units) ; try { vars[ii]->conversion_factor = orig_units.Conversion_to(units_name.c_str()) ; vars[ii]->ref->units = strdup(units_name.c_str()); } catch (Unit::CONVERSION_ERROR & ce_err ) { message_publish(MSG_ERROR, "Variable Server Error: var_units Units conversion error for \"%s\".\n",var_name.c_str()); return(-1) ; } } } } return(0) ; }
//Top of frame job to add new events to processing set. void Trick::EventProcessor::add_pending_events( long long curr_tics , bool is_restart ) { std::vector< Trick::Event * >::iterator it ; for ( it = pending_events.begin() ; it != pending_events.end() ; ) { if ( (*it)->get_cycle_tics() != 0 ) { // this is a cyclic event // If we are not calling this routine during a restart if ( ! is_restart ) { // Set the next time to the current time (*it)->set_next_tics( curr_tics ) ; } } else { // this is a one time event, test to see if the event time has past. if ( (*it)->get_next_tics() < curr_tics ) { // if the time has past, print warning and move to the next event. message_publish(MSG_WARNING, "One time event fire time has already past.\n") ; it = pending_events.erase(it) ; continue ; } } event_set.insert(*it) ; process_event_job->next_tics = (*(event_set.begin()))->get_next_tics() ; it = pending_events.erase(it) ; } }
int Trick::Integrator::integrate_1st_order_ode ( double const* derivs_in, double* state_in_out) { int rc; if (is_2nd_order_ODE_technique) { message_publish(MSG_ERROR, "Integrator ERROR: " "Current integrator is a 2nd order technique.\n"); return 0; } for (int ii = 0; ii < num_state; ++ii) { state[ii] = state_in_out[ii]; deriv[intermediate_step][ii] = derivs_in[ii]; } rc = integrate (); for (int ii = 0; ii < num_state; ++ii) { state_in_out[ii] = state_ws[intermediate_step][ii]; } return rc; }
//Shutdown job that writes the job timeline data to disk and closes log files. int Trick::FrameLog::shutdown() { /** @par Detailed Design: */ int thread, ii, jj; char log_buff[128]; Trick::timeline_t *tl; double start, stop, time_scale; if ( frame_log_flag == false ) { return(0) ; } /** @li Manually create the log_timeline and log_timeline_init files from saved timeline data. */ if (fp_time_main == NULL) { sprintf(log_buff, "%s/log_timeline.csv", command_line_args_get_output_dir()); if ((fp_time_main = fopen(log_buff, "w")) == NULL) { message_publish(MSG_ERROR, "Could not open log_timeline.csv file for Job Timeline Logging\n") ; exit(0); } fprintf(fp_time_main, "trick_frame_log.frame_log.job_time {s},"); fprintf(fp_time_main, "trick_frame_log.frame_log.job_trick_id {--},frame_log.frame_log.job_user_id {--}"); for (jj=1; jj<num_threads; jj++) { fprintf(fp_time_main, ",trick_frame_log.frame_log.job_userC%d_id {--}",jj); } fprintf(fp_time_main, "\n"); sprintf(log_buff, "%s/log_timeline_init.csv", command_line_args_get_output_dir()); if ((fp_time_other = fopen(log_buff, "w")) == NULL) { message_publish(MSG_ERROR, "Could not open log_timeline_init.csv file for Job Timeline Logging\n") ; exit(0); } fprintf(fp_time_other, "trick_frame_log.frame_log.job_init_time {s},"); fprintf(fp_time_other, "trick_frame_log.frame_log.job_trickinit_id {--},trick_frame_log.frame_log.job_userinit_id {--}\n"); } time_scale = 1.0 / exec_get_time_tic_value(); // print to log like this: // (only one of the job ids will be filled in depending on what type of job this is) // start job time, 0, 0 // start job time, trick job id, user job id // stop job time, trick job id, user job id // stop job time, 0, 0 /** @li print a 0 id before each start time & after each stop time for a stairstep effect in plot. */ // cyclic jobs for ( thread = 0 ; thread < num_threads ; thread++ ) { tl = timeline[thread]; for ( ii = 0 ; ii < tl_count[thread] ; ii++ ) { // start & stop time are in tics, so convert to seconds start = tl[ii].start * time_scale; stop = tl[ii].stop * time_scale; fprintf(fp_time_main, "%f,0", start); // start stairstep for (jj=0; jj<num_threads; jj++) { fprintf(fp_time_main, ",0"); } fprintf(fp_time_main, "\n"); if (tl[ii].trick_job) { fprintf(fp_time_main, "%f,%f", start, tl[ii].id); // trick job start for (jj=0; jj<num_threads; jj++) { fprintf(fp_time_main, ",0"); } } else { // user job fprintf(fp_time_main, "%f,0", start); // user job start for (jj=0; jj<num_threads; jj++) { if (jj==thread) { fprintf(fp_time_main, ",%f", tl[ii].id); // user thread id (0=main) } else { fprintf(fp_time_main, ",0"); } } } fprintf(fp_time_main, "\n"); if (tl[ii].trick_job) { fprintf(fp_time_main, "%f,%f", stop, tl[ii].id); // trick job end for (jj=0; jj<num_threads; jj++) { fprintf(fp_time_main, ",0"); } } else { // user job fprintf(fp_time_main, "%f,0", stop); // user job end for (jj=0; jj<num_threads; jj++) { if (jj==thread) { fprintf(fp_time_main, ",%f", tl[ii].id); // user thread id (0=main) } else { fprintf(fp_time_main, ",0"); } } } fprintf(fp_time_main, "\n"); fprintf(fp_time_main, "%f,0", stop); // end stairstep for (jj=0; jj<num_threads; jj++) { fprintf(fp_time_main, ",0"); } fprintf(fp_time_main, "\n"); } // end for thread } // end for ii // non-cyclic jobs for ( thread = 0 ; thread < num_threads ; thread++ ) { tl = timeline_other[thread]; for ( ii = 0 ; ii < tl_other_count[thread] ; ii++ ) { // start & stop time are in tics, so convert to seconds start = tl[ii].start * time_scale; stop = tl[ii].stop * time_scale; fprintf(fp_time_other, "%f,0,0\n", start); // start stairstep if (tl[ii].trick_job) { fprintf(fp_time_other, "%f,%f,0\n", start, tl[ii].id); // trick job start fprintf(fp_time_other, "%f,%f,0\n", stop, tl[ii].id); // trick job end } else { // user job fprintf(fp_time_other, "%f,0,%f\n", start, tl[ii].id); // user job start fprintf(fp_time_other, "%f,0,%f\n", stop, tl[ii].id); // user job end } fprintf(fp_time_other, "%f,0,0\n", stop); // end stairstep } // end for thread } // end for ii fclose(fp_time_main); fclose(fp_time_other); return(0) ; }
int Trick::VariableServerThread::write_binary_data( int Start, char *buf1, int PacketNum ) { int i; int ret ; int HeaderSize, MessageSize; int NumVariablesProcessed; unsigned int msg_type , offset, len ; unsigned int size ; unsigned int swap_int ; char * address = 0 ; char* param_name; //remove warning for unused PacketNum... to be deleted. (void)PacketNum ; /* start the offset 4 bytes into the message, we'll subtract the sizeof offset at the end */ offset = sizeof(msg_type) + sizeof(offset) ; /* if we are here the msg_type is good, so send a 0, swapped or not 0 is still 0 */ msg_type = VS_VAR_LIST ; memcpy(buf1, &msg_type , sizeof(msg_type)) ; HeaderSize = sizeof(msg_type); offset += sizeof(unsigned int) ; HeaderSize += sizeof(unsigned int); for (i = Start; i < (int)vars.size() ; i++) { // data to send was copied to buffer in copy_sim_data address = (char *)vars[i]->buffer_out; size = vars[i]->size ; param_name = vars[i]->ref->reference; len = strlen(param_name) ; // when var_binary_nonames, do not put the variable names into the message to be sent if (binary_data_nonames) { MessageSize = sizeof(int) + sizeof(size) + size ; } else { MessageSize = sizeof(len) + len + sizeof(int) + sizeof(size) + size ; } /* make sure this message will fit in a packet by itself */ if ( (HeaderSize + MessageSize) > MAX_MSG_LEN ) { message_publish(MSG_WARNING, "%p Variable Server buffer[%d] too small (need %d) for symbol %s, SKIPPING IT.\n", &connection, MAX_MSG_LEN, (int)(HeaderSize + MessageSize), vars[i]->ref->reference ); continue; } if ( (offset + MessageSize) < MAX_MSG_LEN ) { if (byteswap) { if (!binary_data_nonames) { swap_int = trick_byteswap_int((int)len) ; memcpy(&buf1[offset] , &swap_int , sizeof(len)) ; offset += sizeof(len) ; memcpy(&buf1[offset] , param_name , (size_t)len) ; offset += len ; } swap_int = trick_byteswap_int(vars[i]->ref->attr->type) ; memcpy(&buf1[offset] , &swap_int , sizeof(int)) ; offset += sizeof(int) ; swap_int = trick_byteswap_int((int)size) ; memcpy(&buf1[offset] , &swap_int , sizeof(size)) ; offset += sizeof(size) ; /* TODO: There is a bug here, this call will want to swap the entire buffer, we may not have the whole buffer */ trick_bswap_buffer(&buf1[offset], address, vars[i]->ref->attr, 1); offset += size ; } else { int temp_i ; unsigned int temp_ui ; if (!binary_data_nonames) { memcpy(&buf1[offset] , &len , sizeof(len)) ; offset += sizeof(len) ; memcpy(&buf1[offset] , param_name , (size_t)len) ; offset += len ; } memcpy(&buf1[offset] , &vars[i]->ref->attr->type , sizeof(int)) ; offset += sizeof(int) ; memcpy(&buf1[offset] , &size , sizeof(size)) ; offset += sizeof(size) ; switch ( vars[i]->ref->attr->type ) { case TRICK_BITFIELD: temp_i = GET_BITFIELD(address , vars[i]->ref->attr->size , vars[i]->ref->attr->index[0].start, vars[i]->ref->attr->index[0].size) ; memcpy(&buf1[offset] , &temp_i , (size_t)size) ; break ; case TRICK_UNSIGNED_BITFIELD: temp_ui = GET_UNSIGNED_BITFIELD(address , vars[i]->ref->attr->size , vars[i]->ref->attr->index[0].start, vars[i]->ref->attr->index[0].size) ; memcpy(&buf1[offset] , &temp_ui , (size_t)size) ; break ; case TRICK_NUMBER_OF_TYPES: // TRICK_NUMBER_OF_TYPES is an error case temp_i = 0 ; memcpy(&buf1[offset] , &temp_i , (size_t)size) ; break ; default: memcpy(&buf1[offset] , address , (size_t)size) ; break ; } offset += size ; } } else { /* indicate that we're over the maximum size */ if (debug >= 2) { message_publish(MSG_DEBUG, "%p tag=<%s> var_server buffer[%d] too small (need %d), sending multiple binary packets.\n", &connection, connection.client_tag, MAX_MSG_LEN, (int)(offset + MessageSize) ); } break ; } } /* adjust the header with the correct information reflecting what has been accomplished */ NumVariablesProcessed = i - Start; offset -= sizeof(offset) ; if (byteswap) { swap_int = trick_byteswap_int((int)offset) ; memcpy(buf1 + sizeof(msg_type) , &swap_int , sizeof(offset)) ; swap_int = trick_byteswap_int( NumVariablesProcessed ) ; memcpy( buf1 + sizeof(msg_type) + sizeof(offset), &swap_int , sizeof(swap_int)) ; } else { memcpy(buf1 + sizeof(msg_type) , &offset , sizeof(offset)) ; memcpy( buf1 + sizeof(msg_type) + sizeof(offset), &NumVariablesProcessed , sizeof( NumVariablesProcessed )) ; } if (debug >= 2) { message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending %u binary bytes containing %d variables.\n", &connection, connection.client_tag, (unsigned int)(offset + sizeof(offset)), NumVariablesProcessed); } len = offset + sizeof(msg_type) ; ret = tc_write(&connection, (char *) buf1, len); if ( ret != (int)len ) { return(-1) ; } /* return the index to the next symbol to send or V->num_vars if all done */ return i; }
int Trick::VariableServerThread::write_data() { int ret; unsigned int i ; char buf1[ MAX_MSG_LEN ]; int len ; // do not send anything when there are no variables! if ( vars.size() == 0 or packets_copied == 0 ) { return(0); } /* Acquire sole access to vars[ii]->buffer_in. */ if ( var_data_staged and pthread_mutex_trylock(©_mutex) == 0 ) { unsigned int ii; void * temp_p; // Swap buffer_in and buffer_out for each vars[ii]. for ( ii = 0 ; ii < vars.size() ; ii++ ) { temp_p = vars[ii]->buffer_in; vars[ii]->buffer_in = vars[ii]->buffer_out; vars[ii]->buffer_out = temp_p; } var_data_staged = false; /* Relinquish sole access to vars[ii]->buffer_in. */ pthread_mutex_unlock(©_mutex) ; if (binary_data) { int Index = 0; int PacketNumber = 0; do { ret = write_binary_data( Index, buf1, PacketNumber ); if ( ret >= 0 ) { Index = ret ; } else { return(-1) ; } PacketNumber++; } while( Index < (int)vars.size() ); } else { /* ascii mode */ char val[MAX_MSG_LEN]; sprintf(buf1, "0\t") ; for (i = 0; i < vars.size(); i++) { ret = vs_format_ascii( vars[i] , val); if (ret < 0) { message_publish(MSG_WARNING, "%p Variable Server string buffer[%d] too small for symbol %s, TRUNCATED IT.\n", &connection, MAX_MSG_LEN, vars[i]->ref->reference ); } /* make sure this message will fit in a packet by itself */ if( strlen( val ) + 2 > MAX_MSG_LEN ) { message_publish(MSG_WARNING, "%p Variable Server buffer[%d] too small for symbol %s, TRUNCATED IT.\n", &connection, MAX_MSG_LEN, vars[i]->ref->reference ); val[MAX_MSG_LEN - 1] = '\0'; } len = strlen(buf1) ; /* make sure there is space for the next tab or next newline and null */ if( len + strlen( val ) + 2 > MAX_MSG_LEN ) { if (debug >= 2) { message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending %d ascii bytes:", &connection, connection.client_tag, (int)strlen(buf1)) ; message_publish(MSG_NORMAL, "%s\n", buf1); } ret = tc_write(&connection, (char *) buf1, len); if ( ret != len ) { return(-1) ; } buf1[0] = '\0'; } strcat(buf1, val); strcat(buf1, "\t"); } len = strlen(buf1) ; if ( len > 0 ) { buf1[ strlen(buf1) - 1 ] = '\n'; if (debug >= 2) { message_publish(MSG_DEBUG, "%p tag=<%s> var_server sending %d ascii bytes:", &connection, connection.client_tag, (int)strlen(buf1)) ; message_publish(MSG_NORMAL, "%s\n", buf1); } ret = tc_write(&connection, (char *) buf1, (int)strlen(buf1)); if ( ret != (int)strlen(buf1) ) { return(-1) ; } } } } return (0); }
int Trick::SlaveInfo::start() { int arg_i; char *display; std::stringstream startup_command ; std::stringstream temp_stream ; struct passwd *passp; int argc ; char ** argv ; std::string slave = "undefined"; /** @par Detailed Design */ argc = command_line_args_get_argc() ; argv = command_line_args_get_argv() ; /** @li If the slave connection type is not specified return an error */ if ( connection == NULL ) { message_publish(MSG_ERROR , "Slave connection type not specified.\n") ; return(-1) ; } /** @li Start remote startup command with remote shell to use and remote machine name*/ switch ( remote_shell ) { case TRICK_RSH: startup_command << unix_rsh << " " << remote_shell_args ; break; case TRICK_USER_REMOTE_SH: if ( user_remote_shell.empty() ) { message_publish(MSG_WARNING , "TRICK_USER_REMOTE_SH specified for Slave startup, but no shell given.\nDefaulting to %s.\n", unix_ssh) ; user_remote_shell = unix_ssh ; } startup_command << user_remote_shell << " " << remote_shell_args ; break; case TRICK_SSH: default: startup_command << unix_ssh << " " << remote_shell_args ; break; } startup_command << " " << machine_name ; /** @li Add the remote display. If a remote display has not been specified, use the environment's */ if ( machine_display.empty() ) { if ((display = (char *) env_get_var("DISPLAY")) == NULL) { message_publish(MSG_ERROR, "Cannot get environment variable $DISPLAY for Slave.\n") ; } else { machine_display = display ; } } /** @li cd to the simulation path in the remote startup command */ if ( sim_path.empty() ) { message_publish(MSG_ERROR, "Slave startup sim_path is empty.\n") ; return(-1) ; } /** @li Set the DISPLAY environment variable in the remote startup command. Use setenv for *csh or export for all other shells */ passp = getpwuid(getuid()); if ( ! machine_display.empty() ) { if (strstr(passp->pw_shell, "csh")) { startup_command << " 'setenv DISPLAY " << machine_display ; } else { startup_command << " 'export DISPLAY=" << machine_display ; } startup_command << " ; cd " << sim_path << " ; " ; } else { startup_command << " 'cd " << sim_path << " ; " ; } if (strstr(passp->pw_shell, "csh")) { startup_command << " setenv TRICK_HOST_CPU `trick-gte TRICK_HOST_CPU` ; " ; } else { startup_command << " export TRICK_HOST_CPU=`trick-gte TRICK_HOST_CPU` ; " ; } /** @li start the simulation in the remote startup command */ if ( S_main_name.empty() ) { S_main_name = "./S_main_${TRICK_HOST_CPU}.exe" ; } startup_command << S_main_name ; /** @li add the user provided run input file if provided */ if ( ! run_input_file.empty() ) { startup_command << " " << run_input_file ; /** @li check to see if master is running with dmtcp slave */ if (run_input_file.find("dmtcp") != std::string::npos) slave_type = "dmtcp"; } /** @li Add the connection specific arguments to the startup command */ startup_command << " " << connection->add_sim_args( slave_type ) ; /* @li Add the additional user arguments to the remote command */ if ( ! other_args.empty() ) { startup_command << " -u " << other_args ; } for (arg_i = 2; arg_i < argc ; arg_i++) { startup_command << " " << argv[arg_i] ; } /* @li start the remote command in the background */ startup_command << "' &" ; message_publish(MSG_INFO, startup_command.str().c_str()) ; /* @li Execute the startup command */ if (system(startup_command.str().c_str())) { perror("Slave_start"); return (-2) ; } /* @li Wait for the slave to connect to the master */ connection->accept() ; /* @li Set the synchronization wait limit */ connection->set_sync_wait_limit(sync_wait_limit) ; /* Set slave to activated */ activated = true; return (0) ; }
int Trick::SlaveInfo::restart_dmtcp_slave() { #ifdef _DMTCP FILE *fp; char *dmtcp_path, line[256]; std::string config_file; std::string dmtcp_command; std::stringstream dmtcp_port_str; pid_t pid, dmtcp_pid; /** @par Detailed Design: */ if ( enabled ) { if (slave_type != "dmtcp") { message_publish(MSG_ERROR, "Cannot auto-start slave because it was not running under dmtcp control.\n") ; return(0); } /** @li If chkpnt_load_auto is specified, restart the slave by executing the user-supplied chkpnt_name... */ if (chkpnt_load_auto) { if (chkpnt_name[0] == MS_ERROR_NAME) { message_publish(MSG_WARNING, "Cannot auto-start slave because master did not receive chkpnt_name from slave.\n"); } else { /** @li First kill slave's dmtcp_coordinator because sometimes it does not quit like it's supposed to. */ if (dmtcp_port > 0) { // slave sends 0 if it can't get the port num from the environment /** @li Get dmtcp path from trick's configure output file (dmtcp is only supported in linux). */ config_file = std::string(getenv("TRICK_HOME")) + "/config_Linux.mk"; if ((fp = fopen(config_file.c_str() , "r")) != NULL ) { while (fgets(line, sizeof(line), fp) != NULL) { if (strncmp(line, "DMTCP", 5)==0) { dmtcp_path = strchr(line, '/'); dmtcp_path[strlen(dmtcp_path)-1] = '\0'; // remove newline character break; } } } /** @li Issue a dmtcp_command to kill the dmtcp_coordinator. */ fprintf(stderr, "Master attempting to kill slave's dmtcp_coordinator port= %ld" " (it may not exist, that's ok)\n", dmtcp_port); //dmtcp_command.str(""); // reset our command string dmtcp_command = dmtcp_path + std::string("/bin/dmtcp_command"); if (access(dmtcp_command.c_str(), F_OK) != 0) { fprintf(stderr, "\nCould not find %s in order to kill the dmtcp_coordinator.\n", dmtcp_command.c_str()); } else { //dmtcp_command << " --quiet -p " << dmtcp_port << " q"; message_publish(MSG_WARNING, "Restarting DMTCP coordinator\n"); if((dmtcp_pid = fork()) == 0) { setsid(); dmtcp_port_str << dmtcp_port; int execReturn = execl(dmtcp_command.c_str(), "dmtcp_command", "--quiet", "-p", dmtcp_port_str.str().c_str(), "q", NULL); _Exit(0); } else { int f_status = 0; if(dmtcp_pid > 0) { waitpid(dmtcp_pid, &f_status, 0); } else { message_publish(MSG_ERROR, "Unable to send DMTCP restart command\n"); } } //system(dmtcp_command.str().c_str()); } } // end if dmtcp_port > 0 /** @li Finally invoke the slave's dmtcp checkpoint script. */ message_publish(MSG_WARNING, "Auto-starting slave: %s.\n", chkpnt_name); if ((pid = fork()) == 0) { setsid(); std::istringstream sChkpnt(chkpnt_name); std::string fileName; while (std::getline(sChkpnt, fileName, '/')); //fprintf(stderr, "------> Starting: %s\n", fileName.c_str()); int execReturn = execl(chkpnt_name, fileName.c_str(), NULL); _Exit(0); } } } // end chkpnt_auto /** @li If our connection is a socket, disconnect the socket and call accept again */ if (dynamic_cast<MSSocket*>(connection)) { connection->disconnect(); //TODO: this will block until slave restarts, possibly causing overruns in freeze mode connection->accept(); } reconnect_count = 0; // start writing status to slave again } #endif return(0) ; }
int Trick::SlaveInfo::read_slave_status() { MS_SIM_COMMAND slave_command ; MS_SIM_COMMAND exec_command ; /** @par Detailed Design: */ /** @li If the slave is an active synchronization partner (activated == true) */ if (activated == true) { /** @li read the current slave exec_command */ slave_command = connection->read_command() ; //printf("DEBUG master read %d command from slave\n", slave_command);fflush(stdout); exec_command = (MS_SIM_COMMAND)exec_get_exec_command() ; // fixup: is it possible we won't get slave's Exit command over socket when it terminates?, set it here if that happens if (dynamic_cast<MSSocket*>(connection)) { if ((slave_command == MS_ErrorCmd) && (reconnect_wait_limit > 0.0) && (reconnect_count == 0)) { slave_command = MS_ExitCmd; } } /** @li If the master is not currently exiting, change modes if the slave is freezing/exiting or has an error */ if ( exec_command != MS_ExitCmd ) { switch ( slave_command ) { case (MS_ErrorCmd): /** @li if the user has set a reconnect_wait_limit, continue on if we are still under that limit, otherwise if the current slave mode cannot be read, exit the master if sync_error_terminate == true, otherwise set the activated flag to false */ if ( (reconnect_count * exec_get_freeze_frame()) < reconnect_wait_limit) { reconnect_count++; } else if (sync_error_terminate == true) { message_publish(MSG_ERROR, "Master lost sync with slave, so master is terminating.\n") ; exec_terminate_with_return(-1, __FILE__, __LINE__ , "Master lost sync with slave.") ; } else { message_publish(MSG_ERROR, "Master lost sync with slave, so slave is being deactivated.\n") ; activated = false ; return(0) ; } break ; case (MS_ExitCmd): /** @li if the current slave mode is exiting, exit the master if sync_error_terminate == true. otherwise wait for slave to reconnect. when wait limit is 0, set the activated flag to false */ if (sync_error_terminate == true){ message_publish(MSG_WARNING, "sync_error_terminate is true: Slave is exiting, so master is terminating.\n") ; exec_terminate_with_return(-1, __FILE__, __LINE__ , "Slave is exiting, so is the master.") ; } else { message_publish(MSG_WARNING, "Slave is exiting.\n") ; // if reconnect_wait_limit is set, master waits for slave to reconnect (e.g. dmtcp restarting) if (reconnect_wait_limit > 0.0) { message_publish(MSG_WARNING, "Master will wait %f seconds for slave to reconnect.\n", reconnect_wait_limit) ; // make reads (shared mem connection) return quickly so we don't overrun waiting for reconnect // TODO: for socket connection we will overrun in the accept call (see restart_dmtcp_slave) connection->set_sync_wait_limit(exec_get_freeze_frame()); if (chkpnt_binary) { restart_dmtcp_slave(); // restart the slave dmtcp executable } } else { message_publish(MSG_WARNING, "reconnect_wait_limit: 0.0 - Master will stop communicating with slave.\n") ; activated = false ; } return(0) ; } break ; case (MS_ChkpntLoadBinCmd): // slave has received our load command and is now sending us his dmtcp port and checkpoint file name dmtcp_port = connection->read_port() ; connection->read_name(chkpnt_name, sizeof(chkpnt_name)); // dir/filename message_publish(MSG_WARNING , "Master received DMTCP Port and Checkpoint Filename from slave.\n"); connection->write_command((MS_SIM_COMMAND)exec_get_exec_command()) ; // send this as an ack so slove can shut down break ; case (MS_FreezeCmd): /** @li if the current slave is freezing, freeze the master too */ message_publish(MSG_INFO, "Slave is freezing.\n") ; exec_set_exec_command(FreezeCmd) ; reconnect_count = 0; break ; case (MS_ReconnectCmd): // set the sync wait limit back to its default connection->set_sync_wait_limit(sync_wait_limit); message_publish(MSG_INFO, "Master has reconnected to slave.\n") ; reconnect_count = 0; break ; default: break ; } } } return(0) ; }
//Create the DP files to display job timelines. int Trick::FrameLog::create_DP_timeline_files() { FILE *fpx; int jj; std::string DP_buff; const char *headerx = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n" \ "<!DOCTYPE product PUBLIC \"-//Tricklab//DTD Product V1.0//EN\" \"Product.dtd\">\n\n" \ "<!-- Description: Plot of Y(t) vs. t, with attributes, titles, labels, units -->\n\n" \ "<product version=\"1.0\">\n"; // DP_rt_timeline -------------------------------------------------------------- DP_buff = DP_dir + "/DP_rt_timeline.xml"; if ((fpx = fopen(DP_buff.c_str(), "w")) == NULL) { message_publish(MSG_WARNING, "Could not open DP_rt_timeline.xml file for Frame Logging\n") ; return(0); } fprintf(fpx, "%s", headerx); fprintf(fpx, " <title>Job Timeline</title>\n <page vcells=\"3\">\n <title>Job Timeline</title>\n"); fprintf(fpx, " <plot grid=\"yes\">\n <title>User Job Timeline</title>\n"); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Job Id</label> </yaxis>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"red\" label=\"User Job Id\">trick_frame_log.frame_log.job_user_id</var>\n") ; fprintf(fpx, " </curve>\n"); fprintf(fpx, " </plot>\n"); fprintf(fpx, " <plot grid=\"yes\">\n <title>Trick Job Timeline</title>\n"); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Job Id</label> </yaxis>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"darkgreen\" label=\"Trick Job Id\">trick_frame_log.frame_log.job_trick_id</var>\n") ; fprintf(fpx, " </curve>\n"); fprintf(fpx, " </plot>\n"); // don't generate the plot without a curve if (num_threads > 1) { fprintf(fpx, " <plot grid=\"yes\">\n <title>Child Job Timeline</title>\n"); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Job Id</label> </yaxis>\n"); for (jj=1; jj<num_threads; jj++) { fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"blue\" label=\"Child%d Job Id\">trick_frame_log.frame_log.job_userC%d_id</var>\n", jj,jj); fprintf(fpx, " </curve>\n"); } fprintf(fpx, " </plot>\n"); } fprintf(fpx, " </page>\n"); fprintf(fpx, " <page>\n <title>Job Timeline (combined)</title>\n"); fprintf(fpx, " <plot grid=\"yes\">\n <title>User and Trick Job Timeline</title>\n"); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Job Id</label> </yaxis>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"darkgreen\" label=\"Trick Job Id\">trick_frame_log.frame_log.job_trick_id</var>\n") ; fprintf(fpx, " </curve>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"red\" label=\"User Job Id\">trick_frame_log.frame_log.job_user_id</var>\n"); fprintf(fpx, " </curve>\n"); for (jj=1; jj<num_threads; jj++) { fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"blue\" label=\"Child%d Job Id\">trick_frame_log.frame_log.job_userC%d_id</var>\n", jj,jj); fprintf(fpx, " </curve>\n"); } fprintf(fpx, " </plot>\n"); fprintf(fpx, " </page>\n</product>"); fclose(fpx); // DP_rt_timeline_init --------------------------------------------------------- DP_buff = DP_dir + "/DP_rt_timeline_init.xml"; if ((fpx = fopen(DP_buff.c_str(), "w")) == NULL) { message_publish(MSG_WARNING, "Could not open DP_rt_timeline_init.xml file for Frame Logging\n") ; return(0); } fprintf(fpx, "%s", headerx); fprintf(fpx, " <title>Non-cyclic Job Timeline</title>\n <page>\n <title>Non-cyclic Job Timeline</title>\n"); fprintf(fpx, " <plot grid=\"yes\">\n <title>User Job Timeline</title>\n"); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Job Id</label> </yaxis>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"red\" label=\"User Job Id\">trick_frame_log.frame_log.job_userinit_id</var>\n") ; fprintf(fpx, " </curve>\n"); fprintf(fpx, " </plot>\n"); fprintf(fpx, " <plot grid=\"yes\">\n <title>Trick Job Timeline</title>\n"); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Job Id</label> </yaxis>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"darkgreen\" label=\"Trick Job Id\">trick_frame_log.frame_log.job_trickinit_id</var>\n") ; fprintf(fpx, " </curve>\n"); fprintf(fpx, " </plot>\n"); fprintf(fpx, " </page>\n"); fprintf(fpx, " <page>\n <title>Non-cyclic Job Timeline (combined)</title>\n"); fprintf(fpx, " <plot grid=\"yes\">\n <title>User and Trick Job Timeline</title>\n"); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Job Id</label> </yaxis>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"darkgreen\" label=\"Trick Job Id\">trick_frame_log.frame_log.job_trickinit_id</var>\n"); fprintf(fpx, " </curve>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"red\" label=\"Trick Job Id\">trick_frame_log.frame_log.job_userinit_id</var>\n"); fprintf(fpx, " </curve>\n"); fprintf(fpx, " </plot>\n"); fprintf(fpx, " </page>\n</product>"); fclose(fpx); return(0); }
//Create the DP files to display trick and user job execution times. int Trick::FrameLog::create_DP_job_files() { std::vector<std::string>::iterator job_iterator; FILE *fpx; int pages, plots, total_plots, vcells, dot; char *bg_color; double time_scale; std::string DP_buff; const char *headerx = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n" \ "<!DOCTYPE product PUBLIC \"-//Tricklab//DTD Product V1.0//EN\" \"Product.dtd\">\n\n" \ "<!-- Description: Plot of Y(t) vs. t, with attributes, titles, labels, units -->\n\n" \ "<product version=\"1.0\">\n"; time_scale = 1.0 / exec_get_time_tic_value(); DP_buff = DP_dir + "/DP_rt_frame.xml"; if ((fpx = fopen(DP_buff.c_str(), "w")) == NULL) { message_publish(MSG_WARNING, "Could not open DP_rt_frame.xml file for Frame Logging\n") ; return(0); } fprintf(fpx, "%s", headerx); fprintf(fpx, " <title>Real-Time Frame Overrun/Underrun History</title>\n <page>\n <title>Real-Time Scheduling Frame</title>\n"); fprintf(fpx, " <plot grid=\"yes\">\n <title>Frame Overrun/Underrun</title>\n"); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Frame Overrun/Underrun</label> </yaxis>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var scale=\"%g\" line_color=\"darkgreen\" label=\"Overrun/Underrun\">%s.rt_sync.frame_overrun_time</var>\n", time_scale,rt_sim_object_name.c_str()); fprintf(fpx, " </curve>\n"); fprintf(fpx, " </plot>\n"); fprintf(fpx, " <plot grid=\"yes\">\n <title>Frame Scheduled Jobs Time</title>\n"); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Frame Scheduled Jobs Time</label> </yaxis>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var scale=\"%g\" line_color=\"red\" label=\"Frame Sched Time\">%s.rt_sync.frame_sched_time</var>\n", time_scale,rt_sim_object_name.c_str()); fprintf(fpx, " </curve>\n"); fprintf(fpx, " </plot>\n"); fprintf(fpx, " </page>\n"); //unsigned int total_pages = (unsigned int)(drg_users.size() / 8) + 1 ; unsigned int total_pages ; if ( drg_users.size() <= 1 ) { total_pages = 1 ; } else { total_pages = (unsigned int)((drg_users.size() - 2)/ 8) + 1 ; } unsigned int page_count ; for ( page_count = 0 ; page_count < total_pages ; page_count++ ) { unsigned int ii = 0 ; // this check is to avoid empty page creation if ((page_count * 8 + ii + 1) >= drg_users.size()) { continue; } fprintf(fpx, " <page>\n"); for ( ii = 0 ; ii < 8 and (page_count * 8 + ii + 1) < drg_users.size() ; ii++ ) { fprintf(fpx, " <plot grid=\"yes\">\n"); fprintf(fpx, " <title>Child thread %d Frame Scheduled Jobs</title>\n", (page_count * 8 + ii + 1)); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Frame Scheduled Jobs Time</label> </yaxis>\n"); fprintf(fpx, " <curve>\n"); fprintf(fpx, " <var>sys.exec.out.time</var>\n"); std::ostringstream group_name ; group_name << "frame_userjobs_C" << (page_count * 8 + ii + 1) ; fprintf(fpx, " <var scale=\"%g\" line_color=\"red\" label=\"Frame Sched Time\">%s.frame_sched_time</var>\n", time_scale,group_name.str().c_str()); fprintf(fpx, " </curve>\n"); fprintf(fpx, " </plot>\n"); } fprintf(fpx, " </page>\n"); } fprintf(fpx, " <table>\n <title>Real-Time Frame Overrun/Underrun History</title>\n"); fprintf(fpx, " <column format=\"%%13.6f\">\n"); fprintf(fpx, " <label>Sim Time</label>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " </column>\n"); fprintf(fpx, " <column format=\"%%13.6f\">\n"); fprintf(fpx, " <label>Overrun/Underrun</label>\n <var scale=\"%g\">%s.rt_sync.frame_overrun_time</var>\n", time_scale,rt_sim_object_name.c_str()); fprintf(fpx, " </column>\n"); fprintf(fpx, " <column format=\"%%13.6f\">\n"); fprintf(fpx, " <label>Frame Sched Time</label>\n <var scale=\"%g\">%s.rt_sync.frame_sched_time</var>\n", time_scale,rt_sim_object_name.c_str()); fprintf(fpx, " </column>\n"); fprintf(fpx, " </table>\n</product>"); fclose(fpx); // sort the saved job names sort(user_jobs.begin(), user_jobs.end()); sort(trick_jobs.begin(), trick_jobs.end()); // DP_rt_userjobs -------------------------------------------------------------- int ii ; char numstr[21]; for ( ii = 0 ; ii < num_threads ; ii++ ) { if ( ii == 0 ) { DP_buff = DP_dir + "/DP_rt_userjobs.xml"; } else { sprintf(numstr, "%d", ii); DP_buff = DP_dir + "/DP_rt_userjobs_C" + numstr + ".xml"; } if ((fpx = fopen(DP_buff.c_str(), "w")) == NULL) { message_publish(MSG_WARNING, "Could not open DP_rt_userjobs.xml file for Frame Logging\n") ; return(0); } fprintf(fpx, "%s", headerx); fprintf(fpx, " <title>User Job Execution History</title>\n"); pages = 0; plots = 0; total_plots = drg_users[ii]->rec_buffer.size(); std::vector <Trick::DataRecordBuffer *>::iterator drb_it ; bg_color = (char *)"cornsilk2"; for ( drb_it = drg_users[ii]->rec_buffer.begin() + 1 ; drb_it != drg_users[ii]->rec_buffer.end() ; drb_it++ ) { if ( ! (*drb_it)->name.compare(0, 5, "frame") ) continue ; // 8 job plots per page if ((plots == 0) || (plots > 8)) { pages++; vcells = (total_plots/pages > 8) * 4; if (pages > 1) { fprintf(fpx, " </page>\n"); } fprintf(fpx, " <page vcells=\"%d\">\n <title>User Job Execution Times</title>\n", vcells); plots = 1; } fprintf(fpx, " <plot grid=\"yes\" background_color=\"%s\">\n <title>%s</title>\n", bg_color, (*drb_it)->name.c_str()); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Execution Time</label> </yaxis>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"red\" scale=\"%g\">%s</var>\n", time_scale, (*drb_it)->name.c_str()); fprintf(fpx, " </curve>\n"); fprintf(fpx, " </plot>\n"); plots++; } fprintf(fpx, " </page>\n</product>"); fclose(fpx); } // DP_rt_trickjobs ------------------------------------------------------------- DP_buff = DP_dir + "/DP_rt_trickjobs.xml"; if ((fpx = fopen(DP_buff.c_str(), "w")) == NULL) { message_publish(MSG_WARNING, "Could not open DP_rt_trickjobs.xml file for Frame Logging\n") ; return(0); } fprintf(fpx, "%s", headerx); fprintf(fpx, " <title>Trick Job Execution History</title>\n"); pages = 0; plots = 0; total_plots = trick_jobs.size(); job_iterator = trick_jobs.begin(); while (job_iterator != trick_jobs.end()) { dot = (*job_iterator).find_first_of("."); // default background color, for trick_whatever jobs and anything else we don't list here bg_color = (char *)"cornsilk3"; // give the different types of trick jobs a different background color if (!(*job_iterator).compare(0,dot,std::string("JOB_") + msg_sim_object_name)) { bg_color = (char *)"lavenderblush3"; } if (!(*job_iterator).compare(0,dot,std::string("JOB_") + dr_sim_object_name) || !(*job_iterator).compare(0,21,std::string("JOB_data_record_group")) ) { bg_color = (char *)"slategray2"; } if (!(*job_iterator).compare(0,dot,std::string("JOB_") + rt_sim_object_name)) { bg_color = (char *)"honeydew3"; } if (!(*job_iterator).compare(0,dot,std::string("JOB_") + ms_sim_object_name)) { bg_color = (char *)"bisque2"; } if (strncmp((*job_iterator).c_str(),"JOB_sys_integ",13)==0) { bg_color = (char *)"burlywood"; } //other good colors in case you need more: //bg_color = "khaki3"; // 8 job plots per page if ((plots == 0) || (plots > 8)) { pages++; vcells = (total_plots/pages > 8) * 4; if (pages > 1) { fprintf(fpx, " </page>\n"); } fprintf(fpx, " <page vcells=\"%d\">\n <title>Trick Job Execution Times</title>\n", vcells); plots = 1; } fprintf(fpx, " <plot grid=\"yes\" background_color=\"%s\">\n <title>%s</title>\n", bg_color, (*job_iterator).c_str()); fprintf(fpx, " <xaxis> <label>Time</label> <units>s</units> </xaxis>\n"); fprintf(fpx, " <yaxis> <label>Execution Time</label> </yaxis>\n"); fprintf(fpx, " <curve>\n <var>sys.exec.out.time</var>\n"); fprintf(fpx, " <var line_color=\"darkgreen\" scale=\"%g\">%s</var>\n", time_scale, (*job_iterator).c_str()); fprintf(fpx, " </curve>\n"); fprintf(fpx, " </plot>\n"); job_iterator++; plots++; } fprintf(fpx, " </page>\n</product>"); fclose(fpx); return(0) ; }