From 7584f368ff92f1bef3bd4e70299714beb93c2370 Mon Sep 17 00:00:00 2001 From: wangtao9 Date: Mon, 17 Apr 2023 06:47:56 +0000 Subject: [PATCH 01/10] modify cpp codegen template to generate lock-free cpp lexer&parser Signed-off-by: wangtao9 --- .../org/antlr/v4/tool/templates/codegen/Cpp/Cpp.stg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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..7d57d807b0 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,7 +144,7 @@ struct StaticData final { }; ::antlr4::internal::OnceFlag LexerOnceFlag; -StaticData *LexerStaticData = nullptr; +static thread_local StaticData *LexerStaticData = nullptr; void LexerInitialize() { assert(LexerStaticData == nullptr); @@ -238,7 +238,7 @@ bool ::sempred(RuleContext *context, size_t ruleIndex, size_t predic void ::initialize() { - ::antlr4::internal::call_once(LexerOnceFlag, LexerInitialize); + LexerInitialize(); } >> @@ -364,7 +364,7 @@ struct StaticData final { }; ::antlr4::internal::OnceFlag ParserOnceFlag; -StaticData *ParserStaticData = nullptr; +static thread_local StaticData *ParserStaticData = nullptr; void ParserInitialize() { assert(ParserStaticData == nullptr); @@ -435,7 +435,7 @@ bool ::sempred(RuleContext *context, size_t ruleIndex, size_t predi void ::initialize() { - ::antlr4::internal::call_once(ParserOnceFlag, ParserInitialize); + ParserInitialize(); } >> From 436d23aca529c40a63ce9bc38f685735cab93f6d Mon Sep 17 00:00:00 2001 From: wangtao9 Date: Tue, 18 Apr 2023 06:55:23 +0000 Subject: [PATCH 02/10] add lockFreeCppTarget option to generate lock-free Cpp lexer and/or parser (default OFF) Signed-off-by: wangtao9 --- .../antlr/v4/tool/templates/codegen/Cpp/Cpp.stg | 16 ++++++++++++++++ .../org/antlr/v4/codegen/model/Recognizer.java | 2 ++ tool/src/org/antlr/v4/tool/Grammar.java | 1 + 3 files changed, 19 insertions(+) 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 7d57d807b0..0e7c2f1007 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,7 +144,11 @@ struct StaticData final { }; ::antlr4::internal::OnceFlag LexerOnceFlag; + static thread_local StaticData *LexerStaticData = nullptr; + +StaticData *LexerStaticData = nullptr; + void LexerInitialize() { assert(LexerStaticData == nullptr); @@ -238,7 +242,11 @@ bool ::sempred(RuleContext *context, size_t ruleIndex, size_t predic void ::initialize() { + LexerInitialize(); + + ::antlr4::internal::call_once(LexerOnceFlag, LexerInitialize); + } >> @@ -364,7 +372,11 @@ struct StaticData final { }; ::antlr4::internal::OnceFlag ParserOnceFlag; + static thread_local StaticData *ParserStaticData = nullptr; + +StaticData *ParserStaticData = nullptr; + void ParserInitialize() { assert(ParserStaticData == nullptr); @@ -435,7 +447,11 @@ bool ::sempred(RuleContext *context, size_t ruleIndex, size_t predi void ::initialize() { + ParserInitialize(); + + ::antlr4::internal::call_once(ParserOnceFlag, ParserInitialize); + } >> diff --git a/tool/src/org/antlr/v4/codegen/model/Recognizer.java b/tool/src/org/antlr/v4/codegen/model/Recognizer.java index 732f50fb20..889591f4a1 100644 --- a/tool/src/org/antlr/v4/codegen/model/Recognizer.java +++ b/tool/src/org/antlr/v4/codegen/model/Recognizer.java @@ -45,6 +45,7 @@ public abstract class Recognizer extends OutputModelObject { @ModelElement public SerializedATN atn; @ModelElement public LinkedHashMap sempredFuncs = new LinkedHashMap(); + @ModelElement public boolean lockFreeCppTarget; public Recognizer(OutputModelFactory factory) { super(factory); @@ -77,6 +78,7 @@ public Recognizer(OutputModelFactory factory) { else { superClass = null; } + lockFreeCppTarget = "ON".equals(g.getOptionString("lockFreeCppTarget")); tokenNames = translateTokenStringsToTarget(g.getTokenDisplayNames(), gen); literalNames = translateTokenStringsToTarget(g.getTokenLiteralNames(), gen); diff --git a/tool/src/org/antlr/v4/tool/Grammar.java b/tool/src/org/antlr/v4/tool/Grammar.java index eabee9175f..2ad34b684b 100644 --- a/tool/src/org/antlr/v4/tool/Grammar.java +++ b/tool/src/org/antlr/v4/tool/Grammar.java @@ -82,6 +82,7 @@ public class Grammar implements AttributeResolver { parserOptions.add("language"); parserOptions.add("accessLevel"); parserOptions.add("exportMacro"); + parserOptions.add("lockFreeCppTarget"); parserOptions.add(caseInsensitiveOptionName); } From a543fa2416c2fa6bb479684e237dae75158a6401 Mon Sep 17 00:00:00 2001 From: wangtao9 Date: Tue, 25 Apr 2023 09:44:52 +0000 Subject: [PATCH 03/10] fix boolean option -lock-free-cpp-target Signed-off-by: wangtao9 --- tool/src/org/antlr/v4/Tool.java | 2 ++ tool/src/org/antlr/v4/codegen/model/Recognizer.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tool/src/org/antlr/v4/Tool.java b/tool/src/org/antlr/v4/Tool.java index 1b7eea7535..a9c330243e 100644 --- a/tool/src/org/antlr/v4/Tool.java +++ b/tool/src/org/antlr/v4/Tool.java @@ -112,6 +112,7 @@ public Option(String fieldName, String name, OptionArgType argType, String descr public boolean warnings_are_errors = false; public boolean longMessages = false; public boolean exact_output_dir = false; + public boolean lock_free_cpp_target = false; public final static Option[] optionDefs = { new Option("outputDirectory", "-o", OptionArgType.STRING, "specify output directory where all output is generated"), @@ -133,6 +134,7 @@ public Option(String fieldName, String name, OptionArgType argType, String descr new Option("force_atn", "-Xforce-atn", "use the ATN simulator for all predictions"), new Option("log", "-Xlog", "dump lots of logging info to antlr-timestamp.log"), new Option("exact_output_dir", "-Xexact-output-dir", "all output goes into -o dir regardless of paths/package"), + new Option("lock_free_cpp_target", "-lock-free-cpp-target", "generate lock-free C++ lexer and/or parser "), }; // helper vars for option management diff --git a/tool/src/org/antlr/v4/codegen/model/Recognizer.java b/tool/src/org/antlr/v4/codegen/model/Recognizer.java index 889591f4a1..3dc14c5848 100644 --- a/tool/src/org/antlr/v4/codegen/model/Recognizer.java +++ b/tool/src/org/antlr/v4/codegen/model/Recognizer.java @@ -78,7 +78,7 @@ public Recognizer(OutputModelFactory factory) { else { superClass = null; } - lockFreeCppTarget = "ON".equals(g.getOptionString("lockFreeCppTarget")); + lockFreeCppTarget = g.tool.lock_free_cpp_target; tokenNames = translateTokenStringsToTarget(g.getTokenDisplayNames(), gen); literalNames = translateTokenStringsToTarget(g.getTokenLiteralNames(), gen); From cf08db7a375b33da96ddcb602f67ac5d5b396719 Mon Sep 17 00:00:00 2001 From: wangtao9 Date: Tue, 25 Apr 2023 09:48:19 +0000 Subject: [PATCH 04/10] remove string option lockFreeCppTarget of grammar Signed-off-by: wangtao9 --- tool/src/org/antlr/v4/tool/Grammar.java | 1 - 1 file changed, 1 deletion(-) diff --git a/tool/src/org/antlr/v4/tool/Grammar.java b/tool/src/org/antlr/v4/tool/Grammar.java index 2ad34b684b..eabee9175f 100644 --- a/tool/src/org/antlr/v4/tool/Grammar.java +++ b/tool/src/org/antlr/v4/tool/Grammar.java @@ -82,7 +82,6 @@ public class Grammar implements AttributeResolver { parserOptions.add("language"); parserOptions.add("accessLevel"); parserOptions.add("exportMacro"); - parserOptions.add("lockFreeCppTarget"); parserOptions.add(caseInsensitiveOptionName); } From 07e222f0f33eb45c8cdacefb9a57d637f607d4fa Mon Sep 17 00:00:00 2001 From: wangtao9 Date: Wed, 26 Apr 2023 08:40:22 +0000 Subject: [PATCH 05/10] use compile-time macro instead of generate-time option Signed-off-by: wangtao9 --- .../v4/tool/templates/codegen/Cpp/Cpp.stg | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) 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 0e7c2f1007..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,14 +144,19 @@ struct StaticData final { }; ::antlr4::internal::OnceFlag LexerOnceFlag; - -static thread_local StaticData *LexerStaticData = nullptr; - +#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> @@ -242,11 +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 } >> @@ -372,14 +377,19 @@ struct StaticData final { }; ::antlr4::internal::OnceFlag ParserOnceFlag; - -static thread_local StaticData *ParserStaticData = nullptr; - +#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> @@ -447,11 +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 } >> From c7eb2dfc8a9f057e69c3af26cd9ac44e779ac652 Mon Sep 17 00:00:00 2001 From: wangtao9 Date: Wed, 26 Apr 2023 08:47:54 +0000 Subject: [PATCH 06/10] remove useless codegen option Signed-off-by: wangtao9 --- tool/src/org/antlr/v4/Tool.java | 2 -- tool/src/org/antlr/v4/codegen/model/Recognizer.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/tool/src/org/antlr/v4/Tool.java b/tool/src/org/antlr/v4/Tool.java index a9c330243e..1b7eea7535 100644 --- a/tool/src/org/antlr/v4/Tool.java +++ b/tool/src/org/antlr/v4/Tool.java @@ -112,7 +112,6 @@ public Option(String fieldName, String name, OptionArgType argType, String descr public boolean warnings_are_errors = false; public boolean longMessages = false; public boolean exact_output_dir = false; - public boolean lock_free_cpp_target = false; public final static Option[] optionDefs = { new Option("outputDirectory", "-o", OptionArgType.STRING, "specify output directory where all output is generated"), @@ -134,7 +133,6 @@ public Option(String fieldName, String name, OptionArgType argType, String descr new Option("force_atn", "-Xforce-atn", "use the ATN simulator for all predictions"), new Option("log", "-Xlog", "dump lots of logging info to antlr-timestamp.log"), new Option("exact_output_dir", "-Xexact-output-dir", "all output goes into -o dir regardless of paths/package"), - new Option("lock_free_cpp_target", "-lock-free-cpp-target", "generate lock-free C++ lexer and/or parser "), }; // helper vars for option management diff --git a/tool/src/org/antlr/v4/codegen/model/Recognizer.java b/tool/src/org/antlr/v4/codegen/model/Recognizer.java index 3dc14c5848..732f50fb20 100644 --- a/tool/src/org/antlr/v4/codegen/model/Recognizer.java +++ b/tool/src/org/antlr/v4/codegen/model/Recognizer.java @@ -45,7 +45,6 @@ public abstract class Recognizer extends OutputModelObject { @ModelElement public SerializedATN atn; @ModelElement public LinkedHashMap sempredFuncs = new LinkedHashMap(); - @ModelElement public boolean lockFreeCppTarget; public Recognizer(OutputModelFactory factory) { super(factory); @@ -78,7 +77,6 @@ public Recognizer(OutputModelFactory factory) { else { superClass = null; } - lockFreeCppTarget = g.tool.lock_free_cpp_target; tokenNames = translateTokenStringsToTarget(g.getTokenDisplayNames(), gen); literalNames = translateTokenStringsToTarget(g.getTokenLiteralNames(), gen); From 5a89776f0c64981c1437ccd6223a4963f256899d Mon Sep 17 00:00:00 2001 From: wangtao9 Date: Thu, 4 May 2023 03:23:41 +0000 Subject: [PATCH 07/10] update doc cpp-target.md Signed-off-by: wangtao9 --- doc/cpp-target.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/cpp-target.md b/doc/cpp-target.md index fc80744dce..16ed8c7cc4 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,11 @@ 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): + +* An **thread local DFA macro**: Add `-DANTLR4_USE_THREAD_LOCAL_CACHE=1` to the compilation options to enable using thread local DAF cache (disable by default). After that, each thread uses its own DFA, and 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 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.). From 4b835b88f7fa450e0761d797ffbf9fe1dacb95e8 Mon Sep 17 00:00:00 2001 From: wangtao9 Date: Thu, 4 May 2023 03:32:27 +0000 Subject: [PATCH 08/10] minor fix doc Signed-off-by: wangtao9 --- doc/cpp-target.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/cpp-target.md b/doc/cpp-target.md index 16ed8c7cc4..8b26b57d7c 100644 --- a/doc/cpp-target.md +++ b/doc/cpp-target.md @@ -105,7 +105,7 @@ For gcc and clang it is possible to use the `-fvisibility=hidden` setting to hid ### Compile Aspects When compiling generated files, you can configure a compile option according to your needs (also optional): -* An **thread local DFA macro**: Add `-DANTLR4_USE_THREAD_LOCAL_CACHE=1` to the compilation options to enable using thread local DAF cache (disable by default). After that, each thread uses its own DFA, and 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 enough, you should consider turning on this option. +* A **thread local DFA macro**: Add `-DANTLR4_USE_THREAD_LOCAL_CACHE=1` to the compilation options will enable using thread local DAF 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 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.). From e2c94d19f45ce501761bbfcde58e4bd9f8112c15 Mon Sep 17 00:00:00 2001 From: wangtao9 Date: Thu, 4 May 2023 07:22:20 +0000 Subject: [PATCH 09/10] fix review comments Signed-off-by: wangtao9 --- doc/cpp-target.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/cpp-target.md b/doc/cpp-target.md index 8b26b57d7c..a86220f115 100644 --- a/doc/cpp-target.md +++ b/doc/cpp-target.md @@ -105,7 +105,7 @@ For gcc and clang it is possible to use the `-fvisibility=hidden` setting to hid ### 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 DAF 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 enough, you should consider turning on this option. +* 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.). From 174e433b0e3deef38e97c65adfe377e20b1f0eb3 Mon Sep 17 00:00:00 2001 From: Tao Wang Date: Fri, 5 May 2023 09:26:40 +0800 Subject: [PATCH 10/10] update doc/cpp-target.md Co-authored-by: Ivan Kochurkin Signed-off-by: Tao Wang --- doc/cpp-target.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/cpp-target.md b/doc/cpp-target.md index a86220f115..d4cd872a4f 100644 --- a/doc/cpp-target.md +++ b/doc/cpp-target.md @@ -103,9 +103,14 @@ 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. +* 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.).