9

Click here to load reader

Blending Realized Code

Embed Size (px)

DESCRIPTION

This document provides an overview of the range of options available in PathMATE to integrate non-modeled C and C++ code, types and components with your PI-MDD modeled systems, and also to provide usage key details on these features.

Citation preview

Page 1: Blending Realized Code

©1995 - 2011 by Pathfinder Solutions

Blending Realized Code with PI-MDD Models

version 1.0

October 17, 2011

PathMATE Technical Notes

Pathfinder Solutions

Wrentham, MA USA

www.Pathfindermdd.com

888-662-7284

Page 2: Blending Realized Code

ii

Table Of Contents

1. Introduction.......................................................................................... 1

2. Basics.................................................................................................... 1

PI-MDD Models are Separate from Code – On Purpose.................................. 1

PI-MDD Models are Generally Preferred To Handwritten Code ........................ 2

But Not Always…..................................................................................... 2

3. Realized Code Outside Modeled Domains .............................................. 2

Realized Scalar Types .............................................................................. 2

Advanced Realized Types ......................................................................... 3

4. Realized Domains.................................................................................. 4

Handwritten <domain>_services_REALIZED.cpp ......................................... 5

Derived Services - InlineCode ................................................................... 5

5. Hybrid Domains..................................................................................... 5

Limitations of Standard Realized Domains................................................... 6

Hybrid or Green Domains ......................................................................... 6

The Dangers of #INLINING....................................................................... 6

When to go Hybrid .................................................................................. 7

Page 3: Blending Realized Code

Blending Realized Code with PI-MDD Models

1

1. Introduction

This document provides an overview of the range of options available in PathMATE to integrate non-modeled C and C++ code, types and components with your PI-MDD modeled systems, and also to provide usage key details on these features.

Integrating modeled systems with external non-modeled elements is a universal and natural element in building PathMATE systems in real-world settings. Legacy code, components from third party developers and other external sources, and code generated from non-PathMATE technologies are all part of the real-world landscape for any complex system, and a universal reality of the vast majority of projects that we build PI-MDD systems in.

It is assumed the reader is familiar with PI-MDD modeling including generating code and the use of model element markings, and with implementation-level programming.

2. Basics

PI-MDD Models are Separate from Code – On Purpose

Platform-Independent Model Driven Development (PI-MDD) is a methodology where executable UML models are constructed with an explicit focus on the problem space subject matter, as opposed to the implementation details of how code runs on a specific target platform. To facilitate this focus a UML-level Action Language is used for detailed behavioral specification for model actions. PI-MDD models - including Actions – generate code that runs on a UML virtual machine layer. High-performance and embedded system use sophisticated self optimization code generation and tightly configured virtual machines targeted to specific deployment platforms. This separation of the problem-space models from the details of how to run reliably and efficiently on a specific platform yields some critical strategic-level benefits:

Much shorter time to market and higher productivity

The focus on the problem space results in a system with much higher concept-to-code fidelity, producing a simply better product

The models in particular and the system overall are far simpler, making them easier to create, debug, deploy and maintain

The discipline of separation results in far stronger modularity, and greater reuse

Page 4: Blending Realized Code

Blending Realized Code with PI-MDD Models

2

The ability to move quickly to new deployment platforms, including dramatic variations in multi-task and multi-processor topologies.

PI-MDD Models are Generally Preferred To Handwritten Code

In short, PI-MDD models are good because they give us Faster, Cheaper and Better systems. So we should model all of our systems in order to get more of this goodness – right? Well … not always.

But Not Always…

PI-MDD Models are not always the best way to address all software needs on a complex system. Sometimes there are large bodies of legacy code that are sufficiently functional and provide a large base to start from. Sometimes code is generated from specialty environments. Sometimes other parts of our team produce code by hand and don’t use models. Sometimes a specific part of our system is awkward to implement in PI-MDD UML and better addressed by the implementation code level of abstraction. Often, there simply isn’t enough time to model all the parts of the system that we’d like to.

What that all adds up to is the need to be able to integrate realized (non-modeled) code with the modeled parts of our system. The purpose of the techniques and mechanisms outlines in the document are to provide the flexibility needed to integrate implementation-code elements with modeled system.

3. Realized Code Outside Modeled Domains

Realized Scalar Types

Likely the first contact modelers have with realized code elements comes in the form of a user-defined data type visible in the model, but with an actual implementation specified at the code level. First let’s consider a simple alias type for a scalar value.

Assume the existence of a SensorInterface domain that publishes a user-defined type si_temperature_t “A temperature value in degrees centigrade, ranging from -100C to 350C”. At the model level we specify the base type for this is Integer. Specifically this means that then things in the model work with and manipulate data atoms if this type it will be treated like an Integer. By default a typedef statement will be generated for this:

typedef int si_temperature_t;

Page 5: Blending Realized Code

Blending Realized Code with PI-MDD Models

3

Let’s assume we don’t want si_temperature_t to be an int, instead let’s use a legacy type definition standard in Our Company: ourco_uint16. To accomplish this we apply the ExternalType marking:

UserNonEnumerate,MySys.SensorInterface.si_temperature_t,ExternalType,ourco_uint16

Now PathMATE generates this for us:

typedef ourco_uint16 si_temperature_t;

But where is OURCO_UINT_16 defined? Let’s say it’s defined in ourco_base_types.h. If there are lots of other things we want to use in there, we can manually add an include for this file to our system-wide includes file, c/system/sys_incl.h, or cpp/system/sys_incl.hpp.

Alternatively if we have an include file that we only want to include where this specific type is used – say uint16.h – then we can use the IncludeFile marking to specify this:

UserNonEnumerate,MySys.SensorInterface.si_temperature_t,IncludeFile,uint16.h

This causes PathMATE to generate an include of this file at the top of each generated module that contains a data atom of the si_temperature_t type. In any of SensorInterface’s client domains we can declare data atoms like attributes, parameters or variables to be of type si_temperature_t and they will be of the appropriate type – ourco_unit16 – at the implementation code level with the correct include where it is needed.

Advanced Realized Types

Assume another realized type, but this one is structure defined in sens_ramp.h:

/* Legacy type used by sensor library to scale raw sensor input values. */

struct Sensor_ValueRamp { ourco_uint8 sensorId; /* Sensor channel this ramp is

calibrated for */ ourco_real32 rampSlope; /* Slope of adjustment line */

ourco_real32 rampBottom; /* Lowest valid value */ ourco_real32 rampTop; /* Highest valid value */ };

The SensorInterface domain publishes a user-defined type si_sensor_value_ramp_t at the model level with a base type of Handle. This means PathMATE treats this essentially like a void*. This type we also mark with ExternalType and IncludeFile:

Page 6: Blending Realized Code

Blending Realized Code with PI-MDD Models

4

UserNonEnumerate,MySys.SensorInterface.si_sensor_value_ramp_t,ExternalType,Sensor_ValueRamp*

UserNonEnumerate,MySys.SensorInterface.si_sensor_value_ramp_t IncludeFile,sens_ramp.h

Typically Realized Complex Types are used to provide modeled client domains with a handle to a resource that they will use via services of the providing realized domain. For example SensorInterface publishes the following services:

si_sensor_value_ramp_t GetChannelDataConditioner(<some selector inputs>);

An old school traditional C programmer may wonder how a modeled client domain gets at the Sensor_ValueRamp members? Their first inclination may be to have the “client” function grab a Sensor_ValueRamp and then intimately condition its own values by directly using the rampSlope, rampTop and rampBottom. Other client functions using sensor input may similarly perform raw value conditioning. Clever programmers may clone these bits. But all this cloning is bad – very bad for many reasons. And through this intimacy the client functions become tightly coupled to the SensorInterface domain. Also bad.

With PI-MDD the discipline of domain separations saves us from these potentially mortal dangers. By allowing the SensorInterface domain retain exclusive responsibility for the details of sensor raw value conditioning including the knowledge of the makeup of the si_sensor_value_ramp_t, we can keep the Sensor_ValueRamp from being exposed to the client domains. They do not need to know the details of the ramp structure, or how to apply it to get a conditioned value. This valuable and useful nugget is captured in this SensorInterface service:

si_temperature_t GetConditionedValue (si_raw_value_t raw_value, si_sensor_value_ramp_t ramp_handle);

The modeled client simply passes the ramp_handle into GetConditionedValue. The realized SensorInterface domain accesses the members of Sensor_ValueRamp. In this manner the clients of SensorInterface are not tightly coupled via the shared knowledge of the details of Sensor_ValueRamp. Cloning is avoided, and integration fire drills consuming Saturdays are minimized.

4. Realized Domains

As implied in the previous sections, SensorInterface is a realized domain. That means that the types () and services () it publishes are visible to the model, the remainder of the domain exists only in the realm of implementation code. The implementation of the domain services are handwritten code, which may call into legacy libraries, external or COTS functions – anywhere, really.

Page 7: Blending Realized Code

Blending Realized Code with PI-MDD Models

5

Handwritten <domain>_services_REALIZED.cpp

The most straightforward genesis and organization of a realized domain follows these steps:

Define all types used in domain service parameters or return values in the model

Define all domain services and parameters in the model

Generate code

Copy the generated <domain>_services.cpp (or .c) file to a realized code folder for the domain, and rename it to <domain>_services_REALIZED.cpp (or .c)

Hand-edit the copied <domain>_services_REALIZED.cpp (or .c) file to add domain services implementations. For services with complex implementation it is recommended that a thin wrapper approach be applied, where the service implementation calls external modules to complete the service behavior.

Derived Services - InlineCode

Where the handwritten <domain>_services_REALIZED.cpp approach generates actual function/method calls that resolve to functions/methods, the Derived Service approach uses something more like a C macro. Code transformation maps support the specification of domain service implementations via directly emitting the desired code in place of the invocation. The expansion of a derived service is specified in a marking for the service – InlineCode. The value specified for the InlineCode marking is the actual code to be substituted for the service invocation.

To make service parameters conveniently available, they via numeric reference: $n$, where n is the number of the ordinal parameter (1-based). For example, presume a domain service GG:ComputeDistance(x, y) is marked:

DomainService,MySys.GG.ComputeDistance,InlineCode,sqrt($1$**2 + $2$**2)

The PAL dist = GG:ComputeDistance(x_coord, y_coord); would generate:

dist = sqrt(x_coord**2 + y_coord**2);

5. Hybrid Domains

Page 8: Blending Realized Code

Blending Realized Code with PI-MDD Models

6

Limitations of Standard Realized Domains

Considered generally, a realized domain with handwritten services is actually a hybrid domain, where types, services and parameters are modeled and the rest is handwritten. This pattern is valuable, especially for organizations new to PI-MDD because it provides clear boundaries for the modeler/coder.

However realizing a domain means the power and convenience of modeling cannot be applied. The flexibility and longevity of Platform Independence are more elusive to achieve. The addition of a realized domain to resolve limitations in PAL or PI-MDD may also distort the architectural perspective, adding a domain where there was no separate subject matter.

Hybrid or Green Domains

A Hybrid Domain is a modeled domain with one or more #INLINE sections in its actions. The #INLINE preprocessing directive for PAL (and it’s partner #END_INLINE) is used to escape to the implementation code level. Consider the PAL segment:

Handle my_reg; #INLINE

my_reg = &BASE_LOAD_REGISTER; #END_INLINE

HardwareMonitoring:Load(my_reg);

This would generate (in C++):

void* my_reg; my_reg = &BASE_LOAD_REGISTER; HardwareMonitoring::Load(my_reg);

The Dangers of #INLINING

Escaping to implementation code seems like a convenient way to cast off all the limitations of UML and PAL. This can be compelling, especially for beginners to PI-MDD that may not know PAL very well but may be very familiar with C. However the constraints imposed by PI-MDD help avoid common coding pitfalls and provide a foundation for automation to help with challenging hurdles. Using #INLINE discards these key benefits provided by PI-MDD disciplines and automation:

Assures platform-independent system, with flexible deployment to test topologies and multiple target architectures

Provides flexibility in applying implementation optimizations – even after the model is complete and tested

Page 9: Blending Realized Code

Blending Realized Code with PI-MDD Models

7

Automated verification of the integrity between model elements and where they are used in actions

Guaranteed conformance to domain boundaries

Prevents unwanted code patterns

Project experience has shown that indiscriminant use of the #INLINE feature substantially impacts system quality, flexibility, maintainability and run-time performance.

When to go Hybrid

As a general rule all newly constructed domains should be modeled. When a modeled domain contains actions where a portion of the action requires implementation code then the limited use of #INLINE should be considered.

When creating a hybrid action, the core requirements for creating any modeled actions still apply:

Clear, concise, and appropriate for the action context

Platform independent

Understandable, maintainable

Rules for Going Green:

Ultimately the action needs to deliver high quality, including within the inline portion. The following guidelines can help Hybrid domains retain the value of the PI-MDD approach:

Limit the extent of the inline section. Do as much in PAL as possible.

Use bitwise PAL operators (same as C) to avoid inline – but ensure these are platform independent

In all code be endian independent

Strive for platform independent code in the inlined implementation code section.

If your action requires platform-specific, endian-specific, or other non-portable constructs, do not use #INLINE. Instead use a Standard Realized Domain to fully isolate this code in a separate module.