Recent

Author Topic: Debug vs release versions (optimisations)  (Read 3411 times)

geraldholdsworth

  • Full Member
  • ***
  • Posts: 226
Debug vs release versions (optimisations)
« on: December 30, 2024, 12:39:36 pm »
Hi all,

Has anyone else experienced this, where their code works absolutely fine in debug mode (i.e., while it is being developed), but works differently once compiled for release?
I can't give any specific examples. However, I have narrowed it down to the Project Options -> Compiler Options -> Compilation and Linking, and changing the Optimisation Levels from 1 to 2 or 3. By default, it seems that the Release uses option 3 which makes one of my projects behave differently to when it is in debug mode (i.e., option 1).

I'm using Lazarus 3.0 on a Mac, and am wondering if the newer versions would act the same. Although, I'm waiting for the release of 4 before I upgrade, but I may need to go sooner.

Oh, interestingly, this doesn't happen with the Linux releases. I do have two installs of Lazarus (same version) - one for developing (downloaded from SourceForge) and the other for cross-compiling (built using FPCUpDeluxe).

Cheers,

Gerald.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 10905
  • Debugger - SynEdit - and more
    • wiki
Re: Debug vs release versions (optimisations)
« Reply #1 on: December 30, 2024, 12:53:11 pm »
There are a variety of possible reasons.

Uninitialized values can behave different depending on optimization. Other than compiler warnings, on Linux those can be found with valgrind. And you can test your app (under debugger) with
-gt
or -gtt
or -gttt
or -gtttt
One at a time...

Then there are dangling pointers (use after free). Optimized code has different mem layout. So a dangling pointer hitting safe ground on O0 may do damage an O2 or O3. Happens frequently.

Or threads and timings... Can trigger race conditions differently.

Probably various other things in your code.

But, also compiler bugs. I know there were some when compiling for Windows. They are rare, and hard to trigger. But they can happen.


geraldholdsworth

  • Full Member
  • ***
  • Posts: 226
Re: Debug vs release versions (optimisations)
« Reply #2 on: December 30, 2024, 01:00:16 pm »
Ah...interesting that you mentioned about uninitialised values - I don't get the warnings under O1, but do under O3. I never thought anything of it.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12107
  • FPC developer.
Re: Debug vs release versions (optimisations)
« Reply #3 on: December 30, 2024, 01:26:49 pm »
And wrong casting of classes (casting a class to a class where it doesn't inherit from).  Use -CR for that.

Usually these are bugs in the code that may or may not be noticed due to memory layout, like e.g. the stack.   Higher optimisation might optimize away temps, making it more critical.

Use these options and valgrind on linux to kill as many bugs as possible. (hoping they are in an easy testable code path)

440bx

  • Hero Member
  • *****
  • Posts: 5070
Re: Debug vs release versions (optimisations)
« Reply #4 on: December 30, 2024, 01:50:43 pm »
Ah...interesting that you mentioned about uninitialised values - I don't get the warnings under O1, but do under O3. I never thought anything of it.
Generic advice: _always_ initialize local ordinal type variables in their declaration and always initialize local structured variables first thing upon entering a function/procedure (use ZeroMemory).  It's the clean/right thing to do, prevents bugs and makes debugging simpler.

Lastly, don't initialize structured variables using "= ();" because the code generated is nothing short of atrocious.

HTH.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

geraldholdsworth

  • Full Member
  • ***
  • Posts: 226
Re: Debug vs release versions (optimisations)
« Reply #5 on: December 30, 2024, 02:07:01 pm »
I usually try to intialise all variables...but obviously, some got missed.

I've now got a list, kindly provided by Lazarus with the O3 option. I'll go through that and see if it makes a difference.

geraldholdsworth

  • Full Member
  • ***
  • Posts: 226
Re: Debug vs release versions (optimisations)
« Reply #6 on: December 30, 2024, 10:23:13 pm »
I've now initialised all the variables that Lazarus indicated...but did so as the function/procedure starts and not in the declaration - does this make a difference?
Also, the structures - I intiated these as, for example, Result:=nil. It works, but is it right?
It made no difference to the result of the project. Still doesn't respond the same way as under O1.

I tried the -CR option, and this just gave me a "Range Check Error" when running the code, with options to continue and risk data loss, or abort.

I also tried the -gt option. Wasn't sure what to expect, but it ran just as it did before. Couldn't find the other options - is this something I need to tack on with Run Parameters?

I no longer have access to a Linux machine with a Lazarus build on it - only macOS.

The code is somewhere near 40,000 lines, across about 20 units, so not an easy one to diagnose this problem.

440bx

  • Hero Member
  • *****
  • Posts: 5070
Re: Debug vs release versions (optimisations)
« Reply #7 on: December 31, 2024, 06:33:49 am »
I've now initialised all the variables that Lazarus indicated...but did so as the function/procedure starts and not in the declaration - does this make a difference?
functionally it doesn't make a difference but, IMO, it's much easier to ensure everything is initialized if all ordinal variables are initialized in their declaration and only the structured variables are initialized in code.

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Seenkao

  • Hero Member
  • *****
  • Posts: 674
    • New ZenGL.
Re: Debug vs release versions (optimisations)
« Reply #8 on: December 31, 2024, 07:48:01 am »
I'm using Lazarus 3.0 on a Mac
Это может зависеть от версии FPC, если вы используете версию 3.3.1, то  она может работать менее стабильно чем версия 3.2.2.
Это может зависеть от того что FPC не достаточно хорошо работает с архитектурой ARM, и при попытке сильнее оптимизировать, код начинает работать неправильно.
Потому, думаю, надо тестировать код и смотреть что он выдаёт в конечном итоге без оптимизиций и с оптимизацией.

Google translate:
It may depend on the FPC version, if you are using version 3.3.1, it may work less stably than version 3.2.2.
It may depend on the fact that FPC does not work well enough with the ARM architecture, and when trying to optimize more, the code starts to work incorrectly.
Therefore, I think, you need to test the code and see what it ultimately produces without optimizations and with optimization.
Rus: Стремлюсь к созданию минимальных и достаточно быстрых приложений.

Eng: I strive to create applications that are minimal and reasonably fast.
Working on ZenGL

jollytall

  • Sr. Member
  • ****
  • Posts: 376
Re: Debug vs release versions (optimisations)
« Reply #9 on: December 31, 2024, 10:28:12 am »
I might have missed the point, but as I read the OP says that he uses different optimization levels for debug and release (as the default for them is). I never let a final program be optimized differently than what is developed/tested. I would say that first debug in low O level (0 or 1), then go up to the required optimization level, test there as well with debugging if needed and if that is OK, then switch off the debug mode.
To me it is not surprising that a program behaves differently in different O levels (due to e.g. initialization - what I sometimes intentionally skip to save time) and so the point is to make proper testing, debugging with the final optimization.

On a side note. When I have an array declared as
Code: Pascal  [Select][+][-]
  1. type tMyArray = array of integer;
  2. var MyArray : tMyArray;
and I want to set its size, like
Code: Pascal  [Select][+][-]
  1. SetLength(MyArray, 10);
then I get a hint on O0, O1, O2 that it does not seem to be initialized. On O3 (and O4) I do not get that. So to make the compiler "happy" I usually do
Code: Pascal  [Select][+][-]
  1. var MyArray : tMyArray = nil;
and it solves the problem, however if it is part of a record/object I cannot do that. To avoid one more instruction
Code: Pascal  [Select][+][-]
  1. MyArray := nil;
before the SetLength I usually simple suppress the hint. So my questions: Why is it even a hint for an array not to be initialized before first setting the size? Can it cause any problem? And if so, why is it not reported in O3? I would have assumed that optimization is changing the generated Assembler/MachineCode, but it should not effect the information provided during compilation.

geraldholdsworth

  • Full Member
  • ***
  • Posts: 226
Re: Debug vs release versions (optimisations)
« Reply #10 on: December 31, 2024, 04:30:40 pm »
I've managed to fix a specific bug. This was caused by an uninitialised variable hidden deep in the code, and gone un-reported.

I must say though, that there are some good tips given in these posts. So, thank you all.

 

TinyPortal © 2005-2018