Optimization

Optimization

Optimization

Although the word “optimization” shares the same root as “optimal,” it is rare for the process of optimization to produce a truly optimal system. The optimized system will typically only be optimal in one application or for one audience. One might reduce the amount of time that a program takes to perform some task at the price of making it consume more memory. In an application where memory space is at a premium, one might deliberately choose a slower algorithm in order to use less memory. Often there is no “one size fits all” design which works well in all cases, so engineers make trade-offs to optimize the attributes of greatest interest. Additionally, the effort required to make a piece of software completely optimal—incapable of any further improvement— is almost always more than is reasonable for the benefits that would be accrued; so the process of optimization may be halted before a completely optimal solution has been reached. Fortunately, it is often the case that the greatest improvements come early in the process.

 

Links:

http://en.wikipedia.org/wiki/Program_optimization

http://www.tantalon.com/pete/cppopt/main.htm

http://en.wikipedia.org/wiki/Compiler_optimization

Stack

Stack

Stack - PUSH/POP

LIFO stack

Stacks are a type of container adaptors, specifically designed to operate in a LIFO context (last-in first-out), where elements are inserted and extracted only from the end of the container.

stacks are implemented as containers adaptors, which are classes that use an encapsulated object of a specific container class as its underlying container, providing a specific set of member functions to access its elements. Elements are pushed/popped from the “back” of the specific container, which is known as the top of the stack.

The underlying container may be any of the standard container class templates or some other specifically designed container class. The only requirement is that it supports the following operations:

  • back()
  • push_back()
  • pop_back()

Link:

http://www.cplusplus.com/reference/stl/stack/

http://en.wikipedia.org/wiki/Stack_(data_structure)

Asserts

 

Assert Safely

Assert Safely

 

Expert programmers use the assert() macro to seed their code with debugging statements. So should we all.

The macro must have no effect on the system – it shouldn’t change memory, interrupt state, or I/O, and it should make no function calls. The user must feel free to sprinkle these at will throughout the program. Disabling the asserts in released code must never change the way the program operates.

The macro generally looks something like:

#define
assert(s)
if (s)
{}else (printf("Error at %s %d: ", __FILE__, __LINE__)

It’s sort of an odd way to write code – if the condition is true (in which case assert() takes no action) there’s a null pair of braces. Why not test the negation of the statement “s”?

Links: http://www.ganssle.com/articles/adifasts.htm

Build a Super Simple Tasker

Almost all embedded systems are event-driven; most of the time they wait for some event such as a time tick, a button press, a mouse click, or the arrival of a data packet. After recognizing the event, the systems react by performing the appropriate computation. This reaction might include manipulating the hardware or generating secondary, “soft” events that trigger other internal software components. Once the event-handling action is complete, such reactive systems enter a dormant state in anticipation of the next event.1

Ironically, most real-time kernels or RTOSes for embedded systems force programmers to model these simple, discrete event reactions using tasks structured as continuous endless loops. To us this seems a serious mismatch–a disparity that’s responsible for much of the familiar complexity of the traditional real-time kernels.

In this article we’ll show how matching the discrete event nature typical of most embedded systems with a simple run-to-completion (RTC) kernel or “tasker” can produce a cleaner, smaller, faster, and more natural execution environment. In fact, we’ll show you how (if you model a task as a discrete, run-to-completion action) you can create a prioritized, fully preemptive, deterministic real-time kernel, which we call Super Simple Tasker (SST), with only a few dozen lines of portable C code.2

Such a real-time kernel is not new; similar kernels are widely used in the industry. Even so, simple RTC schedulers are seldom described in the trade press. We hope that this article provides a convenient reference for those interested in such a lightweight scheduler. But more importantly, we hope to explain why a simple RTC kernel like SST is a perfect match for execution systems built around state machines including those based on advanced UML statecharts. Because state machines universally assume RTC execution semantics, it seems only natural that they should be coupled with a scheduler that expects and exploits the RTC execution model.

We begin with a description of how SST works and explain why it needs only a single stack for all tasks and interrupts. We then contrast this approach with the traditional real-time kernels, which gives us an opportunity to re-examine some basic real-time concepts. Next, we describe a minimal SST implementation in portable ANSI C and back it up with an executable example that you can run on any x86-based PC. We conclude with references to an industrial-strength single-stack kernel combined with an open-source state machine-based framework, which together provide a deterministic execution environment for UML state machines. We’ll assume that you’re familiar with basic real-time concepts, such as interrupt processing, context switches, mutual exclusion and blocking, event queues, and finite state machines.

Links: http://embedded.com/columns/technicalinsights/190302110

Doing design and debug on real-time distributed embedded applications

Real-time system designers and embedded software developers are very familiar with the tools and techniques for designing, developing and debugging standalone or loosely coupled embedded systems. UML may be used at the design stage, an IDE during development and debuggers and logic analyzers (amongst other tools) at the integration and debug phases.

However, as connectivity between embedded systems becomes the norm, what used to be a few nodes connected together with clear functional separation between the applications on each node, is now often tens or hundreds of nodes with logical applications spread across them.

In fact, such distributed systems are becoming increasingly heterogeneous in terms of both operating systems and executing processors with tight connectivity between real-time and enterprise systems becoming the norm.

This article will identify the issues of real-time distributed system development and discuss how development platforms and tools have to evolve to address this challenging new environment.

The idea of a ‘platform’ for development has long pervaded the real-time embedded design space as a means to define the application development environment separately from the underlying (and often very complex) real-time hardware, protocol stacks and device drivers.

Much as the OS evolved to provide the fundamental building blocks of standalone system-development platforms, real-time middleware has evolved to address the distributed-systems development challenges of real-time network performance, scalability and heterogeneous processor and operating system support.

And as has already happened in the evolution of the standard real-time operating system, new tools are becoming available to support development, debug and maintenance of the target environment ” in this case, real-time applications in large distributed systems.

The Distributed-System Development Platform
From the individual application developer’s perspective, there are three basic capabilities which must be provided by an application development platform when a logical application spans multiple networked computers:

1. Communication between threads of execution
2. Synchronization of events
3. Controlled latency and efficient use of the network resources

Communication and synchronization are fairly obvious distributed platform service requirements and are analogous to the services provided by an OS. However for distributed applications they have to run transparently across a network infrastructure of heterogeneous OS’s and processors with all that implies in terms of byte ordering and data representation formats.

It should ideally use a mechanism that does not require the developer to have an explicit understanding of the location of the intended receiver of a message or synchronizing thread so that the network can be treated as a single target system from an application development perspective.
Links: http://embedded.com/design/networking/205920767

Follow

Get every new post delivered to your Inbox.