diff --git a/src/box/lua/slab.cc b/src/box/lua/slab.cc index 131cd2344364ec3015639530627d7a12e1b7c07a..de50dba4fc7054e22b4dcd69d524687dc5a64557 100644 --- a/src/box/lua/slab.cc +++ b/src/box/lua/slab.cc @@ -36,6 +36,7 @@ extern "C" { } /* extern "C" */ #include "box/tuple.h" +#include "box/memtx_engine.h" #include "small/small.h" #include "small/quota.h" #include "memory.h" @@ -43,6 +44,12 @@ extern "C" { /** A callback passed into salloc_stat() and invoked for every slab class. */ extern "C" { +static int +small_stats_noop_cb(const struct mempool_stats * /* stats */, void * /* cb_ctx */) +{ + return 0; +} + static int small_stats_lua_cb(const struct mempool_stats *stats, void *cb_ctx) { @@ -95,40 +102,96 @@ small_stats_lua_cb(const struct mempool_stats *stats, void *cb_ctx) } /* extern "C" */ +static int +lbox_slab_stats(struct lua_State *L) +{ + struct small_stats totals; + lua_newtable(L); + /* + * List all slabs used for tuples and slabs used for + * indexes, with their stats. + */ + small_stats(&memtx_alloc, &totals, small_stats_lua_cb, L); + struct mempool_stats index_stats; + mempool_stats(&memtx_index_extent_pool, &index_stats); + small_stats_lua_cb(&index_stats, L); + + return 1; +} + + static int lbox_slab_info(struct lua_State *L) { struct small_stats totals; + /* + * List all slabs used for tuples and slabs used for + * indexes, with their stats. + */ lua_newtable(L); - lua_pushstring(L, "slabs"); - lua_newtable(L); - small_stats(&memtx_alloc, &totals, small_stats_lua_cb, L); + small_stats(&memtx_alloc, &totals, small_stats_noop_cb, L); + struct mempool_stats index_stats; + mempool_stats(&memtx_index_extent_pool, &index_stats); + + struct slab_arena *tuple_arena = memtx_alloc.cache->arena; + struct quota *memtx_quota = tuple_arena->quota; + double ratio; + char ratio_buf[32]; + + ratio = 100 * ((double) totals.used + / ((double) totals.total + 0.0001)); + snprintf(ratio_buf, sizeof(ratio_buf), "%0.1lf%%", ratio); + + /* + * Fragmentation factor for tuples. Don't account indexes, + * even if they are fragmented, there is nothing people + * can do about it. + */ + lua_pushstring(L, "items_used_ratio"); + lua_pushstring(L, ratio_buf); lua_settable(L, -3); + /** How much address space has been already touched */ + lua_pushstring(L, "arena_size"); + luaL_pushuint64(L, totals.total + index_stats.totals.total); + lua_settable(L, -3); + /** + * How much of this formatted address space is used for + * actual data. + */ lua_pushstring(L, "arena_used"); - luaL_pushuint64(L, totals.used); + luaL_pushuint64(L, totals.used + index_stats.totals.used); lua_settable(L, -3); - lua_pushstring(L, "arena_size"); - luaL_pushuint64(L, totals.total); + /* + * This is pretty much the same as + * box.cfg.slab_alloc_arena, but in bytes + */ + lua_pushstring(L, "quota_size"); + luaL_pushuint64(L, quota_total(memtx_quota)); lua_settable(L, -3); - char value[32]; - double items_used_ratio = 100 - * ((double)totals.used) - / ((double)memtx_alloc.cache->arena->prealloc + 0.0001); - snprintf(value, sizeof(value), "%0.1lf%%", items_used_ratio); - lua_pushstring(L, "items_used_ratio"); - lua_pushstring(L, value); + /* + * How much quota has been booked - reflects the total + * size of slabs in various slab caches. + */ + lua_pushstring(L, "quota_used"); + luaL_pushuint64(L, quota_used(memtx_quota)); lua_settable(L, -3); - double arena_used_ratio = 100 - * ((double)memtx_alloc.cache->arena->used) - / ((double)memtx_alloc.cache->arena->prealloc + 0.0001); - snprintf(value, sizeof(value), "%0.1lf%%", arena_used_ratio); + /** + * This should be the same as arena_size/arena_used, however, + * don't trust totals in the most important monitoring + * factor, it's the quota that give you OOM error in the + * end of the day. + */ + ratio = 100 * ((double) quota_used(memtx_quota) / + ((double) quota_total(memtx_quota) + 0.0001)); + snprintf(ratio_buf, sizeof(ratio_buf), "%0.1lf%%", ratio); + lua_pushstring(L, "arena_used_ratio"); - lua_pushstring(L, value); + lua_pushstring(L, ratio_buf); lua_settable(L, -3); return 1; @@ -144,7 +207,7 @@ lbox_runtime_info(struct lua_State *L) lua_settable(L, -3); lua_pushstring(L, "maxalloc"); - luaL_pushuint64(L, quota_get(runtime.quota)); + luaL_pushuint64(L, quota_total(runtime.quota)); lua_settable(L, -3); return 1; @@ -169,6 +232,10 @@ box_lua_slab_init(struct lua_State *L) lua_pushcfunction(L, lbox_slab_info); lua_settable(L, -3); + lua_pushstring(L, "stats"); + lua_pushcfunction(L, lbox_slab_stats); + lua_settable(L, -3); + lua_pushstring(L, "check"); lua_pushcfunction(L, lbox_slab_check); lua_settable(L, -3); diff --git a/src/box/memtx_engine.cc b/src/box/memtx_engine.cc index a825a23654f75e209c088671c330b2a061c92e87..9480314bd391e1be9a7542fe463595621df95b74 100644 --- a/src/box/memtx_engine.cc +++ b/src/box/memtx_engine.cc @@ -48,12 +48,17 @@ #include "errinj.h" #include "scoped_guard.h" -/** For all memory used by all indexes. */ +/** For all memory used by all indexes. + * If you decide to use memtx_index_arena or + * memtx_index_slab_cache for anything other than + * memtx_index_extent_pool, make sure this is reflected in + * box.slab.info(), @sa lua/slab.cc + */ extern struct quota memtx_quota; static bool memtx_index_arena_initialized = false; static struct slab_arena memtx_index_arena; -static struct slab_cache memtx_index_arena_slab_cache; -static struct mempool memtx_index_extent_pool; +static struct slab_cache memtx_index_slab_cache; +struct mempool memtx_index_extent_pool; /** * To ensure proper statement-level rollback in case * of out of memory conditions, we maintain a number @@ -896,10 +901,10 @@ memtx_index_arena_init() panic_syserror("failed to initialize index arena"); } /* Creating slab cache */ - slab_cache_create(&memtx_index_arena_slab_cache, &memtx_index_arena); + slab_cache_create(&memtx_index_slab_cache, &memtx_index_arena); /* Creating mempool */ mempool_create(&memtx_index_extent_pool, - &memtx_index_arena_slab_cache, + &memtx_index_slab_cache, MEMTX_EXTENT_SIZE); /* Empty reserved list */ memtx_index_num_reserved_extents = 0; diff --git a/src/box/memtx_engine.h b/src/box/memtx_engine.h index 7d823881500ab3efa6418a7893a7f88bf1ff3d15..d8438eed640016d893705be9b822a00343bb66a7 100644 --- a/src/box/memtx_engine.h +++ b/src/box/memtx_engine.h @@ -37,6 +37,9 @@ enum memtx_recovery_state { MEMTX_OK, }; +/** Memtx extents pool, available to statistics. */ +extern struct mempool memtx_index_extent_pool; + struct MemtxEngine: public Engine { MemtxEngine(); virtual Handler *open(); diff --git a/src/lib/small/quota.h b/src/lib/small/quota.h index 70ceb8407f90f6c7710002de7406d3910e1d459b..da5f23fc51d3270d9538e00a040a22a10feb690d 100644 --- a/src/lib/small/quota.h +++ b/src/lib/small/quota.h @@ -77,7 +77,7 @@ quota_init(struct quota *quota, size_t total) * Get current quota limit */ static inline size_t -quota_get(const struct quota *quota) +quota_total(const struct quota *quota) { return (quota->value >> 32) * QUOTA_UNIT_SIZE; } diff --git a/src/lib/small/slab_arena.c b/src/lib/small/slab_arena.c index a233e538fc0bde3f6a7605c710b1f483c6c15874..59ca29846b6180752c6dc584d14288eecc4229e1 100644 --- a/src/lib/small/slab_arena.c +++ b/src/lib/small/slab_arena.c @@ -132,7 +132,7 @@ slab_arena_create(struct slab_arena *arena, struct quota *quota, arena->quota = quota; /** Prealloc can not be greater than the quota */ - prealloc = MIN(prealloc, quota_get(quota)); + prealloc = MIN(prealloc, quota_total(quota)); /** Extremely large sizes can not be aligned properly */ prealloc = MIN(prealloc, SIZE_MAX - arena->slab_size); /* Align prealloc around a fixed number of slabs. */ diff --git a/test/box/admin.result b/test/box/admin.result index 18ae3194f84488a14a3866394d9d888acc5d6901..7a2e8cb1a9bb7a328582a40ac240b7a1305da304 100644 --- a/test/box/admin.result +++ b/test/box/admin.result @@ -118,24 +118,25 @@ end; ... function test_box_slab_info() local tmp = box.slab.info() + local tmp_slabs = box.slab.stats() local cdata = {'arena_size', 'arena_used'} local failed = {} - if type(tmp.slabs) == 'table' then - for name, tbl in ipairs(tmp.slabs) do + if type(tmp_slabs) == 'table' then + for name, tbl in ipairs(tmp_slabs) do local bl, fld = test_slab(tbl) if bl == true then tmp[name] = nil else for k, v in ipairs(fld) do - table.append(failed, v) + table.insert(failed, v) end end end else - table.append(failed, 'box.slab.info().slabs is not ok') + table.insert(failed, 'box.slab.info().slabs is not ok') end - if #tmp.slabs == 0 then - tmp.slabs = nil + if #tmp_slabs == 0 then + tmp_slabs = nil end for k, v in ipairs(cdata) do if check_type(tmp[v], 'number') == false then @@ -164,7 +165,7 @@ function test_fiber(tbl) if type(tbl.backtrace) == 'table' and #tbl.backtrace > 0 then tbl.backtrace = nil else - table.append(failed, 'backtrace') + table.insert(failed, 'backtrace') end if #tbl > 0 or #failed > 0 then return false, failed @@ -183,7 +184,7 @@ function test_box_fiber_info() tmp[name] = nil else for k, v in ipairs(fld) do - table.append(failed, v) + table.insert(failed, v) end end end diff --git a/test/box/admin.test.lua b/test/box/admin.test.lua index 22e7b76088d8989b60345834a87102b93c6e951e..f96fb808b37290903a591a9c765cc61779183c5c 100644 --- a/test/box/admin.test.lua +++ b/test/box/admin.test.lua @@ -72,24 +72,25 @@ end; function test_box_slab_info() local tmp = box.slab.info() + local tmp_slabs = box.slab.stats() local cdata = {'arena_size', 'arena_used'} local failed = {} - if type(tmp.slabs) == 'table' then - for name, tbl in ipairs(tmp.slabs) do + if type(tmp_slabs) == 'table' then + for name, tbl in ipairs(tmp_slabs) do local bl, fld = test_slab(tbl) if bl == true then tmp[name] = nil else for k, v in ipairs(fld) do - table.append(failed, v) + table.insert(failed, v) end end end else - table.append(failed, 'box.slab.info().slabs is not ok') + table.insert(failed, 'box.slab.info().slabs is not ok') end - if #tmp.slabs == 0 then - tmp.slabs = nil + if #tmp_slabs == 0 then + tmp_slabs = nil end for k, v in ipairs(cdata) do if check_type(tmp[v], 'number') == false then @@ -117,7 +118,7 @@ function test_fiber(tbl) if type(tbl.backtrace) == 'table' and #tbl.backtrace > 0 then tbl.backtrace = nil else - table.append(failed, 'backtrace') + table.insert(failed, 'backtrace') end if #tbl > 0 or #failed > 0 then return false, failed @@ -135,7 +136,7 @@ function test_box_fiber_info() tmp[name] = nil else for k, v in ipairs(fld) do - table.append(failed, v) + table.insert(failed, v) end end end diff --git a/test/box/misc.result b/test/box/misc.result index 23bd9464a229430e3239a6a39d1091818e96e1e2..8ff8f3bc9e42856884a49fbed898b9249ae78b28 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -190,7 +190,7 @@ box.slab.info().arena_size > 0; --- - true ... -string.match(tostring(box.slab.info().slabs), '^table:') ~= nil; +string.match(tostring(box.slab.stats()), '^table:') ~= nil; --- - true ... @@ -204,11 +204,12 @@ end; ... t; --- -- - arena_used_ratio +- - quota_used + - arena_used_ratio - items_used_ratio - - arena_used - arena_size - - slabs + - quota_size + - arena_used ... box.runtime.info().used > 0; --- diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua index 97602d056833a21f096b8379e8e86d96aff96bcc..daaf1f71774a7fcce067c455a0b1d50a97c1540d 100644 --- a/test/box/misc.test.lua +++ b/test/box/misc.test.lua @@ -71,7 +71,7 @@ t; string.match(tostring(box.slab.info()), '^table:') ~= nil; box.slab.info().arena_used >= 0; box.slab.info().arena_size > 0; -string.match(tostring(box.slab.info().slabs), '^table:') ~= nil; +string.match(tostring(box.slab.stats()), '^table:') ~= nil; t = {}; for k, v in pairs(box.slab.info()) do table.insert(t, k) diff --git a/test/unit/quota.cc b/test/unit/quota.cc index f1cf7ae3de4b074bd95e468f8b27af03a7bd5293..31c6d0a2de15ef3ec20b0ed098b30d2b2b72eb84 100644 --- a/test/unit/quota.cc +++ b/test/unit/quota.cc @@ -83,7 +83,7 @@ main(int n, char **a) long set_success_count = 0; long use_success_count = 0; for (size_t i = 0; i < THREAD_CNT; i++) { - if (datum[i].last_lim_set == quota_get("a)) + if (datum[i].last_lim_set == quota_total("a)) one_set_successed = true; total_alloc += datum[i].use_change; use_success_count += datum[i].use_change_success; diff --git a/test/unit/slab_arena.c b/test/unit/slab_arena.c index fe71bc713454bd8cd3041f79c2633d04dbb7b919..2f7a5b48d0f37a8f7b555d90049209caf010743e 100644 --- a/test/unit/slab_arena.c +++ b/test/unit/slab_arena.c @@ -11,7 +11,7 @@ slab_arena_print(struct slab_arena *arena) { printf("arena->prealloc = %zu\narena->maxalloc = %zu\n" "arena->used = %zu\narena->slab_size = %u\n", - arena->prealloc, quota_get(arena->quota), + arena->prealloc, quota_total(arena->quota), arena->used, arena->slab_size); }