From: Ron Dempster (rdempste) Date: Thu, 27 Apr 2023 14:08:35 +0000 (+0000) Subject: Pull request #3826: Reap fix master X-Git-Tag: 3.1.61.0~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=75919649148861a1f8bc51c62600399a723b68cd;p=thirdparty%2Fsnort3.git Pull request #3826: Reap fix master Merge in SNORT/snort3 from ~RDEMPSTE/snort3:reap_fix_master to master Squashed commit of the following: commit fcaaf4316971b0f38e170e3d92a98571c184e25a Author: Ron Dempster (rdempste) Date: Thu Apr 20 14:49:11 2023 -0400 flow, hash, stream: add a free list node count that is output as a peg count commit 47a20ab19a85ac3a33787c5ab53a30d15c1208d9 Author: Ron Dempster (rdempste) Date: Wed Apr 19 13:05:52 2023 -0400 memory: fix memory pruning race condition and bail on reap failure --- diff --git a/src/flow/flow_cache.cc b/src/flow/flow_cache.cc index 22460ebb7..238cd49c3 100644 --- a/src/flow/flow_cache.cc +++ b/src/flow/flow_cache.cc @@ -560,3 +560,8 @@ size_t FlowCache::flows_size() const { return hash_table->get_num_nodes(); } + +size_t FlowCache::free_flows_size() const +{ + return hash_table->get_num_free_nodes(); +} diff --git a/src/flow/flow_cache.h b/src/flow/flow_cache.h index a3eb84c6d..0c725c42b 100644 --- a/src/flow/flow_cache.h +++ b/src/flow/flow_cache.h @@ -104,6 +104,7 @@ public: size_t uni_flows_size() const; size_t uni_ip_flows_size() const; size_t flows_size() const; + size_t free_flows_size() const; private: void delete_uni(); diff --git a/src/flow/flow_control.cc b/src/flow/flow_control.cc index ede057017..77e898ae9 100644 --- a/src/flow/flow_control.cc +++ b/src/flow/flow_control.cc @@ -88,6 +88,9 @@ PegCount FlowControl::get_uni_ip_flows() const PegCount FlowControl::get_num_flows() const { return cache->flows_size(); } +PegCount FlowControl::get_num_free_flows() const +{ return cache->free_flows_size(); } + //------------------------------------------------------------------------- // cache foo diff --git a/src/flow/flow_control.h b/src/flow/flow_control.h index 500d9f5a8..fbe9a3f5c 100644 --- a/src/flow/flow_control.h +++ b/src/flow/flow_control.h @@ -98,6 +98,7 @@ public: PegCount get_uni_flows() const; PegCount get_uni_ip_flows() const; PegCount get_num_flows() const; + PegCount get_num_free_flows() const; private: void set_key(snort::FlowKey*, snort::Packet*); diff --git a/src/flow/test/flow_control_test.cc b/src/flow/test/flow_control_test.cc index 8d4bcba57..e00c02de2 100644 --- a/src/flow/test/flow_control_test.cc +++ b/src/flow/test/flow_control_test.cc @@ -85,6 +85,7 @@ unsigned FlowCache::timeout(unsigned, time_t) { return 1; } size_t FlowCache::uni_flows_size() const { return 0; } size_t FlowCache::uni_ip_flows_size() const { return 0; } size_t FlowCache::flows_size() const { return 0; } +size_t FlowCache::free_flows_size() const { return 0; } void Flow::init(PktType) { } void DataBus::publish(unsigned, unsigned, DataEvent&, Flow*) { } void DataBus::publish(unsigned, unsigned, const uint8_t*, unsigned, Flow*) { } diff --git a/src/hash/test/zhash_test.cc b/src/hash/test/zhash_test.cc index 6f590d794..25bad2d5f 100644 --- a/src/hash/test/zhash_test.cc +++ b/src/hash/test/zhash_test.cc @@ -108,16 +108,22 @@ TEST(zhash, create_zhash_test) zh->push(data); } + UNSIGNED_LONGS_EQUAL(0, zh->get_num_nodes()); + UNSIGNED_LONGS_EQUAL(MAX_ZHASH_NODES, zh->get_num_free_nodes()); + std::string key_prefix = "foo"; for (unsigned i = 0; i < MAX_ZHASH_NODES; i++ ) - { + { std::string key; key = key_prefix + std::to_string(i + 1); memcpy(key_buf, key.c_str(), key.size()); unsigned* data = (unsigned*)zh->get(key_buf); CHECK(*data == 0); *data = i + 1; - } + } + + UNSIGNED_LONGS_EQUAL(MAX_ZHASH_NODES, zh->get_num_nodes()); + UNSIGNED_LONGS_EQUAL(0, zh->get_num_free_nodes()); unsigned nodes_walked = 0; unsigned* data = (unsigned*)zh->lru_first(); diff --git a/src/hash/xhash.cc b/src/hash/xhash.cc index 00373b294..654de28be 100644 --- a/src/hash/xhash.cc +++ b/src/hash/xhash.cc @@ -427,6 +427,7 @@ void XHash::save_free_node(HashNode* hnode) hnode->gnext = nullptr; fhead = hnode; } + ++num_free_nodes; } HashNode* XHash::get_free_node() @@ -437,6 +438,7 @@ HashNode* XHash::get_free_node() fhead = fhead->gnext; if ( fhead ) fhead->gprev = nullptr; + --num_free_nodes; } return node; @@ -464,6 +466,7 @@ void XHash::purge_free_list() } fhead = nullptr; + num_free_nodes = 0; } void XHash::clear_hash() diff --git a/src/hash/xhash.h b/src/hash/xhash.h index 94fa86133..f823e3171 100644 --- a/src/hash/xhash.h +++ b/src/hash/xhash.h @@ -74,6 +74,9 @@ public: unsigned get_num_nodes() { return num_nodes; } + unsigned get_num_free_nodes() + { return num_free_nodes; } + void set_memcap(unsigned long memcap) { mem_allocator->set_mem_capacity(memcap); } @@ -113,6 +116,7 @@ protected: unsigned nrows = 0; unsigned keysize = 0; unsigned num_nodes = 0; + unsigned num_free_nodes = 0; bool recycle_nodes = true; bool anr_enabled = true; diff --git a/src/memory/memory_cap.cc b/src/memory/memory_cap.cc index bce614850..ad3d8a647 100644 --- a/src/memory/memory_cap.cc +++ b/src/memory/memory_cap.cc @@ -56,10 +56,9 @@ static std::vector pkt_mem_stats; static MemoryConfig config; static size_t limit = 0; -static std::atomic over_limit { false }; +static bool over_limit = false; static std::atomic current_epoch { 0 }; -static THREAD_LOCAL uint64_t last_dealloc = 0; static THREAD_LOCAL uint64_t start_dealloc = 0; static THREAD_LOCAL uint64_t start_alloc = 0; static THREAD_LOCAL uint64_t start_epoch = 0; @@ -72,13 +71,15 @@ static void epoch_check(void*) uint64_t epoch, total; heap->get_process_total(epoch, total); - current_epoch = epoch; - bool prior = over_limit; over_limit = limit and total > limit; if ( prior != over_limit ) trace_logf(memory_trace, nullptr, "Epoch=%lu, memory=%lu (%s)\n", epoch, total, over_limit?"over":"under"); + if ( over_limit ) + current_epoch = epoch; + else + current_epoch = 0; MemoryCounts& mc = MemoryCap::get_mem_stats(); @@ -221,37 +222,73 @@ void MemoryCap::free_space() MemoryCounts& mc = get_mem_stats(); heap->get_thread_allocs(mc.allocated, mc.deallocated); - if ( !over_limit and !start_dealloc ) - return; - + // Not already pruning if ( !start_dealloc ) { + // Not over the limit + if ( !current_epoch ) + return; + // Already completed pruning in the epoch if ( current_epoch == start_epoch ) return; - start_dealloc = last_dealloc = mc.deallocated; + // Start pruning for this epoch + start_dealloc = mc.deallocated; start_alloc = mc.allocated; start_epoch = current_epoch; mc.reap_cycles++; } - mc.pruned += (mc.deallocated - last_dealloc); - last_dealloc = mc.deallocated; - - uint64_t alloc = mc.allocated - start_alloc; uint64_t dealloc = mc.deallocated - start_dealloc; - if ( dealloc > alloc and ( ( dealloc - alloc ) >= config.prune_target ) ) + uint64_t alloc = mc.allocated - start_alloc; + + // Has the process gone under the limit + if ( !current_epoch ) + { + if ( dealloc > alloc) + mc.reap_decrease += dealloc - alloc; + else + mc.reap_increase += alloc - dealloc; + start_dealloc = 0; + mc.reap_aborts++; + return; + } + // Has this thread freed enough outside of pruning + else if ( dealloc > alloc and ( ( dealloc - alloc ) >= config.prune_target ) ) { + mc.reap_decrease += dealloc - alloc; start_dealloc = 0; return; } ++mc.reap_attempts; - if ( pruner() ) - return; + bool prune_success = pruner(); - ++mc.reap_failures; + // Updates values after pruning + heap->get_thread_allocs(mc.allocated, mc.deallocated); + alloc = mc.allocated - start_alloc; + dealloc = mc.deallocated - start_dealloc; + + if ( prune_success ) + { + // Pruned the target amount, so stop pruning for this epoch + if ( dealloc > alloc and ( ( dealloc - alloc ) >= config.prune_target ) ) + { + mc.reap_decrease += dealloc - alloc; + start_dealloc = 0; + } + } + else + { + // Failed to prune, so stop pruning + if ( dealloc > alloc) + mc.reap_decrease += dealloc - alloc; + else + mc.reap_increase += alloc - dealloc; + start_dealloc = 0; + ++mc.reap_failures; + } } // required to capture any update in final epoch diff --git a/src/memory/memory_cap.h b/src/memory/memory_cap.h index cef9963ce..1d03dee12 100644 --- a/src/memory/memory_cap.h +++ b/src/memory/memory_cap.h @@ -45,7 +45,9 @@ struct MemoryCounts PegCount reap_cycles; PegCount reap_attempts; PegCount reap_failures; - PegCount pruned; + PegCount reap_aborts; + PegCount reap_decrease; + PegCount reap_increase; }; typedef bool (*PruneHandler)(); diff --git a/src/memory/memory_module.cc b/src/memory/memory_module.cc index d3c55890e..b364a846f 100644 --- a/src/memory/memory_module.cc +++ b/src/memory/memory_module.cc @@ -70,7 +70,9 @@ const PegInfo mem_pegs[] = { CountType::NOW, "reap_cycles", "number of actionable over-limit conditions" }, { CountType::NOW, "reap_attempts", "attempts to reclaim memory" }, { CountType::NOW, "reap_failures", "failures to reclaim memory" }, - { CountType::NOW, "pruned", "total amount of memory pruned" }, + { CountType::NOW, "reap_aborts", "abort pruning before target due to process under limit" }, + { CountType::NOW, "reap_decrease", "total amount of the decrease in thread memory while process over limit" }, + { CountType::NOW, "reap_increase", "total amount of the increase in thread memory while process over limit" }, { CountType::END, nullptr, nullptr } }; diff --git a/src/memory/test/memory_cap_test.cc b/src/memory/test/memory_cap_test.cc index 35f5ad8f8..839726781 100644 --- a/src/memory/test/memory_cap_test.cc +++ b/src/memory/test/memory_cap_test.cc @@ -36,6 +36,7 @@ using namespace snort; #include #include +#include using namespace memory; @@ -92,10 +93,21 @@ public: static void periodic_check() { MemoryCap::test_main_check(); } -static int flows; +struct TestFlowData +{ + int flows = 0; + unsigned flow_to_alloc_factor = 1; +}; static bool pruner() -{ return --flows >= 0; } +{ + MockHeap* heap = (MockHeap*)mock().getData("heap").getObjectPointer(); + TestFlowData* fd = (TestFlowData*)mock().getData("flows").getObjectPointer(); + if ( heap && 0 < fd->flows) + heap->dealloc += fd->flow_to_alloc_factor; + fd->flows--; + return fd->flows >= 0; +} static bool pkt_thread = false; @@ -120,8 +132,13 @@ static void free_space() TEST_GROUP(memory_off) { + TestFlowData fd; + void setup() override { + fd = {}; + mock().setDataObject("flows", "TestFlowData", &fd); + mock().setDataObject("heap", "MockHeap", nullptr); MemoryCap::init(1); MemoryCap::set_pruner(pruner); } @@ -129,7 +146,6 @@ TEST_GROUP(memory_off) void teardown() override { MemoryCap::term(); - flows = 0; } }; @@ -140,7 +156,7 @@ TEST(memory_off, disabled) free_space(); - CHECK(flows == 0); + CHECK(fd.flows == 0); const MemoryCounts& mc = MemoryCap::get_mem_stats(); CHECK(mc.start_up_use == 0); @@ -157,7 +173,7 @@ TEST(memory_off, nerfed) free_space(); - CHECK(flows == 0); + CHECK(fd.flows == 0); const MemoryCounts& mc = MemoryCap::get_mem_stats(); CHECK(mc.start_up_use == 0); @@ -173,20 +189,22 @@ TEST(memory_off, nerfed) TEST_GROUP(memory) { + TestFlowData fd; MockHeap* heap = nullptr; void setup() override { + fd = {0, 1}; + mock().setDataObject("flows", "TestFlowData", &fd); MemoryCap::init(1); heap = new MockHeap; MemoryCap::set_heap_interface(heap); + mock().setDataObject("heap", "MockHeap", heap); } void teardown() override { MemoryCap::term(); - heap = nullptr; - flows = 0; } }; @@ -205,7 +223,7 @@ TEST(memory, default_enabled) periodic_check(); CHECK(heap->epoch == 2); - CHECK(flows == 0); + CHECK(fd.flows == 0); MemoryCap::stop(); CHECK(heap->epoch == 3); @@ -217,51 +235,97 @@ TEST(memory, prune1) const uint64_t start = 50; heap->total = start; - MemoryConfig config { cap, 100, 0, 1, true }; + MemoryConfig config { cap, 100, 0, 2, true }; MemoryCap::start(config, pruner); MemoryCap::thread_init(); const MemoryCounts& mc = MemoryCap::get_mem_stats(); CHECK(mc.start_up_use == start); - flows = 2; + fd.flows = 3; free_space(); - CHECK(flows == 2); + UNSIGNED_LONGS_EQUAL(3, fd.flows); - heap->total = cap + 1; + heap->total = cap + 1; // over the limit periodic_check(); CHECK(heap->epoch == 2); - CHECK(flows == 2); + UNSIGNED_LONGS_EQUAL(3, fd.flows); + free_space(); // this prunes 1 + UNSIGNED_LONGS_EQUAL(2, fd.flows); + + free_space(); // finish pruning + UNSIGNED_LONGS_EQUAL(1, fd.flows); + UNSIGNED_LONGS_EQUAL(2, mc.reap_decrease); + free_space(); - CHECK(flows == 1); + UNSIGNED_LONGS_EQUAL(1, fd.flows); + UNSIGNED_LONGS_EQUAL(2, mc.reap_decrease); - heap->total = cap; - periodic_check(); + periodic_check(); // still over the limit CHECK(heap->epoch == 3); - heap->alloc++; - heap->dealloc++; + free_space(); + UNSIGNED_LONGS_EQUAL(0, fd.flows); + + heap->total = cap; // no longer over the limit + periodic_check(); + CHECK(heap->epoch == 4); + + free_space(); // abort + UNSIGNED_LONGS_EQUAL(0, fd.flows); + UNSIGNED_LONGS_EQUAL(3, mc.reap_decrease); + heap->total = cap + 1; // over the limit + periodic_check(); + CHECK(heap->epoch == 5); + + fd.flows = 1; free_space(); - CHECK(flows == 0); + UNSIGNED_LONGS_EQUAL(0, fd.flows); - heap->dealloc++; + heap->total = cap; // no longer over the limit + periodic_check(); + CHECK(heap->epoch == 6); + + heap->alloc += 5; + + free_space(); // abort, reap_increase update + UNSIGNED_LONGS_EQUAL(0, fd.flows); + UNSIGNED_LONGS_EQUAL(3, mc.reap_decrease); + UNSIGNED_LONGS_EQUAL(4, mc.reap_increase); + + heap->total = cap + 1; // over the limit + periodic_check(); + CHECK(heap->epoch == 7); + + fd.flows = 1; free_space(); - CHECK(flows == 0); + UNSIGNED_LONGS_EQUAL(0, fd.flows); - CHECK(mc.start_up_use == start); - CHECK(mc.max_in_use == cap + 1); - CHECK(mc.cur_in_use == cap); + heap->total = cap; // no longer over the limit + periodic_check(); + CHECK(heap->epoch == 8); - CHECK(mc.epochs == heap->epoch); - CHECK(mc.allocated == heap->alloc); - CHECK(mc.deallocated == heap->dealloc); + heap->alloc += 3; + + free_space(); // abort, reap_increase update + UNSIGNED_LONGS_EQUAL(0, fd.flows); + UNSIGNED_LONGS_EQUAL(3, mc.reap_decrease); + UNSIGNED_LONGS_EQUAL(6, mc.reap_increase); - CHECK(mc.reap_cycles == 1); - CHECK(mc.reap_attempts == 2); - CHECK(mc.reap_failures == 0); - CHECK(mc.pruned == 2); + UNSIGNED_LONGS_EQUAL(start, mc.start_up_use); + UNSIGNED_LONGS_EQUAL(cap + 1, mc.max_in_use); + UNSIGNED_LONGS_EQUAL(cap, mc.cur_in_use); + + UNSIGNED_LONGS_EQUAL(heap->epoch, mc.epochs); + UNSIGNED_LONGS_EQUAL(heap->alloc, mc.allocated); + UNSIGNED_LONGS_EQUAL(heap->dealloc, mc.deallocated); + + UNSIGNED_LONGS_EQUAL(4, mc.reap_cycles); + UNSIGNED_LONGS_EQUAL(5, mc.reap_attempts); + UNSIGNED_LONGS_EQUAL(0, mc.reap_failures); + UNSIGNED_LONGS_EQUAL(3, mc.reap_aborts); heap->total = start; MemoryCap::stop(); @@ -276,35 +340,37 @@ TEST(memory, prune3) MemoryCap::start(config, pruner); MemoryCap::thread_init(); - flows = 3; + fd.flows = 3; + fd.flow_to_alloc_factor = 0; heap->total = cap + 1; periodic_check(); CHECK(heap->epoch == 2); - CHECK(flows == 3); + CHECK(fd.flows == 3); free_space(); - CHECK(flows == 2); + CHECK(fd.flows == 2); free_space(); - CHECK(flows == 1); + CHECK(fd.flows == 1); + fd.flow_to_alloc_factor = 1; free_space(); - CHECK(flows == 0); + CHECK(fd.flows == 0); heap->total = cap; periodic_check(); CHECK(heap->epoch == 3); - heap->dealloc++; free_space(); - CHECK(flows == 0); + CHECK(fd.flows == 0); const MemoryCounts& mc = MemoryCap::get_mem_stats(); - CHECK(mc.reap_cycles == 1); - CHECK(mc.reap_attempts == 3); - CHECK(mc.reap_failures == 0); - CHECK(mc.pruned == 1); + UNSIGNED_LONGS_EQUAL(1, mc.reap_cycles); + UNSIGNED_LONGS_EQUAL(3, mc.reap_attempts); + UNSIGNED_LONGS_EQUAL(0, mc.reap_failures); + UNSIGNED_LONGS_EQUAL(1, mc.reap_decrease); + UNSIGNED_LONGS_EQUAL(0, mc.reap_increase); MemoryCap::stop(); } @@ -316,43 +382,37 @@ TEST(memory, two_cycles) MemoryCap::start(config, pruner); MemoryCap::thread_init(); - flows = 3; + fd.flows = 3; heap->total = cap + 1; periodic_check(); - CHECK(flows == 3); - free_space(); // prune 1 flow - CHECK(flows == 2); - - heap->dealloc++; - free_space(); // reset state - CHECK(flows == 2); + CHECK(fd.flows == 3); + free_space(); // prune 1 flow and stop pruning from target + CHECK(fd.flows == 2); - free_space(); // at most 1 reap cycle per epoch - CHECK(flows == 2); + free_space(); + CHECK(fd.flows == 2); heap->total = cap; periodic_check(); free_space(); - CHECK(flows == 2); + CHECK(fd.flows == 2); - heap->total = cap + 10; + fd.flow_to_alloc_factor = 10; + heap->total = cap + 1; periodic_check(); free_space(); - CHECK(flows == 1); - - heap->total = cap; - heap->dealloc += 10; - periodic_check(); + CHECK(fd.flows == 1); free_space(); - CHECK(flows == 1); + CHECK(fd.flows == 1); const MemoryCounts& mc = MemoryCap::get_mem_stats(); - CHECK(mc.reap_cycles == 2); - CHECK(mc.reap_attempts == 2); - CHECK(mc.reap_failures == 0); - CHECK(mc.pruned == 11); + UNSIGNED_LONGS_EQUAL(2, mc.reap_cycles); + UNSIGNED_LONGS_EQUAL(2, mc.reap_attempts); + UNSIGNED_LONGS_EQUAL(0, mc.reap_failures); + UNSIGNED_LONGS_EQUAL(11, mc.reap_decrease); + UNSIGNED_LONGS_EQUAL(0, mc.reap_increase); MemoryCap::stop(); } @@ -367,24 +427,89 @@ TEST(memory, reap_failure) MemoryCap::start(config, pruner); MemoryCap::thread_init(); - flows = 1; + const MemoryCounts& mc = MemoryCap::get_mem_stats(); + + fd.flows = 1; + heap->total = cap + 1; + periodic_check(); + + free_space(); + CHECK(fd.flows == 0); + + free_space(); // reap failure + CHECK(fd.flows == -1); + UNSIGNED_LONGS_EQUAL(1, mc.reap_decrease); + + fd.flows = 1; + heap->total = cap + 1; + periodic_check(); + + free_space(); + CHECK(fd.flows == 0); + + heap->alloc += 3; + + free_space(); // reap failure, reap_increase update + CHECK(fd.flows == -1); + UNSIGNED_LONGS_EQUAL(1, mc.reap_decrease); + UNSIGNED_LONGS_EQUAL(2, mc.reap_increase); + + fd.flows = 1; + heap->total = cap + 1; + periodic_check(); + + free_space(); + CHECK(fd.flows == 0); + + heap->alloc += 2; + + free_space(); // reap failure, reap_increase update + CHECK(fd.flows == -1); + UNSIGNED_LONGS_EQUAL(1, mc.reap_decrease); + UNSIGNED_LONGS_EQUAL(3, mc.reap_increase); + + UNSIGNED_LONGS_EQUAL(3, mc.reap_cycles); + UNSIGNED_LONGS_EQUAL(6, mc.reap_attempts); + UNSIGNED_LONGS_EQUAL(3, mc.reap_failures); + + MemoryCap::stop(); +} + +TEST(memory, reap_freed_outside_of_pruning) +{ + const uint64_t cap = 100; + const uint64_t start = 50; + heap->total = start; + + MemoryConfig config { cap, 100, 0, 2, true }; + MemoryCap::start(config, pruner); + MemoryCap::thread_init(); + + fd.flows = 2; heap->total = cap + 1; periodic_check(); - CHECK(flows == 1); + UNSIGNED_LONGS_EQUAL(2, fd.flows); free_space(); - CHECK(flows == 0); + UNSIGNED_LONGS_EQUAL(1, fd.flows); + + heap->alloc++; + + free_space(); + UNSIGNED_LONGS_EQUAL(0, fd.flows); heap->dealloc++; + free_space(); - CHECK(flows == -1); + UNSIGNED_LONGS_EQUAL(0, fd.flows); const MemoryCounts& mc = MemoryCap::get_mem_stats(); - CHECK(mc.reap_cycles == 1); - CHECK(mc.reap_attempts == 2); - CHECK(mc.reap_failures == 1); - CHECK(mc.pruned == 1); + UNSIGNED_LONGS_EQUAL(1, mc.reap_cycles); + UNSIGNED_LONGS_EQUAL(2, mc.reap_attempts); + UNSIGNED_LONGS_EQUAL(0, mc.reap_failures); + UNSIGNED_LONGS_EQUAL(2, mc.reap_decrease); + UNSIGNED_LONGS_EQUAL(0, mc.reap_increase); MemoryCap::stop(); } diff --git a/src/stream/base/stream_base.cc b/src/stream/base/stream_base.cc index 15abe460f..0f12ff7e3 100644 --- a/src/stream/base/stream_base.cc +++ b/src/stream/base/stream_base.cc @@ -58,6 +58,7 @@ static std::mutex crash_dump_flow_control_mutex; static BaseStats g_stats; THREAD_LOCAL BaseStats stream_base_stats; THREAD_LOCAL PegCount current_flows_prev; +THREAD_LOCAL PegCount current_free_flows_prev; THREAD_LOCAL PegCount uni_flows_prev; THREAD_LOCAL PegCount uni_ip_flows_prev; @@ -87,12 +88,13 @@ const PegInfo base_pegs[] = // Keep the NOW stats at the bottom as it requires special sum_stats logic { CountType::NOW, "current_flows", "current number of flows in cache" }, + { CountType::NOW, "current_free_flows", "current number of free flows in cache" }, { CountType::NOW, "uni_flows", "number of uni flows in cache" }, { CountType::NOW, "uni_ip_flows", "number of uni ip flows in cache" }, { CountType::END, nullptr, nullptr } }; -#define NOW_PEGS_NUM 3 +#define NOW_PEGS_NUM 4 // FIXIT-L dependency on stats define in another file void base_prep() @@ -114,6 +116,7 @@ void base_prep() stream_base_stats.reload_blocked_flow_deletes= flow_con->get_deletes(FlowDeleteState::BLOCKED); stream_base_stats.current_flows = flow_con->get_num_flows(); + stream_base_stats.current_free_flows = flow_con->get_num_free_flows(); stream_base_stats.uni_flows = flow_con->get_uni_flows(); stream_base_stats.uni_ip_flows = flow_con->get_uni_ip_flows(); @@ -134,6 +137,7 @@ void base_sum() array_size(base_pegs) - 1 - NOW_PEGS_NUM); g_stats.current_flows += (int64_t)stream_base_stats.current_flows - (int64_t)current_flows_prev; + g_stats.current_free_flows += (int64_t)stream_base_stats.current_free_flows - (int64_t)current_free_flows_prev; g_stats.uni_flows += (int64_t)stream_base_stats.uni_flows - (int64_t)uni_flows_prev; g_stats.uni_ip_flows += (int64_t)stream_base_stats.uni_ip_flows - (int64_t)uni_ip_flows_prev; @@ -148,6 +152,7 @@ void base_stats() void base_reset(bool reset_all) { current_flows_prev = stream_base_stats.current_flows; + current_free_flows_prev = stream_base_stats.current_free_flows; uni_flows_prev = stream_base_stats.uni_flows; uni_ip_flows_prev = stream_base_stats.uni_ip_flows; diff --git a/src/stream/base/stream_module.h b/src/stream/base/stream_module.h index 96a8f6e19..58e73c5cc 100644 --- a/src/stream/base/stream_module.h +++ b/src/stream/base/stream_module.h @@ -77,6 +77,7 @@ struct BaseStats // Keep the NOW stats at the bottom as it requires special sum_stats logic PegCount current_flows; + PegCount current_free_flows; PegCount uni_flows; PegCount uni_ip_flows;