Knowledgebase: General
7.x: My application runs (very) slowly with EurekaLog
Posted by Aleksandr Alekseev on 02 February 2022 19:56

Problem:

My application is fast when Eurekalog is disabled. But it runs significantly slower with EurekaLog enabled, like 20-50 times. For example, loading data without EurekaLog takes about 0.5 seconds, with EurekaLog - 50 seconds.

 

Reason:

EurekaLog is an exception tracer tool. This means that EurekaLog's code is not executing in your application unless:

  1. Exception occurs;
  2. Memory allocation or deallocation occurs (and you have memory checks enabled - which is a default);
  3. Thread starts or stops (and you have low-level hooks enabled - which is a default);
  4. Startup delays can be caused by EurekaLog starting up and preparing debug information (compressing debug information is not enabled by default);
  5. Startup delays can be caused by EurekaLog verifying your executable file (disabled by default);
  6. EurekaLog is running in troubleshooting logging mode (disabled by default).

This means that EurekaLog can not possibly affect performance of your application unless your application is:

  1. Raising a lot of exceptions;
  2. Allocating large amount of (small) memory blocks;
  3. Constantly restarting threads;
  4. Large application stores debug information as packed;
  5. Large application asks EurekaLog to verify its checksum (CRC);
  6. Running EurekaLog in run-time debug mode.

 

First, you need to find out which part of EurekaLog is slowing you down. In most cases: the performance issues are caused by enabled memory leaks checks (item #2), because EurekaLog has to build a full call stack for EACH memory allocation and deallocation in your application.

 

1. Start with checking if your code raises a lot of exceptions. For example, your or 3rd party code may use constructs like this:

try
  // do something
except
  Result := Default;
end;

Normally, you should see a debugger's notification about an exception. However, certain debugger's options could mask them (e.g. exception notifications could be disabled in settings). Please, go to your debugger's settings and:

  • enable exception notifications;
  • remove exceptions from the ignore list.

Run your code again and watch for exceptions.

Alternatively, you can create a run-time log. Open the produced log file and look for EurekaLog's hooks being called.

 

2. If large amount of exceptions are not the issue then try to find out if your or 3rd party code is doing a lot of memory allocations. You can review your code to ensure it does not abuse the memory manager. For example, allocating a single array/cache is better than allocating millions strings or objects.

You can test if memory operations are causing the issue by going into EurekaLog's memory options and disabling the "Enable extended memory manager" option.

Important: do not keep the "Enable extended memory manager" option disabled. Disabling the option is only meant as a diagnostic tool. Please, refer to the "Solution" section below to learn about the possible ways to fix memory-related performance issues.

 

3. If memory operations are not the issue - try to find out if your or 3rd party code is spawning a lot of threads. Again, you can review your code to ensure that it does not abuse threads. For example, a single thread pool is much better to run short tasks than creating millions threads.

You can test if threads are causing the issue by going into EurekaLog's advanced options and setting the "Low-level injection hooks" option to "Allow for current module only" or "Disabled".

Important: do not permanently set the "Low-level injection hooks" option to anything other than "Allow all". Changing the option is only meant as a diagnostic tool. Please, refer to the "Solution" section below to learn about the possible ways to fix thread-related performance issues.

 

4. If threads are not the issue - check if you have a (very) large application (or a slow network drive) and have enabled the "Compress debug information" option. Storing debug information compressed means that EurekaLog has to unpack it before it can be used - which can take time if your application is very large.

 

5. If debug information is not the issue - check if you have a (very) large application (or a slow network drive) and have enabled the "Check file corruption" option. Enabling this option will cause EurekaLog to read your entire executable in order to calculate its checksum (CRC). 

 

6. If CRC calculation is not the issue - check if you are running EurekaLog in debugging mode. Debugging is OFF by default and can be activated by:

  • passing the --el_debug command line switch;
  • creating the -el_debug suffixed file;
  • using ELogOpen + EL_Debug in the source code.

See this article for more information.

 

Solution:

Once you have determined which part of EurekaLog affects your code then you can fix it either by altering your code or adjusting EurekaLog.

 

1. If the performance issue is caused by exceptions:

  • Consider rewriting your code, so it won't use exceptions as means of normal workflow. For example, constructs like:
    try
      I := StrToInt(S);
    except
      I := -1;
    end;

    can be replaced with:

    I := StrToIntDef(S, -1);

    or:

    if not TryStrToInt(S, I) then
      // Handle bad conversion
  • Alternatively, you can disable EurekaLog for expected exceptions like this:
    SetEurekaLogStateInThread(0, False);
    try
      I := StrToInt(S);
    except
      I := 0;
    end;
    SetEurekaLogStateInThread(0, True);

 

2. If the performance issue is caused by memory operations:

  • Consider rewriting your code so it will use large memory blocks to store many smaller items. For example, an array of records can be an efficient replacement for an array of objects;
  • If only parts of your code are affected - you can disable EurekaLog for such code:

    DisableMemLeaksRegistering;
    try
      // some long executing code
    finally
      EnableMemLeaksRegistering;
    end;
    or:
    SetEurekaLogStateInThread(0, False);
    try
      // some long executing code
    finally
      SetEurekaLogStateInThread(0, True);
    end;
  • If you can not wrap all code in the above mentioned constructs - go to EurekaLog's memory options and disable the "Catch memory leaks" option. Collecting call stacks for each memory allocation takes a lot of time, so disabling this feature should speed up things significantly. Please note that you may keep the "Catch memory leaks" option enabled, because the "Active only when running under debugger" options is also enabled by default, so leaks checks will be on under debugger (developing) and will be off when run outside IDE (production);
  • If above did not help - disable all memory features, except the "Enable extended memory manager" option. We do not recommend to turn off the "Enable extended memory manager" option unless absolutely needed;
  • If above did not help - disable the "Enable extended memory manager" option. Please, refer to help to learn more about the implications of this decision.

 

3. If the performance issue is caused by threads:

  • Consider rewriting your code, so it will use thread pool(s);
  • If only parts of your code are affected - you can disable EurekaLog for such code:
    SetEurekaLogStateInThread(0, False);
    try
      // some long executing code
    finally
      SetEurekaLogStateInThread(0, True);
    end;
  • You can disable EurekaLog for hooking threads by going into EurekaLog's advanced options and setting the "Low-level injection hooks" option to "Allow for current module only" or "Disabled". Please, refer to help to learn more about the implications of this decision.

 

4. If the startup performance issue is caused by debug information then do not compress it.

  • We recommend that you store debug information unpacked (which is a default) - that way it is ready for immediate use. E.g. it is a typical "trade memory for speed" optimization.
  • You can play around with other debug information options in order to minimize debug information size, but we do not recommend it as doing so may decrease detalization level of EurekaLog's reports. EurekaLog has the statistics feature, which you can use for troubleshooting.

 

5. If the startup performance issue is caused by CRC calculation then turn off the corresponding option. There is no other way around it. Either you are checking your executable - in which case EurekaLog has to read it from start to end. Or you don't - in which case Windows will read/load your executable only as neccessary (e.g. progressive loading on demand).

 

6. If the performance issue is caused by debugging mode - simply turn it off. The run-time debugging is not supposed to be used for developing nor production. This feature exists for troubleshooting purposes only. It is not enabled by default and should be turned off immediately after solving an issue for which this mode was enabled in the first place.

 

See also:


Help Desk Software by Kayako Resolve