Turbo Disaster, or When failure was Not an option... - A Success Story of some software integration

Hello everybody,

My name is Sergey Kostrov. I'm an Intel Black Belt Software Developer and am Not an-Intel employee. I'd like to share my experience ( a <strong>Success Story</strong> ) on how some very complex software integration was done a couple of years ago on the <strong>ScaLib</strong> project.

So, It is possible that you've heard a very famous expression <strong>Failure is not an option</strong>. Even if the expression was never told by real Mission Control personnel during <strong>Apollo 13</strong> mission it is related to those dramatic events. Project managers, flight engineers and controllers never gave up when trying to find solutions of different problems with the spacecraft.

In modern <strong>Information Technology</strong> industry software systems are very complex and even a little problem could create lots of troubles for a software developer or a team of developers. There is another famous expression and you've also heard it:

<strong>Google It!</strong>

What does it actually mean? It means, that a software developer thinks that a problem he/she actually deals with is not a unique one and there is already a solution. That is possible! However, for me it means that the developer is not doing the job in a right way and doesn't try to work hard to find a solution by himself/herself. I'm not going to convince anybody that in order to become a real <strong>S</strong>oftware <strong>D</strong>eveloper ( can you see that I stressed with capital <strong>S</strong> and capital <strong>D</strong>? ) an attitude of a <strong>Strong Problem Solver</strong> needs to be grown up.

Here is some set of quotes from a <strong>Technical Report</strong> I've created in 2010 related to how I solved lots of technical problems, actually overwhelming for just one C++ developer responsible for the integration of a legacy C++ compiler with the <strong>ScaLib</strong> project and <strong>4</strong> weeks time frame, <strong>without</strong> asking for help from anybody else due to project constraints:

...
<strong>DevNote #0026</strong>:
Detected problems and issues over the course of integration <strong>Turbo C++ compiler v3.00</strong> with
the <strong>ScaLib</strong> project

This is an outlook on what happened with the ScaLib Project over the course of integration Borland's International Turbo C++ compiler v3.00 in October 2010.

At the end of 2009 a GNU compiler MinGW v3.4.2 was integrated into the Visual Studio 2005 development environment and it significantly helped to clean the C++ codes of the ScaLib library. In the 2nd part of 2010 year a state of the project was considered as a very stable with a very good portability between different Platforms.

A compilation process looked like this:

Every time when the Build was started it has to be done for at least three Platforms, one by one, using two different compilers:

- First step, Visual Studio 2005 compiler ( for Desktop )
- Second step, Visual Studio 2005 compiler ( for Embedded )
- Third step, MinGW v3.4.2 compiler ( for Desktop )

But, I was feeling that two compilers are not enough in order to prove that a quality of portable C++ codes is high. Unfortunately, both compilers, that is, Visual C++ and MinGW v3.4.2, are targeted for Windows Operating Systems.

I suggected to integrate another C++ compiler that doesn't have any Microsoft's or Windows header files. The best candidate for that portability verification task was a compiler from Borland International for an MS-DOS Operating System and I decided to try Turbo C++ version 1.01.

An attempt with Borland International Turbo C++ v1.01 stoped almost instantly. It was unsuccessful because version 1.01 doesn't support C++ templates!

But, I was able to compile many pieces of generic C++ codes in the ScaLib library and it was clear that I'm working in a right direction. So, it was just a matter of time and when Borland International Turbo C++ compiler v3.00 was found on one of my archive CD I decided to start a second attempt.

The key features of the compiler included support of C++ standard 2.1 and version 3.0 templates.

In the morning on <strong>October 11th, 2010</strong> I've finally started the integration of Turbo C++ compiler v3.00 and half an hour later the situation could be described with just two words:

<strong>TURBO DISASTER!</strong>

I've stepped back in time for almost <strong>20 years</strong> and the number of issues and problems was OVERWHELMING. I was simply forced to make records on a clean piece of paper and it was filled on both sides completely in about one hour.

Here is an <strong>initial</strong> list of problems detected during first day of integration:

- A project configuration problems for a new MS-DOS based Platform

- A problem with long file names because in MS-DOS only 8.3 file names are supported ( 12 characters in total )

- There is no support of '_stdcall' key word

- There are no 'BOOL' or 'bool' data types

- There is no '_complex' data type

- An issue with a native data type 'int' because by default it is a 16-bit based

- An issue with a native data type 'long double'

- Usage of MAX_PATH macro constant ( Non-Portability Leak )

- Usage of MB_OK macro constant which is used in famous MessageBox function of Win32 API ( Non-Portability Leak )

- Incompatibility of #pragma directives between Visual C+, MinGW and Turbo C++ compilers

- A problem with forward declarations of template functions

- A problem with declaration constructors of a template class as 'inline'

- A problem with declaration of a parameter based on 'typedef enum' type in a constructor of a template class

- A problem with a data type declared as 'typedef enum' because by default it is a 16-bit based

- A problem with default value declaration for a parameter, like ...param = T()..., in a method of a template class

- A problem with global C++ operators 'new' and 'delete'

- A problem with declaration of global C++ operators 'new' and 'delete' inside a '__cplusplus' block:

#ifdef __cplusplus
extern "C" {
#endif
...
...
#ifdef __cplusplus
};
#endif

- A problem with ';' at the end of a macro with '()'

- An issue with 'strncpy' CRT-function

- A problem with 'reinterpret_cast', 'dynamic_cast' and 'static_cast' C++ operators ( key-words ) which are not supported by Turbo C++ compiler v3.00

- A problem related to data types alignment because it is supported on a global scale by Turbo C++ compiler v3.00 as a command line option and as a #pragma option directive

- A problem with Turbo C++ compiler v3.00 when compiling sources in RELEASE configuration when a big array of data is created locally, that is on the stack

- Turbo C++ compiler v3.00 creates binaries for a Real-Mode Operating System, that is MS-DOS, and there is no direct support for a Protected-Mode or Flat Memory model

- Turbo C++ compiler v3.00 ( command line version ) couldn't find Turbo Link executable if the installation was done in a different from '..\TC30' folder Note: All search paths were added! It is possible that this is an almost 20-year old bug

- Issues with MS-DOS Real-Mode total memory and Turbo C++ compiler v3.00 Memory models constraints

- A problem with the Turbo Link if a Tiny or Compact Memory models are selected:
...
Turbo Link Version 5.0 Copyright (c) 1992 Borland International
Error: Group DGROUP exceeds 64K
...

- Turbo Link was unable to generate COM-executable:
...
Fatal: Cannot generate COM file : segment-relocatable items present
...

- Turbo C++ compiler v3.00 fails to compile some C++ codes and exits with an error message: "FATAL ERROR: GP FAULT"

- A problem with some protected mode instructions generated by Turbo C++ compiler v3.00 in case of Large or Huge Memory models of an application

- The Windows NTVDM crashed when an illegal CPU instruction was executed in a test application

- Math related problems:
...
Floating point error: Divide by 0.
Abnormal program termination
...

- A complitely unexplained error messages "Multi-Bit ECC Error System Halted" and "Divide Error" when executing an application compiled for a Huge Memory model

- Dynamic memory management related problems with a Memory Tracing subsystem in case of selecting different Memory models for a test application

And many, many another issues and problems appearing over the course of firsttwo weeks of integration.

I would split these problems into 3 groups:

- Project configuration due to 8.3 file names in MS-DOS
- Not Portable "Leaks" in the C++ source codes of the ScaLib library
- Turbo C++ compiler v3.00 related

At the end of the second day, when almost 99 percent of all source codes were commented out (!), I had a plan on how to move ahead and about 4 weeks later Turbo C++ compiler v3.00 integration was completed.

And what's the point? It is simple: If I would try to follow the <strong>Google It!</strong> approach the integration of the C++ compiler would be never completed and the project would be possibly canceled. As of today 5 different C++ compilers ( 14 versions ) are integrated with the ScaLib project and in terms of portability this is a really unique one.

I also would like to address my message to modern software developers:

Guys, you need to fight problems and you should not expect that somebody will give you a solution!

Good Luck to everybody!

Best regards,
Sergey Kostrov

Senior C/C++ Software Developer
Intel Black Belt Software Developer ( since September 2012 )
Calgary, Alberta, Canada

For more complete information about compiler optimizations, see our Optimization Notice.

Comments

...Application - TccTestApp -

...
Application - TccTestApp - COS16_TCC ( 16-bit ) - Release
Tests: Start
> Test0001 Start <
***********************************
Configuration - COS16_TCC - Release
CTestSet::InitTestEnv - Passed

* CMatrixSet Start *
> _TMatrixSet Methods <
SysSleep - Completed: 989 ticks
...

Note: One second is 989 ticks
 


// CUnR4in1v1 ( every pass

// CUnR4in1v1 ( every pass executed 4096 times )
 ...
 Matrix Size: 72 x 72
 Processing... ( Add - 1D-based )
 _TMatrixSetF::Add - Pass 01 - Completed:     0.29492 ticks
 _TMatrixSetF::Add - Pass 02 - Completed:     0.28174 ticks
 _TMatrixSetF::Add - Pass 03 - Completed:     0.28174 ticks
 _TMatrixSetF::Add - Pass 04 - Completed:     0.29517 ticks
 _TMatrixSetF::Add - Pass 05 - Completed:     0.28174 ticks
 Add - 1D-based - Passed
 Processing... ( Sub - 1D-based )
 _TMatrixSetF::Sub - Pass 01 - Completed:     0.29492 ticks
 _TMatrixSetF::Sub - Pass 02 - Completed:     0.28174 ticks
 _TMatrixSetF::Sub - Pass 03 - Completed:     0.29517 ticks
 _TMatrixSetF::Sub - Pass 04 - Completed:     0.28174 ticks
 _TMatrixSetF::Sub - Pass 05 - Completed:     0.28174 ticks
 Sub - 1D-based - Passed
 ...

// CUnR8in1v1 ( every pass executed 4096 times )
 ...
 Matrix Size: 72 x 72
 Processing... ( Add - 1D-based )
 _TMatrixSetF::Add - Pass 01 - Completed:     0.29492 ticks
 _TMatrixSetF::Add - Pass 02 - Completed:     0.30859 ticks
 _TMatrixSetF::Add - Pass 03 - Completed:     0.29517 ticks
 _TMatrixSetF::Add - Pass 04 - Completed:     0.30859 ticks
 _TMatrixSetF::Add - Pass 05 - Completed:     0.30835 ticks
 Add - 1D-based - Passed
 Processing... ( Sub - 1D-based )
 _TMatrixSetF::Sub - Pass 01 - Completed:     0.29517 ticks
 _TMatrixSetF::Sub - Pass 02 - Completed:     0.30859 ticks
 _TMatrixSetF::Sub - Pass 03 - Completed:     0.29517 ticks
 _TMatrixSetF::Sub - Pass 04 - Completed:     0.30835 ticks
 _TMatrixSetF::Sub - Pass 05 - Completed:     0.30859 ticks
 Sub - 1D-based - Passed
 ...
 


// CRv2 ( every pass executed

// CRv2 ( every pass executed 4096 times - Best Performance )
 ...
 Matrix Size: 72 x 72
 Processing... ( Add - 1D-based )
 _TMatrixSetF::Add - Pass 01 - Completed:     0.28149 ticks
 _TMatrixSetF::Add - Pass 02 - Completed:     0.28174 ticks
 _TMatrixSetF::Add - Pass 03 - Completed:     0.28174 ticks
 _TMatrixSetF::Add - Pass 04 - Completed:     0.28174 ticks
 _TMatrixSetF::Add - Pass 05 - Completed:     0.28174 ticks
 Add - 1D-based - Passed
 Processing... ( Sub - 1D-based )
 _TMatrixSetF::Sub - Pass 01 - Completed:     0.28174 ticks
 _TMatrixSetF::Sub - Pass 02 - Completed:     0.28149 ticks
 _TMatrixSetF::Sub - Pass 03 - Completed:     0.28174 ticks
 _TMatrixSetF::Sub - Pass 04 - Completed:     0.28174 ticks
 _TMatrixSetF::Sub - Pass 05 - Completed:     0.28174 ticks
 Sub - 1D-based - Passed
 ...
 


[ Example 10 ]

[ Example 10 ]

Testing is always a challenge in a 16-bit software environment because large chunks of memory can not be allocated. Here are a couple of examples:

 

// CRv1A ( every pass executed 4096 times - Worst Performance )
 ...
 Matrix Size: 72 x 72
 Processing... ( Add - 1D-based )
 _TMatrixSetF::Add - Pass 01 - Completed:     0.32202 ticks
 _TMatrixSetF::Add - Pass 02 - Completed:     0.33545 ticks
 _TMatrixSetF::Add - Pass 03 - Completed:     0.33521 ticks
 _TMatrixSetF::Add - Pass 04 - Completed:     0.33545 ticks
 _TMatrixSetF::Add - Pass 05 - Completed:     0.32202 ticks
 Add - 1D-based - Passed
 Processing... ( Sub - 1D-based )
 _TMatrixSetF::Sub - Pass 01 - Completed:     0.33521 ticks
 _TMatrixSetF::Sub - Pass 02 - Completed:     0.33545 ticks
 _TMatrixSetF::Sub - Pass 03 - Completed:     0.33545 ticks
 _TMatrixSetF::Sub - Pass 04 - Completed:     0.33521 ticks
 _TMatrixSetF::Sub - Pass 05 - Completed:     0.32202 ticks
 Sub - 1D-based - Passed
 ...

// CRv1B ( every pass executed 4096 times )
 ...
 Matrix Size: 72 x 72
 Processing... ( Add - 1D-based )
 _TMatrixSetF::Add - Pass 01 - Completed:     0.28174 ticks
 _TMatrixSetF::Add - Pass 02 - Completed:     0.29517 ticks
 _TMatrixSetF::Add - Pass 03 - Completed:     0.29517 ticks
 _TMatrixSetF::Add - Pass 04 - Completed:     0.29517 ticks
 _TMatrixSetF::Add - Pass 05 - Completed:     0.29492 ticks
 Add - 1D-based - Passed
 Processing... ( Sub - 1D-based )
 _TMatrixSetF::Sub - Pass 01 - Completed:     0.29517 ticks
 _TMatrixSetF::Sub - Pass 02 - Completed:     0.29517 ticks
 _TMatrixSetF::Sub - Pass 03 - Completed:     0.28174 ticks
 _TMatrixSetF::Sub - Pass 04 - Completed:     0.29517 ticks
 _TMatrixSetF::Sub - Pass 05 - Completed:     0.29492 ticks
 Sub - 1D-based - Passed
 ...
 


[ Example 9 ]

[ Example 9 ]

There is No any support for 64-bit integer types on 16-bit platforms and a very simple solution based on a Single Precision Floating Point data type ( float ) is used. But, there is a limitation and, for example, a valid range of unsigned 64-bit integers values is from 0 to 16777216 ( that is, from 0 to 2^24 ).
 


[ Example 8 ]

[ Example 8 ]

Here is a Configuration Params Problem and a simple solution looks like:

...
 g_iParam1 = atoi( getenv( "PARAM_1" ) );
 g_iParam2 = atoi( getenv( "PARAM_2" ) );
 g_iParam3 = atoi( getenv( "PARAM_3" ) );
...

Of course, number of parameters defined as Environment Variables needs to be limited but this is a one-line solution compared to a multi-line implemntation of different ini-file, cfg-file, or xml-file readers, etc.

 


[ Example 7 ]

[ Example 7 ]

Here is an example of 8.3-Problem with files names on 16-bit platforms and this is how it affects sources:
...
#if ( defined ( _MS_COMPILER_A_ ) || defined ( _INTEL_COMPILER_B_ ) || defined ( _GCC_COMPILER_C_ ) )
 #include "../../Include/SomeFileWithLongName.h"
#endif
#if ( defined ( _ Turbo C++ Compiler _ ) )
 #include "../../Include/SomeFi~1.h"
#endif
...
 


[ Example 6 ]

[ Example 6 ]

A Complete Binary Compatibility of Data Types breaks when data transferred between platforms using TCP/IP or RS-232 if a union, like

typedef union tagSomeUnion
{
 char A;
 char B;
 char C;
 size_t D;
} SomeUnion;

is used. This is why:

16-bit platform: sizeof( SomeUnion ) = 2 bytes
32-bit platform: sizeof( SomeUnion ) = 4 bytes
64-bit platform: sizeof( SomeUnion ) = 8 bytes

and so on.

Note: Microsoft's RPC manages Binary Compatibility very good but I don't have a Microsoft C++ compiler version 1.5 ( for MS DOS ). Next, Turbo C++ compiler doesn't provide any support for RPC on a 16-bit platforms. Also, it doesn't have a 16-bit Interface Definition Language ( IDL ) compiler to compile the IDL files with declared interfaces. Tools from competitors, like CORBA or DCE, do not help as well since I don't think they were ever released for 16-bit platforms.

 


[ Example 5 ]

[ Example 5 ]

There are internal problems with Turbo C++ compiler. For example, it fails to build an executable in Debug configuration when a copy constructor is declared in some class. At the same time, in Release configuration an executable could be successfully built.
 



Pages