UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Visitor druehm92
Visitor
428 Views
Registered: ‎08-12-2019

MicroBlaze Compiler

In a current project, we are using the following compiler for the MicroBlaze: https://www.xilinx.com/support/answers/71201.html (2018.2). A slight software modification led to an obvious higher memory usage, from 68KB to 152KB. The adaption of code is shown below:

Old code:

virtual bool ReadMessage(Message_t* pMsg){return false;}

virtual bool WriteMessage(Message_t* pMsg, Message_t* pAnswer){return false;};

New code:    

virtual bool ReadMessage(Message_t* pMsg) = 0;

virtual bool WriteMessage(Message_t* pMsg, Message_t* pAnswer) = 0;

 

So, we changed the two virtual functions to pure virtual functions. Why does this simple code adaption lead to this immense increase in memory usage?

Thank you in advance.

 

4 Replies
Xilinx Employee
Xilinx Employee
318 Views
Registered: ‎11-30-2007

Re: MicroBlaze Compiler

I am not a SW expert - but from what I know - pure virtual functions in an embedded project do not make any sense.

They are not callable - so why should they exist?

pure virtual functions are usually part of C++ classes - and made in the base class to be overloaded in sub-classes.

The base class itself is not instantiable at all - therefore this pure virtual function can never be called at runtime.

 

usually you should be aware than adding C++ features into the codebase - this can increase size and runtime of the executable.

An increase by a few KB doesn't seem very much to me. Usually the compiler have to add additional code to call e.g. constructors and destructors when C++ features like this is being used. And all dynamic linking has to be created too for runtime objects.

 

So it might be possible that there is an increase of size. For size restricted Microblaze systems I would highly recommend to use pure Ansi-C (not C++) code only with static initialization of all memories (no malloc calls at all).

 

Kind regards - Karsten

0 Kudos
310 Views
Registered: ‎07-23-2019

Re: MicroBlaze Compiler

If you are messing around with virtual functions on a poor Microblaze, I bet I could reduce your code size to below 16 KB by just binning all the C++ crap you probably have... If you care about size (and other factors), think simple. That, unfortunately, means to work more and 'borrow' less code. It's how it is, did you want it good, cheap and quick?

 

0 Kudos
226 Views
Registered: ‎10-02-2019

Re: MicroBlaze Compiler

Probably I had not given enough content. The functions are part of a class. Also there exist a derived class which overrides the functions. The derived class is instantiated, and the functions are called. This implementation is working with a memory usage of 68KB. The only change we did in the code was to make the already virtual functions in the base class pure virtual to ensure that they must be implemented in the derived class. Therefore, we also can omit the default implementation (return false) in the base class.

Hence the functions were already virtual before and VTAB must have been created also in the previous version. From our point it is not clear why the change of two functions from the base class from virtual with default implementation to pure virtual functions lead to a memory increase from 68KB to 152KB. Also, I expect that all the mentioned points (constructors, destructors, dynamic linking) were also needed in the previous version.

That we use C++ features on the Microblaze is because these classes belong to our communication which we share with other cores. Hence, we use only some basic C++ features (Inheritance, [pure] virtual functions) we would have expected that this is supported without large memory consumption. But if these features are not usable without memory consumption, we may have to reconsider our concept. Nevertheless, I am interested why the change from virtual functions with default implementation to pure virtual functions leads to a memory increase by 123%.

0 Kudos
Xilinx Employee
Xilinx Employee
142 Views
Registered: ‎11-30-2007

Re: MicroBlaze Compiler

Hi,

 

today I tried a very simple example - with Microblaze on an ARTY board - connected to an UART to test the C++ behaviour.

I created a base class and derived two subclasses.

the base class has an virtual function that is overloaded by the sub classes.

 

I created two versions of the base class to test the behaviour with virtual versus pure virtual classes - and checking the sizes of the executables.

One version of the base class is just virtual - but empty, the other version has a pure virtual function (this class cannot be instantiated in the code).

I tested correct behaviour (but used printf instead of cout) to print something of the overloaded functions in my sub classes.

 

Everything behaves correctly - and the code size is identical.

This test was created with Vivado 2019.1 release.

 

Here is the test code:

 

/*
* Empty C++ Application
*/

#include <stdio.h>

// enable one of the two defines:
#define BASE_VERSION1
//#define BASE_VERSION1

// sizes of executables:

// with non pure virtual functions - see Base class version 1
// mb-size myapp.elf |tee "myapp.elf.size"
// text data bss dec hex filename
// 29328 1308 3172 33808 8410 myapp.elf

// with non pure virtual functions - see Base class version 1
// mb-size myapp.elf |tee "myapp.elf.size"
// text data bss dec hex filename
// 29328 1308 3172 33808 8410 myapp.elf


//=======================================================
// base class - either normal class or pure virtual class
//=======================================================

#ifdef BASE_VERSION1
class Base {
public:
virtual void foo(void) {
printf("Base\n");
}; // standard, callable, but virtual, can be overloaded
};
#endif

#ifdef BASE_VERSION2
// pure virtual:
class Base {
public:
virtual void foo(void) = 0;
};
#endif


//=======================================================
// derived classes
//=======================================================
class Sub1 : public Base {
public:
virtual void foo(void) {
printf("Sub1\n");
};
};

class Sub2 : public Base {
public:
virtual void foo(void) {
printf("Sub2\n");
};
};

int main()
{
// checker if pure virtual class can be implemeted or not
// works with BASE_VERSION1 but not with BASE_VERSION2:
//Base base;
//base.foo();

Sub1 sub1;
sub1.foo();

Sub2 sub2;
sub2.foo();

return 0;
}

 

Kind regards - Karsten

0 Kudos