// Copyright (c) 2014 Carnegie Mellon University. // All Rights Reserved. // Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: // 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following acknowledgments and disclaimers. // 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following acknowledgments and disclaimers in the documentation and/or other materials provided with the distribution. // 3. Products derived from this software may not include “Carnegie Mellon University,” "SEI” and/or “Software Engineering Institute" in the name of such derived product, nor shall “Carnegie Mellon University,” "SEI” and/or “Software Engineering Institute" be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact permission@sei.cmu.edu. // ACKNOWLEDGMENTS AND DISCLAIMERS: // This material is based upon work funded and supported by the Department of Defense under Contract No. FA8721-05-C-0003 with Carnegie Mellon University for the operation of the Software Engineering Institute, a federally funded research and development center. // // Any opinions, findings and conclusions or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the United States Department of Defense. // // NO WARRANTY. THIS CARNEGIE MELLON UNIVERSITY AND SOFTWARE ENGINEERING INSTITUTE MATERIAL IS FURNISHED ON AN “AS-IS” BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT. // // This material has been approved for public release and unlimited distribution. // // Carnegie Mellon® is registered in the U.S. Patent and Trademark Office by Carnegie Mellon University. // // DM-0000875 // // ------------------------------------------------------------------------------------------ // What does this program do? // It performs schedulabilty analysis of tasks with multiple stages // where the task may suspend after having executed a stage. // It can also configure priorities and phi (enforcement). // You can read more about this topic and how this is done in: // J. Kim, B. Andersson, D. de Niz and R. Rajkumar, // ``Segment-Fixed Priority Scheduling for Self-Suspending Real-Time Tasks,'' // in Proceedings of the 34th IEEE Real-Time Systems Symposium, Vancouver, Canada, // December 3-6, 2013. // // How do I install it? // First install Gurobi. It is a software tool that solves Mixed-Integer Linear Programs (MILP). // It is free for academic use. // Then find out which compiler you want to use. // If you use Microsoft Visual Studio then make sure that you have below // #define COMPILEMSVS 1 // otherwise make sure you have // #define COMPILEMSVS 0 // below // // How do I actually run it? // In windows, open a console and type: // multistage.exe -i taskset.txt -o taskset_results_from_analysis.txt // In a Unix-like operating system, open a console and type: // gcc -o multistage -O3 multistage.cpp -lm // multistage -i taskset.txt -o taskset_results_from_analysis.txt // // Special advice for Microsoft Visual Studio users: // If you use Microsoft Visual Studio then do the following: // - click project | properties | configuration properties | C/C++ | Precompiled Headers | // set Precompiled Header to "Not using Precompiled headers" // - click project | properties | configuration properties | preprocessor | // add // ;_CRT_SECURE_NO_WARNINGS // at the end of // Preprocessor Definitions // - Make sure you have the following files in your local directory: // liblpsolve55 // liblpsolve55d // lp_Hash.h // lp_lib.h // lp_matrix.h // lp_mipbb.h // lp_SOS.h // lp_types.h // lp_utils.h // lpsolve55.dll // lpsolve55.lib // // What is the file format of the input file? // // 5 method to be applied, 5 means "assign priorities and phi" // One could use one of the other methods too. // 2 means perform schedulability analysis. // 3 means assign priorities assuming that phi are given. // 4 means assign phi assuming that priorities are given. // 3 number of tasks in task set // 1 here is some info for task \tau_1 // 1.000000 1.000000 T_1=1 and D_1=1 // 2 s_1=2 // 0.1 0.06 0.125 C_1,1 =0.1 G_1,1=0.06, C_1,2=0.125 // 6 5 prio_1,1=6, prio_1,2=5 // 0.45 phi_1,1=0.45 // 2 here is some info for task \tau_2 // 2.000000 2.000000 T_2=2 and D_2=2 // 2 s_2=2 // 0.2 0.12 0.25 C_2,1 =0.2 G_2,1=0.12, C_2,2=0.25 // 4 3 prio_2,1=4, prio_2,2=3 // 0.90 phi_2,1=0.90 // 3 here is some info for task \tau_3 // 4.000000 4.000000 T_3=4 and D_3=4 // 2 s_3=2 // 0.4 0.24 0.5 C_3,1 =0.4 G_3,1=0.24, C_3,2=0.5 // 2 1 prio_3,1=2, prio_3,2=1 // 1.80 phi_3,1=1.80 // // Important note about priorities: // It can be seen that the format above assigns priorities to segments. // In order for the tool to work correctly, these priorities must be in the range [1,maxprio] // where maxprio = sum_{j=1..n} s_j // // Another important note about priorities: // A high number means high priority // // How large systems can be processed? // When the tool is used for schedulability analysis one can typically take task sets with 20 tasks and perform schedulability analysis within a 20 seconds. // When the tool is used to find phi and priority assignment one can typicallly take task sets with 6 tasks as input and the analysis terminates within a minute; // for task sets with more tasks, it may happen that the tool does not terminate. // // History of this source code: // The first version was written in the spring of 2013. // Then some correction was made in early 2016 (dealing with carry-in) // ------------------------------------------------------------------------------------------ // multistage.cpp : Defines the entry point for the console application. // // #include "stdafx.h" #define COMPILEMSVS 0 #if COMPILEMSVS #include "stdafx.h" #include "lp_lib.h" #endif #if COMPILEMSVS #else #define REAL double #endif // using namespace System; // We add these in order to do file I/O like in UNIX. And ceil(..) #include #include #if COMPILEMSVS #include #endif #include #if COMPILEMSVS #include #endif #include #include // this is needed for the constant S_IWRITE #include // this is needed for strcmp // These are needed for _chdir // #include #if COMPILEMSVS #include #else #include #endif #include #include #define USE_LP_SOLVE 0 #define USE_GUROBI 1 // functions in DLL which solves ILP #if COMPILEMSVS make_lp_func *_make_lp; delete_lp_func *_delete_lp; add_constraint_func *_add_constraint; set_obj_fn_func *_set_obj_fn; set_add_rowmode_func *_set_add_rowmode; set_maxim_func *_set_maxim; write_lp_func *_write_lp; set_verbose_func *_set_verbose; solve_func *_solve; get_objective_func *_get_objective; get_primal_solution_func *_get_primal_solution; set_int_func *_set_int; get_Nrows_func *_get_Nrows; read_LP_func *_read_LP; set_anti_degen_func *_set_anti_degen; #endif #define MAXNTASKS 1000 #define MAXNSEGPERTASK 100 int counterforILPsolver; int generate_experiments = 0; int run_experiments = 0; char inputfilename[20000]="taskset.txt"; char outputfilename[20000]="taskset_results_from_analysis.txt"; struct task { int id; REAL T; REAL D; int nseg; REAL C[MAXNSEGPERTASK+1]; // C[1], C[2], ..., C[nseg-1], C[nseg] REAL G[MAXNSEGPERTASK]; // G[1], G[2], ..., G[nseg-1] int prio[MAXNSEGPERTASK+1]; // prio[1], prio[2], ..., prio[nseg-1], prio[nseg] REAL phi[MAXNSEGPERTASK]; // phi[1], phi[2], ..., phi[nseg-1] REAL R[MAXNSEGPERTASK+1]; // R[1], R[2], ..., R[nseg-1], R[nseg] }; int useanalysismethod; int ntasks; struct task tasks[MAXNTASKS+1]; int success; // MS Visual studion does not allow write. So we call this function mywrite that in turn // calls _write. If you compile this under Linux then just change // _write to write int mywrite( int fh, char* tempstr, int len) { #if COMPILEMSVS return _write( fh, tempstr, len ); #else return write( fh, tempstr, len ); #endif } int myopen( char* fn, int m1, int m2) { #if COMPILEMSVS return _open( fn, m1, m2); #else return open( fn, m1, m2); #endif } int myclose( int fh) { #if COMPILEMSVS return _close( fh); #else return close( fh); #endif } void printtask(FILE* myfile, int i) { int s; fprintf( myfile, "task id = %d. T = %lf, D = %lf \n", tasks[i].id, tasks[i].T, tasks[i].D ); for (s=1;s<=tasks[i].nseg;s++) { if (s==1) { fprintf( myfile, "C_%d_%d = %lf", i, s, tasks[i].C[s] ); } else { fprintf( myfile, ",G_%d_%d = %lf,C_%d_%d = %lf", i,s-1,tasks[i].G[s-1], i,s,tasks[i].C[s] ); } } fprintf( myfile, "\n"); for (s=1;s<=tasks[i].nseg;s++) { if (s==1) { fprintf( myfile, "prio_%d_%d = %d", i,s, tasks[i].prio[s]); } else { fprintf( myfile, ",prio_%d_%d = %d", i,s,tasks[i].prio[s]); } } fprintf( myfile, "\n"); for (s=1;s<=tasks[i].nseg-1;s++) { if (s==1) { fprintf( myfile, "phi_%d_%d = %lf", i,s, tasks[i].phi[s]); } else { fprintf( myfile, ",phi_%d_%d = %lf", i,s,tasks[i].phi[s]); } } fprintf( myfile, "\n"); for (s=1;s<=tasks[i].nseg;s++) { if (s==1) { fprintf( myfile, "R_%d_%d = %lf", i,s, tasks[i].R[s]); } else { fprintf( myfile, ",R_%d_%d = %lf", i,s,tasks[i].R[s]); } } fprintf( myfile, "\n"); fprintf( myfile, "\n"); } void printtasksinternal(FILE* myfile) { int i; fprintf( myfile, "useanalysismethod = %d\n", useanalysismethod); fprintf( myfile, "ntasks = %d\n", ntasks); for (i=1;i<=ntasks;i++) { printtask( myfile, i); } } void printtasks() { printtasksinternal( stdout); } void printtaskstooutputfile() { FILE* myfile; myfile = fopen( outputfilename, "w"); printtasksinternal( myfile); fclose( myfile); } void readtasksetfromfile(char* p) { int temp; FILE* myfile; int i; int s; printf("The filename is %s\n", p); myfile = fopen( p, "rt"); if (myfile==NULL) { printf("Error opening file\n"); scanf("%d", &temp); exit(0); } fscanf(myfile, "%d", &useanalysismethod); fscanf(myfile, "%d", &ntasks); printf("ntasks = %d\n", ntasks); for (i=1;i<=ntasks;i++) { fscanf(myfile,"%d", &(tasks[i].id)); fscanf(myfile,"%lf", &(tasks[i].T)); fscanf(myfile,"%lf", &(tasks[i].D)); fscanf(myfile,"%d", &(tasks[i].nseg)); for (s=1;s<=tasks[i].nseg;s++) { if (s==1) { fscanf(myfile,"%lf", &(tasks[i].C[s])); } else { fscanf(myfile,"%lf", &(tasks[i].G[s-1])); fscanf(myfile,"%lf", &(tasks[i].C[s])); } } for (s=1;s<=tasks[i].nseg;s++) { fscanf(myfile,"%d", &(tasks[i].prio[s])); } for (s=1;s<=tasks[i].nseg-1;s++) { fscanf(myfile,"%lf", &(tasks[i].phi[s])); } } fclose( myfile); printtasks(); } void writetasksettofile(char* fn) { FILE* myfile; int i; int temp; int s; myfile = fopen( fn, "w"); if (myfile==NULL) { printf("Error opening file\n"); scanf("%d", &temp); exit(0); } fprintf(myfile, "%d\n", useanalysismethod); fprintf(myfile, "%d\n", ntasks); for (i=1;i<=ntasks;i++) { fprintf(myfile,"%d\n", tasks[i].id); fprintf(myfile,"%lf\n", tasks[i].T); fprintf(myfile,"%lf\n", tasks[i].D); for (s=1;s<=tasks[i].nseg;s++) { if (s==1) { fprintf( myfile, "%lf", i, s, tasks[i].C[s] ); } else { fprintf( myfile, " %lf %lf", i,s-1,tasks[i].G[s-1], i,s,tasks[i].C[s] ); } } fprintf( myfile, "\n"); for (s=1;s<=tasks[i].nseg;s++) { if (s==1) { fprintf( myfile, "%d", tasks[i].prio[s]); } else { fprintf( myfile, " %d", tasks[i].prio[s]); } } fprintf( myfile, "\n"); for (s=1;s<=tasks[i].nseg-1;s++) { if (s==1) { fprintf( myfile, "%lf", tasks[i].phi[s]); } else { fprintf( myfile, " %lf", tasks[i].phi[s]); } } fprintf( myfile, "\n"); for (s=1;s<=tasks[i].nseg;s++) { if (s==1) { fprintf( myfile, "R_%d_%d = %lf", i,s, tasks[i].R[s]); } else { fprintf( myfile, ",R_%d_%d = %lf", i,s,tasks[i].R[s]); } } fprintf(myfile,"%lf\n", tasks[i].C[1]); fprintf(myfile,"%lf\n", tasks[i].G[1]); fprintf(myfile,"%lf\n", tasks[i].C[2]); fprintf(myfile,"%d\n", tasks[i].prio[1]); fprintf(myfile,"%d\n", tasks[i].prio[2]); fprintf(myfile,"%lf\n", tasks[i].phi[1]); fprintf(myfile,"%lf\n", tasks[i].R[1]); fprintf(myfile,"%lf\n", tasks[i].R[2]); } fclose( myfile); printtasks(); } void writeresponsetimeandprioandphitofile(char* fn) { FILE* myfile; int i; int temp; myfile = fopen( fn, "w"); if (myfile==NULL) { printf("Error opening file\n"); scanf("%d", &temp); exit(0); } fprintf(myfile,"success = %d\n", success ); for (i=1;i<=ntasks;i++) { fprintf(myfile,"task with id=%d has R1=%lf R2=%lf phi=%lf prio1=%d prio2=%d \n", tasks[i].id, tasks[i].R[1], tasks[i].R[2], tasks[i].phi[1], tasks[i].prio[1], tasks[i].prio[2] ); } fclose( myfile); } void initializetaskset() { // We initialize some data structures. The data in these datastructures will be overwritten by the call "readtasksetfromfile" below. // But in some cases, we want to run the tool without input file and then it is convenience to have a default taskset. useanalysismethod = 1; // this is calculating response times ntasks = 3; tasks[1].id = 1; tasks[1].T = 1.00; tasks[1].D = 1.00; tasks[1].nseg = 2; tasks[1].C[1] = 0.1; tasks[1].G[1] = 0.06; tasks[1].C[2] = 0.125; tasks[1].prio[1] = 6; tasks[1].prio[2] = 5; tasks[1].phi[1] = 0.45; tasks[1].R[1] = -1; tasks[1].R[2] = -1; tasks[2].id = 2; tasks[2].T = 2.00; tasks[2].D = 2.00; tasks[2].nseg = 2; tasks[2].C[1] = 0.2; tasks[2].G[1] = 0.12; tasks[2].C[2] = 0.25; tasks[2].prio[1] = 4; tasks[2].prio[2] = 3; tasks[2].phi[1] = 0.90; tasks[2].R[1] = -1; tasks[2].R[2] = -1; tasks[3].id = 3; tasks[3].T = 4.00; tasks[3].D = 4.00; tasks[3].nseg = 2; tasks[3].C[1] = 0.4; tasks[3].G[1] = 0.24; tasks[3].C[2] = 0.50; tasks[3].prio[1] = 2; tasks[3].prio[2] = 1; tasks[3].phi[1] = 1.80; tasks[3].R[1] = -1; tasks[3].R[2] = -1; readtasksetfromfile( inputfilename ); printtasks(); } void make_gurobifn( char* fn, char* gurobifn) { sprintf(gurobifn,"g%s", fn); } void make_gurobiresultfn( char* fn, char* gurobiresultfn) { char tempstr[20000]; int index; int l; sprintf(gurobiresultfn,"g%s", fn); l = strlen( gurobiresultfn); index = l-1; while ((gurobiresultfn[index]!='.') && (index>=0)) { index--; } if (gurobiresultfn[index]=='.') { strcpy( tempstr, gurobiresultfn ); tempstr[index] = 0; sprintf( gurobiresultfn, "%s.sol", tempstr); } } void modify_string_to_match_gurobi( char* tempstr) { ; // in previous versions, here added multiplication sign here. But now we do not. } void deletespacesinthebeginningofstring(char* tempstr) { int l; int firstnonspace; int i; l = strlen(tempstr); firstnonspace = 0; while ((tempstr[firstnonspace]=' ') && (firstnonspace=0)) { index--; } if (pythonscriptfn[index]=='.') { strcpy( tempstr, pythonscriptfn ); tempstr[index] = 0; sprintf( pythonscriptfn, "%s.py", tempstr); } } void create_Gurobi_script( char* fn) { int i; int k; FILE* f; char pythonscriptfn[20000]; char gurobiresultfn[20000]; create_pythonscriptfn( pythonscriptfn, fn); make_gurobiresultfn( fn, gurobiresultfn); f = fopen( pythonscriptfn, "w"); fprintf( f, "from gurobipy import *\n"); fprintf( f, "m = read('g%s')\n", fn); fprintf( f, "m.optimize()\n"); fprintf( f, "m.write('%s')\n", gurobiresultfn); fprintf( f, "exit()\n"); fclose( f); } void create_Gurobi_command_line_for_executing_script( char* commandstringwithscript, char* fn) { char pythonscriptfn[20000]; create_pythonscriptfn( pythonscriptfn, fn); #if COMPILEMSVS sprintf( commandstringwithscript, "gurobi.bat %s", pythonscriptfn); #else sprintf( commandstringwithscript, "gurobi.sh %s", pythonscriptfn); #endif } void addobjectivefunction( int fh) { char tempstr[20000]; sprintf( tempstr, "min: R_1_1;\n\n"); mywrite( fh, tempstr, strlen( tempstr) ); } void addconstraintspriorities_are_given(int fh) { int i; int s; int p; int maxprio; char tempstr[20000]; maxprio = getnumberofprioritylevelsneededinorderforeachsegmenttohaveauniquepriority(); for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (p=1;p<=maxprio;p++) { if (tasks[i].prio[s]==p) { sprintf( tempstr,"y_%d_%d_%d = 1;\n", i, s, p); mywrite( fh, tempstr, strlen( tempstr) ); } else { sprintf( tempstr,"y_%d_%d_%d = 0;\n", i, s, p); mywrite( fh, tempstr, strlen( tempstr) ); } } } } } void addconstraintsphi_values_are_given(int fh) { int i; int s; char tempstr[20000]; for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { if (s>=2) { sprintf( tempstr,"phi_%d_%d = %lf;\n", i, s-1, tasks[i].phi[s-1]); mywrite( fh, tempstr, strlen( tempstr) ); } } } } void addconstraintsphiforfirstsegmentiszero(int fh) { int i; char tempstr[20000]; for (i=1;i<=ntasks;i++) { sprintf( tempstr,"phi_%d_0 = 0;\n", i ); mywrite( fh, tempstr, strlen( tempstr) ); } } void addconstraintsphasesarenondecreasing(int fh) { int i; int s; char tempstr[20000]; for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg-1;s++) { sprintf( tempstr,"phi_%d_%d - phi_%d_%d <= 0;\n", i,s-1,i,s ); mywrite( fh, tempstr, strlen( tempstr) ); } } } void addconstraintseachtasktakesexactlyoneprioritylevel(int fh) { int i; int p; int s; int maxprio; char tempstr[20000]; maxprio = getnumberofprioritylevelsneededinorderforeachsegmenttohaveauniquepriority(); for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (p=1;p<=maxprio;p++) { if (p==1) { sprintf( tempstr," y_%d_%d_%d ", i,s,p ); mywrite( fh, tempstr, strlen( tempstr) ); } else { sprintf( tempstr," + y_%d_%d_%d ", i,s,p ); mywrite( fh, tempstr, strlen( tempstr) ); } } sprintf( tempstr," = 1;\n" ); mywrite( fh, tempstr, strlen( tempstr) ); } } } void addconstraintsschedulability(int fh) { int i; int s; char tempstr[20000]; for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg-1;s++) { sprintf( tempstr,"R_%d_%d - phi_%d_%d <= %lf;\n", i, s, i, s, -tasks[i].G[s]); mywrite( fh, tempstr, strlen( tempstr) ); } } for (i=1;i<=ntasks;i++) { sprintf( tempstr,"R_%d_%d <= %lf;\n", i, tasks[i].nseg, tasks[i].D); mywrite( fh, tempstr, strlen( tempstr) ); } } void addconstraintsprioritylevelpriorityrelationships(int fh) { int i; int j; int s; int sprimeprime; int p; int pprime; int maxprio; char tempstr[20000]; maxprio = getnumberofprioritylevelsneededinorderforeachsegmenttohaveauniquepriority(); for (i=1;i<=ntasks;i++) { for (j=1;j<=ntasks;j++) { for (s=1;s<=tasks[i].nseg;s++) { for (sprimeprime=1;sprimeprime<=tasks[j].nseg;sprimeprime++) { for (p=1;p<=maxprio;p++) { for (pprime=1;pprime<=maxprio;pprime++) { if ((j!=i) && (p<=pprime)) { sprintf( tempstr,"y_%d_%d_%d + y_%d_%d_%d - x_%d_%d_%d_%d <= 1;\n", i,s,p, j,sprimeprime,pprime, i,s,j,sprimeprime); mywrite( fh, tempstr, strlen( tempstr) ); } } } } } } } } void addconstraintsresponsetimeandwaitingtime(int fh) { int i; int s; char tempstr[20000]; for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { sprintf( tempstr,"R_%d_%d - phi_%d_%d - w_%d_%d = 0;\n", i,s,i,s-1,i,s); mywrite( fh, tempstr, strlen( tempstr) ); } } } void addconstraintswaitingtimeandinterference(int fh) { int i; int s; int j; char tempstr[20000]; for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { sprintf( tempstr,"w_%d_%d ", i,s ); mywrite( fh, tempstr, strlen( tempstr) ); for (j=1;j<=ntasks;j++) { if (j!=i) { sprintf( tempstr," - I_%d_%d_%d ", i,s,j ); mywrite( fh, tempstr, strlen( tempstr) ); } } sprintf( tempstr," = %lf;\n", tasks[i].C[s] ); mywrite( fh, tempstr, strlen( tempstr) ); } } } REAL getDMAX() { int i; REAL t; t = -1.0; for (i=1;i<=ntasks;i++) { if (tasks[i].D>t) { t = tasks[i].D; } } return t; } int prec(int sprime,int j) { if (sprime==1) { tasks[j].nseg; } else { return sprime-1; } } void addconstraintsinterferencefordifferentphases(int fh) { int i; int j; int s; int sprime; double DMAX; char tempstr[20000]; for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (j=1;j<=ntasks;j++) { if (j!=i) { for (sprime=1;sprime<=tasks[j].nseg;sprime++) { if (sprime==1) { sprintf( tempstr,"decisionmax_%d_%d_%dU%d", i,s,j,sprime ); mywrite( fh, tempstr, strlen( tempstr) ); } else { sprintf( tempstr," + decisionmax_%d_%d_%dU%d", i,s,j,sprime ); mywrite( fh, tempstr, strlen( tempstr) ); } } sprintf( tempstr," = 1;\n" ); mywrite( fh, tempstr, strlen( tempstr) ); } } } } for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (j=1;j<=ntasks;j++) { for (sprime=1;sprime<=tasks[j].nseg;sprime++) { if (j!=i) { sprintf( tempstr,"CIexec_%d_%d_%dU%d + NCIexec_%d_%d_%dU%d - I_%d_%d_%d <= 0;\n", i,s,j,sprime, i,s,j,sprime, i,s,j ); mywrite( fh, tempstr, strlen( tempstr) ); } } } } } DMAX = getDMAX(); for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (j=1;j<=ntasks;j++) { for (sprime=1;sprime<=tasks[j].nseg;sprime++) { if (j!=i) { sprintf( tempstr,"I_%d_%d_%d - CIexec_%d_%d_%dU%d - NCIexec_%d_%d_%dU%d + %lf decisionmax_%d_%d_%dU%d <= %lf;\n", i,s,j, i,s,j,sprime, i,s,j,sprime, DMAX, i,s,j,sprime, DMAX ); mywrite( fh, tempstr, strlen( tempstr) ); } } } } } for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (j=1;j<=ntasks;j++) { for (sprime=1;sprime<=tasks[j].nseg;sprime++) { if (j!=i) { sprintf( tempstr,"CIexec_%d_%d_%dU%d - %lf x_%d_%d_%d_%d = 0;\n", i,s,j,sprime, tasks[j].C[ prec(sprime,j) ], i,s,j,prec(sprime,j) ); mywrite( fh, tempstr, strlen( tempstr) ); } } } } } } void addconstraintsinterferenceforaphaseissumofterms(int fh) { int i; int j; int s; int sprime; int sprimeprime; double DMAX; char tempstr[20000]; for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (j=1;j<=ntasks;j++) { for (sprime=1;sprime<=tasks[j].nseg;sprime++) { if (j!=i) { sprintf( tempstr,"NCIexec_%d_%d_%dU%d ",i,s,j,sprime ); mywrite( fh, tempstr, strlen( tempstr) ); for (sprimeprime=1;sprimeprime<=tasks[j].nseg;sprimeprime++) { sprintf( tempstr," - NCIexecterm_%d_%d_%d_%dU%d ", i,s,j,sprimeprime, sprime ); mywrite( fh, tempstr, strlen( tempstr) ); } sprintf( tempstr," = 0;\n" ); mywrite( fh, tempstr, strlen( tempstr) ); } } } } } } void addconstraintsinterferencetermdependsonwaitingtime(int fh) { int i; int s; int j; int sprime; int sprimeprime; REAL DMAX; char tempstr[20000]; DMAX = getDMAX(); for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (j=1;j<=ntasks;j++) { for (sprime=1;sprime<=tasks[j].nseg;sprime++) { for (sprimeprime=1;sprimeprime<=tasks[j].nseg;sprimeprime++) { if (j!=i) { sprintf( tempstr,"NCIexecterm_%d_%d_%d_%dU%d - %lf x_%d_%d_%d_%d <= 0;\n", i,s,j,sprimeprime, sprime, DMAX, i,s,j,sprimeprime ); mywrite( fh, tempstr, strlen( tempstr) ); sprintf( tempstr,"NCIexecterm_%d_%d_%d_%dU%d - %lf njobs_%d_%d_%d_%dU%d + %lf x_%d_%d_%d_%d <= %lf;\n", i,s,j,sprimeprime, sprime, tasks[j].C[sprimeprime], i,s,j,sprimeprime, sprime, DMAX, i,s,j,sprimeprime, DMAX ); mywrite( fh, tempstr, strlen( tempstr) ); sprintf( tempstr,"NCIexecterm_%d_%d_%d_%dU%d - %lf njobs_%d_%d_%d_%dU%d - %lf x_%d_%d_%d_%d >= %lf;\n", i,s,j,sprimeprime, sprime, tasks[j].C[sprimeprime], i,s,j,sprimeprime, sprime, DMAX, i,s,j,sprimeprime, -DMAX ); mywrite( fh, tempstr, strlen( tempstr) ); if (sprimeprime>=sprime) { /* sprintf( tempstr, "%lf njobs_%d_%d_%d_%dU%d + phi_%d_%d - phi_%d_%d - w_%d_%d <= %lf;\n", tasks[j].T, i,s,j,sprimeprime, sprime, j,sprimeprime-1, j, sprime-1, i,s, tasks[j].T ); mywrite( fh, tempstr, strlen( tempstr) ); */ sprintf( tempstr, "%lf njobs_%d_%d_%d_%dU%d + phi_%d_%d - phi_%d_%d - w_%d_%d >= 0;\n", tasks[j].T, i,s,j,sprimeprime, sprime, j,sprimeprime-1, j, sprime-1, i,s ); mywrite( fh, tempstr, strlen( tempstr) ); } else { /* sprintf( tempstr, "%lf njobs_%d_%d_%d_%dU%d + phi_%d_%d - phi_%d_%d - w_%d_%d <= 0;\n", tasks[j].T, i,s,j,sprimeprime, sprime, j,sprimeprime-1, j, sprime-1, i,s ); mywrite( fh, tempstr, strlen( tempstr) ); */ sprintf( tempstr, "%lf njobs_%d_%d_%d_%dU%d + phi_%d_%d - phi_%d_%d - w_%d_%d >= %lf;\n", tasks[j].T, i,s,j,sprimeprime, sprime, j,sprimeprime-1, j, sprime-1, i,s, -tasks[j].T ); mywrite( fh, tempstr, strlen( tempstr) ); } } } } } } } } void addconstraintsaboutthatvariablesarebinary( int fh) { int i; int s; int j; int sprimeprime; int sprime; int p; int maxprio; char tempstr[20000]; maxprio = getnumberofprioritylevelsneededinorderforeachsegmenttohaveauniquepriority(); for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (p=1;p<=maxprio;p++) { sprintf( tempstr, "bin y_%d_%d_%d;\n", i,s,p ); mywrite( fh, tempstr, strlen( tempstr) ); } } } for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (j=1;j<=ntasks;j++) { for (sprimeprime=1;sprimeprime<=tasks[j].nseg;sprimeprime++) { if (j!=i) { sprintf( tempstr, "bin x_%d_%d_%d_%d;\n", i,s,j,sprimeprime ); mywrite( fh, tempstr, strlen( tempstr) ); } } } } } for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (j=1;j<=ntasks;j++) { for (sprime=1;sprime<=tasks[j].nseg;sprime++) { if (j!=i) { sprintf( tempstr, "bin decisionmax_%d_%d_%dU%d;\n", i,s,j,sprime ); mywrite( fh, tempstr, strlen( tempstr) ); } } } } } } void addconstraintsaboutthatvariablesareinteger( int fh) { int i; int s; int j; int sprimeprime; int sprime; char tempstr[20000]; for (i=1;i<=ntasks;i++) { for (s=1;s<=tasks[i].nseg;s++) { for (j=1;j<=ntasks;j++) { for (sprimeprime=1;sprimeprime<=tasks[j].nseg;sprimeprime++) { for (sprime=1;sprime<=tasks[j].nseg;sprime++) { if (j!=i) { sprintf( tempstr, "int njobs_%d_%d_%d_%dU%d;\n", i,s,j,sprimeprime, sprime ); mywrite( fh, tempstr, strlen( tempstr) ); } } } } } } } void mycopyfile(char* source,char* destination) { char tempstr[20000]; #if COMPILEMSVS sprintf( tempstr, "copy %s %s", source, destination ); #else sprintf( tempstr, "cp %s %s", source, destination ); #endif system(tempstr); } REAL max2real( REAL t1, REAL t2) { if (t1>=t2) { return t1; } else { return t2; } } // this works only if we have two segments for each task int do_responsetimeanalysis_with_iterations() { int i; int j; int xi1j1; int xi1j2; int xi2j1; int xi2j2; REAL t; REAL newt; REAL term1; REAL term2; REAL aterm; // Let us now compute R_i^1 for (i=1;i<=ntasks;i++) { t = -1; newt = tasks[i].C[1]; while (newt>t) { t = newt; newt = tasks[i].C[1]; for (j=1;j<=ntasks;j++) { if (j!=i) { if (tasks[j].prio[1]>=tasks[i].prio[1]) { xi1j1 = 1; } else { xi1j1 = 0; } if (tasks[j].prio[2]>=tasks[i].prio[1]) { xi1j2 = 1; } else { xi1j2 = 0; } term1 = ceil( t/tasks[j].T )*tasks[j].C[1]*xi1j1 + ceil( (t-tasks[j].phi[1])/tasks[j].T )*tasks[j].C[2]*xi1j2; term2 = ceil( t-(tasks[j].T-tasks[j].phi[1])/tasks[j].T )*tasks[j].C[1]*xi1j1 + ceil( t/tasks[j].T )*tasks[j].C[2]*xi1j2; aterm = max2real( term1, term2); newt = newt + aterm; } } } tasks[i].R[1] = newt; } // Let us now compute R_i^2 for (i=1;i<=ntasks;i++) { t = -1; newt = tasks[i].C[2]; while (newt>t) { t = newt; newt = tasks[i].C[2]; for (j=1;j<=ntasks;j++) { if (j!=i) { if (tasks[j].prio[1]>=tasks[i].prio[2]) { xi2j1 = 1; } else { xi2j1 = 0; } if (tasks[j].prio[2]>=tasks[i].prio[2]) { xi2j2 = 1; } else { xi2j2 = 0; } term1 = ceil( t/tasks[j].T )*tasks[j].C[1]*xi2j1 + ceil( (t-tasks[j].phi[1])/tasks[j].T )*tasks[j].C[2]*xi2j2; term2 = ceil( t-(tasks[j].T-tasks[j].phi[1])/tasks[j].T )*tasks[j].C[1]*xi2j1 + ceil( t/tasks[j].T )*tasks[j].C[2]*xi2j2; aterm = max2real( term1, term2); newt = newt + aterm; } } } tasks[i].R[2] = tasks[i].phi[1] + newt; } // let us check schedulability for (i=1;i<=ntasks;i++) { if (tasks[i].R[1]+tasks[i].G[1]>tasks[i].phi[1]) { return 0; } if (tasks[i].R[2]>tasks[i].D) { return 0; } } return 1; } int do_schedulability_analysis_with_MILP_assuming_prio_and_phi_are_given() { #if COMPILEMSVS lprec* mylprec; #endif char fn[20000]; char gurobifn[20000]; char gurobiresultfn[20000]; char commandstring[20000]; char commandstringwithscript[20000]; int fh; int ret; REAL v; int* feas; REAL* value; int tempapa; int temp; char gurobifn2[20000]; feas = &ret; value = &v; sprintf( fn, "anilp%d.lp", counterforILPsolver); counterforILPsolver++; sprintf( gurobifn2, "apa"); #if COMPILEMSVS fh = myopen( fn, O_CREAT | O_WRONLY, S_IWRITE); #else fh = myopen( fn, O_CREAT | O_RDWR, S_IRWXU); #endif if (fh<0) { printf("Error in resp. Failed to open file.\n"); exit(-1); fflush(stdout); } addobjectivefunction( fh); addconstraintspriorities_are_given(fh); addconstraintsphi_values_are_given(fh); addconstraintsphiforfirstsegmentiszero(fh); addconstraintsphasesarenondecreasing(fh); addconstraintseachtasktakesexactlyoneprioritylevel(fh); addconstraintsschedulability(fh); addconstraintsprioritylevelpriorityrelationships(fh); addconstraintsresponsetimeandwaitingtime(fh); addconstraintswaitingtimeandinterference(fh); addconstraintsinterferencefordifferentphases(fh); addconstraintsinterferenceforaphaseissumofterms(fh); addconstraintsinterferencetermdependsonwaitingtime(fh); addconstraintsaboutthatvariablesarebinary( fh); addconstraintsaboutthatvariablesareinteger( fh); myclose( fh); make_gurobifn( fn, gurobifn); make_gurobiresultfn( fn, gurobiresultfn); fill_gurobifile( fn, gurobifn); mycopyfile(gurobifn,gurobifn2); // fill_gurobifile_change_optimization_to_satisfaction( gurobifn2, gurobifn); #if COMPILEMSVS if (USE_LP_SOLVE==1) { mylprec = _read_LP(fn, NORMAL, NULL); if (mylprec==NULL) { printf("Error in resp\n"); exit(-1); } _set_anti_degen( mylprec, ANTIDEGEN_FIXEDVARS | ANTIDEGEN_DYNAMIC ); ret = _solve( mylprec); if (ret==OPTIMAL) { *feas = 1; *value = _get_objective(mylprec); } else { *feas = 0; } _delete_lp( mylprec); } #endif if (USE_GUROBI==1) { create_Gurobi_script( fn); create_Gurobi_command_line_for_executing_script( commandstringwithscript, fn ); printf("%s\n", commandstringwithscript); system( commandstringwithscript); extract_objective_function_from_solution_from_Gurobi(gurobiresultfn, feas, value); } return (*feas); } int do_assign_priorities_assuming_that_phi_is_given() { #if COMPILEMSVS lprec* mylprec; #endif char fn[20000]; char gurobifn[20000]; char gurobiresultfn[20000]; char commandstring[20000]; char commandstringwithscript[20000]; int fh; int ret; REAL v; int* feas; REAL* value; int tempapa; int temp; char gurobifn2[20000]; feas = &ret; value = &v; sprintf( fn, "anilp%d.lp", counterforILPsolver); counterforILPsolver++; sprintf( gurobifn2, "apa"); #if COMPILEMSVS fh = myopen( fn, O_CREAT | O_WRONLY, S_IWRITE); #else fh = myopen( fn, O_CREAT | O_RDWR, S_IRWXU); #endif if (fh<0) { printf("Error in resp. Failed to open file.\n"); exit(-1); fflush(stdout); } addobjectivefunction( fh); // addconstraintspriorities_are_given(fh); addconstraintsphi_values_are_given(fh); addconstraintsphiforfirstsegmentiszero(fh); addconstraintsphasesarenondecreasing(fh); addconstraintseachtasktakesexactlyoneprioritylevel(fh); addconstraintsschedulability(fh); addconstraintsprioritylevelpriorityrelationships(fh); addconstraintsresponsetimeandwaitingtime(fh); addconstraintswaitingtimeandinterference(fh); addconstraintsinterferencefordifferentphases(fh); addconstraintsinterferenceforaphaseissumofterms(fh); addconstraintsinterferencetermdependsonwaitingtime(fh); addconstraintsaboutthatvariablesarebinary( fh); addconstraintsaboutthatvariablesareinteger( fh); myclose( fh); make_gurobifn( fn, gurobifn); make_gurobiresultfn( fn, gurobiresultfn); fill_gurobifile( fn, gurobifn); mycopyfile(gurobifn,gurobifn2); // fill_gurobifile_change_optimization_to_satisfaction( gurobifn2, gurobifn); #if COMPILEMSVS if (USE_LP_SOLVE==1) { mylprec = _read_LP(fn, NORMAL, NULL); if (mylprec==NULL) { printf("Error in resp\n"); exit(-1); } _set_anti_degen( mylprec, ANTIDEGEN_FIXEDVARS | ANTIDEGEN_DYNAMIC ); ret = _solve( mylprec); if (ret==OPTIMAL) { *feas = 1; *value = _get_objective(mylprec); } else { *feas = 0; } _delete_lp( mylprec); } #endif if (USE_GUROBI==1) { create_Gurobi_script( fn); create_Gurobi_command_line_for_executing_script( commandstringwithscript, fn ); printf("%s\n", commandstringwithscript); system( commandstringwithscript); extract_objective_function_from_solution_from_Gurobi(gurobiresultfn, feas, value); } return (*feas); } int do_assign_phi_assuming_that_priorities_are_given() { #if COMPILEMSVS lprec* mylprec; #endif char fn[20000]; char gurobifn[20000]; char gurobiresultfn[20000]; char commandstring[20000]; char commandstringwithscript[20000]; int fh; int ret; REAL v; int* feas; REAL* value; int tempapa; int temp; char gurobifn2[20000]; feas = &ret; value = &v; sprintf( fn, "anilp%d.lp", counterforILPsolver); counterforILPsolver++; sprintf( gurobifn2, "apa"); #if COMPILEMSVS fh = myopen( fn, O_CREAT | O_WRONLY, S_IWRITE); #else fh = myopen( fn, O_CREAT | O_RDWR, S_IRWXU); #endif if (fh<0) { printf("Error in resp. Failed to open file.\n"); exit(-1); fflush(stdout); } addobjectivefunction( fh); addconstraintspriorities_are_given(fh); // addconstraintsphi_values_are_given(fh); addconstraintsphiforfirstsegmentiszero(fh); addconstraintsphasesarenondecreasing(fh); addconstraintseachtasktakesexactlyoneprioritylevel(fh); addconstraintsschedulability(fh); addconstraintsprioritylevelpriorityrelationships(fh); addconstraintsresponsetimeandwaitingtime(fh); addconstraintswaitingtimeandinterference(fh); addconstraintsinterferencefordifferentphases(fh); addconstraintsinterferenceforaphaseissumofterms(fh); addconstraintsinterferencetermdependsonwaitingtime(fh); addconstraintsaboutthatvariablesarebinary( fh); addconstraintsaboutthatvariablesareinteger( fh); myclose( fh); make_gurobifn( fn, gurobifn); make_gurobiresultfn( fn, gurobiresultfn); fill_gurobifile( fn, gurobifn); mycopyfile(gurobifn,gurobifn2); // fill_gurobifile_change_optimization_to_satisfaction( gurobifn2, gurobifn); #if COMPILEMSVS if (USE_LP_SOLVE==1) { mylprec = _read_LP(fn, NORMAL, NULL); if (mylprec==NULL) { printf("Error in resp\n"); exit(-1); } _set_anti_degen( mylprec, ANTIDEGEN_FIXEDVARS | ANTIDEGEN_DYNAMIC ); ret = _solve( mylprec); if (ret==OPTIMAL) { *feas = 1; *value = _get_objective(mylprec); } else { *feas = 0; } _delete_lp( mylprec); } #endif if (USE_GUROBI==1) { create_Gurobi_script( fn); create_Gurobi_command_line_for_executing_script( commandstringwithscript, fn ); printf("%s\n", commandstringwithscript); system( commandstringwithscript); extract_objective_function_from_solution_from_Gurobi(gurobiresultfn, feas, value); } return (*feas); } int do_assign_phi_and_priorities() { #if COMPILEMSVS lprec* mylprec; #endif char fn[20000]; char gurobifn[20000]; char gurobiresultfn[20000]; char commandstring[20000]; char commandstringwithscript[20000]; int fh; int ret; REAL v; int* feas; REAL* value; int tempapa; int temp; char gurobifn2[20000]; feas = &ret; value = &v; sprintf( fn, "anilp%d.lp", counterforILPsolver); counterforILPsolver++; sprintf( gurobifn2, "apa"); #if COMPILEMSVS fh = myopen( fn, O_CREAT | O_WRONLY, S_IWRITE); #else fh = myopen( fn, O_CREAT | O_RDWR, S_IRWXU); #endif if (fh<0) { printf("Error in resp. Failed to open file.\n"); exit(-1); fflush(stdout); } addobjectivefunction( fh); // addconstraintspriorities_are_given(fh); // addconstraintsphi_values_are_given(fh); addconstraintsphiforfirstsegmentiszero(fh); addconstraintsphasesarenondecreasing(fh); addconstraintseachtasktakesexactlyoneprioritylevel(fh); addconstraintsschedulability(fh); addconstraintsprioritylevelpriorityrelationships(fh); addconstraintsresponsetimeandwaitingtime(fh); addconstraintswaitingtimeandinterference(fh); addconstraintsinterferencefordifferentphases(fh); addconstraintsinterferenceforaphaseissumofterms(fh); addconstraintsinterferencetermdependsonwaitingtime(fh); addconstraintsaboutthatvariablesarebinary( fh); addconstraintsaboutthatvariablesareinteger( fh); myclose( fh); make_gurobifn( fn, gurobifn); make_gurobiresultfn( fn, gurobiresultfn); fill_gurobifile( fn, gurobifn); mycopyfile(gurobifn,gurobifn2); // fill_gurobifile_change_optimization_to_satisfaction( gurobifn2, gurobifn); #if COMPILEMSVS if (USE_LP_SOLVE==1) { mylprec = _read_LP(fn, NORMAL, NULL); if (mylprec==NULL) { printf("Error in resp\n"); exit(-1); } _set_anti_degen( mylprec, ANTIDEGEN_FIXEDVARS | ANTIDEGEN_DYNAMIC ); ret = _solve( mylprec); if (ret==OPTIMAL) { *feas = 1; *value = _get_objective(mylprec); } else { *feas = 0; } _delete_lp( mylprec); } #endif if (USE_GUROBI==1) { create_Gurobi_script( fn); create_Gurobi_command_line_for_executing_script( commandstringwithscript, fn ); printf("%s\n", commandstringwithscript); system( commandstringwithscript); extract_objective_function_from_solution_from_Gurobi(gurobiresultfn, feas, value); } return (*feas); } int doit() { printf("do it\n"); if (useanalysismethod==1) { printf("Feature not implemented"); exit(0); // success = do_responsetimeanalysis_with_iterations(); // this works only if we have two segments for each task // return success; } if (useanalysismethod==2) { success = do_schedulability_analysis_with_MILP_assuming_prio_and_phi_are_given(); return success; } if (useanalysismethod==3) { success = do_assign_priorities_assuming_that_phi_is_given(); return success; } if (useanalysismethod==4) { success = do_assign_phi_assuming_that_priorities_are_given(); return success; } if (useanalysismethod==5) { success = do_assign_phi_and_priorities(); return success; } } void parsearguments( int argc, char *argv[], char *envp[]) { int temp; int i; i = 1; while (i<=argc-1) { if (strcmp( argv[i], "-i")==0) { strcpy( inputfilename, argv[i+1] ); i = i + 2; } else { if (strcmp( argv[i], "-o")==0) { strcpy( outputfilename, argv[i+1] ); i = i + 2; } else { if (strcmp( argv[i], "-g")==0) { generate_experiments = 1; i = i + 1; } else { if (strcmp( argv[i], "-r")==0) { run_experiments = 1; i = i + 1; } else { i++; } } } } } } int main( int argc, char *argv[], char *envp[]) { printf("Starting tool for tasks with multiple stages\n"); parsearguments(argc, argv, envp); initializetaskset(); // if we have an input file then these will be overwritten by the parameters of the input file doit(); writeresponsetimeandprioandphitofile(outputfilename); return 0; }