Allow for read only S_sie.resource (#1420)

This commit is contained in:
Jacqueline Deans 2023-04-17 17:23:48 -05:00 committed by GitHub
parent 7d2d5d870c
commit d76de7e1ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 524 additions and 14 deletions

View File

@ -12,6 +12,7 @@ S_main_${TRICK_HOST_CPU}.exe [trick_version] [sie]
RUN_<name>/<input_file_name> [-d]
[-O <output_file_path>]
[-OO <output_file_path>]
[--read-only-sim]
[-u <user_defined_arguments>]
```
@ -21,6 +22,7 @@ S_main_${TRICK_HOST_CPU}.exe [trick_version] [sie]
- The '-d' argument is optional and, if specified, starts the simulation in an input file verification mode. In this mode the entire input file is read, echoed to standard out, and then the simulation exits without calling any jobs listed in the S_define file. This mode helps debug input file syntax errors.
- The '-O <output_file_path>' option allows the user to specify the directory to which simulation data log files will be written. If this option is omitted, the RUN_<name> directory is used.
- The '-OO <output_file_path>' option allows the user to specify the directory to which ALL simulation output files will be written. If this option is omitted, the RUN_<name> directory is used.
- The '--read-only-sim' flag can be used to redirect all files written at simulation runtime into the output directory.
- The '-u' option specifies that all remaining arguments are meant to be used by user supplied jobs. All arguments after the -u can be accessed internal to the simulation jobs by calling the get_cmnd_args() function of the executive as illustrated below. In a master/slave simulation, the master's -u args will be passed to the slave.
The following code example shows how a function can access the command line arguments during execution.

View File

@ -139,6 +139,9 @@ namespace Trick {
*/
void set_output_dir(std::string output_directory) ;
// Helper method to create full path
static int create_path(const std::string& dirname);
} ;
}

View File

@ -43,9 +43,11 @@ namespace Trick {
void sie_print_json() ;
void sie_append_runtime_objs() ;
void runtime_objects_print(std::fstream & sie_out) ;
std::string get_runtime_sie_dir();
private:
// These are called at trick-cp time
void top_level_objects_print(std::ofstream & sie_out) ;
void top_level_objects_json(std::ofstream & sie_out) ;
@ -53,6 +55,8 @@ namespace Trick {
Trick::AttributesMap * class_attr_map ; /* ** -- This is be ignored by ICG */
Trick::EnumAttributesMap * enum_attr_map ; /* ** -- This is be ignored by ICG */
bool move_runtime_generation;
} ;
}

View File

@ -8,6 +8,7 @@ void sie_class_attr_map_print_xml(void) ;
void sie_enum_attr_map_print_xml(void) ;
void sie_top_level_objects_print_xml(void) ;
void sie_append_runtime_objs(void) ;
std::string sie_get_runtime_sie_dir(void);
#ifdef __cplusplus
}

View File

@ -229,6 +229,7 @@ class SieSimObject : public Trick::SimObject {
Trick::Sie sie ;
SieSimObject() {
{TRK} P0 ("default_data") sie.process_sim_args() ;
// We now append runtime objects when sie is requested by variable server instead.
// {TRK} P65535 ("initialization") sie.sie_append_runtime_objs() ;
}

9
test/SIM_test_output_dir/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
.trick
MONTE_RUN_*
*log.csv
S_main*
*.resource
S_source.hh
build
makefile
trick.zip

View File

@ -0,0 +1,7 @@
trick.stop(15.0);
# trick.real_time_enable()
# trick.sim_control_panel_set_enabled(True)
trick.sie_append_runtime_objs()

View File

@ -0,0 +1,34 @@
/************************TRICK HEADER*************************
PURPOSE:
()
LIBRARY DEPENDENCIES:
*************************************************************/
#include "sim_objects/default_trick_sys.sm"
##include "starter.h"
class StarterSimObject : public Trick::SimObject {
public:
Starter starter;
StarterSimObject() {
("default_data") trick_ret = starter.default_data();
("initialization") trick_ret = starter.init();
(5.0, "scheduled") trick_ret = starter.scheduled();
("shutdown") starter.shutdown();
// ("derivative") trick_ret = starter.deriv();
// ("integration") trick_ret = starter.integ();
}
};
StarterSimObject starterSimObject;
IntegLoop integLoop (0.01) starterSimObject;
/*
void create_connections() {
integLoop.getIntegrator(Runge_Kutta_4, <NUMBER_OF_VARIABLES>);
}
*/

View File

@ -0,0 +1,8 @@
TRICK_CFLAGS += -I./models
TRICK_CXXFLAGS += -I./models
clean: output_clean
output_clean:
rm -rf sim_output

View File

@ -0,0 +1,44 @@
/*************************************************************************
PURPOSE: (A sim object that is allocated at runtime)
LIBRARY DEPENDENCY:
(
)
**************************************************************************/
#include "sim_services/SimObject/include/SimObject.hh"
class DynamicObj : public Trick::SimObject {
// This class should be allocated dynamically
public:
DynamicObj() {}
int doSomething () {
// Do something that we can test for here i guess
return 0;
}
/**
* Calls all jobs that are not "dynamic_event" class
* @param curr_job - the current job instance
* @return always 0
*/
virtual int call_function( Trick::JobData * curr_job ) {
return 0;
}
/**
* Calls all jobs that are "dynamic_event" class
* @param curr_job - the current job instance
* @return always 0
*/
virtual double call_function_double( Trick::JobData * curr_job ) {
return 0;
}
int a;
std::string b;
double * c;
};

View File

@ -0,0 +1,66 @@
#include <cstdio>
#include "starter.h"
#include "trick/integrator_c_intf.h"
#include "trick/exec_proto.h"
#include "trick/message_proto.h"
#include "trick/mm_macros.hh"
Starter::Starter() {
}
int Starter::default_data() {
// Allocate a dynamic object
DynamicObj * obj = new DynamicObj() ;
obj->a = 5;
obj->b = "Hello world!";
obj->c = (double *) malloc (sizeof(double) * 3);
obj->c[0] = 0.0;
obj->c[1] = 1.0;
obj->c[2] = 2.0;
TMM_declare_ext_var(obj, TRICK_STRUCTURED,"DynamicObj", 0, "DynamicObj_alloc", 0, NULL) ;
return 0;
}
int Starter::init() {
return 0;
}
int Starter::scheduled() {
message_publish(MSG_NORMAL, "Hello World!\n");
return 0;
}
int Starter::deriv() {
return 0;
}
int Starter::integ() {
int ipass;
load_state(
NULL /* list is NULL terminated */
);
/* LOAD THE POSITION AND VELOCITY STATE DERIVATIVES */
load_deriv(
NULL /* list is NULL terminated */
);
/* Call the Trick integrate service */
ipass = integrate();
/* unload new state */
unload_state(
NULL /* list is NULL terminated */
);
/* returns 0 if integerate() was successful */
return ipass;
}
int Starter::shutdown() {
return 0;
}

View File

@ -0,0 +1,21 @@
/*************************************************************************
PURPOSE: (Starter class)
LIBRARY DEPENDENCY:
(
(starter.cpp)
)
**************************************************************************/
#include "dynamic_obj.h"
class Starter {
public:
Starter();
int default_data();
int init();
int scheduled();
int deriv();
int integ();
int shutdown();
};

View File

@ -0,0 +1,20 @@
import sys
if len(sys.argv) != 3:
print ("Usage: check_file_endings.py <ref_file> <cmp_file>")
exit(1)
ref_file = sys.argv[1]
cmp_file = sys.argv[2]
ref_lines = reversed(list(open(ref_file)))
cmp_lines = reversed(list(open(cmp_file)))
for ref_line, cmp_line in zip(ref_lines, cmp_lines):
if (ref_line != cmp_line):
print("Difference in files: ", ref_line, "vs", cmp_line)
exit(1)
print("Success!")
exit(0)

View File

@ -0,0 +1,5 @@
<!--
Runtime Allocations
Do not edit this comment or file content past this point
-->
</sie>

View File

@ -0,0 +1,35 @@
<!--
Runtime Allocations
Do not edit this comment or file content past this point
-->
<top_level_object
name="DynamicObj_alloc"
type="DynamicObj"
alloc_memory_init="0">
</top_level_object>
<top_level_object
name="trick_frame"
type="Trick__FrameDataRecordGroup"
alloc_memory_init="0">
</top_level_object>
<top_level_object
name="trick_frame_trick_jobs"
type="Trick__FrameDataRecordGroup"
alloc_memory_init="0">
</top_level_object>
<top_level_object
name="trick_frame_userjobs_main"
type="Trick__FrameDataRecordGroup"
alloc_memory_init="0">
</top_level_object>
<top_level_object
name="trick_injector_executor_0"
type="InjectorExecSimObject"
alloc_memory_init="0">
</top_level_object>
</sie>

View File

@ -284,6 +284,18 @@ SIM_events:
returns: 255
SIM_test_output_dir:
path: test/SIM_test_output_dir
build_args: "-t"
binary: "T_main_{cpu}_test.exe"
runs:
RUN_test/input.py -OO sim_output --read-only-sim:
returns: 0
analyze: 'python3 test/SIM_test_output_dir/ref_files/check_file_endings.py test/SIM_test_output_dir/ref_files/ref_compiletime_S_sie.resource test/SIM_test_output_dir/S_sie.resource'
analyze: 'python3 test/SIM_test_output_dir/ref_files/check_file_endings.py test/SIM_test_output_dir/ref_files/ref_runtime_S_sie.resource test/SIM_test_output_dir/sim_output/S_sie.resource'
# The variable server client and SIM_amoeba sometimes fail to connect and need to be retried
SIM_test_varserv:
path: test/SIM_test_varserv

View File

@ -20,6 +20,9 @@
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include "trick/CommandLineArguments.hh"
#include "trick/memorymanager_c_intf.h"
@ -84,6 +87,54 @@ std::string & Trick::CommandLineArguments::get_cmdline_name_ref() {
return(cmdline_name) ;
}
// Helper function - create a full path with error checking along the way
int Trick::CommandLineArguments::create_path(const std::string& dirname) {
size_t cur_index = 0;
std::string full_dir (dirname);
// These syscalls don't seem to take care of home special character, so do it manually
// I think the shell should handle it before it gets here, but just in case check for it
if (dirname.at(0) == '~') {
struct passwd *pw = getpwuid(getuid());
full_dir = std::string(pw->pw_dir) + dirname.substr(1, dirname.size());
}
while (cur_index != full_dir.size()) {
cur_index = full_dir.find('/', cur_index+1);
if (cur_index == std::string::npos) {
cur_index = full_dir.size();
}
std::string cur_dir = full_dir.substr(0, cur_index);
struct stat info;
if(stat( cur_dir.c_str(), &info ) != 0) {
// does not exist - make it
if (mkdir(cur_dir.c_str(), 0775) == -1) {
std::cerr << "Error creating directory " << cur_dir << std::endl;
return 1;
}
} else {
// Does exist
if(info.st_mode & S_IFDIR) {
// Is a directory
if (info.st_mode & S_IWUSR) {
// Perfect, nothing to do here
} else {
// Not writeable
std::cerr << "Intermediate directory " << cur_dir << " is not writable, unable to create output directory." << std::endl;
return 1;
}
} else {
// Does exist, but is a file
std::cerr << "Intermediate directory " << cur_dir << " is not a directory, unable to create output directory." << std::endl;
return 1;
}
}
}
return 0;
}
/**
@details
-# Save the number of command line arguments.
@ -209,7 +260,7 @@ int Trick::CommandLineArguments::process_sim_args(int nargs , char **args) {
/* Create output directory if necessary. */
if (access(output_dir.c_str(), F_OK) != 0) {
if (mkdir(output_dir.c_str(), 0775) == -1) {
if (create_path(output_dir) != 0) {
std::cerr << "\nERROR: While trying to create output directory \"" << output_dir << "\" : " << std::strerror(errno) << std::endl ;
exit(1) ;
}

View File

@ -0,0 +1,2 @@
create_path_test
*.o

View File

@ -0,0 +1,42 @@
#SYNOPSIS:
#
# make [all] - makes everything.
# make TARGET - makes the given target.
# make clean - removes all files generated by make.
include $(dir $(lastword $(MAKEFILE_LIST)))../../../../share/trick/makefiles/Makefile.common
# Replace -isystem with -I so ICG doesn't skip Trick headers
TRICK_SYSTEM_CXXFLAGS := $(subst -isystem,-I,$(TRICK_SYSTEM_CXXFLAGS))
# Flags passed to the preprocessor.
TRICK_CXXFLAGS += -I$(GTEST_HOME)/include -I$(TRICK_HOME)/include -g -Wall -Wextra -std=c++11 ${TRICK_SYSTEM_CXXFLAGS} ${TRICK_TEST_FLAGS}
# so it seems like there's some weirdness linking in the bitfield objects since they are C
MM_OBJECTS = $(TRICK_HOME)/trick_source/sim_services/MemoryManager/object_${TRICK_HOST_CPU}/extract_bitfield.o \
$(TRICK_HOME)/trick_source/sim_services/MemoryManager/object_${TRICK_HOST_CPU}/extract_unsigned_bitfield.o
TRICK_LIBS = -L${TRICK_LIB_DIR} -ltrick_mm -ltrick_units -ltrick -ltrick_mm -ltrick_units -ltrick
TRICK_EXEC_LINK_LIBS += -L${GTEST_HOME}/lib64 -L${GTEST_HOME}/lib -lgtest -lgtest_main -lpthread
# All tests produced by this Makefile. Remember to add new tests you
# created to the list.
TESTS = create_path_test
# House-keeping build targets.
all : $(TESTS)
test: $(TESTS)
./create_path_test --gtest_output=xml:${TRICK_HOME}/trick_test/create_path_test.xml
clean :
rm -f $(TESTS) *.o *.gcno *.gcda
create_path_test.o : create_path_test.cpp
$(TRICK_CXX) $(TRICK_CXXFLAGS) -c $<
create_path_test : create_path_test.o $(MM_OBJECTS)
$(TRICK_CXX) $(TRICK_SYSTEM_LDFLAGS) -o $@ $^ -L${TRICK_HOME}/lib_${TRICK_HOST_CPU} $(TRICK_LIBS) $(TRICK_EXEC_LINK_LIBS)

View File

@ -0,0 +1,99 @@
#include <iostream>
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include "gtest/gtest.h"
#include "trick/CommandLineArguments.hh"
namespace Trick {
// Clean up the directory created
void rm_dir(const std::string& dir) {
const int result = remove( dir.c_str() );
if( result != 0 && errno == 66){
// Failed because directory is not empty
// Remove stuff and try again
DIR *temp_dir;
struct dirent *ent;
if ((temp_dir = opendir (dir.c_str())) != NULL) {
// Go through everything in this directory
while ((ent = readdir (temp_dir)) != NULL) {
if (!(strcmp(".", ent->d_name) == 0 || strcmp("..", ent->d_name) == 0 )) {
// remove it
rm_dir(dir + "/" + std::string(ent->d_name));
}
}
closedir (temp_dir);
}
// Try again
remove( dir.c_str() );
}
}
bool dir_correct(const std::string& dir) {
// Make sure that the directory exists and is writeable
struct stat info;
if(stat( dir.c_str(), &info ) == 0) {
if (info.st_mode & S_IFDIR && info.st_mode & S_IWUSR ) {
return true;
}
}
return false;
}
TEST(CreatePathTest, BasicTest) {
std::string dir = "a/b/c";
ASSERT_EQ(CommandLineArguments::create_path(dir), 0);
ASSERT_TRUE(dir_correct(dir));
rm_dir("a");
}
TEST(CreatePathTest, PreExistingDir) {
std::string dir = "pre_existing_output_dir";
ASSERT_EQ(CommandLineArguments::create_path(dir), 0);
ASSERT_TRUE(dir_correct(dir));
}
TEST(CreatePathTest, PreExistingInPath) {
std::string dir = "pre_existing_output_dir/a/b/c";
ASSERT_EQ(CommandLineArguments::create_path(dir), 0);
ASSERT_TRUE(dir_correct(dir));
rm_dir("pre_existing_output_dir/a");
}
TEST(CreatePathTest, FileInPath) {
std::string dir = "pre_existing_output_dir/some_file/a";
ASSERT_EQ(CommandLineArguments::create_path(dir), 1);
}
TEST(CreatePathTest, AbsolutePath) {
char buf[1024];
getcwd(buf, 1024);
std::string dir = std::string(buf) + "/a/b/c";
ASSERT_EQ(CommandLineArguments::create_path(dir), 0);
ASSERT_TRUE(dir_correct(dir));
rm_dir(std::string(buf) + std::string("/a"));
}
TEST(CreatePathTest, dotdotinpath) {
std::string dir = "../a/b/c";
ASSERT_EQ(CommandLineArguments::create_path(dir), 0);
ASSERT_TRUE(dir_correct(dir));
rm_dir("../a");
}
}

View File

@ -22,6 +22,8 @@ Trick::Sie::Sie() {
class_attr_map = Trick::AttributesMap::attributes_map() ;
enum_attr_map = Trick::EnumAttributesMap::attributes_map() ;
move_runtime_generation = false;
the_sie = this ;
}
@ -43,10 +45,17 @@ int Trick::Sie::process_sim_args() {
// Silently exit the sim without printing the termination message
exit(0) ;
}
// Otherwise, go through the rest of the sim args and look for --read-only-sim
for (int i = 1; i < argc; i++) {
if (strcmp("--read-only-sim", argv[i]) == 0) {
// Set this flag to move runtime generation of sie into the output directory
move_runtime_generation = true;
}
}
}
return(0) ;
}
void Trick::Sie::top_level_objects_print(std::ofstream & sie_out) {
@ -136,10 +145,9 @@ void Trick::Sie::top_level_objects_json(std::ofstream & sie_out) {
sie_out << " ]\n";
}
void Trick::Sie::sie_print_xml() {
std::ofstream sie_out ;
std::string file_name = std::string(command_line_args_get_default_dir()) + "/" + "S_sie.resource" ;
std::string file_name = std::string(get_runtime_sie_dir()) + "/" + "S_sie.resource" ;
sie_out.open(file_name.c_str()) ;
sie_out << "<?xml version=\"1.0\"?>\n\n" ;
sie_out << "<sie>\n\n" ;
@ -150,10 +158,31 @@ void Trick::Sie::sie_print_xml() {
sie_out.close() ;
}
void copy_file (const std::string& original_filename, const std::string& copy_filename) {
std::ifstream original;
std::ofstream copy;
original.open(original_filename.c_str(), std::ios::binary);
copy.open(copy_filename.c_str(), std::ios::binary);
copy << original.rdbuf();
original.close();
copy.close();
}
void Trick::Sie::sie_append_runtime_objs() {
std::fstream sie_out ;
std::string file_name = std::string(command_line_args_get_default_dir()) + "/" + "S_sie.resource" ;
sie_out.open(file_name.c_str(), std::fstream::in | std::fstream::out) ;
if (move_runtime_generation) {
std::string original_sie_filename = std::string(command_line_args_get_default_dir()) + "/" + "S_sie.resource" ;
std::string copy_sie_filename = std::string(command_line_args_get_output_dir()) + "/" + "S_sie.resource" ;
copy_file(original_sie_filename, copy_sie_filename);
}
std::string sie_filename = get_runtime_sie_dir() + "/" + "S_sie.resource" ;
sie_out.open(sie_filename.c_str(), std::fstream::in | std::fstream::out) ;
sie_out.seekg(-1, sie_out.end);
const char * comment = "<!--\nRuntime Allocations\nDo not edit this comment or file content past this point\n-->\n";
const int commentLength = 86;
@ -180,9 +209,17 @@ void Trick::Sie::sie_append_runtime_objs() {
sie_out.close();
}
std::string Trick::Sie::get_runtime_sie_dir() {
if (move_runtime_generation) {
return std::string(command_line_args_get_output_dir()) ;
} else {
return std::string(command_line_args_get_default_dir()) ;
}
}
void Trick::Sie::sie_print_json() {
std::ofstream sie_out ;
std::string file_name = std::string(command_line_args_get_default_dir()) + "/" + "S_sie.json" ;
std::string file_name = std::string(get_runtime_sie_dir()) + "/" + "S_sie.json" ;
sie_out.open(file_name.c_str()) ;
sie_out << "{\n" ;
class_attr_map->print_json(sie_out) ;
@ -195,7 +232,7 @@ void Trick::Sie::sie_print_json() {
void Trick::Sie::class_attr_map_print_xml() {
std::ofstream sie_out ;
std::string file_name = std::string(command_line_args_get_default_dir()) + "/" + "S_sie_class.xml" ;
std::string file_name = std::string(get_runtime_sie_dir()) + "/" + "S_sie_class.xml" ;
sie_out.open(file_name.c_str()) ;
sie_out << "<?xml version=\"1.0\"?>\n\n" ;
sie_out << "<sie>\n" ;
@ -206,7 +243,7 @@ void Trick::Sie::class_attr_map_print_xml() {
void Trick::Sie::enum_attr_map_print_xml() {
std::ofstream sie_out ;
std::string file_name = std::string(command_line_args_get_default_dir()) + "/" + "S_sie_enum.xml" ;
std::string file_name = std::string(get_runtime_sie_dir()) + "/" + "S_sie_enum.xml" ;
sie_out.open(file_name.c_str()) ;
sie_out << "<?xml version=\"1.0\"?>\n\n" ;
sie_out << "<sie>\n" ;
@ -217,7 +254,7 @@ void Trick::Sie::enum_attr_map_print_xml() {
void Trick::Sie::top_level_objects_print_xml() {
std::ofstream sie_out ;
std::string file_name = std::string(command_line_args_get_default_dir()) + "/" + "S_sie_top_level_objects.xml" ;
std::string file_name = std::string(get_runtime_sie_dir()) + "/" + "S_sie_top_level_objects.xml" ;
sie_out.open(file_name.c_str()) ;
sie_out << "<?xml version=\"1.0\"?>\n\n" ;
sie_out << "<sie>\n" ;

View File

@ -33,3 +33,10 @@ extern "C" void sie_append_runtime_objs(void) {
the_sie->sie_append_runtime_objs() ;
}
}
extern "C" std::string sie_get_runtime_sie_dir(void) {
if ( the_sie != NULL ) {
return the_sie->get_runtime_sie_dir() ;
}
}

View File

@ -497,20 +497,20 @@ int Trick::VariableServerThread::send_file(std::string file_name) {
int Trick::VariableServerThread::send_sie_resource() {
sie_append_runtime_objs() ;
return transmit_file(std::string(command_line_args_get_default_dir()) + "/S_sie.resource") ;
return transmit_file(std::string(sie_get_runtime_sie_dir()) + "/S_sie.resource") ;
}
int Trick::VariableServerThread::send_sie_class() {
sie_class_attr_map_print_xml() ;
return transmit_file(std::string(command_line_args_get_default_dir()) + "/" + "S_sie_class.xml") ;
return transmit_file(std::string(sie_get_runtime_sie_dir()) + "/" + "S_sie_class.xml") ;
}
int Trick::VariableServerThread::send_sie_enum() {
sie_enum_attr_map_print_xml() ;
return transmit_file(std::string(command_line_args_get_default_dir()) + "/" + "S_sie_enum.xml") ;
return transmit_file(std::string(sie_get_runtime_sie_dir()) + "/" + "S_sie_enum.xml") ;
}
int Trick::VariableServerThread::send_sie_top_level_objects() {
sie_top_level_objects_print_xml() ;
return transmit_file(std::string(command_line_args_get_default_dir()) + "/" + "S_sie_top_level_objects.xml") ;
return transmit_file(std::string(sie_get_runtime_sie_dir()) + "/" + "S_sie_top_level_objects.xml") ;
}