/** @details -# If real-time synchronization has been enabled: -# Set the active flag to true. -# If real-time synchronization has been disabled set the active flag to false. */ int Trick::RealtimeSync::initialize() { if ( enable_flag ) { active = true ; enable_flag = false ; } if ( disable_flag ) { active = false ; disable_flag = false ; } tics_per_sec = exec_get_time_tic_value(); /* Start the sleep timer hardware if realtime is active */ start_sleep_timer(); if ( align_sim_to_wall_clock ) { rt_clock->sync_to_wall_clock( align_tic_mult , tics_per_sec ) ; message_publish(MSG_INFO, "Syncing sim to %f second wall clock interval\n", align_tic_mult ) ; if ( exec_get_mode() == Freeze ) { rt_clock->clock_spin(exec_get_freeze_time_tics()) ; } else { rt_clock->clock_spin(exec_get_time_tics()) ; } } return(0) ; }
int Trick::Master::init() { unsigned int ii ; /** @li Call Trick::SlaveInfo::start() for each slave */ if ( enabled ) { for ( ii = 0 ; ii < slaves.size() ; ii++ ) { slaves[ii]->start() ; /** @li Write the master's software frame to each slave */ slaves[ii]->connection->write_time(exec_get_software_frame_tics()) ; /** @li Write the master's time tic value to each slave */ slaves[ii]->connection->write_time(exec_get_time_tic_value()) ; /** @li Write the master's sync_wait_limit to each slave */ slaves[ii]->connection->write_time((long long)(slaves[ii]->sync_wait_limit * exec_get_time_tic_value())) ; /** @li Cast the freeze command and write it to the slave */ slaves[ii]->connection->write_command((MS_SIM_COMMAND)exec_get_freeze_command()) ; /** @li Write a flag word containing the checkpoint pre_init, post_init, and end flags to the slave */ slaves[ii]->connection->write_time((long long) ((get_checkpoint_pre_init() << 2) + (get_checkpoint_post_init() << 1) + (get_checkpoint_end())) ); } // Freezes are only allowed on frame boundaries when Master/Slave is enabled. exec_set_freeze_on_frame_boundary(true) ; } return(0) ; }
TEST_F(ExecutiveTest , JobCycleNotDivisibleByTimeTic) { //req.add_requirement("r_exec_jobs"); //"The Executive Scheduler shall provide the capability to list jobs not handled by any scheduler." EXPECT_EQ(exec_get_time_tic_value(), 1000000) ; exec_add_sim_object(&empty_so , "empty_so") ; EXPECT_EQ(exec.check_all_job_cycle_times() , -1 ) ; }
Trick::VariableServerThread::VariableServerThread(TCDevice * in_listen_dev) : Trick::ThreadBase("VarServer") , listen_dev(in_listen_dev) { debug = 0 ; enabled = true ; log = false ; connection_accepted = false ; conn_type = TCP ; copy_mode = VS_COPY_ASYNC ; write_mode = VS_WRITE_ASYNC ; frame_multiple = 1 ; frame_offset = 0 ; freeze_frame_multiple = 1 ; freeze_frame_offset = 0 ; binary_data = false; multicast = false; byteswap = false ; retry_bad_ref = false ; pause_cmd = false ; exit_cmd = false ; send_stdio = false ; update_rate = 0.1 ; cycle_tics = (long long)(update_rate * exec_get_time_tic_value()) ; next_tics = TRICK_MAX_LONG_LONG ; freeze_next_tics = TRICK_MAX_LONG_LONG ; connection.disabled = TC_COMM_FALSE ; connection.disable_handshaking = TC_COMM_TRUE ; connection.blockio_limit = 0.0 ; connection.blockio_type = TC_COMM_BLOCKIO ; connection.client_id = 0 ; connection.dmtcp_use_real = 1 ; strcpy(connection.client_tag, "") ; connection.error_handler = (TrickErrorHndlr *) calloc(1, (int)sizeof(TrickErrorHndlr)); connection.error_handler->report_level = TRICK_ERROR_CAUTION; pthread_mutex_init(©_mutex, NULL); var_data_staged = false; packets_copied = 0 ; incoming_msg = (char *) calloc(1, MAX_CMD_LEN); stripped_msg = (char *) calloc(1, MAX_CMD_LEN); }
//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) ; }
//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::copy_sim_data() { unsigned int ii ; VariableReference * curr_var ; if ( vars.size() == 0 ) { return 0 ; } if ( pthread_mutex_trylock(©_mutex) == 0 ) { // Get the simulation time we start this copy time = (double)exec_get_time_tics() / exec_get_time_tic_value() ; for ( ii = 0 ; ii < vars.size() ; ii++ ) { curr_var = vars[ii] ; // if this variable is unresolved, try to resolve it if ( retry_bad_ref ) { if (curr_var->ref->address == &bad_ref_int) { REF2 *new_ref = ref_attributes(const_cast<char*>(curr_var->ref->reference)); if (new_ref != NULL) { curr_var->ref = new_ref; } } } // if there's a pointer somewhere in the address path, follow it in case pointer changed if ( curr_var->ref->pointer_present == 1 ) { curr_var->address = follow_address_path(curr_var->ref) ; if ( curr_var->address == NULL ) { std::string save_name(curr_var->ref->reference) ; if ( curr_var->ref->attr) { free(curr_var->ref->attr) ; } free(curr_var->ref) ; curr_var->ref = make_error_ref(save_name) ; curr_var->address = curr_var->ref->address ; } else { curr_var->ref->address = curr_var->address ; } } // if this variable is a string we need to get the raw character string out of it. if (( curr_var->string_type == TRICK_STRING ) && !curr_var->need_deref) { std::string * str_ptr = (std::string *)curr_var->ref->address ; curr_var->address = (void *)(str_ptr->c_str()) ; } // if this variable itself is a pointer, dereference it if ( curr_var->need_deref) { curr_var->address = *(void**)curr_var->ref->address ; } // handle c++ string and char* if ( curr_var->string_type == TRICK_STRING ) { if (curr_var->address == NULL) { curr_var->size = 0 ; } else { curr_var->size = strlen((char*)curr_var->address) + 1 ; } } // handle c++ wstring and wchar_t* if ( curr_var->string_type == TRICK_WSTRING ) { if (curr_var->address == NULL) { curr_var->size = 0 ; } else { curr_var->size = wcslen((wchar_t *)curr_var->address) * sizeof(wchar_t); } } memcpy( curr_var->buffer_in , curr_var->address , curr_var->size ) ; } retry_bad_ref = false ; // Indicate that sim data has been written and is now ready in the buffer_in's of the vars variable list. var_data_staged = true; packets_copied++ ; pthread_mutex_unlock(©_mutex) ; } return (0) ; }
TEST_F(ExecutiveTest , DefaultTimeTicValue) { //req.add_requirement("2436759852"); // "The Executive Scheduler shall default to 1,000,000 tics/second") ; EXPECT_EQ(exec_get_time_tic_value(), 1000000) ; }
int Trick::VariableServerThread::var_cycle(double in_rate) { update_rate = in_rate ; cycle_tics = (long long)(update_rate * exec_get_time_tic_value()) ; return(0) ; }