diff --git a/doc/cpp-target.md b/doc/cpp-target.md index fc80744dce..d4cd872a4f 100644 --- a/doc/cpp-target.md +++ b/doc/cpp-target.md @@ -78,7 +78,7 @@ This example assumes your grammar contains a parser rule named `key` for which t There are a couple of things that only the C++ ANTLR target has to deal with. They are described here. -### Build Aspects +### Code Generation Aspects The code generation (by running the ANTLR4 jar) allows to specify 2 values you might find useful for better integration of the generated files into your application (both are optional): * A **namespace**: use the **`-package`** parameter to specify the namespace you want. @@ -102,6 +102,16 @@ In order to create a static lib in Visual Studio define the `ANTLR4CPP_STATIC` m For gcc and clang it is possible to use the `-fvisibility=hidden` setting to hide all symbols except those that are made default-visible (which has been defined for all public classes in the runtime). +### Compile Aspects + +When compiling generated files, you can configure a compile option according to your needs (also optional): + +* A **thread local DFA macro**: Add `-DANTLR4_USE_THREAD_LOCAL_CACHE=1` to the compilation options +will enable using thread local DFA cache (disabled by default), after that, each thread uses its own DFA. +This will increase memory usage to store thread local DFAs and redundant computation to build thread local DFAs (not too much). +The benefit is that it can improve the concurrent performance running with multiple threads. +In other words, when you find your concurent throughput is not high enough, you should consider turning on this option. + ### Memory Management Since C++ has no built-in memory management we need to take extra care. For that we rely mostly on smart pointers, which however might cause time penalties or memory side effects (like cyclic references) if not used with care. Currently however the memory household looks very stable. Generally, when you see a raw pointer in code consider this as being managed elsewhere. You should never try to manage such a pointer (delete, assign to smart pointer etc.). diff --git a/tool/resources/org/antlr/v4/tool/templates/codegen/Cpp/Cpp.stg b/tool/resources/org/antlr/v4/tool/templates/codegen/Cpp/Cpp.stg index a34283be4d..6fc4419d02 100644 --- a/tool/resources/org/antlr/v4/tool/templates/codegen/Cpp/Cpp.stg +++ b/tool/resources/org/antlr/v4/tool/templates/codegen/Cpp/Cpp.stg @@ -144,10 +144,19 @@ struct StaticData final { }; ::antlr4::internal::OnceFlag LexerOnceFlag; +#if ANTLR4_USE_THREAD_LOCAL_CACHE +static thread_local +#endif StaticData *LexerStaticData = nullptr; void LexerInitialize() { +#if ANTLR4_USE_THREAD_LOCAL_CACHE + if (LexerStaticData != nullptr) { + return; + } +#else assert(LexerStaticData == nullptr); +#endif auto staticData = std::make_unique\<StaticData>( std::vector\{ "}; separator = ", ", wrap, anchor> @@ -238,7 +247,11 @@ bool ::sempred(RuleContext *context, size_t ruleIndex, size_t predic void ::initialize() { +#if ANTLR4_USE_THREAD_LOCAL_CACHE + LexerInitialize(); +#else ::antlr4::internal::call_once(LexerOnceFlag, LexerInitialize); +#endif } >> @@ -364,10 +377,19 @@ struct StaticData final { }; ::antlr4::internal::OnceFlag ParserOnceFlag; +#if ANTLR4_USE_THREAD_LOCAL_CACHE +static thread_local +#endif StaticData *ParserStaticData = nullptr; void ParserInitialize() { +#if ANTLR4_USE_THREAD_LOCAL_CACHE + if (ParserStaticData != nullptr) { + return; + } +#else assert(ParserStaticData == nullptr); +#endif auto staticData = std::make_unique\<StaticData>( std::vector\{ "}; separator = ", ", wrap, anchor> @@ -435,7 +457,11 @@ bool ::sempred(RuleContext *context, size_t ruleIndex, size_t predi void ::initialize() { +#if ANTLR4_USE_THREAD_LOCAL_CACHE + ParserInitialize(); +#else ::antlr4::internal::call_once(ParserOnceFlag, ParserInitialize); +#endif } >>