Changeset 13719 for trunk


Ignore:
Timestamp:
Oct 10, 2019 2:41:07 PM (2 months ago)
Author:
Christian Andersson
Message:

Recommitted changeset:13700 to trunk with two bug fixes. Related to ticket:5837

Location:
trunk
Files:
31 edited
11 copied

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/CHANGELOG.txt

    r13703 r13719  
    11================= Unreleased ==================
     2# Feature ; Minor ; Compiler; #5837
     3Added a pre-compiled evaluator used for evaluating external functions
     4during the compilation (for performance). Activated by the option
     5"external_constant_evaluation_dynamic"
     6
    27# Fixed ; Minor ; Compiler ; #5855
    38Nominal are now always positive in the FMI model description.
  • trunk/Compiler/ModelicaCBackEnd/src/jastadd/CCodeGen/CCodeGenExternalCeval.jrag

    r13703 r13719  
    248248        Collection<ExternalArgument> res = new LinkedHashSet<>();
    249249        if (hasReturnVar()) {
    250             res.add(getReturnVar().externalArgument());
    251         }
     250            res.add(returnVarToSerialize());
     251        }
     252        res.addAll(argVarsToSerialize());
     253        return res;
     254    }
     255   
     256    syn ExternalArgument FExternalStmt.returnVarToSerialize() = getReturnVar().externalArgument();
     257    syn Collection<ExternalArgument> FExternalStmt.argVarsToSerialize() {
     258        Collection<ExternalArgument> res = new LinkedHashSet<>();
    252259        for (FExp e : getArgs()) {
    253260            res.add(e.externalArgument());
     
    288295        }
    289296        return functionArgs;
     297    }
     298   
     299
     300    syn String FType.cMappedTypeString() = cMappedTypeStringScalar() + (isArray() ? "v" : "");
     301
     302    syn String FType.cMappedTypeStringScalar() {
     303        throw new InternalCompilerError("cMappedTypeStringScalar() is not supported for class type " + getClass().getSimpleName());
     304    }
     305    eq FArrayType.cMappedTypeStringScalar() = getFPrimitiveType().cMappedTypeStringScalar();
     306    eq FIntegerType.cMappedTypeStringScalar() = "i";
     307    eq FEnumType.cMappedTypeStringScalar() = "i";
     308    eq FBooleanType.cMappedTypeStringScalar() = "i";
     309    eq FRealType.cMappedTypeStringScalar() = "d";
     310    eq FStringType.cMappedTypeStringScalar() = "s";
     311    eq FRecordType.cMappedTypeStringScalar() {
     312        String o = "R[";
     313        for (FRecordComponentType rType: getComponents()) {
     314                o = o.concat(rType.getFType().cMappedTypeStringScalar());
     315                o = o.concat(",");
     316        }
     317        return o.concat("]");
     318    }
     319   
     320    syn String FExternalStmt.functionReturnArgSerialized() {
     321        if (hasReturnVar()) {
     322            return returnVarToSerialize().type().cMappedTypeString();
     323        } else {
     324            return "void";
     325        }
     326    }
     327   
     328    syn String FExternalStmt.functionArgsSerialized() {
     329        String input = "";
     330        for (ExternalArgument var : argVarsToSerialize()) {
     331            if (var.isOutput()) {
     332               input = input.concat("*");
     333            }
     334            input += var.type().cMappedTypeString() + ",";
     335        }
     336        return input;
    290337    }
    291338   
     
    347394            }
    348395        }
     396    }
     397   
     398    public String FClass.externalCTypes() {
     399        StringBuilder sb = new StringBuilder();
     400        for (FExternalStmt stmt : myExternals()) {
     401            if (stmt.dynamicEvaluatorEnabled()) {
     402                sb.append(stmt.getName());
     403                sb.append("\n");
     404                sb.append(stmt.functionReturnArgSerialized());
     405                sb.append("\n");
     406                sb.append(stmt.functionArgsSerialized());
     407                sb.append("\n");
     408            }
     409        }
     410        return sb.toString();
    349411    }
    350412
  • trunk/Compiler/ModelicaCBackEnd/templates/ceval_external_template.c

    r13703 r13719  
    1414*/
    1515
    16 #include <stdio.h>
    17 #include <stdlib.h>
    18 #include <string.h>
    19 #include "jmi.h"
    20 #include "jmi_dyn_mem.h"
    21 #include "ModelicaUtilities.h"
    22 #include <fcntl.h>
     16#include "jmi_evaluator_util.h"
     17
     18/* Must be defined here in order to override the methods from jmi_global.c */
     19void jmi_global_log(int warning, const char* name, const char* fmt, const char* value) {
     20    _jmi_global_log(warning, name, fmt, value);
     21}
     22void jmi_throw() {
     23    _jmi_throw();
     24}
     25void* jmi_global_calloc(size_t n, size_t s) {
     26    return _jmi_global_calloc(n,s);
     27}
    2328
    2429$ECE_external_includes$
    2530 
    26 /* Manual debugging */
    27 #define JMCEVAL_DEBUG 0
    28 #define JMCEVAL_DBGP(x) if (JMCEVAL_DEBUG) { printf(x); fflush(stdout);}
    29 
    30 /* Format specifier when printing jmi_real_t */
    31 #define JMCEVAL_realFormat "%.16f"
    32 
    3331/* Used record definitions */
    3432$ECE_record_definitions$
    35 
    36 /* Parses ND dimensions into dimension buffer d*/
    37 #define JMCEVAL_parseArrayDims(ND) \
    38     for (di = 0; di < ND; di++) { scanf("%d",&d[di]); }
    39 
    40 /* Parse/print basic types */
    41 double JMCEVAL_parseReal() {
    42     /* Char buffer when reading jmi_real_t. This is necessary
    43        since "%lf" is not allowed in c89. */
    44     char buff[32];
    45     JMCEVAL_DBGP("Parse number: ");
    46     scanf("%s",buff);
    47     return strtod(buff, 0);
    48 }
    49 
    50 void JMCEVAL_printReal(double x) {
    51     printf(JMCEVAL_realFormat, x); \
    52     printf("\n"); \
    53     fflush(stdout); \
    54 }
    55 
    56 char* JMCEVAL_parseString() {
    57     int d[1];
    58     char* str;
    59     size_t si,di;
    60     JMCEVAL_parseArrayDims(1);
    61     getchar();
    62     str = ModelicaAllocateString(d[0]);
    63     JMCEVAL_DBGP("Parse string: ");
    64     for (si = 0; si < d[0]; si++) str[si] = getchar();
    65     str[d[0]] = '\0';
    66     return str;
    67 }
    68 
    69 void JMCEVAL_printString(const char* str) {
    70     printf("%u\n%s\n", (unsigned)strlen(str), str);
    71     fflush(stdout);
    72 }
    73 
    74 #define JMCEVAL_parseInteger()  JMCEVAL_parseReal()
    75 #define JMCEVAL_parseBoolean()  JMCEVAL_parseInteger()
    76 #define JMCEVAL_parseEnum()     JMCEVAL_parseInteger()
    77 #define JMCEVAL_printInteger(X) JMCEVAL_printReal(X)
    78 #define JMCEVAL_printBoolean(X) JMCEVAL_printInteger(X)
    79 #define JMCEVAL_printEnum(X)    JMCEVAL_printInteger(X)
    80 #define JMCEVAL_parse(TYPE, X)  X = JMCEVAL_parse##TYPE()
    81 #define JMCEVAL_print(TYPE, X)  JMCEVAL_print##TYPE(X)
    82 
    83 /* Parse/print arrays */
    84 #define JMCEVAL_parseArray(TYPE,ARR) for (vi = 1; vi <= ARR->num_elems; vi++) { JMCEVAL_parse(TYPE, jmi_array_ref_1(ARR,vi)); }
    85 #define JMCEVAL_printArray(TYPE,ARR) for (vi = 1; vi <= ARR->num_elems; vi++) { JMCEVAL_print(TYPE, jmi_array_val_1(ARR,vi)); }
    86 
    87 /* Used by ModelicaUtilities */
    88 void jmi_global_log(int warning, const char* name, const char* fmt, const char* value)
    89 {
    90     printf("LOG\n");
    91     JMCEVAL_printInteger((double)warning);
    92     JMCEVAL_printString(name);
    93     JMCEVAL_printString(fmt);
    94     JMCEVAL_printString(value);
    95 }
    96 
    97 jmp_buf jmceval_try_location;
    98 
    99 #define JMCEVAL_try() (setjmp(jmceval_try_location) == 0)
    100 
    101 void jmi_throw()
    102 {
    103     longjmp(jmceval_try_location, 1);
    104 }
    105 
    106 jmi_dynamic_function_memory_t* dyn_fcn_mem = NULL;
    107 
    108 jmi_dynamic_function_memory_t* jmi_dynamic_function_memory() {
    109     if (dyn_fcn_mem == NULL) { dyn_fcn_mem = jmi_dynamic_function_pool_create(1024*1024); }
    110     return dyn_fcn_mem;
    111 }
    112 
    113 void* jmi_global_calloc(size_t n, size_t s)
    114 {
    115     return jmi_dynamic_function_pool_direct_alloc(dyn_fcn_mem, n*s, 1);
    116 }
    117 
    118 void JMCEVAL_setup() {
    119 #ifdef _WIN32
    120     /* Prevent win from translating \n to \r\n */
    121     _setmode(fileno(stdout), _O_BINARY);
    122 #endif
    123 }
    124 
    125 int JMCEVAL_cont(const char* word) {
    126     char l[10];
    127     char* s = fgets(l, 10, stdin);
    128     if (strlen(s) == 1) {
    129         s = fgets(l, 10, stdin); /* Extra call to fix stray newline */
    130     }
    131     if (s == NULL) {
    132         exit(2);
    133     }
    134     if (strlen(s) == strlen(word)) {
    135         return strncmp(l, word, strlen(word)) == 0;
    136     }
    137     return 0;
    138 }
    139 
    140 void JMCEVAL_check(const char* str) {
    141     printf("%s\n",str);
    142     fflush(stdout);
    143 }
    144 
    145 void JMCEVAL_failed() {
    146     JMCEVAL_check("ABORT");
    147 }
    14833
    14934/* Main */
     
    19580        JMCEVAL_failed();
    19681    }
    197     jmi_dynamic_function_pool_destroy(dyn_fcn_mem);
     82    _jmi_dynamic_function_pool_destroy();
    19883    JMCEVAL_check("END");
    19984    return 0;
  • trunk/Compiler/ModelicaCBackEnd/test/modelica/CCodeGenExternalCevalTests.mo

    r13703 r13719  
    1717
    1818package CCodeGenExternalCevalTests
     19
     20model ExtDynFcn1
     21        type E = enumeration(A,B);
     22    function f
     23        input Real a1;
     24        input Integer a2;
     25        input Boolean a3;
     26        input String a4;
     27        input E a5;
     28        output Real b1;
     29        output Integer b2;
     30        output Boolean b3;
     31        output String b4;
     32        output E b5;
     33        external;
     34    end f;
     35   
     36    Real x1;
     37    Integer x2;
     38    Boolean x3;
     39    String x4;
     40    E x5;
     41equation
     42    (x1,x2,x3,x4,x5) = f(1,2,true,"s",E.A);
     43
     44    annotation(__JModelica(UnitTesting(tests={
     45        FClassMethodTestCase(
     46            name="ExtDynFcn1",
     47            methodName="externalCTypes",
     48            description="Test that the different primitive types generates the correct C mapping",
     49            external_constant_evaluation_dynamic=true,
     50            methodResult="
     51f
     52void
     53d,i,i,s,i,*d,*i,*i,*s,*i,
     54")})));
     55end ExtDynFcn1;
     56
     57model ExtDynFcn2
     58type E = enumeration(A,B);
     59function f
     60    input Real[:] a1;
     61    input Integer[:] a2;
     62    input Boolean[:] a3;
     63    input String[:] a4;
     64    input E[:] a5;
     65    output Real[size(a1,1)] b1;
     66    output Integer[size(a2,1)] b2;
     67    output Boolean[size(a3,1)] b3;
     68    output String[size(a4,1)] b4;
     69    output E[size(a5,1)] b5;
     70    external;
     71end f;
     72    Real[1] x1;
     73    Integer[1] x2;
     74    Boolean[1] x3;
     75    String[1] x4;
     76    E[1] x5;
     77equation
     78    (x1,x2,x3,x4,x5) = f({1},{2},{true},{"s"},{E.A});
     79
     80    annotation(__JModelica(UnitTesting(tests={
     81        FClassMethodTestCase(
     82            name="ExtDynFcn2",
     83            methodName="externalCTypes",
     84            description="Test that the different primitive types (arrays of) generates the correct C mapping",
     85            external_constant_evaluation_dynamic=true,
     86            methodResult="
     87f
     88void
     89dv,i,iv,i,iv,i,sv,i,iv,i,*dv,i,*iv,i,*iv,i,*sv,i,*iv,i,
     90")})));
     91end ExtDynFcn2;
     92
     93model ExtDynFcn3
     94    type E = enumeration(A,B);
     95    record R
     96        Real a1;
     97        Integer a2;
     98        Boolean a3;
     99        String a4;
     100        E a5;
     101        R2 r2;
     102    end R;
     103    record R2
     104        Real x;
     105    end R2;
     106   
     107    function f
     108        input R a;
     109        output R b;
     110        external f(a,b);
     111    end f;
     112   
     113    R r = f(R(1,2,true,"s",E.A, R2(3)));
     114
     115    annotation(__JModelica(UnitTesting(tests={
     116        FClassMethodTestCase(
     117            name="ExtDynFcn3",
     118            methodName="externalCTypes",
     119            description="Test that records generates the correct C mapping",
     120            external_constant_evaluation_dynamic=true,
     121            methodResult="
     122f
     123void
     124R[d,i,i,s,i,R[d,],],*R[d,i,i,s,i,R[d,],],
     125")})));
     126end ExtDynFcn3;
     127
    19128
    20129model Scalar
     
    789898end ExtObj5;
    790899
     900model ExtDynObj1
     901    function use1
     902        input  Os.Obj1 o1;
     903        output Real x;
     904        external annotation(Library="extObjectsUse", Include="#include \"extObjectsUse.h\"",
     905            LibraryDirectory="modelica://Library2", IncludeDirectory="Include2");
     906    end use1;
     907
     908    Os.Obj1 o1 = Os.Obj1(3.13, 3, true, "A message");
     909    Real x = use1(o1);
     910
     911    annotation(__JModelica(UnitTesting(tests={
     912        FClassMethodTestCase(
     913            name="ExtDynObj1",
     914            methodName="externalCTypes",
     915            description="Verifies that external objects are not handled by the dynamic evaluator",
     916            methodResult="
     917")})));
     918end ExtDynObj1;
     919
     920
    791921model Dgelsx
    792922    function dgelsx
  • trunk/Compiler/ModelicaCompiler/module.options

    r13703 r13719  
    136136external objects during compilation.If less than 1, no processes will be kept
    137137alive, i.e. this feature is turned off."
     138
     139********************************************************************************
     140BOOLEAN external_constant_evaluation_dynamic compiler experimental false
     141
     142"If enabled, calls to external functions will be evaluated during compilation
     143using a pre-compiled program (instead of generating and compiling one), if
     144possible."
    138145
    139146********************************************************************************
     
    458465
    459466********************************************************************************
    460 
  • trunk/Compiler/ModelicaCompiler/src/jastadd/ModelicaCompiler.jrag

    r13703 r13719  
    12661266        /* Temporary fix to problems with long compilation times due to later evaluations */
    12671267        getExternalFunctionCache().tearDown();
    1268         options.setIntegerOption("external_constant_evaluation", 0);
     1268        options.external_constant_evaluation.setValue(0);
    12691269       
    12701270        hookModelTransformed(fc);
  • trunk/Compiler/ModelicaCompiler/src/java/org/jmodelica/util/ccompiler/CCompilerDelegator.java

    r13703 r13719  
    351351        };
    352352    }
     353
     354    public abstract Set<String> expandCompilerSpecificLibraryPaths(ModelicaLogger log, AbstractOptionRegistry options,
     355            Set<String> extLibDirs, String platform);
    353356}
    354357
  • trunk/Compiler/ModelicaCompiler/src/java/org/jmodelica/util/ccompiler/GccCompilerDelegator.java

    r13703 r13719  
    2626import java.util.Set;
    2727
     28import org.jmodelica.common.options.AbstractOptionRegistry;
    2829import org.jmodelica.util.EnvironmentUtils;
    2930import org.jmodelica.util.exceptions.CcodeCompilationException;
     
    106107            vars.put("AR", new File(mingw_bin, "ar").getPath());
    107108        }
     109    }
     110   
     111    @Override
     112    public Set<String> expandCompilerSpecificLibraryPaths(ModelicaLogger log, AbstractOptionRegistry options, Set<String> extLibDirs, String platform) {
     113        Set<String> expandedLibDirs = expandLibraries(extLibDirs, platform, "gcc" + compilerVersionNumber());
     114        return expandedLibDirs;
    108115    }
    109116   
  • trunk/Compiler/ModelicaFlatTree/src/jastadd/ConstantEvaluation/ConstantEvaluation.jrag

    r13703 r13719  
    50795079        }
    50805080       
    5081         public AlgorithmEvaluator createAlgorithmEvaluator(AbstractOptionRegistry options, Map<CommonVariableDecl, CValue> values) {
     5081        public AlgorithmEvaluator createAlgorithmEvaluator(OptionRegistry options, Map<CommonVariableDecl, CValue> values) {
    50825082            return new AlgorithmEvaluator(externalEvaluationEnabled, options, values);
    50835083        }
    50845084       
    5085         public AlgorithmEvaluator createEmptyAlgorithmEvaluator(AbstractOptionRegistry options) {
     5085        public AlgorithmEvaluator createEmptyAlgorithmEvaluator(OptionRegistry options) {
    50865086            return new AlgorithmEvaluator(true, options, Collections.<CommonVariableDecl, CValue>emptyMap());
    50875087        }
     
    51495149       
    51505150        @Override
    5151         public AlgorithmEvaluator createAlgorithmEvaluator(AbstractOptionRegistry options, Map<CommonVariableDecl, CValue> values) {
     5151        public AlgorithmEvaluator createAlgorithmEvaluator(OptionRegistry options, Map<CommonVariableDecl, CValue> values) {
    51525152            return new PartialAlgorithmEvaluator(externalEvaluationEnabled(), options, values, this);
    51535153        }
     
    51835183       
    51845184        @Override
    5185         public AlgorithmEvaluator createAlgorithmEvaluator(AbstractOptionRegistry options, Map<CommonVariableDecl, CValue> values) {
     5185        public AlgorithmEvaluator createAlgorithmEvaluator(OptionRegistry options, Map<CommonVariableDecl, CValue> values) {
    51865186            if (this.values == null) {
    51875187                this.values = values;
     
    52775277    public class AlgorithmEvaluator extends VariableEvaluator {
    52785278       
    5279         protected Map<CommonVariableDecl, CValue> values;
    5280         private AbstractOptionRegistry options;
    5281        
    5282         public AlgorithmEvaluator(boolean evaluateExternalEnabled, AbstractOptionRegistry options, Map<CommonVariableDecl, CValue> values) {
     5279        protected final Map<CommonVariableDecl, CValue> values;
     5280        private final OptionRegistry options;
     5281       
     5282        public AlgorithmEvaluator(boolean evaluateExternalEnabled, OptionRegistry options, Map<CommonVariableDecl, CValue> values) {
    52835283            super(evaluateExternalEnabled);
    52845284            this.values  = values;
     
    52875287       
    52885288        public int externalEvaluation() {
    5289             return externalEvaluationEnabled() ? options.getIntegerOption("external_constant_evaluation") : 0;
     5289            return externalEvaluationEnabled() ? options.external_constant_evaluation.getValue() : 0;
    52905290        }
    52915291       
     
    53515351        protected ArrayList<IfEvaluation> ifStack;
    53525352       
    5353         public PartialAlgorithmEvaluator(boolean evaluateExternalEnabled, AbstractOptionRegistry options,
     5353        public PartialAlgorithmEvaluator(boolean evaluateExternalEnabled, OptionRegistry options,
    53545354                Map<CommonVariableDecl, CValue> values, PartialVariableEvaluator variableEvaluator) {
    53555355            super(evaluateExternalEnabled, options, values);
     
    53685368       
    53695369        @Override
    5370         public AlgorithmEvaluator createAlgorithmEvaluator(AbstractOptionRegistry options, Map<CommonVariableDecl, CValue> values) {
     5370        public AlgorithmEvaluator createAlgorithmEvaluator(OptionRegistry options, Map<CommonVariableDecl, CValue> values) {
    53715371            return variableEvaluator.createAlgorithmEvaluator(options, values);
    53725372        }
  • trunk/Compiler/ModelicaFlatTree/src/jastadd/ConstantEvaluation/ExternalConstantEvaluation.jrag

    r13703 r13719  
    2626import java.util.TimerTask;
    2727
     28import org.jmodelica.common.evaluation.ExternalFunctionCompiler;
    2829import org.jmodelica.common.evaluation.ExternalFunction;
    2930import org.jmodelica.common.evaluation.ExternalProcessCache;
    3031import org.jmodelica.common.evaluation.ExternalProcessCacheImpl;
    3132import org.jmodelica.common.evaluation.ExternalProcessMultiCache;
     33import org.jmodelica.common.evaluation.FailedExternalFunction;
    3234import org.jmodelica.common.evaluation.ProcessCommunicator;
    3335
     
    4951    class ModelicaCompiler {}
    5052   
    51     ModelicaCompiler   implements ExternalProcessMultiCache.Compiler<ExternalArgument, FExternalStmt>;
     53    ModelicaCompiler   implements ExternalFunctionCompiler<ExternalArgument, FExternalStmt>;
    5254    FExternalStmt      implements ExternalProcessMultiCache.External<ExternalArgument>;
    5355    ExternalArgument   extends    ExternalProcessMultiCache.Variable<CValue,FType>;
     
    8991     * Check if this external function should be cached as a live process.
    9092     */
    91     syn boolean FExternalStmt.shouldCacheProcess() {
    92         return myOptions().getIntegerOption("external_constant_evaluation_max_proc") > 0;
    93     }
     93    syn int FExternalStmt.processLimit() =
     94            myOptions().external_constant_evaluation_max_proc.getValue();
     95   
     96    syn boolean FExternalStmt.dynamicEvaluatorEnabled() =
     97            myOptions().external_constant_evaluation_dynamic.getValue()
     98            && !externalObjectsToSerialize().iterator().hasNext();
    9499   
    95100    /**
     
    169174        ExternalFunctionCache efc = root().getUtilInterface().getExternalFunctionCache();
    170175        if (efc == null) {
    171             return new ExternalProcessCacheImpl<>(root().getUtilInterface().getModelicaCompiler())
    172                 .failedEval(this, "external function cache unavailable", false);
     176            return FailedExternalFunction.<ExternalArgument, CValue, FType, FExternalStmt>failedEval(
     177                    root().getUtilInterface().getModelicaCompiler(),
     178                    this, "external function cache unavailable", false);
    173179        }
    174180        return efc.getExternalProcessCache(getLibTopPackagePath()).getExternalFunction(this);
     
    205211       
    206212        if (error != null) {
    207             throw new ConstantEvaluationException(null, ExternalProcessCacheImpl.failedEvalMsg(getName(), error));
     213            throw new ConstantEvaluationException(null, FailedExternalFunction.failedEvalMsg(getName(), error));
    208214        }
    209215       
  • trunk/Compiler/ModelicaFrontEnd/src/java/org/jmodelica/common/evaluation/ExternalProcessCache.java

    r13703 r13719  
    2424
    2525    protected abstract void tearDown();
    26 
    27     public abstract ExternalFunction<K, V> failedEval(External<?> ext, String msg, boolean log);
    2826   
    2927
  • trunk/Compiler/ModelicaFrontEnd/src/java/org/jmodelica/common/evaluation/ExternalProcessCacheImpl.java

    r13703 r13719  
    33import java.io.File;
    44import java.io.FileNotFoundException;
    5 import java.io.IOException;
    65import java.io.PrintStream;
    76import java.util.ArrayList;
    87import java.util.HashMap;
     8import java.util.HashSet;
    99import java.util.LinkedHashSet;
    1010import java.util.Map;
    11 
    12 import org.jmodelica.common.evaluation.ExternalProcessMultiCache.Compiler;
     11import java.util.Set;
     12
    1313import org.jmodelica.common.evaluation.ExternalProcessMultiCache.External;
    1414import org.jmodelica.common.evaluation.ExternalProcessMultiCache.Type;
     
    1616import org.jmodelica.common.evaluation.ExternalProcessMultiCache.Variable;
    1717import org.jmodelica.util.EnvironmentUtils;
     18import org.jmodelica.util.SystemUtil;
    1819import org.jmodelica.util.ccompiler.CCompilerDelegator;
    1920import org.jmodelica.util.exceptions.CcodeCompilationException;
    2021import org.jmodelica.util.logging.ModelicaLogger;
    21 import org.jmodelica.util.values.ConstantEvaluationException;
    2222
    2323public class ExternalProcessCacheImpl<K extends Variable<V, T>, V extends Value, T extends Type<V>, E extends External<K>> extends ExternalProcessCache<K, V, T, E> {
     
    2626     * Maps external functions names to compiled executables.
    2727     */
    28     private Map<String, ExternalFunction<K, V>> cachedExternals = new HashMap<String, ExternalFunction<K, V>>();
     28    private final Map<String, ExternalFunction<K, V>> cachedExternals = new HashMap<String, ExternalFunction<K, V>>();
    2929
    3030    /**
    3131     * Keeps track of all living processes, least recently used first.
    3232     */
    33     private LinkedHashSet<ExternalFunction<K, V>> livingCachedExternals = new LinkedHashSet<ExternalFunction<K, V>>();
    34 
    35     private Compiler<K, E> mc;
    36 
    37     public ExternalProcessCacheImpl(Compiler<K, E> mc) {
     33    private final LinkedHashSet<ExternalFunction<K, V>> livingCachedExternals = new LinkedHashSet<ExternalFunction<K, V>>();
     34
     35    private final ExternalFunctionCompiler<K, E> mc;
     36
     37    public ExternalProcessCacheImpl(ExternalFunctionCompiler<K, E> mc) {
    3838        this.mc = mc;
    3939    }
     
    4242        return mc.log();
    4343    }
    44 
     44   
     45    private String getPlatform() {
     46        return CCompilerDelegator.reduceBits(EnvironmentUtils.getJavaPlatform(),
     47                mc.getCCompiler().getTargetPlatforms());
     48    }
     49   
     50    private String getSharedLibrary(External<K> ext) {
     51        String sharedLib = "";
     52        String extLibrary = "";
     53       
     54        if (ext.library() != null && ext.library().length == 1) {
     55            extLibrary = ext.library()[0];
     56        } else {
     57            return sharedLib;
     58        }
     59       
     60        HashSet<String> externalLibraryDirectories = new HashSet<String>();
     61        externalLibraryDirectories.add(ext.libraryDirectory());
     62        Set<String> expandedLibDirs = mc.getCCompiler().expandCompilerSpecificLibraryPaths(mc.log(), ext.myOptions(),
     63                                                   externalLibraryDirectories, getPlatform());
     64       
     65        for (String dir : expandedLibDirs) {
     66            File testlib1 = new File(dir, extLibrary + SystemUtil.sharedLibraryExtension());
     67            File testlib2 = new File(dir, "lib" + extLibrary + SystemUtil.sharedLibraryExtension());
     68           
     69            if (testlib1.exists() && !testlib1.isDirectory()) {
     70                sharedLib = testlib1.toString();
     71                break;
     72            }
     73            if (testlib2.exists() && !testlib2.isDirectory()) {
     74                sharedLib = testlib2.toString();
     75                break;
     76            }
     77        }
     78       
     79        return sharedLib;
     80    }
     81   
     82    private static ArrayList<String> builtinExternalFunctions = new ArrayList<String>() {{
     83        add("ModelicaStrings_substring");
     84        add("ModelicaStrings_length");
     85        add("ModelicaStrings_skipWhiteSpace");
     86        add("ModelicaStrings_compare");
     87    }};
     88   
     89    private static ArrayList<String> supportedSignatures = new ArrayList<String>() {{
     90        add("d+d,d,");
     91        add("d+i,");
     92        add("d+i,d,d,");
     93        add("s+s,i,i,");
     94        add("i+s,");
     95        add("i+s,i,");
     96        add("i+s,s,i,");
     97        add("i+i,i,");
     98        add("void+i,d,d,*R[d,d,d,d,d,d,d,d,d,d,d,],");
     99        add("void+d,d,*d,");
     100    }};
     101   
     102    public boolean canUseEvaluator(E ext, ArrayList<String> arguments) {
     103        if (!ext.dynamicEvaluatorEnabled()) {
     104            return false;
     105        }
     106       
     107        String sharedLibrary = getSharedLibrary(ext);
     108        String functionName  = ext.getName();
     109        String outputArguments = ext.functionReturnArgSerialized();
     110        String inputArguments  = ext.functionArgsSerialized();
     111       
     112        if (sharedLibrary.equals("")) {
     113            if (builtinExternalFunctions.contains(functionName)) {
     114                sharedLibrary = "NoSharedLibrary";
     115            } else {
     116                mc.log().debug("Could not find a shared library containing '" + functionName + "'. Disabling use of the evaluator...");
     117                return false;
     118            }
     119        }
     120       
     121        if (!supportedSignatures.contains(outputArguments+"+"+inputArguments)) {
     122            mc.log().debug("The function signature, outputs '" + outputArguments + "', inputs '" + inputArguments + "', is not supported. Disabling use of the evaluator...");
     123            return false;
     124        }
     125       
     126        arguments.add(sharedLibrary);
     127        arguments.add(functionName);
     128        arguments.add(outputArguments);
     129        arguments.add(inputArguments);
     130
     131        return true;
     132    }
     133   
    45134    @Override
    46135    public ExternalFunction<K, V> getExternalFunction(E ext) {
     
    48137        if (ef == null) {
    49138            if (mc == null) {
    50                 return failedEval(ext, "Missing ModelicaCompiler", false);
     139                return FailedExternalFunction.<K,V,T,E>failedEval(mc, ext, "Missing ModelicaCompiler", false);
    51140            }
    52141            try {
    53142                long time = System.currentTimeMillis();
    54                 String executable = mc.compileExternal(ext);
    55                 if (ext.shouldCacheProcess()) {
    56                     ef = new MappedExternalFunction(ext, executable);
     143                String executable = null;
     144                ArrayList<String> arguments = new ArrayList<String>();
     145                String debugMsg = "";
     146                ExternalFunctionExecutable extFunctionExecutable;
     147                if (canUseEvaluator(ext, arguments)) {
     148                    String jmHome = System.getenv("JMODELICA_HOME");
     149                    String bits = getPlatform().contains("64") && SystemUtil.isWindows() ? "64" : "";
     150                    executable = jmHome + File.separator + "bin" + bits + File.separator + "jmi_evaluator" + SystemUtil.executableExtension();
     151                   
     152                    arguments.add(0, executable); /* Needs to be first */
     153                   
     154                    extFunctionExecutable = new ExternalFunctionExecutableDynamic(arguments);
     155                   
     156                    debugMsg = "Succesfully connected external function '" + ext.getName() + "' to the evaluator '"
     157                            + executable + "' with outputs: '" + ext.functionReturnArgSerialized() + "' and inputs: '" + ext.functionArgsSerialized() + "'";
    57158                } else {
    58                     ef = new CompiledExternalFunction(ext, executable);
     159                    executable = mc.compileExternal(ext);
     160                   
     161                    extFunctionExecutable = new ExternalFunctionExecutableGenerated(executable);
     162                   
     163                    debugMsg = "Succesfully compiled external function '" + ext.getName() + "' to executable '"
     164                            + executable + "' code for evaluation";
     165                }
     166               
     167                if (ext.processLimit() > 0) {
     168                    ef = new MappedExternalFunction<K,V,T,E>(mc, ext, extFunctionExecutable, livingCachedExternals);
     169                } else {
     170                    ef = new ExternalFunctionImpl<K,V,T,E>(mc, ext, extFunctionExecutable);
    59171                }
    60172                time = System.currentTimeMillis() - time;
    61                 mc.log().debug("Succesfully compiled external function '" + ext.getName() + "' to executable '"
    62                         + executable + "' code for evaluation, time: " + time + "ms");
     173                mc.log().debug(debugMsg +", time: " + time + "ms");
    63174            } catch (FileNotFoundException e) {
    64                 ef = failedEval(ext, "c-code generation failed '" + e.getMessage() + "'", true);
     175                ef = FailedExternalFunction.<K,V,T,E>failedEval(mc, ext, "c-code generation failed '" + e.getMessage() + "'", true);
    65176                mc.log().debug(ef.getMessage());
    66177            } catch (CcodeCompilationException e) {
    67                 ef = failedEval(ext, "c-code compilation failed '" + e.getMessage() + "'", true);
     178                ef = FailedExternalFunction.<K,V,T,E>failedEval(mc, ext, "c-code compilation failed '" + e.getMessage() + "'", true);
    68179                mc.log().debug(ef.getMessage());
    69180                e.printStackTrace(new PrintStream(mc.log().debugStream()));
     
    95206    }
    96207
    97     @Override
    98     public ExternalFunction<K, V> failedEval(External<?> ext, String msg, boolean log) {
    99         return new FailedExternalFunction(failedEvalMsg(ext.getName(), msg), log);
    100     }
    101 
    102     public static String failedEvalMsg(String name, String msg) {
    103         return "Failed to evaluate external function '" + name + "', " + msg;
    104     }
    105 
    106     private class FailedExternalFunction implements ExternalFunction<K, V> {
    107         private String msg;
    108         private boolean log;
    109 
    110         public FailedExternalFunction(String msg, boolean log) {
    111             this.msg = msg;
    112             this.log = log;
    113         }
    114 
    115         @Override
    116         public String getMessage() {
    117             return msg;
    118         }
    119 
    120         @Override
    121         public int evaluate(External<K> ext, Map<K, V> values, int timeout) throws IOException {
    122             if (log) {
    123                 log().debug("Evaluating failed external function: " + ext.getName());
    124             }
    125             throw new ConstantEvaluationException(null, getMessage());
    126         }
    127 
    128         @Override
    129         public void destroyProcess() {
    130             // Do nothing
    131         }
    132 
    133         @Override
    134         public void remove() {
    135             // Do nothing
    136         }
    137     }
    138 
    139     /**
    140      * Represents an external function that has been compiled successfully.
    141      */
    142     private class CompiledExternalFunction implements ExternalFunction<K, V> {
    143         protected String executable;
    144         protected ProcessBuilder processBuilder;
    145         private String msg;
    146 
    147         public CompiledExternalFunction(External<K> ext, String executable) {
    148             this.executable = executable;
    149             this.processBuilder = createProcessBuilder(ext);
    150             this.msg = "Succesfully compiled external function '" + ext.getName() + "'";
    151         }
    152 
    153         @Override
    154         public String getMessage() {
    155             return msg;
    156         }
    157 
    158         protected ProcessCommunicator<V, T> createProcessCommunicator() throws IOException {
    159             return new ProcessCommunicator<V, T>(mc, processBuilder.start());
    160         }
    161 
    162         @Override
    163         public int evaluate(External<K> ext, Map<K, V> values, int timeout) throws IOException {
    164             log().debug("Evaluating compiled external function: " + ext.getName());
    165             ProcessCommunicator<V, T> com = null;
    166             try {
    167                 com = createProcessCommunicator();
    168                 setup(ext, values, timeout, com);
    169                 evaluate(ext, values, timeout, com);
    170                 return teardown(timeout, com);
    171             } finally {
    172                 if (com != null) {
    173                     com.destroy();
    174                 }
    175             }
    176         }
    177 
    178         public void setup(External<K> ext, Map<K, V> values, int timeout, ProcessCommunicator<V, T> com)
    179                 throws IOException {
    180             com.startTimer(timeout);
    181             com.accept("START");
    182             for (K eo : ext.externalObjectsToSerialize()) {
    183                 com.put(values.containsKey(eo) ? values.get(eo) : eo.ceval(), eo.type());
    184             }
    185             com.accept("READY");
    186             com.cancelTimer();
    187         }
    188 
    189         public void evaluate(External<K> ext, Map<K, V> values, int timeout, ProcessCommunicator<V, T> com)
    190                 throws IOException {
    191             com.startTimer(timeout);
    192             com.check("EVAL");
    193 
    194             for (K arg : ext.functionArgsToSerialize()) {
    195                 com.put(values.containsKey(arg) ? values.get(arg) : arg.ceval(), arg.type());
    196             }
    197             com.accept("CALC");
    198             com.accept("DONE");
    199             for (K cvd : ext.varsToDeserialize())
    200                 values.put(cvd, com.get(cvd.type()));
    201             com.accept("READY");
    202             com.cancelTimer();
    203         }
    204 
    205         public int teardown(int timeout, ProcessCommunicator<V, T> com) throws IOException {
    206             com.startTimer(timeout);
    207             com.check("EXIT");
    208             com.accept("END");
    209             int result = com.end();
    210             com.cancelTimer();
    211             // log().debug("SUCCESS TEARDOWN");
    212             return result;
    213         }
    214 
    215         @Override
    216         public void destroyProcess() {
    217             // Do nothing
    218         }
    219 
    220         @Override
    221         public void remove() {
    222             new File(executable).delete();
    223         }
    224 
    225         private ProcessBuilder createProcessBuilder(External<K> ext) {
    226             ProcessBuilder pb = new ProcessBuilder(executable);
    227             Map<String, String> env = pb.environment();
    228             if (env.keySet().contains("Path")) {
    229                 env.put("PATH", env.get("Path"));
    230                 env.remove("Path");
    231             }
    232             pb.redirectErrorStream(true);
    233             if (ext.libraryDirectory() != null) {
    234                 // Update environment in case of shared library
    235                 String platform = CCompilerDelegator.reduceBits(EnvironmentUtils.getJavaPlatform(),
    236                         mc.getCCompiler().getTargetPlatforms());
    237                 File f = new File(ext.libraryDirectory(), platform);
    238                 String libLoc = f.isDirectory() ? f.getPath() : ext.libraryDirectory();
    239                 appendPath(env, libLoc, platform);
    240             }
    241             return pb;
    242         }
    243 
    244         /**
    245          * Append a library location <code>libLoc</code> to the path variable in
    246          * environment <code>env</code>.
    247          */
    248         private void appendPath(Map<String, String> env, String libLoc, String platform) {
    249             String sep = platform.startsWith("win") ? ";" : ":";
    250             String var = platform.startsWith("win") ? "PATH" : "LD_LIBRARY_PATH";
    251             String res = env.get(var);
    252             if (res == null)
    253                 res = libLoc;
    254             else
    255                 res = res + sep + libLoc;
    256             env.put(var, res);
    257         }
    258     }
    259 
    260     /**
    261      * A CompiledExternalFunction which can cache several processes with external
    262      * object constructor only called once.
    263      */
    264     private class MappedExternalFunction extends CompiledExternalFunction {
    265 
    266         private Map<String, ExternalFunction<K, V>> lives = new HashMap<>();
    267 
    268         private final int externalConstantEvaluationMaxProc;
    269 
    270         public MappedExternalFunction(External<K> ext, String executable) {
    271             super(ext, executable);
    272             externalConstantEvaluationMaxProc = ext.myOptions()
    273                     .getIntegerOption("external_constant_evaluation_max_proc");
    274         }
    275 
    276         /**
    277          * Find a LiveExternalFunction based on the external object of this external
    278          * function. Start a new process if not up already. Failure to set up (call
    279          * constructor) will cache and return a Failed external function.
    280          */
    281         private ExternalFunction<K, V> getActual(External<K> ext, Map<K, V> values, int timeout) {
    282             Variable<V, T> cvd = ext.cachedExternalObject();
    283             String name = cvd == null ? "" : cvd.ceval().getMarkedExternalObject();
    284             ExternalFunction<K, V> ef = lives.get(name);
    285             if (ef == null) {
    286                 LiveExternalFunction lef = new LiveExternalFunction();
    287                 try {
    288                     lef.ready(ext, values, timeout);
    289                     ef = lef;
    290                 } catch (IOException e) {
    291                     lef.destroyProcess();
    292                     ef = failedEval(ext, " error starting process '" + e.getMessage() + "'", true);
    293                 } catch (ConstantEvaluationException e) {
    294                     lef.destroyProcess();
    295                     ef = failedEval(ext, " error starting process '" + e.getMessage() + "'", true);
    296                 }
    297                 lives.put(name, ef);
    298             }
    299             return ef;
    300         }
    301 
    302         @Override
    303         public int evaluate(External<K> ext, Map<K, V> values, int timeout) throws IOException {
    304             return getActual(ext, values, timeout).evaluate(ext, values, timeout);
    305         }
    306 
    307         @Override
    308         public void destroyProcess() {
    309             for (ExternalFunction<K, V> ef : lives.values()) {
    310                 ef.destroyProcess();
    311             }
    312             lives.clear();
    313         }
    314 
    315         /**
    316          * Represents a (possible) living external function process.
    317          */
    318         private class LiveExternalFunction implements ExternalFunction<K, V> {
    319 
    320             protected ProcessCommunicator<V, T> com;
    321 
    322             public LiveExternalFunction() {
    323                 super();
    324             }
    325 
    326             @Override
    327             public String getMessage() {
    328                 return MappedExternalFunction.this.getMessage();
    329             }
    330 
    331             @Override
    332             public int evaluate(External<K> ext, Map<K, V> values, int timeout) throws IOException {
    333                 log().debug("Evaluating live external function: " + ext.getName());
    334                 try {
    335                     ready(ext, values, timeout);
    336                     long time = System.currentTimeMillis();
    337                     MappedExternalFunction.this.evaluate(ext, values, timeout, com);
    338                     time = System.currentTimeMillis() - time;
    339                     log().debug("Finished evaluating live external function, time: " + time + "ms");
    340                 } catch (ProcessCommunicator.AbortConstantEvaluationException e) {
    341 
    342                 } catch (ConstantEvaluationException e) {
    343                     destroyProcess();
    344                     throw e;
    345                 } catch (IOException e) {
    346                     destroyProcess();
    347                     throw e;
    348                 }
    349                 return 0;
    350             }
    351 
    352             /**
    353              * Make sure process is ready for evaluation call.
    354              */
    355             protected void ready(External<K> ext, Map<K, V> values, int timeout) throws IOException {
    356                 if (com == null) {
    357                     long time1 = System.currentTimeMillis();
    358                     // Start process if not live.
    359                     com = createProcessCommunicator();
    360                     long time2 = System.currentTimeMillis();
    361                     // Send external object constructor inputs
    362                     MappedExternalFunction.this.setup(ext, values, timeout, com);
    363                     long time3 = System.currentTimeMillis();
    364                     log().debug("Setup live external function: " + ext.getName()
    365                               + ", createProcessCommunicator() time: " + (time2 - time1)
    366                               + "ms, setup time: " + (time3 - time2) + "ms");
    367                 }
    368 
    369                 // Mark as most recently used
    370                 livingCachedExternals.remove(this);
    371                 livingCachedExternals.add(this);
    372 
    373                 // If we are over the allowed number of cached processes
    374                 // we kill the least recently used.
    375                 if (livingCachedExternals.size() > externalConstantEvaluationMaxProc) {
    376                     livingCachedExternals.iterator().next().destroyProcess();
    377                 }
    378             }
    379 
    380             @Override
    381             public void destroyProcess() {
    382                 if (com != null) {
    383                     livingCachedExternals.remove(this);
    384                     com.destroy();
    385                     com = null;
    386                 }
    387             }
    388 
    389             @Override
    390             public void remove() {
    391                 // Removing this executable is handled by surrounding MappedExternalFunction
    392                 throw new UnsupportedOperationException();
    393             }
    394         }
    395     }
    396208}
  • trunk/Compiler/ModelicaFrontEnd/src/java/org/jmodelica/common/evaluation/ExternalProcessMultiCache.java

    r13703 r13719  
    22
    33import java.io.BufferedWriter;
    4 import java.io.FileNotFoundException;
    54import java.io.IOException;
    65import java.util.LinkedHashMap;
    76import java.util.Map;
    87
    9 import org.jmodelica.common.LogContainer;
    108import org.jmodelica.common.options.AbstractOptionRegistry;
    11 import org.jmodelica.util.ccompiler.CCompilerDelegator;
    12 import org.jmodelica.util.exceptions.CcodeCompilationException;
    139
    1410public class ExternalProcessMultiCache<K extends ExternalProcessMultiCache.Variable<V, T>, V extends ExternalProcessMultiCache.Value, T extends ExternalProcessMultiCache.Type<V>, E extends ExternalProcessMultiCache.External<K>> {
    15 
    16     public interface Compiler<K, E extends External<K>> extends LogContainer {
    17         public String compileExternal(E ext) throws FileNotFoundException, CcodeCompilationException;
    18 
    19         public CCompilerDelegator getCCompiler();
    20     }
    2111
    2212    public interface External<K> {
    2313        public String getName();
    2414
    25         public boolean shouldCacheProcess();
     15        public int processLimit();
     16
     17        public boolean dynamicEvaluatorEnabled();
    2618
    2719        public AbstractOptionRegistry myOptions();
     
    3527        public Iterable<K> functionArgsToSerialize();
    3628
     29        public String functionArgsSerialized();
     30
     31        public String functionReturnArgSerialized();
     32
    3733        public Iterable<K> varsToDeserialize();
     34
     35        public String[] library();
    3836    }
    3937
     
    5654    private Map<String, ExternalProcessCache<K, V, T, E>> map = new LinkedHashMap<>();
    5755
    58     private Compiler<K, E> mc;
     56    private ExternalFunctionCompiler<K, E> mc;
    5957
    60     public ExternalProcessMultiCache(Compiler<K, E> mc) {
     58    public ExternalProcessMultiCache(ExternalFunctionCompiler<K, E> mc) {
    6159        this.mc = mc;
    6260    }
  • trunk/Compiler/ModelicaFrontEnd/src/java/org/jmodelica/util/SystemUtil.java

    r13703 r13719  
    7272        return isLinux() ? "" : ".exe";
    7373    }
     74   
     75    public static String sharedLibraryExtension() {
     76        if (isWindows()) {
     77            return ".dll";
     78        } else if (isLinux()) {
     79            return ".so";
     80        } else {
     81            return ".dylib";
     82        }
     83    }
    7484
    7585    /**
  • trunk/Compiler/ModelicaFrontEnd/test/junit/org/jmodelica/test/common/ExternalProcessCacheTest.java

    r13703 r13719  
    99import java.io.IOException;
    1010
     11import org.jmodelica.common.evaluation.ExternalFunctionCompiler;
     12import org.jmodelica.common.evaluation.ExternalFunction;
    1113import org.jmodelica.common.evaluation.ExternalProcessCache;
    12 import org.jmodelica.common.evaluation.ExternalFunction;
    1314import org.jmodelica.common.evaluation.ExternalProcessMultiCache;
     15import org.jmodelica.common.evaluation.ExternalProcessMultiCache.External;
     16import org.jmodelica.common.evaluation.ExternalProcessMultiCache.Type;
     17import org.jmodelica.common.evaluation.ExternalProcessMultiCache.Value;
    1418import org.jmodelica.common.evaluation.ExternalProcessMultiCache.Variable;
     19import org.jmodelica.common.evaluation.ProcessCommunicator;
    1520import org.jmodelica.common.options.AbstractOptionRegistry;
    16 import org.jmodelica.common.evaluation.ExternalProcessMultiCache.Value;
    17 import org.jmodelica.common.evaluation.ExternalProcessMultiCache.Type;
    18 import org.jmodelica.common.evaluation.ExternalProcessMultiCache.External;
    19 import org.jmodelica.common.evaluation.ProcessCommunicator;
    2021import org.jmodelica.util.ccompiler.CCompilerDelegator;
    2122import org.jmodelica.util.exceptions.CcodeCompilationException;
     
    7475    class ExternalProcessCacheMock<K extends Variable<V,T>, V extends Value, T extends Type<V>, E extends External<K>> extends ExternalProcessMultiCache<K,V,T,E> {
    7576
    76         public ExternalProcessCacheMock(Compiler<K,E> mc) {
     77        public ExternalProcessCacheMock(ExternalFunctionCompiler<K,E> mc) {
    7778            super(mc);
    7879        }
     
    108109        }
    109110
    110         @Override
    111         public ExternalFunction<K,V> failedEval(External<?> ext, String msg, boolean log) {
    112             // TODO Auto-generated method stub
    113             return null;
    114         }
    115        
    116     }
    117 
    118     class CompilerMock implements ExternalProcessMultiCache.Compiler<VariableMock, ExternalMock> {
     111    }
     112
     113    class CompilerMock implements ExternalFunctionCompiler<VariableMock, ExternalMock> {
    119114
    120115        @Override
     
    189184
    190185        @Override
    191         public boolean shouldCacheProcess() {
    192             // TODO Auto-generated method stub
     186        public int processLimit() {
     187            // TODO Auto-generated method stub
     188            return 0;
     189        }
     190
     191        @Override
     192        public boolean dynamicEvaluatorEnabled() {
    193193            return false;
    194194        }
     
    223223            return null;
    224224        }
     225       
     226        @Override
     227        public String functionArgsSerialized() {
     228            // TODO Auto-generated method stub
     229            return null;
     230        }
     231       
     232        @Override
     233        public String functionReturnArgSerialized() {
     234            // TODO Auto-generated method stub
     235            return null;
     236        }
    225237
    226238        @Override
     
    229241            return null;
    230242        }
     243       
     244        @Override
     245        public String[] library() {
     246            // TODO Auto-generated method stub
     247            return null;
     248        }
    231249
    232250    }
  • trunk/Python/src/tests_jmodelica/files/Modelica/ExtFunctionTests.mo

    r13703 r13719  
    11package ExtFunctionTests
     2
     3model Evaluator_Double
     4    function d_i
     5     input Integer a;
     6     output Real b;
     7
     8     external "C" b=f_d_i(a) annotation(Library="evaluatorTestsShared",
     9                             Include="#include \"evaluatorTests.h\"");
     10    end d_i;
     11   
     12    function d_idd
     13     input Integer a;
     14     input Real b;
     15     input Real c;
     16     output Real d;
     17
     18     external "C" d=f_d_idd(a,b,c) annotation(Library="evaluatorTestsShared",
     19                             Include="#include \"evaluatorTests.h\"");
     20    end d_idd;
     21   
     22   
     23    Real c = d_i(1);
     24    Real d = d_idd(1, 2.0, 3.0);
     25end Evaluator_Double;
     26
     27model Evaluator_Integer
     28    function i_ii
     29     input Integer a;
     30     input Integer b;
     31     output Integer c;
     32
     33     external "C" c=f_i_ii(a,b) annotation(Library="evaluatorTestsShared",
     34                             Include="#include \"evaluatorTests.h\"");
     35    end i_ii;
     36   
     37    constant Integer c = i_ii(1,2);
     38end Evaluator_Integer;
     39
     40model Evaluator_Record
     41    record R
     42        Real x0;
     43        Real x1;
     44        Real x2;
     45        Real x3;
     46        Real x4;
     47        Real x5;
     48        Real x6;
     49        Real x7;
     50        Real x8;
     51        Real x9;
     52        Real x10;
     53    end R;
     54    function iddpR_ddddddddddd_
     55     input Integer a;
     56     input Real b;
     57     input Real c;
     58     output R d;
     59
     60     external "C" f___iddpR_ddddddddddd_(a,b,c,d) annotation(Library="evaluatorTestsShared",
     61                             Include="#include \"evaluatorTests.h\"");
     62    end iddpR_ddddddddddd_;
     63   
     64    constant R c = iddpR_ddddddddddd_(1,2.0,3.0);
     65end Evaluator_Record;
     66
     67
     68model Evaluator_Substring
     69    constant String full="Yy00";
     70    constant String sub=Modelica.Utilities.Strings.substring(full,1,1);
     71    constant String string1 = "This is line 111";
     72    constant String string2 = Modelica.Utilities.Strings.substring(string1,9,12); // string2 = \"line\"
     73    constant Integer len = Modelica.Utilities.Strings.length(string1);
     74    constant Integer start = Modelica.Utilities.Strings.Advanced.skipWhiteSpace("   Hello", 1);
     75    constant Boolean not_equal = Modelica.Utilities.Strings.isEqual("Temp", "test", true);
     76    constant Boolean equal = Modelica.Utilities.Strings.isEqual("Temp", "Temp", true);
     77end Evaluator_Substring;
     78
     79model Evaluator_Add
     80 function add1
     81     input Real a;
     82     input Real b;
     83     output Real c;
     84
     85     external "C" c=add(a,b) annotation(Library="addNumbersShared",
     86                             Include="#include \"addNumbers.h\"");
     87 end add1;
     88 
     89 function add2
     90     input Real a;
     91     input Real b;
     92     output Real c;
     93
     94     external "C" add_output(a,b,c) annotation(Library="addNumbersShared",
     95                             Include="#include \"addNumbers.h\"");
     96 end add2;
     97
     98 constant Real a = 1;
     99 constant Real b = 2;
     100 Real c = add1(a,b);
     101 Real d = add2(a,b);
     102end Evaluator_Add;
     103
     104model Evaluator_Multiple_Add
     105 function add
     106     input Real a;
     107     input Real b;
     108     input Real c;
     109     input Real d;
     110     input Real e;
     111     input Real f;
     112     input Real g;
     113     input Real h;
     114     input Real i;
     115     output Real o;
     116
     117     external "C" o=multiple_add(a,b,c,d,e,f,g,h,i) annotation(Library="addNumbersShared",
     118                             Include="#include \"addNumbers.h\"");
     119 end add;
     120 
     121 constant Real a = 1;
     122 constant Real b = 2;
     123 Real c = add(a,b,a,b,a,b,a,b,a);
     124end Evaluator_Multiple_Add;
     125
     126model Evaluator_Unknown_Shared
     127    function unknown_function
     128        input Real a;
     129        output Real b;
     130        external "C" b = unknown(a) annotation(Library="unknown");
     131    end unknown_function;
     132   
     133    constant Real a = unknown_function(1.0);
     134end Evaluator_Unknown_Shared;
    2135
    3136model ExtFunctionTest1
  • trunk/Python/src/tests_jmodelica/files/Modelica/Resources/CMakeLists.txt

    r13703 r13719  
    3838include_directories(${TOP_SRC}/RuntimeLibrary/src/jmi)
    3939
     40set(EVALUATORTESTS_Sources
     41    src/evaluatorTests.c
     42    Include/evaluatorTests.h
     43)
     44
    4045set(ADDNUMBERS_Sources
    4146    src/addNumbers.c
     
    7075endif()
    7176
     77#Build evaluatorTests library
     78add_library(evaluatorTestsShared SHARED ${EVALUATORTESTS_Sources})
     79if(NOT MSVC)
     80    set_target_properties(evaluatorTestsShared PROPERTIES COMPILE_FLAGS "-Wall -g -std=c89 -pedantic -Werror -O2")
     81endif()
     82
    7283#Build addNumbers library
    7384add_library(addNumbers STATIC ${ADDNUMBERS_Sources})
     85add_library(addNumbersShared SHARED ${ADDNUMBERS_Sources})
    7486if(NOT MSVC)
    7587    set_target_properties(addNumbers PROPERTIES COMPILE_FLAGS "-Wall -g -std=c89 -pedantic -Werror -O2")
     88    set_target_properties(addNumbersShared PROPERTIES COMPILE_FLAGS "-Wall -g -std=c89 -pedantic -Werror -O2")
    7689endif()
    7790
     
    106119
    107120#Install the libraries
     121install(TARGETS evaluatorTestsShared DESTINATION "${TEST_LIBRARY_INSTALL_DIR}")
    108122install(TARGETS addNumbers DESTINATION "${TEST_LIBRARY_INSTALL_DIR}")
     123install(TARGETS addNumbersShared DESTINATION "${TEST_LIBRARY_INSTALL_DIR}")
    109124install(TARGETS arrayFunctions DESTINATION "${TEST_LIBRARY_INSTALL_DIR}")
    110125install(TARGETS externalFunctionsC DESTINATION "${TEST_LIBRARY_INSTALL_DIR}")
  • trunk/Python/src/tests_jmodelica/files/Modelica/Resources/Include/addNumbers.h

    r13703 r13719  
    22#define ADDNUMBERS_H
    33
    4 double add(double a, double b);
     4#if defined _WIN32
     5    #define DllExport __declspec(dllexport)
     6#else
     7    #define DllExport
     8#endif
     9
     10DllExport double add(double a, double b);
     11DllExport void add_output(double a, double b, double *c);
     12DllExport double multiple_add(double a, double b, double c, double d, double e, double f, double g, double h, double i);
    513void multiplyAnArray(int* inputs, int* outputs, int size, int m);
    614
  • trunk/Python/src/tests_jmodelica/files/Modelica/Resources/src/addNumbers.c

    r13703 r13719  
    11#include "addNumbers.h"
    22
    3 double add(double a, double b)
     3DllExport double add(double a, double b)
    44{
    5   return a+b;
     5  return a + b;
     6}
     7
     8DllExport void add_output(double a, double b, double *c)
     9{
     10  *c = a + b;
     11}
     12
     13DllExport double multiple_add(double a, double b, double c, double d, double e, double f, double g, double h, double i)
     14{
     15  return a+b+c+d+e+f+g+h+i;
    616}
    717
  • trunk/Python/src/tests_jmodelica/general/test_extfunctions.py

    r13703 r13719  
    2222
    2323import nose
     24import fnmatch
    2425
    2526from pymodelica import compile_fmu
    2627from pymodelica.common.core import get_platform_dir, create_temp_dir
    27 from pyfmi import load_fmu
     28from pyfmi import load_fmu, FMUModelME2
    2829from pyfmi.fmi import FMUException
    2930from tests_jmodelica import testattr, get_files_path
     
    3334path_to_mofiles = os.path.join(get_files_path(), 'Modelica')
    3435
     36class TestEvaluator:
     37    @classmethod
     38    def setUpClass(cls):
     39        """
     40        Sets up the test class.
     41        """
     42        cls.fpath = path(path_to_mofiles, "ExtFunctionTests.mo")
     43   
     44    @testattr(stddist_base = True)
     45    def test_builtin_substring(self):
     46        cpath = "ExtFunctionTests.Evaluator_Substring"
     47        fmu_name = compile_fmu(cpath, self.fpath, compiler_options={"external_constant_evaluation_dynamic":True}, compiler_log_level="d:log.txt")
     48       
     49        nbr_of_evaluator_calls = 0
     50        with open("log.txt") as f:
     51            res = fnmatch.filter(f, "Succesfully connected external function '*' to the evaluator*")
     52            nbr_of_evaluator_calls = len(res)
     53       
     54        assert nbr_of_evaluator_calls == 4, "Wrong number of external function calls, check log."
     55       
     56        model = load_fmu(fmu_name)
     57       
     58        assert model.get("sub")[0] == "Y", model.get("sub")
     59        assert model.get("string2")[0] == "line", model.get("string2")
     60        assert model.get("len") == 16, model.get("len")
     61        assert model.get("start") == 4, model.get("start")
     62        assert not model.get("not_equal"), model.get("not_equal")
     63        assert model.get("equal"), model.get("equal")
     64   
     65    @testattr(stddist_base = True)
     66    def test_add(self):
     67        cpath = "ExtFunctionTests.Evaluator_Add"
     68        fmu_name = compile_fmu(cpath, self.fpath, compiler_options={"external_constant_evaluation_dynamic":True}, version=2.0, compiler_log_level="d:log.txt")
     69       
     70        nbr_of_evaluator_calls = 0
     71        with open("log.txt") as f:
     72            res = fnmatch.filter(f, "Succesfully connected external function '*' to the evaluator*")
     73            nbr_of_evaluator_calls = len(res)
     74       
     75        assert nbr_of_evaluator_calls == 2, "Wrong number of external function calls, check log."
     76       
     77        model = FMUModelME2(fmu_name, _connect_dll=False)
     78       
     79        assert model.get_variable_start("c") == 3, model.get_variable_start("c")
     80        assert model.get_variable_start("d") == 3, model.get_variable_start("d")
     81   
     82    @testattr(stddist_base = True)
     83    def test_unsupported_signature(self):
     84        cpath = "ExtFunctionTests.Evaluator_Multiple_Add"
     85        fmu_name = compile_fmu(cpath, self.fpath, compiler_options={"external_constant_evaluation_dynamic":True}, compiler_log_level="d:log.txt")
     86       
     87        matches = 0
     88        with open("log.txt") as f:
     89            res = fnmatch.filter(f, "*is not supported. Disabling use of the evaluator*")
     90            matches = len(res)
     91       
     92        assert matches == 1, "Does not seem to disabling the evaluator"
     93
     94    @testattr(stddist_base = True)
     95    def test_unknown_shared_library(self):
     96        cpath = "ExtFunctionTests.Evaluator_Unknown_Shared"
     97        try:
     98            fmu_name = compile_fmu(cpath, self.fpath, compiler_options={"external_constant_evaluation_dynamic":True}, compiler_log_level="d:log_unknown_shared.txt")
     99        except: #The compilation will fail, the interesting parts will though still be contained in the log file
     100            pass
     101       
     102        matches = 0
     103        with open("log_unknown_shared.txt") as f:
     104            res = fnmatch.filter(f, "Could not find a shared library containing*")
     105            matches = len(res)
     106       
     107        assert matches == 1, "Seems to have found an unknown shared library"
     108   
     109    @testattr(stddist_base = True)
     110    def test_double_return(self):
     111        cpath = "ExtFunctionTests.Evaluator_Double"
     112        fmu_name = compile_fmu(cpath, self.fpath, compiler_options={"external_constant_evaluation_dynamic":True}, version=2.0, compiler_log_level="d:log.txt")
     113       
     114        nbr_of_evaluator_calls = 0
     115        with open("log.txt") as f:
     116            res = fnmatch.filter(f, "Succesfully connected external function '*' to the evaluator*")
     117            nbr_of_evaluator_calls = len(res)
     118       
     119        assert nbr_of_evaluator_calls == 2, "Wrong number of external function calls, check log."
     120       
     121        model = FMUModelME2(fmu_name, _connect_dll=False)
     122       
     123        assert model.get_variable_start("c") == 3.0, model.get_variable_start("c")
     124        assert model.get_variable_start("d") == 9.0, model.get_variable_start("d")
     125   
     126    @testattr(stddist_base = True)
     127    def test_integer_return(self):
     128        cpath = "ExtFunctionTests.Evaluator_Integer"
     129        fmu_name = compile_fmu(cpath, self.fpath, compiler_options={"external_constant_evaluation_dynamic":True}, version=2.0, compiler_log_level="d:log.txt")
     130       
     131        nbr_of_evaluator_calls = 0
     132        with open("log.txt") as f:
     133            res = fnmatch.filter(f, "Succesfully connected external function '*' to the evaluator*")
     134            nbr_of_evaluator_calls = len(res)
     135       
     136        assert nbr_of_evaluator_calls == 1, "Wrong number of external function calls, check log."
     137       
     138        model = FMUModelME2(fmu_name, _connect_dll=False)
     139       
     140        assert model.get_variable_start("c") == 3.0, model.get_variable_start("c")
     141   
     142    @testattr(stddist_base = True)
     143    def test_record(self):
     144        cpath = "ExtFunctionTests.Evaluator_Record"
     145        fmu_name = compile_fmu(cpath, self.fpath, compiler_options={"external_constant_evaluation_dynamic":True}, version=2.0, compiler_log_level="d:log.txt")
     146       
     147        nbr_of_evaluator_calls = 0
     148        with open("log.txt") as f:
     149            res = fnmatch.filter(f, "Succesfully connected external function '*' to the evaluator*")
     150            nbr_of_evaluator_calls = len(res)
     151       
     152        assert nbr_of_evaluator_calls == 1, "Wrong number of external function calls, check log."
     153       
     154        model = FMUModelME2(fmu_name, _connect_dll=False)
     155       
     156        assert model.get_variable_start("c.x0") == 1.0, model.get_variable_start("c.x0")
     157        assert model.get_variable_start("c.x1") == 2.0, model.get_variable_start("c.x1")
     158        assert model.get_variable_start("c.x2") == 3.0, model.get_variable_start("c.x2")
     159        assert model.get_variable_start("c.x3") == 3.0, model.get_variable_start("c.x3")
     160        assert model.get_variable_start("c.x4") == 4.0, model.get_variable_start("c.x4")
     161        assert model.get_variable_start("c.x5") == 5.0, model.get_variable_start("c.x5")
     162        assert model.get_variable_start("c.x6") == 6.0, model.get_variable_start("c.x6")
     163        assert model.get_variable_start("c.x7") == 7.0, model.get_variable_start("c.x7")
     164        assert model.get_variable_start("c.x8") == 8.0, model.get_variable_start("c.x8")
     165        assert model.get_variable_start("c.x9") == 9.0, model.get_variable_start("c.x9")
     166        assert model.get_variable_start("c.x10") == 10.0, model.get_variable_start("c.x10")
     167   
    35168class TestExternalStatic:
    36169
  • trunk/RuntimeLibrary/CMakeLists.txt

    r13703 r13719  
    5555if(" ${CMAKE_C_FLAGS} " MATCHES " -m64 ")
    5656    set(RTLIB_LIB_DIR ${JMODELICA_INSTALL_DIR}/lib/RuntimeLibrary64)
     57    set(RTLIB_BIN_DIR ${JMODELICA_INSTALL_DIR}/bin64)
    5758else()
    5859    set(RTLIB_LIB_DIR ${JMODELICA_INSTALL_DIR}/lib/RuntimeLibrary)
     60    set(RTLIB_BIN_DIR ${JMODELICA_INSTALL_DIR}/bin)
    5961endif()
    6062install(CODE "file(MAKE_DIRECTORY $ENV{DESTDIR}${RTLIB_LIB_DIR})")
     
    9193add_subdirectory(src/modules)
    9294
     95#Add evaluator
     96include_directories(src/evaluator)
     97add_subdirectory(src/evaluator)
    9398
    9499if(EXTRA_RUNTIME_MODULES)
  • trunk/RuntimeLibrary/Makefiles/Makefile.linux

    r13703 r13719  
    126126LIBS_FMUCS10 = -lfmi1_cs -lfmi1_me $(LIBS_FMU_STD) $(LIB_COMMON) -l:libsundials_cvode.a
    127127LIBS_FMU20   = -lfmi2 $(LIBS_FMU_STD) $(LIB_COMMON) -l:libsundials_cvode.a
    128 LIBS_CEVAL   = $(LIBS_FMU_STD)
     128LIBS_CEVAL   = -ljmi_evaluator_util $(LIBS_FMU_STD)
    129129
    130130# Include paths for compilation
  • trunk/RuntimeLibrary/Makefiles/Makefile.macosx

    r13703 r13719  
    125125LIBS_FMUCS10 = -lfmi1_cs -lfmi1_me $(LIBS_FMU_STD) $(LIB_COMMON) $(SUNDIALS_HOME)/lib/libsundials_cvode.a
    126126LIBS_FMU20   = -lfmi2 $(LIBS_FMU_STD) $(LIB_COMMON) $(SUNDIALS_HOME)/lib/libsundials_cvode.a
    127 LIBS_CEVAL   = $(LIBS_FMU_STD)
     127LIBS_CEVAL   = -ljmi_evaluator_util $(LIBS_FMU_STD)
    128128
    129129# Include paths for compilation
  • trunk/RuntimeLibrary/Makefiles/Makefile.windows

    r13703 r13719  
    160160LIBS_FMUCS10 = -lfmi1_cs -lfmi1_me $(LIBS_FMU_ALL)
    161161LIBS_FMU20   = -lfmi2              $(LIBS_FMU_ALL)
    162 LIBS_CEVAL = $(LIBS_FMU_STD)
     162LIBS_CEVAL = -ljmi_evaluator_util $(LIBS_FMU_STD)
    163163
    164164# Include paths for compilation
  • trunk/RuntimeLibrary/src

  • trunk/RuntimeLibrary/src/evaluator/jmi_evaluator.c

    r13602 r13719  
    246246}
    247247
     248void jmi_call_integer_fcn_ii(generic_funcptr fcn, int *out) {
     249    JMI_DEF(INT, arg_0)
     250    JMI_DEF(INT, arg_1)
     251    JMI_DEF(INT_EXT, tmp_0)
     252    JMI_DEF(INT_EXT, tmp_1)
     253
     254    JMCEVAL_parse(Integer, arg_0);
     255    JMCEVAL_parse(Integer, arg_1);
     256
     257    JMCEVAL_check("CALC");
     258    if (JMCEVAL_try()) {
     259        /* Calc phase */
     260        tmp_0 = (int)arg_0;
     261        tmp_1 = (int)arg_1;
     262        *out = ((f_i_ii)fcn)(arg_0, arg_1);
     263    }
     264    else {
     265        JMCEVAL_failed();
     266    }
     267}
     268
    248269void jmi_call_integer_fcn(generic_funcptr fcn, const char* inputs) {
    249270    JMI_DEF(INT, i_output)
     
    259280    } else if (strcmp(inputs, "s,s,i,") == 0) {
    260281        jmi_call_integer_fcn_ssi(fcn, &tmp_output);
     282    } else if (strcmp(inputs, "i,i,") == 0) {
     283        jmi_call_integer_fcn_ii(fcn, &tmp_output);
    261284    } else {
    262285        printf(ERROR_NOT_SUPPORTED_INPUT_ARGS_MSG);
  • trunk/RuntimeLibrary/src/fmi1_cs/CMakeLists.txt

    r13703 r13719  
    3737
    3838#Install the libraries
    39 install(TARGETS fmi1_cs DESTINATION "${RTLIB_LIB_DIR}")
     39if (NOT MSVC)
     40    install(TARGETS fmi1_cs DESTINATION "${RTLIB_LIB_DIR}")
     41endif()
    4042
    4143#Install header files
  • trunk/RuntimeLibrary/src/fmi1_me/CMakeLists.txt

    r13703 r13719  
    3939
    4040#Install the libraries
    41 install(TARGETS fmi1_me DESTINATION "${RTLIB_LIB_DIR}")
     41if (NOT MSVC)
     42    install(TARGETS fmi1_me DESTINATION "${RTLIB_LIB_DIR}")
     43endif()
    4244
    4345#Install header files
  • trunk/RuntimeLibrary/src/fmi2/CMakeLists.txt

    r13703 r13719  
    4949
    5050#Install the libraries
    51 install(TARGETS fmi2 DESTINATION "${RTLIB_LIB_DIR}")
     51if (NOT MSVC)
     52    install(TARGETS fmi2 DESTINATION "${RTLIB_LIB_DIR}")
     53endif()
    5254
    5355#Install header files
  • trunk/RuntimeLibrary/src/jmi/CMakeLists.txt

    r13703 r13719  
    202202
    203203    #Install the libraries
    204     install(TARGETS jmi
    205         DESTINATION "${RTLIB_LIB_DIR}")
     204    if (NOT MSVC)
     205        install(TARGETS jmi
     206            DESTINATION "${RTLIB_LIB_DIR}")
     207    endif()
    206208
    207209    #Install header files
     
    247249
    248250    #Install the libraries
    249     install(TARGETS ModelicaExternalC ModelicaStandardTables ModelicaIO ModelicaMatIO zlib
    250         DESTINATION "${RTLIB_LIB_DIR}")
     251    if (NOT MSVC)
     252        install(TARGETS ModelicaExternalC ModelicaStandardTables ModelicaIO ModelicaMatIO zlib
     253            DESTINATION "${RTLIB_LIB_DIR}")
     254    endif()
    251255
    252256    install(DIRECTORY "${MSLCSOURCES}/"
Note: See TracChangeset for help on using the changeset viewer.