1 / 25

A Case Study on Partial Evaluation in Embedded Software Design

A Case Study on Partial Evaluation in Embedded Software Design. Michael Jung Ralf Laue Sorin Alexander Huss Integrated Circuits and Systems Lab Darmstadt University of Technology. Introduction.

toyah
Download Presentation

A Case Study on Partial Evaluation in Embedded Software Design

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. A Case Study on Partial Evaluation in Embedded Software Design Michael Jung Ralf Laue Sorin Alexander Huss Integrated Circuits and Systems Lab Darmstadt University of Technology

  2. Introduction • Embedded systems software design: software generators help to achieve both resuability and efficiency • Generators usually implemented by hand: • time-consuming and error-prone • Implementing software generators with partial evaluation constitute way out

  3. Overview • Problem illustration • Introduction to basics • OSEK • Partial Evaluation • Implementation • Results

  4. Problem Illustration Reusability Efficient Implementation High Degree of Configurability (Parameters, Indirections, ...) Conflicting Goals Hand Optimized and Specialized Code Low Level Machine- Intimate Code High Level of Abstraction (e.g.OOP) Hard economical constraints led to the fact that embedded software is usually highly specialized for the application at hand and therefore not reusable

  5. Development Time End of Assembly Line Time Run Time t e.g. bus bandwidth e.g. amount of fuel to inject Binding Time of Parameters • Parameterization happens at different times during product life cycle: • Parameters bound to concrete values before run time are called static. Run time parameters are called dynamic • This distinction is usually not exploited in reusable software modules Configuration

  6. Generative Programming takes advantage of static parameters Domain Specific Language specifies static parameters at a high level of abstraction Generator generates optimized code from generic components Translator Specification in a DSL Generator Implementation Components [2] Generative Programming

  7. OSEK OS - Generator • OSEK is a specification for embedded OS (developed by university and automotive industry) • Domain Specific Language for OSEK is OIL (OSEK Implementation Language) • OIL specifies features like number of tasks and resources or level of error management • Generator applies OIL specification and generates specialized code containing only needed functionality

  8. OSEK Generation Flow optional OSEK Builder [1] Application Configuration File (OIL) "C" code User's source code System Generator OSEK OS Kernel Files produced by SG "C" code "C" code Compiler Object libraries Linker Device Driver Executable File

  9. Shortcomings of Generators • Generators are typically implemented by hand (e.g. OSEK) • Verifying correctness of hand-written generators is hard • Partial Evaluation promises some means of automation

  10. static input GenericProgram Generator Partial Evaluator Divisonstatic vs.dynamicparameters dynamicinput SpecializedProgram output [3] Partial Evaluation • A Partial Evaluator computes a Generator from • a generic parameterizable software module • a division of the parameters in static and dynamic ones • Given concrete values for the static parameters this Generator computes a specialized software module exhibiting the same behaviour as the original program with the same inputs

  11. void power_gen(unsigned n) { printf(„void power(int x, unsigned n) {\n“); printf(„ int r=1;\n“); printf(„ assert(n==%d);\n“, n); while (n) { if (n&1) printf(„ r=r*x;\n“); printf(„ x=x*x;\n“); n=n>>1; } printf(„ return r;\n}“); } void power(int x, unsigned n) { int r=1; assert(n==3); r=r*x; x=x*x; r=r*x; x=x*x; return r; } Partial Evaluation: Example x : dynamic n : static int power(int x, unsigned n) { int r=1; while (n) { if (n&1) r=r*x; x=x*x; n=n>>1; } return r; } n = 3

  12. Partial Evaluation: Advantages • Generators are typically implemented by hand: • division of parameters in static and dynamic ones is build into generator  cannot easily be changed later on • With Partial Evaluation generators for all 2P can automatically be synthesized • Verifying correctness of hand-written generators is hard: • Assuming the Partial Evaluator is correct: only the generic program has to be checked

  13. Implementation – Basic Ideas • OSEK-Implementation with C-Mix/II (which processes the complete C-syntax) • C-Mix/II creates an OSEK-generator out of generic OS code • Given the information specified in the OIL-file, this generator computes specialized OS code • Instead of writing an own parser for OIL, we mapped OIL to XML and used an XML-parser

  14. Implementation • Two function-types have to be specialized: • Initialization-functions: creation(malloc) and initialization of OS-data-structures • API-functions: include only the necessary code paths for the chosen functionality • For this, the functions get an additional parameter containing the XML-tree containing the OIL-information, which is static and will not be present in the specialized code

  15. Implementation User written/designed Code to be specialized i386 3rd party tools Part of OSEK-Implementation C-Mix/II Partition static/dynamic Text-file Program Generator OIL/XML Specialized Code General Code Application Code M68K Compiler/Linker Executable

  16. Example: Initialization TaskRefType *OSEK_ready_queues_head; TaskRefType *OSEK_ready_queues_back; void OSEK_init_ready_queue(xmlNodePtr config) { unsigned int *priority_mapping, maxPriority; priority_mapping = create_priority_mapping(config); maxPriority = priority_mapping[max_priority(config)]+1; OSEK_ready_queues_head = malloc(sizeof(TaskRefType)*maxPriority); OSEK_ready_queues_back = malloc(sizeof(TaskRefType)*maxPriority); for (i=0; i<maxNeededPriority; i++) { OSEK_ready_queues_head[i] = INVALID_TASK; OSEK_ready_queues_back[i] = INVALID_TASK; } // for } // OSEK_init_ready_queue

  17. TaskRefType OSEK_ready_queues_head[3] = { INVALID_TASK, INVALID_TASK, INVALID_TASK }; TaskRefType OSEK_ready_queues_back[3] = { INVALID_TASK, INVALID_TASK, INVALID_TASK }; Example: Intialization • Number of tasks > 3 • Exactly 3 different unique priorities were assigned to the tasks • Gaps between priorities possible

  18. Example: API-Function StatusType InitMessage( SymbolicName msg, ApplicationDataRef data, xmlNodePtr config) { read_COM_xml(config); if (COM_cmix_use_parameter_access) { COM_error_last_message = msg; COM_error_last_dataref = data; } // if if (COM_cmix_use_GetServiceId) COM_error_last_service_called = COMServiceId_InitMessage; ... if (COM_cmix_COMStatus_is_extended) { if ((msg < 0) || (msg >= COM_cmix_message_amount) || (COM_MessageStore[msg].type != RECEIVE_UNQUEUED)) { if (COM_cmix_user_error_hook && !COM_cmix_ErrorHook_is_active) { COM_cmix_ErrorHook_is_active = 1; COMErrorHook(E_COM_ID); COM_cmix_ErrorHook_is_active = 0; } // if return E_COM_ID; } // if } // if COM_MessageStorage[msg].content.\ receive_unqueued_internal.data=*data; return E_OK; } // InitMessage

  19. Example: API-Function StatusType InitMessage(SymbolicName msg, ApplicationDataRef data) { if ((msg < 0) || (msg >= COM_cmix_message_amount) || (COM_MessageStorage[msg].type != RECEIVE_UNQUEUED)) { return E_COM_ID; } // if COM_MessageStorage[msg].content.\ receive_unqueued_internal_data=*data; return E_OK; } // InitMessage • Selected: • No error reporting • No error hooks • Sanity checks

  20. Result: Code Sizes

  21. Results: Observed Weaknesses Although the implementation was feasible, there were some problems, because of limited functionality of the used Partial Evaluator (C-Mix/II): • Reflection: • Need to access objects (i.e., task functions) via their name • void* GetFuncPtr( const char* name) • Cross partial evaluation: • Generator is executed on host machine, generating code for embedded system hardware • Need for identical semantics on both machines

  22. Results: Observed Weaknesses • Code bloat: • Unrolling loops, different versions of one function • In our case: only elimination of unused code • Function signatures: • Partial evaluator changes function signature not desirable for reusable software modules • No splitting of structs: • C-Mix/II: if any part of a struct is dynamic, whole struct is dynamic • Spaghetti code: • C-Mix/II: control flow implemented with goto

  23. Conclusion • Conclusion: • We consider partial evaluation a promising approach to build efficient reusable software for embedded systems • A couple of problems still have to be addressed with better tools • Future Work: • Implementation of a Partial Evaluator considering the domain of resource constrained embedded systems: • Cross-Partial Evaluation • Code Bloat

  24. Thanks for your attention Questions? References [1] The OSEK Group: OSEK/VDX Operating System Version 2.2.2, July 2004 [2] K. Czarnecki, U.W. Eisenecker: Generative Programming - Methods, Tools, and Applications, Addison Wesley, 2000 [3] N. D. Jones, C. K. Gomard, and P. Sestoft: Partial Evaluation and Automatic Program Generation, Prentice Hall, 1993 [4] R. Laue: Fallstudie: Implementierung von Software Generatoren mittels partieller Evaluierung, TU Darmstadt, Diplomarbeit, November 2003 [5] M. Jung, and S.A. Huss: Fast Points-to Analysis for Languages with Structured Types, SCOPES 2004, Springer LNCS 3199, 2004

  25. Result: Initialization unsigned char heap_location_1[12]; unsigned char heap_location_2[12]; TaskRefType *OSEK_ready_queues_head; TaskRefType *OSEK_ready_queues_back; void OSEK_init_ready_queue() { OSEK_ready_queues_head = heap_location_1; OSEK_ready_queues_back = heap_location_2; OSEK_ready_queues_head[0] = INVALID_TASK; OSEK_ready_queues_back[0] = INVALID_TASK; OSEK_ready_queues_head[1] = INVALID_TASK; OSEK_ready_queues_back[1] = INVALID_TASK; OSEK_ready_queues_head[2] = INVALID_TASK; OSEK_ready_queues_back[2] = INVALID_TASK; } // OSEK_init_ready_queue

More Related