• No results found

Incremental Compilation and Dynamic Loading of Functions in OpenModelica

N/A
N/A
Protected

Academic year: 2021

Share "Incremental Compilation and Dynamic Loading of Functions in OpenModelica"

Copied!
114
0
0

Loading.... (view fulltext now)

Full text

(1)

Institutionen för datavetenskap

Department of Computer and Information

Science

Master’s Thesis

Incremental Compilation and

Dynamic Loading of Functions in

OpenModelica

Kim Jansson, Joel Klinghed

Reg Nr: LIU-IDA/LITH-EX-A--08/029--SE Linköping 2008

Department of Computer and Information Science Linköpings universitet

(2)
(3)

Institutionen för datavetenskap

Department of Computer and Information

Science

Master’s Thesis

Incremental Compilation and

Dynamic Loading of Functions in

OpenModelica

Kim Jansson, Joel Klinghed

Reg Nr: LIU-IDA/LITH-EX-A--08/029--SE Linköping 2008

Supervisor: Peter Fritzson

ida, Linköpings universitet

Adrian Pop

ida, Linköpings universitet

Examiner: Peter Fritzson

ida, Linköpings universitet

Department of Computer and Information Science Linköpings universitet

(4)
(5)

Avdelning, Institution

Division, Department

Programming Environments Laboratory

Department of Computer and Information Science Linköpings universitet

SE-581 83 Linköping, Sweden

Datum Date 2008-06-12 Språk Language  Svenska/Swedish  Engelska/English   Rapporttyp Report category  Licentiatavhandling  Examensarbete  C-uppsats  D-uppsats  Övrig rapport  

URL för elektronisk version

http://www.ep.liu.se

ISBN

ISRN

LIU-IDA/LITH-EX-A--08/029--SE

Serietitel och serienummer

Title of series, numbering

ISSN

Titel

Title

Incremental Compilation and Dynamic Loading of Functions in OpenModelica

Författare

Author

Kim Jansson, Joel Klinghed

Sammanfattning

Abstract

Advanced development environments are essential for efficient realization of com-plex industrial products. Powerful equation-based object-oriented (EOO) lan-guages such as Modelica are successfully used for modeling and virtual prototyping complex physical systems and components. The Modelica language enables engi-neers to build large, sophisticated and complex models. Modelica environments should scale up and be able to handle these large models. This thesis addresses the scalability of Modelica tools by employing incremental compilation and dynamic loading. The design, implementation and evaluation of this approach is presented. OpenModelica is an open-source Modelica environment developed at PELAB in which we have implemented our strategy for incremental compilation and dynamic loading of functions. We have tested the performance of these strategies in a num-ber of different scenarios in order to see how much of an impact they have on the compilation and execution time.

Our solution contains an overhead of one or two hash calls during runtime as it uses dynamic hashes instead of static arrays.

Nyckelord

Keywords

(6)
(7)

Abstract

Advanced development environments are essential for efficient realiza-tion of complex industrial products. Powerful equarealiza-tion-based object-oriented (EOO) languages such as Modelica are successfully used for modeling and virtual prototyping complex physical systems and com-ponents. The Modelica language enables engineers to build large, so-phisticated and complex models. Modelica environments should scale up and be able to handle these large models. This thesis addresses the scalability of Modelica tools by employing incremental compilation and dynamic loading. The design, implementation and evaluation of this approach is presented. OpenModelica is an open-source Model-ica environment developed at PELAB in which we have implemented our strategy for incremental compilation and dynamic loading of func-tions. We have tested the performance of these strategies in a number of different scenarios in order to see how much of an impact they have on the compilation and execution time.

Our solution contains an overhead of one or two hash calls during runtime as it uses dynamic hashes instead of static arrays.

(8)
(9)

Acknowledgments

We would like to thank our examiner Peter Fritzson and our super-visor Adrian Pop for their input and support during the work on this thesis.

(10)
(11)

Contents

1 Introduction 3 1.1 Intended Audience . . . 3 1.2 Background . . . 3 1.3 Purpose . . . 4 1.4 Goals . . . 4 1.5 Method . . . 4 1.6 Limitations . . . 4 1.7 Thesis Outline . . . 5

I

Theoretical Background

7

2 Techniques 9 2.1 Dynamic Libraries . . . 9 2.2 Virtual Function . . . 10 2.3 Incremental Compilation . . . 10

3 Equation-Based Object-Oriented Languages 11 3.1 Modelica Language . . . 11

3.2 OpenModelica Environment . . . 12

3.2.1 OpenModelica Modules . . . 12

3.3 MetaModelica and RML . . . 13

II

Incremental Compilation and Dynamic

Load-ing of Functions

15

4 Dynamic Loading of Functions 17 4.1 Variable Passing . . . 18

(12)

x Contents

4.2 Packages . . . 18

4.3 Overloading Functions . . . 19

5 Incremental Compilation 21 5.1 Virtual Functions . . . 21

5.1.1 Why Not Use Static Function Arrays? . . . 22

5.1.2 Master Lookup . . . 23 5.2 Patches . . . 24 6 Simulations 29 7 Extra Improvements 31 7.1 Arrays . . . 31 7.2 Records . . . 32 8 Implementation Details 35 8.1 Data Encapsulation . . . 35 8.1.1 Modelica Types . . . 35

8.1.2 The Bridge Between System and C/C++ Code 37 8.2 Function Cache . . . 39

8.2.1 CompiledCFunction: the Uniontype . . . 39

8.2.2 Functions . . . 41 8.3 System . . . 46 8.3.1 Modelica Functions . . . 46 8.3.2 Internal functions . . . 51

III

Result

53

9 Benefits 55 9.1 Dynamic Loading of Functions . . . 55

9.2 Incremental Compilation . . . 55

10 Conclusion and Future Work 57 10.1 Conclusion . . . 57

10.1.1 Dynamic Loading of Functions . . . 57

10.1.2 Incremental Compilation . . . 58

10.2 Future Work . . . 59

(13)

Contents xi

10.2.2 Static Array Function Lookups: Implementation 61

Bibliography 63

A Interfaces 65

A.1 base_array Interface . . . 65

A.2 read_write Interface . . . 70

A.3 dynlib Interface . . . 77

A.4 strhash Interface . . . 78

B Performance Tests 81 B.1 Process Calling Overhead . . . 81

B.1.1 Result . . . 81

B.1.2 Procedure . . . 82

B.2 External Function-call . . . 83

B.2.1 Result . . . 83

B.2.2 Procedure . . . 83

B.3 Incremental Compilation: Single Package . . . 85

B.3.1 Result . . . 85

B.3.2 Procedure . . . 85

B.4 Incremental Compilation: Multiple Packages . . . 91

B.4.1 Result . . . 91

B.4.2 Procedure . . . 91

B.5 Incremental Compilation: Simulations . . . 96

B.5.1 Result . . . 96

(14)
(15)

List of Figures

3.1 Modules in the OpenModelica Compiler . . . 12

5.1 Associative Arrays . . . 27

5.2 Sequence for looking up functions . . . 27

5.3 Overloading of packages and their functions . . . 28

B.1 Benchmark of a single package with nested functions on Linux . . . 88

B.2 Benchmark of a single package with nested functions on Windows . . . 88

B.3 Benchmark of a single package using many functions on Linux . . . 89

B.4 Benchmark of a single package using many functions on Windows . . . 89

B.5 Benchmark of a single package using few functions on Linux . . . 90

B.6 Benchmark of a single package using few functions on Windows . . . 90

B.7 Benchmark of multiple packages using 50% of the func-tions on Linux . . . 93

B.8 Benchmark of multiple packages using 50% of the func-tions on Windows . . . 93

B.9 Benchmark of multiple packages using 90% of the func-tions on Linux . . . 94

B.10 Benchmark of multiple packages using 90% of the func-tions on Windows . . . 94

B.11 Benchmark of multiple packages using 90% of the func-tions with fewer OpenModelica restarts on Linux . . . 95

B.12 Benchmark of multiple packages using 90% of the func-tions with fewer OpenModelica restarts on Windows . . 95

B.13 Benchmark of simulation using 50% of the functions on Linux . . . 97

B.14 Benchmark of simulation using 50% of the functions on Windows . . . 97

B.15 Benchmark of simulation using 90% of the functions on Linux . . . 98

(16)

Contents 1

B.16 Benchmark of simulation using 90% of the functions on Windows . . . 98

List of Tables

B.1 Measurements of process calling overhead . . . 81 B.2 Measurements of external function calls . . . 83

Terms and Definitions

• dll : Dynamically loaded library.

• CORBA : Common Object Request Broker Architecture. • External function : a non-built-in function called by

OpenMod-elica. Not to be confused with Imported function.

• Imported function : an externally implemented function in

ei-ther C or Fortran referenced in Modelica using the “external” keyword. Imported functions are a subset of External functions.

• OMC : OpenModelica Interactive Compiler. • OMShell : OpenModelica Shell.

• Package function : an external function defined in a package

class.

(17)
(18)

Chapter 1

Introduction

In this chapter we will give a brief introduction of this thesis, its outline and goals.

1.1

Intended Audience

This thesis is intended for anyone interested in more technical aspects of Modelica and OpenModelica. The reader may be an OpenModelica developer or a person interested in compiler construction.

1.2

Background

Modeling and simulation of large and complex systems like cars or space shuttles is today a growing field. Thus the need for good mod-eling and simulation tools is apparent. The Modelica language is an object-oriented, multi-domain modeling language specialized for sim-ulations. OpenModelica is a project with the goal to build a complete modeling and simulation environment using the Modelica language.

OpenModelica has some issues. One of them is a long turn-around time after small code changes when developing large Modelica projects. The main problem is that each changed file needs to be recompiled and the complete project re-linked each time. With sufficiently large files this takes a while. One proposed solution is to use Incremental Compilation to decrease the amount of code that needs to be recom-piled.

(19)

4 Introduction

Another issue is the use of an ineffective and inexact method of transferring variables to and from functions. This is because text files are used as medium.

1.3

Purpose

The purpose of this project is to make OpenModelica more effective when functions are called and when they are recompiled. The thesis investigates the possibility of using incremental compilation to lower turn-around time in large OpenModelica projects. It also investigates if there exists a more effective solution for transferring variables to and from functions.

1.4

Goals

The goals of this project are to implement incremental compilation and dynamic loading of functions in OpenModelica. As a side goal we will also thoroughly re-factor argument passing to and from functions. The aim is to implement these features in such a manner that developers using OpenModelica can benefit from these features without modifying their code.

1.5

Method

This project was performed at PELAB, Linköping University. As the project emphasizes on implementation there was not a great need for prestudies. This gave us the opportunity to use an agile development process in which we could implement small precise features that to-gether formed the complete solution. Since agile development relies heavily on testing it was a big help that there already existed a large collection of unit tests for OpenModelica.

1.6

Limitations

Since the project is limited in time it was decided that our solution did not need to include a way to automatically mark modified functions.

(20)

1.7 Thesis Outline 5

We did not have access to any sufficiently large Modelica projects dur-ing the development of this project to test the performance thoroughly. This was limiting because the benefits of incremental compilation be-comes more prominent the larger the files and the project are. When compiling small projects it may even be a disadvantage because of the extra work.

1.7

Thesis Outline

This thesis is divided into three distinct parts. The first part gives the reader the needed theoretical background, mainly focusing on three of the languages involved in OpenModelica – Modelica, MetaMod-elica, RML – and some of the techniques that will be used for the implementation. The second part describes the project more detailed, including the design of our implementation as well as technical de-tails. The third part describes the result of the project – for example performance benchmarks – and conclusions drawn from them.

(21)
(22)

Part I

Theoretical Background

(23)
(24)

Chapter 2

Techniques

This chapter mainly contains a short explanation of the different tech-niques we used in this project.

2.1

Dynamic Libraries

A long time ago there were only static libraries; collections of precom-piled code ready to be inserted into programs at compile-time. Static libraries leads to a lot of code duplication, for example all programs written in C would contain its own copy of the not so small standard C library. As a countermeasure dynamic libraries were introduced. Dynamic libraries enables programs to share code by loading these shared libraries dynamically at runtime. Dynamic libraries were not available to the programmer at first and thus they were only used by the operating system and the linker. Later on, API:s were developed to expose this functionality. [3]

Dynamic loading of libraries is to this day and age well supported in most operating systems. They are slightly different in some of the capabilities and usability but the important features are there.

For some reason most programming environments still has – if any – quite rudimentary support for dynamic loading of libraries and func-tions therein. For example C and C++ has no standardized support for dynamic loading even though it is a common part of most setups. Most Unix variants uses the POSIX API and on Microsoft Windows it is part of the Windows API. [7, 1]

(25)

10 Techniques

2.2

Virtual Function

Virtual function is a term from the object-oriented paradigm. A vir-tual function is a function that can be redefined further down the inheritance chain. This makes it possible to call a generic BaseObject but still use the redefined function in the SubObject. [6] In C++ this is often implemented using a lookup-table of function pointers hidden by the language syntax. [5] We choose to use the term Virtual function even though we do not use objects as such, instead of an inheritance chain our solution uses a patch chain.

2.3

Incremental Compilation

Incremental compilation means that when the compiler compiles a project it only compiles those parts of the code that were actually modified, using some container such as block, function, class or file as lowest denominator. For example most modern compilers can compile each file as a single unit and then only recompile those that have been modified. The point of incremental compilation is to decrease the turn-around time for a recompilation, especially when only minor modifications have been made to the code.

(26)

Chapter 3

Equation-Based

Object-Oriented Languages

This chapter provides a short overview of what the Modelica lan-guage is. It also contains an overview of OpenModelica - in which we will add dynamic loading and incremental compilation - and a brief introduction to MetaModelica and RML which are used to compile OpenModelica.

3.1

Modelica Language

Modelica is an object-oriented modeling language for declarative equation-based mathematical modeling of large and heterogeneous physical sys-tems. Modelica was designed with the main objective of facilitating exchange of models, model libraries, and simulation specifications. [9] The one aspect of Modelica that really stands out and differentiates Modelica from regular languages is that it enables acausal modeling, i.e. it is possible to describe the behavior of a component without defining which variables are input and which are output. As long as enough variables are specified Modelica solves the system of equations to assign the right values to the remaining variables.

Various formalisms can be expressed in the more general Modelica formalism. In this respect Modelica has a multi-domain modeling ca-pability which gives the user the possibility to combine electrical, me-chanical, hydraulic, thermodynamic, etc., model components within the same application model. [9]

(27)

12 Equation-Based Object-Oriented Languages

Figure 3.1. Modules in the OpenModelica Compiler

3.2

OpenModelica Environment

OpenModelica is a complete Modelica modeling, compilation and sim-ulation environment based on free software. Notable components of the OpenModelica environment are OpenModelica Interactive

Com-piler (OMC) and OMShell. The OpenModelica Interactive ComCom-piler

is the core component of the environment and provides advanced inter-active functionality for model management. The OMC functionality is available via command line scripting, CORBA or socket interface. [4]

OMShell is an interactive command handler that provides very basic

functionality for loading and simulation of models.

3.2.1

OpenModelica Modules

Figure 3.1 on page 12 contains an overview of the modules in the OpenModelica Compiler. We have chosen to emphasis on the modules we have modified during the course of this thesis.

• The Ceval module performs evaluation of expressions both at

(28)

respon-3.3 MetaModelica and RML 13

sible for compiling all code generated by CodeGen and SimCode-Gen modules.

• The ClassLoader modules loads packages and libraries.

• The CodeGen module generates C code both for external

func-tions, packages and simulations.

• The DAE module defines the differential algebraic equation

rep-resentation.

• The Exp module defines the expression representation. • The Inst module instantiates code.

• The Interactive module handles interactive sessions.

• The SimCodeGen module generates C++ code for simulations. • The Static module performs static semantics and type checking. • The System module contains a collection of OS-level helper

func-tions.

3.3

MetaModelica and RML

Relational Meta-Language (RML) is a meta-language and compiler generator, implementing Natural Semantics. [2] Natural Semantics is a specification formalism that is used to specify the semantics of programming languages. [8]

Initially the OpenModelica compiler was developed using RML. OpenModelica users usually have detailed knowledge of Modelica but little RML or Natural Semantics knowledge. To enable users to con-tribute to the open-source project OpenModelica the compiler was converted from RML to MetaModelica. MetaModelica is a modeling language based on Modelica with several extensions that allow pro-gram language specification. [9]

(29)
(30)

Part II

Incremental Compilation

and Dynamic Loading of

Functions

(31)
(32)

Chapter 4

Dynamic Loading of

Functions

One of the problems given to us to solve was the low performance in evaluating function calls in OpenModelica. This was because external functions were compiled into executables, launched through the system shell and used text-files for variable passing.

All external functions in OpenModelica, except those called from simulation objects, were generated to C-code and compiled one by one into executables. External functions called from simulation objects were included in the simulation object’s C++-code and compiled to-gether with the model into a simulation executable. When OMC called an external function the function was compiled and executed – each and every time.

The first step when improving the call performance was to com-pile external functions as dynamic libraries rather than executables, thus removing the penalties for launching new processes which on at least some platforms are expensive. See appendix B.1 on page 81 for benchmark data.

The second step was to make sure external functions were compiled only if needed during an instance of OMC using a cache to remem-ber compiled and dynamically loaded functions. To handle function overloading, the cache is cleared when a loadFile call loads a Modelica file with a function using the same full name. In order to only com-pile external functions when a new implementation was given, we also needed to implement functionality to verify the currently compiled

(33)

18 Dynamic Loading of Functions

version originated from the same source file and is up-to-date.

4.1

Variable Passing

When calling functions from OMC, the variables had to be converted from MetaModelica/RML into C-based data types and then passed to and from the executable containing the function code. Simulation ob-jects however handled their own variable passing directly in C-code as the simulation object generated all of its external functions code inside its own executable. Variable passing between OMC and a simulation also use text-files as the medium.

The third step when improving the call performance was to use direct-memory access for variable passing. Dynamically loading ex-ternal functions into the OMC process made it possible to use direct memory access. Here we had to decide how we were going to encapsu-late the data. Our options were to either use the already existing RML encapsulation or to build our own based on the old file-based encapsu-lation. The benefit of using the already existing RML encapsulation would be that we would not have to decapsulate and encapsulate the data as it is already passed through RML to C. The drawbacks were that we would have to make the RML headers a part of OpenMod-elica and thus increasing the dependencies. The benefits of building our own encapsulation would be that we could make a less complex solution. We would not need to change the code generation in Open-Modelica as we could reuse the abstract data-types already defined. With this in mind we decided to build our own data encapsulation. More detailed information about the resulting conversion code and encapsulating of data can be found in chapter 8.1 on page 35.

4.2

Packages

The old implementation did not distinguish between different external functions – all were treated equally. One executable was created for each and every external function that was called within a project. This method creates a large number of files and many file operations are needed when compiling and loading the functions

(34)

4.3 Overloading Functions 19

Introducing dynamic loading of functions did not remedy the prob-lem of many files and file operations. As a solution we selected to group functions together in fewer and larger files using a language de-fined grouping: Top-Level Package. Package functions implemented in other languages, imported functions, are still handled as separate external functions. All other package functions are grouped together and need to be compiled as such – all at the same time.

4.3

Overloading Functions

OpenModelica has always had a problem with overloading of func-tions. If you have two top-level external functions that share the same full name in two different source files, they will overload each other. The old implementation solved this problem by always compiling the function when it was called. When introducing dynamic loading of functions we also tried to lower the number of compilations as they often were unnecessary. One problem we encountered while doing this was that non-package external functions creates a dynamic library based upon the full function name. When loading a source file any already loaded external functions with the same full names would be recompiled. In order to solve this we added a function that returns the source file for the external function, so when a source file containing external functions is loaded we can tell if any already existing dynam-ically linked library originates from the right source file or if it needs to be compiled.

(35)
(36)

Chapter 5

Incremental Compilation

To decrease the time spent compiling rather than developing during a large project, incremental compilation in various forms are often used. The OpenModelica environment uses C and C++ compilers to do the last step when assembling executables. These compilers have support for incremental compilation based on files. This is not suf-ficient as Modelica projects tend to have very large files containing many functions. Even if only one of these functions are modified the whole file needs to be recompiled. Our goal is to improve the incre-mental compilation in OpenModelica so that only modified functions are recompiled.

5.1

Virtual Functions

For incremental compilation at the function level we have to be able to replace references to functions in already generated and compiled code. This is where the concept of virtual functions come in handy. Our virtual functions are implemented using several associative arrays of function names and pointers.

The point of using these associative arrays is to make it possible to associate a function name with a newer version of that function without having to change any other code. The reason why no code needs changing is that all function-calls uses lookup to find out which function to call. Each external function will at the start of the func-tion body lookup all of its dependencies. This has to be done at each function-call because between calls a loadFile may have changed

(37)

22 Incremental Compilation

some dependency functions. These lookups are only run once inside a function as we can guarantee that loadFile will not be called dur-ing the function-call. The associative arrays uses hashdur-ing techniques to remain reasonably fast but still dynamic and flexible. The reason why the associative array needs to be dynamic is because we want to be able to add new functions to a package incrementally. Flexibility is needed because we wish to be able to replace implementations of packages on the fly. OpenModelica does not require a file to be named after its package, thus different implementations of a package can exist in different files and might need to replace the other implementation when loaded by loadFile.

5.1.1

Why Not Use Static Function Arrays?

OMC is an interactive compiler. This means that OMC does not know which files that are going to be loaded during a session. Because of this it is complicated to use static package or function arrays for external functions in OMC.

Inside a package it is known at compilation time which functions that are present, so a static array is no problem. Using a fully static array would however mean that you have to do a full compilation when you add a new function. To remedy this you can use static indexes but a dynamic array. Using static indexes in a package would replace a hash-lookup with an array-lookup which is faster.

If one wishes to have a table of function pointers in each package you would still need either a hash-lookup for the package or a static index that gets initialized when the package is loaded, demanding that the package in question is loaded. This creates problems when you have cross-dependencies between packages.

Another solution is to let OMC have one large table for all ex-ternal functions, both those in packages and those outside. This will remove the extra package lookup in the solution mentioned above. Each loaded package would get a “base index” in the large function table. We can however not guarantee that the package always gets the same “base index” as the same package can be used in different projects with different lists of packages. Also, this will mean we have to give a package a new “base index” if they fill their allotted slot, ie. gets a new function. Then we also have to update all packages

(38)

de-5.1 Virtual Functions 23

pendent on this package so that they use the new “base index”. None of this solves the problems with cross-dependencies between packages as packages when loaded still need to get the “base index” for all packages they are dependent upon.

Another problem arises if you want to be able to reuse libraries compiled using static hashes in-between OMC sessions. When we load a package we can not be satisfied by the fact that the dll of the loaded package is more recent than its source file. We also need to check that any package dependency has not been recompiled. If the package dependencies are more recent we can not be certain that the hash indexes are valid.

An example of this would be if we have two packages, pkg1 and

pkg2. pkg1 is dependent on pkg2. In one OMC session both packages

are compiled and the indexes are OK. We now remove the pkg2 dll-file and start OMC in a new session where only pkg2 is used which compile a new dll-file for pkg2. Next we load pkg1, the indexes in pkg1 are now invalid. This would be even more complicated if we have circular dependencies between pkg1 and pkg2.

So if one were to use static arrays you do not only need to change the dynamic hash to a static array, a lot of other code needs to be rewritten as well.

We did not have the time to pursue this fully so this is something that could use more investigation, see chapter 10.2.2 in page 61 for suggestions on which functions need to be modified.

5.1.2

Master Lookup

To facilitate the need for a lookup function we created a master_lookup. The master_lookup function has two associative arrays, one for pack-ages and one for non-package external functions.

As we group all the external functions within a package together into one dynamic library we were able to put an associative array for that package along with a local lookup function in the same dynamic library. An overview is displayed in figure 5.1 on page 27.

The associative array for packages in master_lookup contains package names and a pointer to their lookup function while the asso-ciative array for external functions contains function names and their function pointers. Their interaction is displayed in figure 5.2 on page

(39)

24 Incremental Compilation

27.

5.2

Patches

Virtual functions makes it possible to implement incremental compila-tion at a funccompila-tion level since we can replace funccompila-tions during runtime. Because we group all the functions in a package together, without patches the whole package would need to be recompiled even if only one function has been modified. To introduce incremental compilation at function level, we group modified functions together in patches and compile only those. When loading a package, all patches are automat-ically loaded in chronological order replacing function pointers in the associative array of the package. We load all patches chronologically because it is faster to replace a function several times than it is to find out which version is the latest and only load that one.

Lets show this with an example. For an overview of the different components involved see figure 5.3 on page 28. In this example we assume that we have an editor that notices modifications and creates the necessary patch files to use incremental compilation. We have two packages, Pkg1 and Pkg2 each in its own Modelica source file, pkg1.mo and pkg2.mo respectively. Pkg1 has a function that calls

Pkg2.function. Pkg2 has also a function that initially adds the two

arguments.

We use the OMShell to input the following commands: OMShell

-loadFile("pkg1.mo") loadFile("pkg2.mo") Pkg1.function(1,2)

// ** Here we edit pkg2.mo ** loadFile("pkg2.mo")

Pkg1.function(1,2)

(40)

5.2 Patches 25

1. OMC preloads both Pkg1 and Pkg2 after their respective

load-File calls.

2. OMC wants to evaluate Pkg1.function but realizes that neither Pkg1 nor Pkg2 are initialized or compiled.

3. OMC does a full compile of both Pkg1 and Pkg2 as Pkg1 has dependencies on Pkg2.

4. OMC initializes the resulting dll:s. When the dll:s are being loaded the pkghash in OMC gets two new entries. The key is a hash of the package name and the data is the address to the

lookup function for that package.

5. OMC evaluates the function Pkg1.function.

(a) OMC looks up the lookup function for Pkg1 using the pkghash and uses that function to find the function pointer to Pkg1.function.

(b) OMC calls Pkg1.function.

(c) Pkg1.function is dependent on Pkg2.function so Pkg1.function uses master_lookup to find out the function pointer for that function and stores that pointer for the remainder of the scope of the function. So even if Pkg2.function would be called inside a loop it would only need to lookup the function pointer once.

(d) The function pointer is used to call Pkg2.function which is evaluated and return its result.

(e) Pkg1.function can now be evaluated and returns its result to OMC.

** pkg2.mo is altered and loadFile("pgk2.mo") is executed. ** 6. OMC removes the old Pkg2 entry from the pkghash as it has

not yet made certain that the newly loaded Pkg2 is the same package or originated from the same source file as the old Pkg2. * Pkg1.function is called again *

(41)

26 Incremental Compilation

(a) OMC realizes that Pkg2 is not loaded yet.

i. OMC notices that Pkg2.dll already exists but that pkg2.mo has been modified and that there exists a patch file indicating that we only need a partial compilation re-sulting in a patch dll instead of a full recompilation. ii. OMC loads the same old Pkg2.dll again.

iii. The function hash in Pkg2 is instantiated with the function pointers for the functions in the old base dll. iv. The dll patch is loaded by the Pkg2.dll and the function

pointer to Pkg2.function is updated in the Pkg2s own function hash.

v. OMC adds Pkg2 to the pkghash again with the same old lookup function.

(b) Pkg1.function uses master_lookup to find out the function pointer to Pkg2.function.

(c) The function pointer is used to call Pkg2.function which is evaluated and returns its result.

(d) Pkg1.function can now be evaluated and returns its result to OMC.

(42)

5.2 Patches 27

Figure 5.1. Associative Arrays

(43)

28 Incremental Compilation

Figure 5.3. Package #2 is patched and pointers in both pkghash and

(44)

Chapter 6

Simulations

With dynamic loading of functions and incremental compilation of packages added to OpenModelica it was time to let simulations make use of it as well.

Simulations has always been handled differently than the other generated code in many aspects. First and foremost, they have always been compiled as stand-alone executables to make it possible to run them outside of OMC. We wanted to keep this particular feature as it can be very usable. As the simulations were compiled and executed outside of OMC they did not have to call external functions the same way, instead all of the external functions were collected into one single C++ file and compiled together. This removed the need for using text files for variable passing and thus simulations did not suffer from the speed penalties those brought.

Development of simulations that use a lot of external functions would benefit from the same incremental compilation that the rest of OpenModelica now utilizes. To be able to benefit from incremental compilation and at the same time keep simulations independent of OMC every simulation executable have to implement its own version of master_lookup as the one in OpenModelica would not be avail-able. The master_lookup in simulations will however be simpler as no support for overloading is needed. This means we could separate all the actual simulation code from the external functions and their packages in such a way that if an external function was modified, only it need to be recompiled and if the simulation model is modified, only the main simulation executable need to be recompiled. We also made

(45)

30 Simulations

sure that simulation executables are only recompiled if their model code has changed and not at every simulate call which was the case earlier.

(46)

Chapter 7

Extra Improvements

This chapter details other modifications we did during the thesis that are not directly connected to either dynamic loading or incremental compilation.

7.1

Arrays

To facilitate the communication between external functions and Open-Modelica the module read_write is used. For simple data types such as real, integer or boolean nothing special is needed. Complex data types such as arrays are a different matter. All types of arrays need dynamic allocation and a lot of functionality such as transpose, sum and copy. String arrays and other arrays of complex types (arrays of arrays, tuples, or records are as of yet not supported) also need encap-sulation of data. When we got involved in this project real arrays and integer arrays were in pretty good shape, boolean arrays seemed to be implemented and string arrays were non-existent. As we changed to using direct memory instead of using files as medium for transferring variables to and from external functions, support for boolean arrays, which had earlier been unsupported, came almost without charge. In the following days it became apparent that most of the boolean array functionality actually were stubs.

Later on a need for string arrays came into light and now it was time for an overhaul of the array functions. Quite a bit of the array code was, as you probably can imagine, very similar and instead of copying the code yet again for string and boolean arrays we

(47)

32 Extra Improvements

ized it into a super array type; base_array. As this is all written in C, we could not use any language features to implement class hierar-chies but the principle is still valid. So all common code got put into base_array and the interfaces for real and integer arrays got syn-chronized. Boolean and string arrays implements the same interface as real and integer arrays barring matrix and most vector operations. An identity matrix is not well defined for either boolean nor string arrays and neither is inner space products or even min/max/sum.

More in-depth information about base_array can be found in chapter 8.1.1 on page 36.

7.2

Records

OpenModelica has never had the functionality to transfer record vari-ables to and from external functions. As we started making test cases and subsequently test which parts that were implemented and which were not we came to the conclusion that records had been skipped all the way from instantiation onto code generation. The type record was added into Expression and DAE modules so the code generator had something to work with. With the exception of finding where it was needed the addition of the type itself was simple enough. Only one additional member was needed in the record type compared to the primitive types and that was the class name of the record. This was very much needed in generation of the corresponding C struct for each and every type of record and what better to use as an unique identi-fier than the full class path of the record? It makes the code readable because it is easy to directly map the C struct to the Modelica record counterpart. Then it was just a matter of getting the code generator to generate code for the records as structs using the class definition of the record, change member access code and build a read_write con-tainer to handle sending arbitrary record data between the external functions and the Values module in OMC. Sending records to a func-tion was not all that bad as both System.executeFuncfunc-tion (with a lot of help from Values.Value) and the external function code knows exactly what the record looks like and what members it has. When re-ceiving the return value System.executeFunction is unaware of the record type and member variables. The solution for this was to make

(48)

7.2 Records 33

the external function code send all needed type information back with the actual data.

(49)
(50)

Chapter 8

Implementation Details

In this chapter we will go into detail concerning our implementation.

8.1

Data Encapsulation

Data encapsulation is used when C and C++ code need to work on variables coming from or are about to be returned to OMC. The whole chain is actually: “Modelica function ↔ Values module ↔ RML ↔ System module ↔ read_write ↔ C or C++ code”. In this chapter we will only talk about “System ↔ read_write ↔ C or C++ code” as this is the part we have modified and worked with.

8.1.1

Modelica Types

Simple types such as integer, real and boolean are not encapsulated at all but instead directly mapped to the corresponding primitive types in C: int, double and signed char respectively.

Strings

Strings are mapped to char pointers as this is what C itself uses. These are however accompanied by utility functions to make it easier to allocate, deallocate and handle strings.

(51)

36 Implementation Details

Arrays

While doing a cleanup of the array code in c_runtime we chose to split as much of the common array functionality as possible to work with a generic array class, base_array. More about why and a more high level explanation can be found in chapter 7.1 on page 31.

C has no language constructs for object-oriented programming but the concepts can still be used. So base_array is implemented as an interface but without use of virtual functions or the different access types: public,protected or private. For a full listing of the base_array interface see appendix A.1 on page 65.

All subclass arrays inheriting from the superclass base_array are really just typecasting. An instance of integer_array is just an base_array instance but every function in the integer_array in-terface knows that it should typecast the base_array data pointer member to a modelica_integer pointer before trying to access any elements. The same goes for allocation and deallocation of the data pointer member which is always handled by the subclasses. The base_array class implements the generic index, size and dimension function as those are common to all subclasses.

The subclass interfaces were kept intact barring inlining of a couple common functions and some minor cosmetic changes.

Tuples

Tuples are not encapsulated the same way other data types are. C or C++ functions returning multiple variables always does this us-ing tuples but the C or C++ code has no concept of this. It just writes multiple variables to the read_write module and let it deal with it. See chapter 8.1.2 on page 37. Currently the code generators Codegen and SimCodegen does not support sending tuples to external functions.

Records

Records are mapped to C structs. No utility functions are needed as read_write handles all the work of sending this data between System and the C or C++ code. More about this in chapter 7.2 on page 32

(52)

8.1 Data Encapsulation 37

and in the interface for read_write found in appendix A.2 on page 70.

8.1.2

The Bridge Between System and C/C++

Code

read_write is a collection of functions working with so called

type_description objects. Together they form the bridge between the C code implementation of the System module and the generated C code of external functions. For the complete read_write interface, see A.2 on page 70.

When OMC calls an external function, System.executeFunction gets a list of input arguments encapsulated by RML and the Values module. From these arguments System.executeFunction builds a list of type_description objects by first decapsulating the argu-ments and then re-encapsulating them using the write_modelica functions from read_write.

The reason for this double encapsulation is primarily that

System.executeFunction can not be written in such a way that it generically can call different function pointers with different argu-ments, thus we must encapsulate the arguments into a list that can be sent to a unique wrapper function for each external function. Sec-ondly we do not reuse the Values and RML encapsulation as that would require the code generators to be rewritten in a non-trivial manner. All external functions would also need to link to RML and the Values module and by doing that increase the dependencies for external functions.

The unique wrapper function for each external function is gen-erated by the code generators. These wrapper functions decapsu-late the input arguments from read_write and send them to the real C function. The wrapper function then receive the return val-ues from the real C function and encapsulates them before send-ing them back to read_write and System.executeFunction. As System.executeFunction receives the return values it decapsulates and re-encapsulates them again this time using RML and Values.

Multiple return values from an external function are always col-lected into a tuple, the generated C or C++ code has however no knowledge of this. The solution is to let an external function wrapper

(53)

38 Implementation Details

call write_modelica a variable number of times. If write_modelica is called more than once the return value is put into a tuple.

This process does not in principle differ much from the old way of transferring arguments between external functions and OMC using text-files. The differences are that all transfer goes through direct-memory instead of files. Support for string arrays and records has also been added.

(54)

8.2 Function Cache 39

8.2

Function Cache

In the old version of OpenModelica, 1.4.3, there existed a list of ex-ternal functions called cflist. When we started to implement dynamic loading of functions for the 1.4.4 version it was natural to continue using this list as a cache for compiled external functions.

The first new version only contained the full function path and a handle to the function pointer. So when OMC needed to call a function it had two possible scenarios:

• The function is in the cache so OMC only needs to call the

cached handle.

• The function is not in the cache so OMC need to first compile

the function, then call it and last save the resulting handle into the cache for use the next time the function is called.

With continued development and the introduction of packages and incremental compilation we needed to save more and more information in this function cache. The result became a list of CompiledCFunction entries.

8.2.1

CompiledCFunction: the Uniontype

Interactive.CompiledCFunction is a uniontype we have added con-taining two types of records: CFunction and VirtualFunction. These two record types represents external functions in different stages.

The CFunction record :

Absyn.Path path: The full function path so that the function can be found in the cache.

Integer funcHandle: A handle to the function pointer loaded in System. So OMC do not have to load the function again. The CFunction represents non-package external functions that has been compiled.

(55)

40 Implementation Details

The VirtualFunction record type:

Absyn.Path path: The full function path so that the function can be found in the cache.

Option<Integer> funcHandle: If the function is compiled the member contains a handle to the function pointer loaded in System. If the function is yet to be compiled the member is not set. A package function is added to the cache as soon as its package is loaded but is not compiled until one function in the package is called.

Option<Absyn.Path> pkg: If the record points at a package function this member contains the full package path. Non-package external functions needs to be preloaded under cer-tain conditions and for those this member is not set. String pkg: If the record points at a package function this

member contains the directory path to the package source file. If it points at a non-package function, this is just the empty string.

The VirtualFunction represents several types of functions. 1. Preloaded package functions.

2. Compiled package functions.

3. Package functions that need recompilation. 4. Non-package functions that need recompilation.

Preloaded functions are needed because there is not enough infor-mation in order to instantiate the functions as their containing package are loaded. When calling one of these preloaded function the whole package is compiled and all records of functions in that package is upgraded to “Compiled package functions”.

Compiled package functions need to store more information than a non-package function after it has been compiled which is why we do not use the CFunction record type for these.

The reason why we need to be able to mark functions for recompi-lation is because of the possibility that functions and packages can be

(56)

8.2 Function Cache 41

replaced either with modified or completely new implementations. For example if we have two packages Pkg1 and Pkg2. Function Pkg1.f depends on Pkg2.f. Pkg1.f is called which forces OMC to compile both Pkg1 and Pkg2. Then Pgk2.f is altered and Pkg2 reloaded. When loading a package all items in the functions cache that matches that package path are removed and replaced by “Functions that need recompilation”. This is because if we would not mark the functions, that some other function is dependent upon, we could end up in a sit-uation where Pkg1.f is called and as this function already is compiled we do not recheck all of its dependencies. As Pkg1.f is evaluated it would then not find Pkg2.f as it has yet been reloaded. To solve this we mark functions as “need recompilation” and after a loadFile or loadModel we look in the function cache for marked files and try to re-compile them. We only need to do this after loadFile and loadModel as those are the only two functions that can load and replace pack-ages and this means that we do not need to check the dependencies of already compiled functions every time the are called.

8.2.2

Functions

Almost every function we have written in the Meta-Modelica parts of OMC works with the function cache. It is the list around whom all other functions revolve – at least when it comes to dynamic loading of functions and incremental compilation.

These are the main functions that we have added to OMC that work with the function cache:

Static.isFunctionInCflist

Given a function path and the current function cache it will return an entry found matching the function.

It has three return values:

• Is function in cache? – true if it is, false if it is not.

• Function handle – optional, set if the function is in the

cache and it is a compiled function.

• Package path – optional, set if the function is in the cache

(57)

42 Implementation Details

Called by a lot of functions needing to know how to call a given function.

Ceval.compileFunction

Given the return values from a Static.isFunctionInCflist call and the current environment it tries to make sure the func-tion is compiled.

This function was added as it became more and more compli-cated to handle all different types of functions available in the function cache. It handles these three different combinations:

• The function cache returned a handle to the function.

Noth-ing needs to be done.

• The function cache returned a function path without a

package. It is an external function that need recompila-tion, call Ceval.compileExternalFunction.

• The function cache returned a function path and a package

path. It is either a preloaded package function or a pack-age function that need recompilation. In either case, call Ceval.compilePackageFunction.

Called by a lot of functions after they have called

Static.isFunctionInCflist in the search for a function han-dle.

Ceval.compilePackageFunction

Compiles the package library containing the given function and the current environment.

It calls Ceval.compilePackageLib to do the actual compilation and then it replaces every preloaded package function entry in the function cache with corresponding compiled function entry. After that it calls Ceval.touchFunctions to try and compile each and every dependency returned by

Ceval.compilePackageLib.

Called by a lot of functions that needs a preloaded package func-tion found in the cache to be compiled.

(58)

8.2 Function Cache 43

Ceval.compileExternalFunction

Compiles a function as a dynamic library given the full function path and the current environment.

It calls Ceval.compileExtFuncLib to do the actual compilation and then it adds an entry in the function cache with the handle to the compiled function. After that it calls Ceval.touchFunctions to try and compile each and every dependency returned by Ceval.compileExtFuncLib.

Called by a lot of functions that needs an external function not found in the cache to be compiled.

Ceval.touchFunctions

Tries to make sure a given list of functions is compiled using the function cache and the current environment.

For each function it does the following routine:

• The function is in the cache as either a compiled

non-package function or a compiled non-package function. Nothing needs to be done.

• The function is in the cache as a preloaded package

func-tion, call Ceval.compilePackageFunction and continue.

• The function is not in the cache, call

Ceval.compileExternalFunction and continue. Called by Ceval.compilePackageFunction and

Ceval.compileExternalFunction to try and compile all de-pendencies returned by

Ceval.compilePackageLib or Ceval.compileExtFuncLib. Ceval.compilePackageLib

Compiles a package library given the full path to the package, the source file from which the package defintion originated and the current environment.

It does all the checking that is needed before determining if we need to either do a full compilation of the package, compiling a patch or doing nothing. Returns a list of all called functions from within functions inside the package, i.e. the package de-pendencies.

(59)

44 Implementation Details

Called by Ceval.compilePackageFunction. Ceval.loadPackageLib

Preloads a package given the full path of the package, its class defintion, the path to the directory containing the package source files and the current environment.

Preloading a package means to fill the function cache with preloaded package function entries for each and every function inside the package.

Called by ClassLoader.packageLoader which in turn is called by loadFile and loadModel.

Ceval.compileExtFuncLib

Compiles a function as a dynamic library given the full function path and the current environment.

It does all the checking that is needed before determining if we need to either do a full compile of the library or do nothing. Returns a list of all function this function calls, i.e. its depen-dencies.

Called by Ceval.compileExternalFunction. Ceval.tryToRecompile

Given the function cache and the current environment it will search for functions marked as need recompilation and compile those.

Called by Ceval.cevalInteractiveFunctions after it has eval-uated either a loadFile or loadModel call.

Interactive.removeAnySubFunctions

Given a class that is about to be replaced, it will clear the func-tion cache of all compiled entries and free any handles that are subitems to the class.

It is called by Interactive.replaceClassInProgram which in turn is called by Interactive.updateProgram when a loadFile or loadModel replaces a class in the environment.

Interactive.removeCf

(60)

8.2 Function Cache 45

function cache of all compiled entries and free any handles that this function has.

It is called by Interactive.replaceClassInProgram which in turn is called by Interactive.updateProgram when a loadFile or loadModel replaces a class in the environment.

(61)

46 Implementation Details

8.3

System

The dynamic loading of functions and packages needed a couple of low-level C functions to do the actual dirty work of loading and unloading the libraries. Also as generated C and C++ code need access to OMC:s master_lookup this function and its associative arrays needed to be low-level as well.

8.3.1

Modelica Functions

This is a list of the new functions we added to the System module: System.loadPkg

Loads and initializes a package library given the file path to the dynamic library (.so or .dll file) and the package path generated from its Absyn.Path.

If the dynamic library loaded OK it will add the package to the pkghash. Returns an handle to the library.

Called by Ceval.compilePackageFunction. System.loadExtFunc

Loads and initializes a external function given the full path to the function generated from its Absyn.Path.

If the dynamic library loaded OK it will add the function to the exthash. Returns an handle to the library.

Called by Ceval.compileExternalFunction. System.lookupFunction

Searches for a function inside a library given the library handle and a function name. Returns a handle to the function if found. Every generated function has results in two functions. One real C or C++ function that does the actual calculations and only takes normal arguments and one external wrapper function that System.executeFunction uses when OMC want to call a func-tion directly. This funcfunc-tion is used by OMC to find this wrapper function.

Called by Ceval.compilePackageFunction and Ceval.compileExternalFunction.

(62)

8.3 System 47

System.freeFunction

Decrement the given function handle reference counter. A li-brary is not freed before all its function handles have reached zero.

Called by Ceval.cevalCallFunction and Interactive.removeCf. System.loadLibrary

Loads a library given its file path. Returns a handle to the library.

Not called anymore but does a small part of what System.loadPkg and System.loadExtFunc does.

System.freeLibrary

Decrements a given library handle reference counter.

Not called anymore but is a complement to System.loadLibrary. System.removePackageFromHash

Removes a package from the pkghash given its package path. Will also free the associated library handles.

Called by Ceval.compilePackageLib and Interactive.removeAnySubFunctions. System.removeExtFuncFromHash

Removes a non-package external function from the exthash given its function path. Will also free the associated function and library handles.

Called by Ceval.compileExternalFunction,

Ceval.cevalCallFunction and Interactive.removeCf. System.getPackageSourceFile

Returns the source file used to define the package when it was last compiled given a library handle.

Used to make sure the found package library originates from the same source file as the current package defintion.

(63)

48 Implementation Details

System.getExtFuncSourceFile

Returns the source file used to define the function when it was last compiled given a library handle.

Used to make sure the found non-package external function li-brary originates from the same source file as the current function definition.

Called by Ceval.compileExternalFunction. System.getSimulationSourceFile

Returns the source file used to define the model when the simu-lation was last compiled given the full file path to the simusimu-lation executable.

Used to make sure the found simulation executable actually comes from the same source file as the current model definition does.

Called by Ceval.buildModel. System.nameToPath

Converts a given string into an Absyn.Path.

Called by Ceval.compilePackageLib to parse function paths written to the patches file.

System.getLastPkgFile

Returns the last patch library given a file path to a package library.

Called by Ceval.compilePackageLib to figure out which is the last and thus newest patch library for a given package.

System.deletePatches

Given a file path to a package library it removes all patch li-braries found.

Called by Ceval.compilePackageLib to make sure no old patches get reloaded when doing a full compile of a package.

System.getExeExt

Returns the extension for executables on the current platform. “.exe” on Windows and empty string on Unix.

(64)

8.3 System 49

Called by Ceval.buildModel to figure out what the compiled simulation executable is going to be called.

System.getDllExt

Returns the extension for dynamic libraries on the current plat-form. “.dll” on Windows and “.so” on Unix.

Called by a lot of function that need to know that package and non-package external function libraries are going to be called. System.setCompilerC

Set the command used to compile C code into executables. System.getCompilerC

Get the command to use for compiling C code into execuables. Called by Ceval.generateMakefileHeader.

System.setCompilerCXX

Set the command used to compile C++ code into executables. System.getCompilerCXX

Get the command to use for compiling C++ code into exe-cuables.

Called by Ceval.generateMakefileHeader. System.setCFlags

Set the flags to use with the command when compiling C code into executables.

System.getCFlags

Get the flags to use with the command when compiling C code into executables.

Called by Ceval.generateMakefileHeader. System.setLinkC

Set the command used to compile C code into dynamic libraries. System.getLinkC

Get the command to use for compiling C code into dynamic libraries.

(65)

50 Implementation Details

System.setLinkCXX

Set the command used to compile C++ code into dynamic li-braries.

System.getLinkCXX

Get the command to use for compiling C++ code into dynamic libraries.

Called by Ceval.generateMakefileHeader. System.setLinkCFlags

Set the flags used with the command when compiling C code into dynamic libraries.

System.getLinkCFlags

Get the flags to use with the command when compiling C code into dynamic libraries.

Called by Ceval.generateMakefileHeader. System.setLinkSimFlags

Set the flags used with the command when compiling dynamic libraries to be used by an simulation executable.

System.getLinkSimFlags

Get the flags to use with the command when compiling dynamic libraries to be used by an simulation executable.

Called by Ceval.generateMakefileHeader. System.setLinkSimRunFlags

Set the flags used with the command when compiling an simu-lation executable.

System.getLinkSimRunFlags

Get the flags to use with the command when compiling C code into dynamic libraries.

(66)

8.3 System 51

8.3.2

Internal functions

These are the new important functions we have added to the C code implementation of System module but that is not used or visible by Meta-Modelica parts of OMC.

master_lookup

For in-depth information about why and what master_lookup does see chapter 5.1.2 on page 23.

The two associative arrays pkghash and ext_vtable that

master_lookup makes heavy use of are implemented by strhash_t added to c_runtime for which you can find the interface for in appendix A.4 on page 78.

load_library

Loads a library given a file path and returns a library handle. Uses the platform independent functions for dynamic library handling collected under dynlib which interface can be found in appendix A.3 on page 77.

lookup_function

Lookup a function in a library given a library handle and a function name. Returns a function handle.

(67)
(68)

Part III

Result

(69)
(70)

Chapter 9

Benefits

In this chapter we will discuss the benefits of incremental compilation and dynamic loading of functions.

9.1

Dynamic Loading of Functions

A requirement to benefit from dynamic loading of functions is that the project uses external functions. The largest single benefit of utilizing dynamic loading of functions is the decreased runtime. The decreased runtime has its origin in decreased call time of external functions. A comparison between the methods used in OpenModelica can be found in Appendix B.2.1 on page 83.

Another factor is that OpenModelica used to compile external functions each and every time they were called. With dynamic loading this is only compiled if needed, thus the time saved increases with the number of times an external function is called.

The precision of real values has been improved because of the new variable-passing. When writing real values to file using a human read-able format you loose precision so the improvement in precision is a result of passing variables through memory instead of files.

9.2

Incremental Compilation

Incremental compilation on a function level may decreases turn-around time when compiling during development of a Modelica project. First

(71)

56 Benefits

time compilation of a package might take a longer time as all its external functions dependencies also need to be compiled. In earlier versions of OpenModelica only dependencies for called functions need to be compiled. In substantial projects, packet functions should be most common and developers work on a small subset of the whole project. Thus there is no need to recompile the whole project all the time and incremental compilation is a time saver.

Those who will benefit the most from incremental compilation are those who use an agile development method since the core in agile methods are small modifications and frequent testing.

(72)

Chapter 10

Conclusion and Future Work

In this chapter we draw conclusions based on the benchmarks of our implementation and give examples of future work.

10.1

Conclusion

This project has resulted in an OpenModelica version capable of dy-namic loading of functions and incremental compilation on function level. Both of these features does reduce compile- and runtime. To be able to analyze the performance of complex features one needs good test cases and representative data. We have tried to find some larger real world Modelica projects but we were unable to locate any so we had to manufacture our own. See Appendix B.3 on page 85, B.4 on page 91 and B.5 on page 96.

10.1.1

Dynamic Loading of Functions

Dynamic loading of functions works very well and decreases runtime for external and package function calls from OMC. OMC used to use the System call to execute the executable generated when evaluating an external function, we now use dynamic loading which is ∼28 times faster on Linux and ∼160 times faster on Windows. Benchmark data can be found in appendix B.2.1 on page 83. Simulations already com-piled all called functions as one single unit, already passing arguments through memory and did not need to call any external executables. As such dynamic loading of functions does not improve the

References

Related documents

Industrial Emissions Directive, supplemented by horizontal legislation (e.g., Framework Directives on Waste and Water, Emissions Trading System, etc) and guidance on operating

Indeed, in athletes the atria are characterized by a preserved reservoir function, normal myocardial stiffness, and dynamic changes in response to different

spårbarhet av resurser i leverantörskedjan, ekonomiskt stöd för att minska miljörelaterade risker, riktlinjer för hur företag kan agera för att minska miljöriskerna,

46 Konkreta exempel skulle kunna vara främjandeinsatser för affärsänglar/affärsängelnätverk, skapa arenor där aktörer från utbuds- och efterfrågesidan kan mötas eller

The increasing availability of data and attention to services has increased the understanding of the contribution of services to innovation and productivity in

Parallellmarknader innebär dock inte en drivkraft för en grön omställning Ökad andel direktförsäljning räddar många lokala producenter och kan tyckas utgöra en drivkraft

Närmare 90 procent av de statliga medlen (intäkter och utgifter) för näringslivets klimatomställning går till generella styrmedel, det vill säga styrmedel som påverkar

I dag uppgår denna del av befolkningen till knappt 4 200 personer och år 2030 beräknas det finnas drygt 4 800 personer i Gällivare kommun som är 65 år eller äldre i