diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-07 10:07:44 +0200 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-06-07 10:07:44 +0200 |
commit | 6a2d1112c3cf64b46f7c60d7878d5cc8101fc5cd (patch) | |
tree | edc830d4507fc8b05c2202dcebb499d16563cb3d | |
parent | 57ca292c8844e566184e3f7e5c98fa98991684bd (diff) | |
download | lanes-6a2d1112c3cf64b46f7c60d7878d5cc8101fc5cd.tar.gz lanes-6a2d1112c3cf64b46f7c60d7878d5cc8101fc5cd.tar.bz2 lanes-6a2d1112c3cf64b46f7c60d7878d5cc8101fc5cd.zip |
Debug code to help track linda gc during keeper operation
-rw-r--r-- | deep_test/deeptest.lua | 52 | ||||
-rw-r--r-- | src/debug.h | 2 | ||||
-rw-r--r-- | src/linda.cpp | 2 | ||||
-rw-r--r-- | src/linda.h | 32 | ||||
-rw-r--r-- | src/lindafactory.cpp | 2 |
5 files changed, 71 insertions, 19 deletions
diff --git a/deep_test/deeptest.lua b/deep_test/deeptest.lua index 99cf1e4..250eb98 100644 --- a/deep_test/deeptest.lua +++ b/deep_test/deeptest.lua | |||
@@ -1,6 +1,8 @@ | |||
1 | local lanes = require("lanes").configure{ with_timers = false} | 1 | local lanes = require("lanes").configure{ with_timers = false} |
2 | local l = lanes.linda "my linda" | 2 | local l = lanes.linda "my linda" |
3 | 3 | ||
4 | local table_unpack = table.unpack or unpack -- Lua 5.1 support | ||
5 | |||
4 | -- we will transfer userdata created by this module, so we need to make Lanes aware of it | 6 | -- we will transfer userdata created by this module, so we need to make Lanes aware of it |
5 | local dt = lanes.require "deep_test" | 7 | local dt = lanes.require "deep_test" |
6 | 8 | ||
@@ -93,24 +95,44 @@ if DEEP then | |||
93 | print "================================================================" | 95 | print "================================================================" |
94 | print "DEEP" | 96 | print "DEEP" |
95 | local d = dt.new_deep(nupvals) | 97 | local d = dt.new_deep(nupvals) |
96 | if DEEP == "gc" then | 98 | if type(DEEP) == "string" then |
97 | local thrasher = function(repeat_, size_) | 99 | local gc_tests = { |
98 | print "in thrasher" | 100 | thrasher = function(repeat_, size_) |
99 | -- result is a table of repeat_ tables, each containing size_ entries | 101 | print "in thrasher" |
100 | local result = {} | 102 | -- result is a table of repeat_ tables, each containing size_ entries |
101 | for i = 1, repeat_ do | 103 | local result = {} |
102 | local batch_values = {} | 104 | for i = 1, repeat_ do |
103 | for j = 1, size_ do | 105 | local batch_values = {} |
104 | table.insert(batch_values, j) | 106 | for j = 1, size_ do |
107 | table.insert(batch_values, j) | ||
108 | end | ||
109 | table.insert(result, batch_values) | ||
110 | end | ||
111 | print "thrasher done" | ||
112 | return result | ||
113 | end, | ||
114 | stack_abuser = function(repeat_, size_) | ||
115 | print "in stack_abuser" | ||
116 | for i = 1, repeat_ do | ||
117 | local batch_values = {} | ||
118 | for j = 1, size_ do | ||
119 | table.insert(batch_values, j) | ||
120 | end | ||
121 | -- return size_ values | ||
122 | local _ = table_unpack(batch_values) | ||
105 | end | 123 | end |
106 | table.insert(result, batch_values) | 124 | print "stack_abuser done" |
125 | return result | ||
107 | end | 126 | end |
108 | print "thrasher done" | 127 | } |
109 | return result | ||
110 | end | ||
111 | -- have the object call the function from inside one of its functions, to detect if it gets collected from there (while in use!) | 128 | -- have the object call the function from inside one of its functions, to detect if it gets collected from there (while in use!) |
112 | local r = d:invoke(thrasher, REPEAT or 10, SIZE or 10) | 129 | local testf = gc_tests[DEEP] |
113 | print("invoke -> ", tostring(r)) | 130 | if testf then |
131 | local r = d:invoke(gc_tests[DEEP], REPEAT or 10, SIZE or 10) | ||
132 | print("invoke -> ", tostring(r)) | ||
133 | else | ||
134 | print("unknown test '" .. DEEP .. "'") | ||
135 | end | ||
114 | else | 136 | else |
115 | performTest(d) | 137 | performTest(d) |
116 | end | 138 | end |
diff --git a/src/debug.h b/src/debug.h index a0a4b8d..99fe48a 100644 --- a/src/debug.h +++ b/src/debug.h | |||
@@ -15,6 +15,7 @@ inline void LUA_ASSERT_IMPL(lua_State* L_, bool cond_, char const* file_, int co | |||
15 | } | 15 | } |
16 | 16 | ||
17 | #define LUA_ASSERT(L_, cond_) LUA_ASSERT_IMPL(L_, cond_, __FILE__, __LINE__, #cond_) | 17 | #define LUA_ASSERT(L_, cond_) LUA_ASSERT_IMPL(L_, cond_, __FILE__, __LINE__, #cond_) |
18 | #define LUA_ASSERT_CODE(code_) code_ | ||
18 | 19 | ||
19 | class StackChecker | 20 | class StackChecker |
20 | { | 21 | { |
@@ -102,6 +103,7 @@ class StackChecker | |||
102 | #else // HAVE_LUA_ASSERT() | 103 | #else // HAVE_LUA_ASSERT() |
103 | 104 | ||
104 | #define LUA_ASSERT(L_, c) nullptr // nothing | 105 | #define LUA_ASSERT(L_, c) nullptr // nothing |
106 | #define LUA_ASSERT_CODE(code_) nullptr | ||
105 | 107 | ||
106 | #define STACK_CHECK_START_REL(L_, offset_) | 108 | #define STACK_CHECK_START_REL(L_, offset_) |
107 | #define STACK_CHECK_START_ABS(L_, offset_) | 109 | #define STACK_CHECK_START_ABS(L_, offset_) |
diff --git a/src/linda.cpp b/src/linda.cpp index 8b6df8e..3449f89 100644 --- a/src/linda.cpp +++ b/src/linda.cpp | |||
@@ -181,6 +181,8 @@ int Linda::ProtectedCall(lua_State* L_, lua_CFunction f_) | |||
181 | lua_State* const _KL{ _K ? _K->L : nullptr }; | 181 | lua_State* const _KL{ _K ? _K->L : nullptr }; |
182 | if (_KL == nullptr) | 182 | if (_KL == nullptr) |
183 | return 0; | 183 | return 0; |
184 | |||
185 | LUA_ASSERT_CODE(auto const _koip{ _linda->startKeeperOperation(L_) }); | ||
184 | // if we didn't do anything wrong, the keeper stack should be clean | 186 | // if we didn't do anything wrong, the keeper stack should be clean |
185 | LUA_ASSERT(L_, lua_gettop(_KL) == 0); | 187 | LUA_ASSERT(L_, lua_gettop(_KL) == 0); |
186 | 188 | ||
diff --git a/src/linda.h b/src/linda.h index 8db380a..809ade5 100644 --- a/src/linda.h +++ b/src/linda.h | |||
@@ -23,15 +23,39 @@ using LindaGroup = Unique<int>; | |||
23 | class Linda | 23 | class Linda |
24 | : public DeepPrelude // Deep userdata MUST start with this header | 24 | : public DeepPrelude // Deep userdata MUST start with this header |
25 | { | 25 | { |
26 | public: | ||
27 | class KeeperOperationInProgress | ||
28 | { | ||
29 | private: | ||
30 | Linda& linda; | ||
31 | [[maybe_unused]] lua_State* const L; // just here for inspection while debugging | ||
32 | |||
33 | public: | ||
34 | KeeperOperationInProgress(Linda& linda_, lua_State* const L_) | ||
35 | : linda{ linda_ } | ||
36 | , L{ L_ } | ||
37 | { | ||
38 | [[maybe_unused]] int const _prev{ linda.keeperOperationCount.fetch_add(1, std::memory_order_seq_cst) }; | ||
39 | } | ||
40 | |||
41 | public: | ||
42 | ~KeeperOperationInProgress() | ||
43 | { | ||
44 | [[maybe_unused]] int const _prev{ linda.keeperOperationCount.fetch_sub(1, std::memory_order_seq_cst) }; | ||
45 | } | ||
46 | }; | ||
47 | |||
26 | private: | 48 | private: |
27 | static constexpr size_t kEmbeddedNameLength = 24; | 49 | static constexpr size_t kEmbeddedNameLength = 24; |
28 | using EmbeddedName = std::array<char, kEmbeddedNameLength>; | 50 | using EmbeddedName = std::array<char, kEmbeddedNameLength>; |
29 | // depending on the name length, it is either embedded inside the Linda, or allocated separately | 51 | // depending on the name length, it is either embedded inside the Linda, or allocated separately |
30 | std::variant<std::string_view, EmbeddedName> nameVariant; | 52 | std::variant<std::string_view, EmbeddedName> nameVariant{}; |
53 | // counts the keeper operations in progress | ||
54 | std::atomic<int> keeperOperationCount{}; | ||
31 | 55 | ||
32 | public: | 56 | public: |
33 | std::condition_variable readHappened; | 57 | std::condition_variable readHappened{}; |
34 | std::condition_variable writeHappened; | 58 | std::condition_variable writeHappened{}; |
35 | Universe* const U{ nullptr }; // the universe this linda belongs to | 59 | Universe* const U{ nullptr }; // the universe this linda belongs to |
36 | int const keeperIndex{ -1 }; // the keeper associated to this linda | 60 | int const keeperIndex{ -1 }; // the keeper associated to this linda |
37 | CancelRequest cancelRequest{ CancelRequest::None }; | 61 | CancelRequest cancelRequest{ CancelRequest::None }; |
@@ -60,7 +84,9 @@ class Linda | |||
60 | public: | 84 | public: |
61 | [[nodiscard]] Keeper* acquireKeeper() const; | 85 | [[nodiscard]] Keeper* acquireKeeper() const; |
62 | [[nodiscard]] std::string_view getName() const; | 86 | [[nodiscard]] std::string_view getName() const; |
87 | [[nodiscard]] bool inKeeperOperation() const { return keeperOperationCount.load(std::memory_order_seq_cst) != 0; } | ||
63 | void releaseKeeper(Keeper* keeper_) const; | 88 | void releaseKeeper(Keeper* keeper_) const; |
64 | [[nodiscard]] static int ProtectedCall(lua_State* L_, lua_CFunction f_); | 89 | [[nodiscard]] static int ProtectedCall(lua_State* L_, lua_CFunction f_); |
90 | [[nodiscard]] KeeperOperationInProgress startKeeperOperation(lua_State* const L_) { return KeeperOperationInProgress{ *this, L_ }; }; | ||
65 | [[nodiscard]] Keeper* whichKeeper() const { return U->keepers.getKeeper(keeperIndex); } | 91 | [[nodiscard]] Keeper* whichKeeper() const { return U->keepers.getKeeper(keeperIndex); } |
66 | }; | 92 | }; |
diff --git a/src/lindafactory.cpp b/src/lindafactory.cpp index 3f4b9b0..6a2b000 100644 --- a/src/lindafactory.cpp +++ b/src/lindafactory.cpp | |||
@@ -69,7 +69,7 @@ void LindaFactory::createMetatable(lua_State* L_) const | |||
69 | void LindaFactory::deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) const | 69 | void LindaFactory::deleteDeepObjectInternal(lua_State* L_, DeepPrelude* o_) const |
70 | { | 70 | { |
71 | Linda* const _linda{ static_cast<Linda*>(o_) }; | 71 | Linda* const _linda{ static_cast<Linda*>(o_) }; |
72 | LUA_ASSERT(L_, _linda); | 72 | LUA_ASSERT(L_, _linda && !_linda->inKeeperOperation()); |
73 | Keeper* const _myK{ _linda->whichKeeper() }; | 73 | Keeper* const _myK{ _linda->whichKeeper() }; |
74 | // if collected after the universe, keepers are already destroyed, and there is nothing to clear | 74 | // if collected after the universe, keepers are already destroyed, and there is nothing to clear |
75 | if (_myK) { | 75 | if (_myK) { |