/****************************************************************************** Program: EEDAG: Parallel Task Scheduling Simulator Authors: Ziliang Zong and Jonathan Bush Time Released: September 1, 2013 Acknowledgement: This work is supported by the National Science Foundation under Grants No. CNS-1116691, CNS-1118043, and CNS-1118037. Description: In this program, it will build a Directed Acyclic Graph (DAG), which is basically an m-ary tree, to support the scheduling of parallel tasks running on supercomputers such as clusters or grids. Input: The input will include two items: a valid Standard Task Graph (STG) file and the Communication-Computation-Ratio (CCR). The program will check the existence of the stg file and the validity of CCR (0.1 - 10) and remind users the correct input format when an invalid format is given. If the user did not give the CCR, 1 is used as the default CCR in the program to calculate the communication cost among tasks. The input is read from the command line. Output: The program will generate two output files: the intermediate source code file (with the running code for the according DAG) and the result file with the Parameters Calculation Results and the Scheduling Decisions. Given an example DAG with the name "example.stg," the output files will be "example.cpp," which is the intermediate executable file and the "example.stgr," which will show the scheduling results. Usage: task_scheduler example.stg 5 OR task_scheduler example.stg If less than one or more than two arguments is passed, the program will exit. If there is a problem opening the file, the program will exit. If there is a problem opening the intermediate file, the program will exit. If the CCR entered is less than 0.1 or greater than 10, the program wil exit. Program License Agreement: This simulator is provided to the computing society for free and it can only be used for non-commercial purposes. You are not allowed to install or use this simulator if you do not agree to be bound by the following terms. 1. You may use, copy, reproduce, and distribute this simulator for any non-commercial purpose. Some purposes which we consider as non-commercial include teaching, academic research, public demonstrations and personal experimentation. You may also distribute this simulator with books or other teaching materials, or publish the simulator on websites, that are intended to teach the use of the simulator for academic or other non-commercial purposes. 2. You may not use or distribute this program or any derivative works in any form for commercial purposes. Examples of commercial purposes would include running business operations, licensing, leasing, or selling the simulator, distributing the simulator for use with commercial products, using the simulator in the creation or use of commercial products or any other activity which purpose is to procure a commercial gain to you or others. 3. You may create derivative works based on this simultor and distribute the modified versions for non-commercial purposes. 4. If you distribute the simulator or any derivative works of the simulator, you will distribute them under the same terms and conditions as in this license, and you will not grant additional rights that are different from this license agreement. 5. If you have created derivative works of the simulator, and distribute such derivative works, you will ensure the modified files to carry prominent notices so that recipients know that they are not receiving the original Simultor. Example notices should state: (i) that you have changed the Software; and (ii) the date of any changes. 6. You will not remove any copyright or other notices from the original simulator. 7. You will not attempt to modify the binary code. 8. This simultor is provided as "it is" and it may not fulfill your particular purposes or needs. We will not provide technical support for the simulator. 9. The software may not be reliable and we are not responsible for any damages caused by running this simulatro. YOU MUST PASS THIS LIMITATION OF LIABILITY ON WHENEVER YOU DISTRIBUTE THE SOFTWARE OR DERIVATIVE WORKS. Please cite one or more of the following published papers when using this simulator or making derivative works of this simulator. 1. Z.L. Zong, J. Bush, R. Ge, X. Li, Z.Z. Chen, "Energy-Efficient Scheduling for Multicore Systems with Bounded Resources", In Proceedings of the IEEE International Conference on Green Computing and Communications (GreenCom), Beijing, Aug. 2013. 2. Z. L. Zong, A. Manzanares, X. J. Ruan, and X. Qin, "EAD and PEBD: Two Energy-Aware Duplication Scheduling Algorithms for Parallel Tasks on Homogeneous Clusters", IEEE Transactions on Computers, vol. 60, no. 3, pp. 360-374, Mar. 2011. 3. Z. L. Zong, X. Qin, M. Nijim, X. J. Ruan, K. Bellam, and M. Alghamdi, "Energy-Efficient Scheduling for Parallel Applications Running on Heterogeneous Clusters", In Proceedings of the International Conference on Parallel Processing (ICPP), Xi'an, China, Sept. 2007. 4. Z. L. Zong, A. Manzanares, B. Stinar, and X. Qin, "Energy-Efficient Duplication Strategies for Scheduling Precedence Constrained Parallel Tasks on Clusters", In Proceedings of the International Conference on Cluster Computing, Barcelona (Cluster), Spain, Sept. 2006. ******************************************************************************/ #include #include #include #include using namespace std; /****************************************************************************** Function name: main Parameters: int argc - The number of arguments in argv char * argv[] - The array of command line arguments Description: Checks the command line. If the user entered the wrong value for the CCR, the program exits with error code one. If the user passed in the wrong number of arguments, the program exits with error code two. If unable to open the file passed by the user, the program exits with error code three. If unable to open the intermediate file, the program exits with error code four. The program will read the file passed in, example.stg, and create an intermediate file, example.cpp, which will construct a DAG for the scheduling of tasks. It will then calculate the values for the tasks and print the results to a new file, example.stgr. ******************************************************************************/ int main( int argc, char * argv[] ) { ifstream fin; //file input ofstream fout; //file output double CCR; //CCR int i; //counter i int j; //counter j int total_tasks; //stores total tasks in the stg file int task_number; //stores current task number int num_preds; //stores current task's number of predecessors int proc_time; //stores current task's process time int pred; //stores current predecessor string mystring; //multipurpose string string::size_type idx; //index for searching strings std::istringstream stm; //parses CCR passed in by user //If the user didn't pass a CCR, set it to 1.0. if( argc == 2 ) { CCR = 1.0; } //If the user entered a CCR, set it. else if( argc == 3 ) { //Check the CCR entered stm.str( argv[2] ); stm >> CCR; //If the CCR is isn't within range, print error and exit. if( CCR < 0.1 || CCR > 10 ) { cout << "The CCR entered must be in the range 0.1 to 10.\n" << "Exiting program.\n"; exit(1); } } //If the program doesn't have the correct arguments, print error and exit. else { cout << "Please enter one file and an optional CCR value.\n" << "Usage: prog2.exe example.stg\n" << "or Usage: prog2.exe example.stg 1.0\n" << "Exiting program.\n"; exit(2); } //Open the file given by the user, .stg fin.open( argv[1] ); //If there is a problem opening the file, print error and exit. if( !fin ) { cout << "Problem opening your file.\n" << "Exiting program.\n"; exit(3); } //Open an intermediate file, .cpp mystring = argv[1]; idx = mystring.find("."); mystring.resize( idx ); mystring += ".cpp"; fout.open( mystring.c_str() ); //If there is a problem opening the file, print error and exit. if( !fout ) { cout << "Problem opening the temporary file.\n" << "Exiting program.\n"; exit(4); } //Seek to the beginning of both files fout.seekp( 0, ios::beg ); fin.seekg( 0, ios::beg ); //Construct intermediate file, .cpp //Includes for intermediate file fout << "#include \n"; fout << "using namespace std;\n\n"; //Structure prototypes fout << "//Structure prototypes\n"; fout << "struct node;\n"; fout << "struct pred_list;\n"; fout << "struct child_list;\n\n"; //Define structure for constructing nodes in DAG fout << "struct node\n"; fout << "{\n"; fout << "pred_list * preds;\n"; fout << "child_list * children;\n"; fout << "node * next_level;\n"; fout << "int task_number;\n"; fout << "int proc_time;\n"; fout << "double comm_time;\n"; fout << "int level;\n"; fout << "double EST;\n"; fout << "double ECT;\n"; fout << "node * FP;\n"; fout << "double LACT;\n"; fout << "double LAST;\n"; fout << "bool used;\n"; fout << "};\n\n"; //Define structure for keeping track of node's predecessors fout << "struct pred_list\n"; fout << "{\n"; fout << "node * pred;\n"; fout << "pred_list * next;\n"; fout << "};\n\n"; //Define structure for keeping track of node's children fout << "struct child_list\n" << "{\n" << "node * child;\n" << "child_list * next;\n" << "};\n\n"; //Function definition(s) fout << "//Function definition(s)\n"; fout << "void find_FP( node *& task );\n"; fout << "double find_EST( node * task );\n"; fout << "int find_level( node * task );\n"; fout << "double find_LACT( node * task );\n"; fout << "bool find_next_unused( node *& task, node * bottom );\n"; fout << "void sort_level( node *& head, node*& add );\n\n"; //Start of int main() fout << "int main()\n"; fout << "{\n"; //Seek to beginning of .stg fin.seekg( 0, ios::beg ); //Get total tasks fin >> total_tasks; //Create top and bottom pointers fout << "node * top;\n"; fout << "node * bottom;\n\n"; //Create task nodes for( i = 0; i <= total_tasks + 1; i++ ) { //Get task number and create new node with this number fin >> task_number; fout << "//Task number " << task_number << "\n"; fout << "node * task" << task_number << " = new node;\n"; //If task is the first or last node, then update the pointers if( i == 0 ) { fout << "top = task" << task_number << ";\n"; } else if( i == total_tasks + 1 ) { fout << "bottom = task" << task_number << ";\n"; } //Initialize node //Set the task number in the node fout << "task" << task_number << "->task_number = " << task_number << ";\n"; //Get process time and update the data in the node fin >> proc_time; fout << "task" << task_number << "->proc_time = " << proc_time << ";\n"; //Update the communication time in the node fout << "task" << task_number << "->comm_time = " << CCR * proc_time << ";\n"; //Set pointers to NULL and used to false fout << "task" << task_number << "->used = false;\n"; fout << "task" << task_number << "->FP = NULL;\n"; fout << "task" << task_number << "->preds = NULL;\n"; fout << "task" << task_number << "->children = NULL;\n"; fout << "task" << task_number << "->next_level = NULL;\n\n"; //Get num_parents fin >> num_preds; //If the task has predecessors, fill out the appropriate connections. if ( num_preds ) { //Create the pred_list structures for this node for( j = 0; j < num_preds; j++ ) { fout << "pred_list * preds" << task_number << "_" << j << " = new pred_list;\n"; //Initialize their pointers to NULL fout << "preds" << task_number << "_" << j << "->pred = NULL;\n"; fout << "preds" << task_number << "_" << j << "->next = NULL;\n"; } fout << "\n"; //Set current task's preds pointer to the first predecessor fout << "task" << task_number << "->preds = preds" << task_number << "_0;\n\n"; for( j = 0; j < num_preds; j++ ) { //Get predecessor's task number fin >> pred; //and add it to the current node's list fout << "preds" << task_number << "_" << j << "->pred = task" << pred << ";\n"; //If this isn't the first predecessor if( j != 0 ) { //Then update the next pointer in the previous pred_list fout << "preds" << task_number << "_" << j - 1 << "->next = preds" << task_number << "_" << j << ";\n"; } //Check if the predecessor has a child yet fout << "if( task" << pred << "->children == NULL )\n"; fout << "{\n"; //If it doesn't, create a new child_list structure and point to it fout << "child_list * child" << pred << "_0 = new child_list;\n" << "child" << pred << "_0->child = task" << task_number << ";\n" << "child" << pred << "_0->next = NULL;\n" << "task" << pred << "->children = child" << pred << "_0;\n"; fout << "}\n"; //Else, if it does fout << "else\n"; fout << "{\n"; //Create child_list temp for the new child fout << "child_list * temp = new child_list;\n" << "temp->child = task" << task_number << ";\n" << "temp->next = NULL;\n"; //And create child_list childPtr to traverse the children fout << "child_list * childPtr = task" << pred << "->children;\n"; //And follow siblings until NULL fout << "while( childPtr->next != NULL )\n"; fout << "{\n"; fout << "childPtr = childPtr->next;\n"; fout << "}\n\n"; //Then set the new child as the next sibling fout << "childPtr->next = temp;\n"; fout << "}\n\n"; } } fout << "\n"; } //Calculate levels of task nodes fout << "//Calculate levels of task nodes\n"; for( i = total_tasks + 1; i >= 0; i-- ) { fout << "task" << i << "->level = find_level( task" << i << " );\n"; if( i != total_tasks + 1 ) { fout << "sort_level( bottom, task" << i << " );\n"; } } fout << "\n"; //Calculate EST & ECT of task nodes fout << "//Calculate EST & ECT of task nodes\n"; for( i = 0; i <= total_tasks + 1; i++ ) { fout << "task" << i << "->EST = find_EST( task" << i << " );\n"; fout << "task" << i << "->ECT = task" << i << "->EST + task" << i << "->proc_time;\n"; } fout << "\n"; //Calculate FP of task nodes fout << "//Calculate FP of task nodes\n"; for( i = 0; i <= total_tasks + 1; i++ ) { fout << "find_FP( task" << i << " );\n"; } fout << "\n"; //Calculate LACT & LAST of task nodes fout << "//Calculate LACT & LAST of task nodes\n"; for( i = total_tasks + 1; i >= 0; i-- ) { fout << "task" << i << "->LACT = find_LACT( task" << i << " );\n"; fout << "task" << i << "->LAST = task" << i << "->LACT - task" << i << "->proc_time;\n\n"; } //Print nodes' parameter information //Print header fout << "//Print data for each node\n"; fout << "cout << \"Task\\tLevel\\tEST\\tECT\\tLAST\\tLACT\\tFP\\n\";\n"; //Loop and print the data for each node for( i = 0; i <= total_tasks + 1; i++ ) { fout << "//Task number " << i << "\n"; fout << "cout << task" << i << "->task_number << \"\\t\"" << "<< task" << i << "->level << \"\\t\"" << "<< task" << i << "->EST << \"\\t\"" << "<< task" << i << "->ECT << \"\\t\"" << "<< task" << i << "->LAST << \"\\t\"" << "<< task" << i << "->LACT << \"\\t\";" << "\nif( task" << i << "->FP != NULL )\n" << "{\n" << "cout << task" << i << "->FP->task_number << \"\\n\";\n" << "}\n" << "else\n" << "{\n" << "cout << \"--\\n\";\n" << "}\n\n"; } //Print schedule length fout << "cout << \"\\nThe schedule length for the input DAG is \"" << "<< bottom->ECT << endl;\n"; //Assign tasks to processors fout << "\n//Assign tasks to processors\n"; //Create nodes v and u. Set v = bottom. fout << "node * v = bottom;\n"; fout << "node * u;\n"; fout << "bool all_used = false;\n"; //Start processor counter to 1 fout << "int i = 1;\n"; //Print task associated with this processor fout << "v->used = true;\n"; fout << "cout << \"\\nProcessor \" << i << \": Task \" << v->task_number;\n\n"; //Loop fout << "do\n"; fout << "{\n"; //Create node u = v's FP fout << "u = v->FP;\n"; //If u has already been used fout << "if( u->used == true )\n"; fout << "{\n"; //Check if we want to duplicate it in another processor fout << "if( v->LAST - u->LACT < u->comm_time )\n"; fout << "{\n"; //If true, we duplicate u fout << "cout << \" -> Task \" << u->task_number;\n"; fout << "}\n"; fout << "}\n"; //Else u hasn't been used fout << "else\n"; fout << "{\n"; //Set u's used value to true fout << "u->used = true;\n"; //Assign it to the processor fout << "cout << \" -> Task \" << u->task_number;\n"; fout << "}\n\n"; //Set v = u fout << "v = u;\n\n"; //If v == entry task fout << "if( v == top )\n"; fout << "{\n"; fout << "all_used = find_next_unused( v, bottom );\n\n"; fout << "if( v-> used != true )\n"; fout << "{\n"; fout << "i++;\n"; fout << "v->used = true;\n"; fout << "cout << \"\\n\\nProcessor \" << i << \": Task \" << v->task_number;\n\n"; fout << "}\n"; fout << "}\n"; //Continue looping while not all tasks have been assigned to processors fout << "} while( !all_used );\n"; fout << "cout << endl;\n"; //End of int main() fout << "\nreturn 0;\n"; fout << "}\n\n"; //Start of int find_level( node * task ) fout << "int find_level( node * task )\n"; fout << "{\n"; //Create child_list temp and node max fout << "child_list * temp;\n"; fout << "node * max;\n"; //If task has no children, return the proc time of task fout << "if( task->children == NULL )\n"; fout << "{\n"; fout << "return task->proc_time;\n"; fout << "}\n"; //Otherwise we set temp and max = first child of task fout << "temp = task->children;\n"; fout << "max = temp->child;\n"; //While we haven't run out of siblings fout << "while( temp->next != NULL )\n"; fout << "{\n"; //Set temp = temp's sibling fout << "temp = temp->next;\n"; //If temp's level is greater than max's fout << "if( temp->child->level > max->level )\n"; fout << "{\n"; //Set max = temp fout << "max = temp->child;\n"; fout << "}\n"; fout << "}\n"; //Return max's level + task's proc time fout << "return max->level + task->proc_time;\n"; //End of int find_level( node * task ) fout << "}\n\n"; //Start of double find_EST( node * task ) fout << "double find_EST( node * task )\n"; fout << "{\n"; //Create local variables fout << "double min_outer_loop;\n"; fout << "double max_inner_loop;\n"; fout << "pred_list * outer_temp;\n"; fout << "pred_list * inner_temp;\n\n"; //If task has no predecessors, EST = proc_time fout << "if( task->preds == NULL )\n"; fout << "{\n"; fout << "return task->proc_time;\n"; fout << "}\n\n"; //Otherwise, set outer_temp to the task's predecessor list fout << "outer_temp = task->preds;\n"; //Start the maximum value for the inner loop with the first predecessor's proc_time fout << "max_inner_loop = outer_temp->pred->ECT;\n"; //Set inner_temp to the task's predecessor list fout << "inner_temp = task->preds;\n\n"; //Traverse through the predecessors fout << "while( inner_temp != NULL )\n"; fout << "{\n"; //If inner_temp == outer_temp, skip it fout << "if( inner_temp == outer_temp )\n"; fout << "{\n"; fout << "//do nothing\n"; fout << "}\n"; //Otherwise check if inner_temp's ECT + comm_time is greater than max_inner_loop fout << "else if( inner_temp->pred->ECT + inner_temp->pred->comm_time > max_inner_loop )\n"; fout << "{\n"; //If so, set max_inner_loop to this value fout << "max_inner_loop = inner_temp->pred->ECT + inner_temp->pred->comm_time;\n"; fout << "}\n\n"; fout << "inner_temp = inner_temp->next;\n"; fout << "}\n\n"; //Seed the min_outer_loop with this first max_inner_loop value fout << "min_outer_loop = max_inner_loop;\n"; //Now check the next predecessor fout << "outer_temp = outer_temp->next;\n\n"; //Loop algorithm fout << "while( outer_temp != NULL )\n"; fout << "{\n"; fout << "max_inner_loop = outer_temp->pred->ECT;\n"; //Set inner_temp to the task's predecessor list fout << "inner_temp = task->preds;\n\n"; //Traverse through the predecessors fout << "while( inner_temp != NULL )\n"; fout << "{\n"; //If inner_temp == outer_temp, skip it fout << "if( inner_temp == outer_temp )\n"; fout << "{\n"; fout << "//do nothing\n"; fout << "}\n"; //Otherwise check if inner_temp's ECT + comm_time is greater than max_inner_loop fout << "else if( inner_temp->pred->ECT + inner_temp->pred->comm_time > max_inner_loop )\n"; fout << "{\n"; //If so, set max_inner_loop to this value fout << "max_inner_loop = inner_temp->pred->ECT + inner_temp->pred->comm_time;\n"; fout << "}\n\n"; fout << "inner_temp = inner_temp->next;\n"; fout << "}\n"; //If the max_inner_loop is less than the min_outer_loop fout << "if( max_inner_loop < min_outer_loop )\n"; fout << "{\n"; //Then set min_outer_loop to this value fout << "min_outer_loop = max_inner_loop;\n"; fout << "}\n\n"; //Check the next predecessor fout << "outer_temp = outer_temp->next;\n"; fout << "}\n\n"; fout << "return min_outer_loop;\n"; //End of double find_EST( node * task ) fout << "}\n\n"; //Start of void find_FP( node *& task ) fout << "void find_FP( node *& task )\n"; fout << "{\n"; //Create max and temp fout << "pred_list * max;\n"; fout << "pred_list * temp;\n\n"; //Set temp = task's predecessor list fout << "temp = task->preds;\n\n"; //Start max as the first predecessor fout << "max = temp;\n"; //If max is NULL, return fout << "if( max == NULL )\n"; fout << "{\n"; fout << "task->FP = NULL;\n"; fout << "return;\n"; fout << "}\n\n"; //While we still have predecessors to check fout << "while( temp != NULL )\n"; fout << "{\n"; fout << "if( temp->pred->ECT + temp->pred->comm_time > max->pred->ECT + max->pred->comm_time )\n"; fout << "{\n"; //If so, set max to this value fout << "max = temp;\n"; fout << "}\n"; //Move to next predecessor fout << "temp = temp->next;\n"; fout << "}\n\n"; fout << "task->FP = max->pred;\n"; //End of void find_FP( node *& task ) fout << "}\n\n"; //Start of double find_LACT( node * task ) fout << "double find_LACT( node * task )\n"; fout << "{\n"; //Create temp and min fout << "child_list * temp;\n"; fout << "double min;\n\n"; //If the task has no children, return its ECT fout << "if( task->children == NULL )\n"; fout << "{\n"; fout << "return task->ECT;\n"; fout << "}\n\n"; //Otherwise fout << "else\n"; fout << "{\n"; //Set temp = first child fout << "temp = task->children;\n\n"; //While temp isn't NULL fout << "while( temp != NULL )\n"; fout << "{\n"; //If temp's FP is the task fout << "if( temp->child->FP->task_number == task->task_number )\n"; fout << "{\n"; //And if this is the first child fout << "if( temp == task->children )\n"; fout << "{\n"; //Start min with this value fout << "min = temp->child->LAST;\n"; fout << "}\n"; //Otherwise check if temp's LACT - proc_time < min fout << "else if( temp->child->LAST < min )\n"; fout << "{\n"; //If so, set min to this value fout << "min = temp->child->LAST;\n"; fout << "}\n"; fout << "}\n\n"; //Otherwise this task isn't the FP of temp fout << "else\n"; fout << "{\n"; //If this is the first child fout << "if( temp == task->children )\n"; fout << "{\n"; //Start min with this value fout << "min = temp->child->LAST - task->comm_time;\n"; fout << "}\n"; //Otherwise check if temp's LACT - proc_time - task's comm_time < min fout << "else if( temp->child->LAST - task->comm_time < min )\n"; fout << "{\n"; //If so, set min to this value fout << "min = temp->child->LAST - task->comm_time;\n"; fout << "}\n"; fout << "}\n\n"; //Go to the next sibling fout << "temp = temp->next;\n"; fout << "}\n\n"; fout << "}\n\n"; fout << "return min;\n"; //End of double find_LACT( node * task ) fout << "}\n\n"; //Start of void sort_level( node *& head, node *& add ) fout << "void sort_level( node *& head, node *& add )\n"; fout << "{\n"; //Create temporary pointer nodes fout << "node * previousNode = NULL;\n"; fout << "node * nodePtr = head;\n\n"; //If the head's next_level pointer is NULL, set it to add fout << "if( head->next_level == NULL )\n"; fout << "{\n"; fout << "head->next_level = add;\n"; fout << "}\n"; //Otherwise fout << "else\n"; fout << "{\n"; //Skip nodes whose level is greater than add's fout << "while ( nodePtr != NULL && nodePtr->level <= add->level )\n"; fout << "{\n"; fout << "previousNode = nodePtr;\n"; fout << "nodePtr = nodePtr->next_level;\n"; fout << "}\n\n"; //Then insert add into the proper place in the list fout << "previousNode->next_level = add;\n"; fout << "add->next_level = nodePtr;\n"; fout << "}\n"; //End of void sort_level( node * task ) fout << "}\n\n"; //Start of bool find_next_unused( node *& task, node * bottom ) fout << "bool find_next_unused( node *& task, node * bottom )\n"; fout << "{\n"; //Create temp node for traversal fout << "node * temp = bottom;\n"; fout << "while( temp != NULL )\n"; fout << "{\n"; //If temp isn't used fout << "if( temp->used == false )\n"; fout << "{\n"; //Set task equal to temp and return false to indicate not all nodes used fout << "task = temp;\n"; fout << "return false;\n"; fout << "}\n\n"; //Traverse the list to the next node in the sorted-by-level list fout << "temp = temp->next_level;\n"; fout << "}\n\n"; //If we made it all the way through the list, return true to indicate all nodes used. fout << "return true;\n"; //End of bool find_next_unused( node *& task, node * bottom ) fout << "}\n"; //End of intermediate file, .cpp //Close .cpp and .stg fout.close(); fin.close(); //Construct the string for compiling .cpp mystring.insert( 0, "cl /EHsc " ); //Compile it system( mystring.c_str() ); //Construct the string to run the new program and output to .stgr mystring = argv[1]; idx = mystring.find( "." ); mystring.resize( idx ); mystring += " > "; mystring += argv[1]; idx = mystring.find( "." ); mystring.resize( idx ); mystring += ".stgr"; //Run it system( mystring.c_str() ); return 0; }