compile-time-regular-expressions icon indicating copy to clipboard operation
compile-time-regular-expressions copied to clipboard

compilation with debugging symbols very slow

Open llllllllll opened this issue 4 years ago • 7 comments

First, thanks for this wonderful library. I am amazed at how fast it can match and isolate groups!

I was evaluating using ctre for some datetime parsing, like you have in the readme; however, I am finding that the compile times are extremely long when emitting debugging symbols. I have a file, which does have some other medium weight templates, but with only 3 regex literals in the file, the compilation time goes from less than a minute to 22 minutes. Without debugging symbols, it only takes 25 seconds, so I don't believe that it is due to slowness in the library itself.

I am compiling with gcc 9.1.0, and the 3 regular expressions I am using are:

(\\d{4})-(\\d{2})-(\\d{2})
(\\d{4})-(\\d{2})-(\\d{2})( |T)(\\d{2}):(\\d{2}):(\\d{2})
(\\d{4})-(\\d{2})-(\\d{2})( |T)(\\d{2}):(\\d{2}):(\\d{2})(\\.\\d{1,9})?

I would like to add many more formats, but I am waiting to implement that until I know what is going on with the compile times. This project is currently using C++ 17 and only gcc, so I am using the _ctre UDL. In testing, I have tried the C++20 cnttp version and noticed that it is a bit faster. I am not really able to reproduce this when I just compile the longest regex standalone, so I am wondering if there is a weird interaction with the existing code somewhere.

I would like to preserve debugging symbols if possible, and if needed I could try just moving all the ctre stuff to its own object without symbols, but I am wondering if there is something else to try? If it would help, I can see about getting the actual offending code to you on Monday.

llllllllll avatar Sep 27 '19 23:09 llllllllll

The compilation time is really oddly big. I would like to see the offending code.

hanickadot avatar Sep 28 '19 07:09 hanickadot

Hi all, I believe I've created a minimal working example for this issue. The code indeed takes over a minute to build even without debug symbols. I did not go the extra mile to wait for over 25 minutes on my VM for a version with debug symbols, though I might do just that tommorow.

I believe I pinned down the potential offender: forced inlining of code. I've temporarily changed the definitions of CTLL_FORCE_INLINE and CTRE_FORCE_INLINE & removed forced inlining (patch available here). The benchmark results can be found here - tl;dr: build time goes down to 2 seconds for non-debug version.

Of course what I did is not necessarily a correct way to handle long compile times - my comment is missing:

  1. runtime benchmark of two versions.
  2. precisely pinpointed cause of the issue (I'll look at .objs and symbols soon for the provided example).

I am aware that staying away from forced inlining is probably not an option.

Needless to say I might have done something incorrectly. Feel free to point out any issues. E: Alright, I've spotted an error. I'll update the results today. E2: I've tested the provided example on MSVC - x86 Debug build takes few seconds, though x86 Release build runs out of heap space (I have 16 gigabytes of ram - I'd expect it to be enough). E3: Clang 9.0 takes ~a minute to build with "-g -O3" - even with enabled forced inlining.

E4: I've updated the build benchmark results with the output of gcc's -ftime-report (available here). As you can see, 86% of the time is spent in phase "trivially dead code". This is just my gut feeling, but disabling forced inlining might help as non-inlined functions are optimized just once/left for runtime evaluation. Though I'm also curious why clang/msvc don't have the same issue. AFAIK MSVC runs local optimizations after inlining and Clang/GCC do so before inlining pass - hence I'd expect clang to have the same problem as gcc. As mentioned in E3 though, clang's builds are within "sane" build time range.

osiewicz avatar Nov 12 '19 23:11 osiewicz

Hi, I've spottedthis issue in latest MSVC 2019 (19.26.28806) now, except the debug compilation is fine, but in release (/Ox flag) the compilation never ends. Removing inlining indeed unblocks it.

Archie3d avatar Jun 17 '20 23:06 Archie3d

@Archie3d does it happen for any pattern? if not, please provide your test case.

hanickadot avatar Jun 18 '20 07:06 hanickadot

@hanickadot no, the shorter the pattern the faster it compiles. For this one it takes forever:

static constexpr auto pattern = ctll::fixed_string { "^([a-z]+)://(([\\w\\-\\.]+)(:([\\w\\-\\?&=]+))?@)?([\\w\\-\\.]+)(:(\\d+)+)?(/[\\w\\.\\-/\\?\\(\\)&=%~]*)?$" };

though when I remove the trailing groups the compilation goes faster (than my patience wears out :)

Compilation flags (MSVC2019):

/EHsc /std:c++latest /bigobj /Ox

clang does not seem to suffer though.

Archie3d avatar Jun 18 '20 16:06 Archie3d

That's a problem of MVSC and their constexpr evaluator :( It's not forever only too long. It's definitely a different issue than #78, please create a new one.

This issue about MSVC creating a lot of debug symbols.

hanickadot avatar Jun 18 '20 17:06 hanickadot

+1 for the patch provided by @osiewicz , it cut my build times down from 4 mins to 11 seconds with clang, and from 3 mins to 12 seconds with gcc. I wonder if this could be merged with a macro to override the default inlining behaviour for better build times?

nitronoid avatar Dec 28 '20 23:12 nitronoid