@@ -44,6 +44,7 @@ static umf_result_t CTL_READ_HANDLER(name)(void *ctx,
4444 disjoint_pool_t * pool = (disjoint_pool_t * )ctx ;
4545
4646 if (arg == NULL ) {
47+ LOG_ERR ("arg is NULL" );
4748 return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
4849 }
4950
@@ -64,6 +65,7 @@ static umf_result_t CTL_WRITE_HANDLER(name)(void *ctx,
6465 (void )source , (void )indexes , (void )size ;
6566 disjoint_pool_t * pool = (disjoint_pool_t * )ctx ;
6667 if (arg == NULL ) {
68+ LOG_ERR ("arg is NULL" );
6769 return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
6870 }
6971
@@ -81,6 +83,7 @@ CTL_READ_HANDLER(used_memory)(void *ctx, umf_ctl_query_source_t source,
8183 disjoint_pool_t * pool = (disjoint_pool_t * )ctx ;
8284
8385 if (arg == NULL || size != sizeof (size_t )) {
86+ LOG_ERR ("arg is NULL or size is not sizeof(size_t)" );
8487 return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
8588 }
8689
@@ -119,6 +122,7 @@ CTL_READ_HANDLER(reserved_memory)(void *ctx, umf_ctl_query_source_t source,
119122 disjoint_pool_t * pool = (disjoint_pool_t * )ctx ;
120123
121124 if (arg == NULL || size != sizeof (size_t )) {
125+ LOG_ERR ("arg is NULL or size is not sizeof(size_t)" );
122126 return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
123127 }
124128
@@ -148,12 +152,178 @@ CTL_READ_HANDLER(reserved_memory)(void *ctx, umf_ctl_query_source_t source,
148152 return UMF_RESULT_SUCCESS ;
149153}
150154
151- static const umf_ctl_node_t CTL_NODE (stats )[] = {CTL_LEAF_RO (used_memory ),
152- CTL_LEAF_RO (reserved_memory )};
155+ static umf_result_t CTL_READ_HANDLER (count )(void * ctx ,
156+ umf_ctl_query_source_t source ,
157+ void * arg , size_t size ,
158+ umf_ctl_index_utlist_t * indexes ) {
159+ (void )source ;
160+
161+ disjoint_pool_t * pool = (disjoint_pool_t * )ctx ;
162+ if (arg == NULL || size != sizeof (size_t )) {
163+ LOG_ERR ("arg is NULL or size is not sizeof(size_t)" );
164+ return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
165+ }
166+
167+ if (* (size_t * )indexes -> arg != SIZE_MAX ) {
168+ LOG_ERR ("to read buckets count, you must call it without bucket id" );
169+ return UMF_RESULT_ERROR_INVALID_ARGUMENT ;
170+ }
171+
172+ assert (pool );
173+ * (size_t * )arg = pool -> buckets_num ;
174+
175+ return UMF_RESULT_SUCCESS ;
176+ }
177+
178+ #define DEFINE_STATS_HANDLER (NAME , MEMBER ) \
179+ static umf_result_t CTL_READ_HANDLER(NAME)( \
180+ void *ctx, umf_ctl_query_source_t source, void *arg, size_t size, \
181+ umf_ctl_index_utlist_t *indexes) { \
182+ (void)source; \
183+ (void)indexes; \
184+ disjoint_pool_t *pool = (disjoint_pool_t *)ctx; \
185+ \
186+ if (arg == NULL || size != sizeof(size_t)) { \
187+ LOG_ERR("arg is NULL or size is not sizeof(size_t)"); \
188+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
189+ } \
190+ \
191+ if (!pool->params.pool_trace) { \
192+ LOG_ERR("pool trace is disabled, cannot read " #NAME); \
193+ return UMF_RESULT_ERROR_NOT_SUPPORTED; \
194+ } \
195+ \
196+ size_t total = 0; \
197+ for (size_t i = 0; i < pool->buckets_num; ++i) { \
198+ bucket_t *bucket = pool->buckets[i]; \
199+ utils_mutex_lock(&bucket->bucket_lock); \
200+ total += bucket->MEMBER; \
201+ utils_mutex_unlock(&bucket->bucket_lock); \
202+ } \
203+ \
204+ *(size_t *)arg = total; \
205+ return UMF_RESULT_SUCCESS; \
206+ }
207+
208+ DEFINE_STATS_HANDLER (alloc_num , alloc_count )
209+ DEFINE_STATS_HANDLER (alloc_pool_num , alloc_pool_count )
210+ DEFINE_STATS_HANDLER (free_num , free_count )
211+ DEFINE_STATS_HANDLER (curr_slabs_in_use , curr_slabs_in_use )
212+ DEFINE_STATS_HANDLER (curr_slabs_in_pool , curr_slabs_in_pool )
213+ DEFINE_STATS_HANDLER (max_slabs_in_use , max_slabs_in_use )
214+ DEFINE_STATS_HANDLER (max_slabs_in_pool , max_slabs_in_pool )
215+
216+ static const umf_ctl_node_t CTL_NODE (stats )[] = {
217+ CTL_LEAF_RO (used_memory ), CTL_LEAF_RO (reserved_memory ),
218+ CTL_LEAF_RO (alloc_num ), CTL_LEAF_RO (alloc_pool_num ),
219+ CTL_LEAF_RO (free_num ), CTL_LEAF_RO (curr_slabs_in_use ),
220+ CTL_LEAF_RO (curr_slabs_in_pool ), CTL_LEAF_RO (max_slabs_in_use ),
221+ CTL_LEAF_RO (max_slabs_in_pool ), CTL_NODE_END ,
222+ };
223+
224+ #undef DEFINE_STATS_HANDLER
225+
226+ #ifdef UMF_DEVELOPER_MODE
227+ #define VALIDATE_BUCKETS_NAME (indexes ) \
228+ if (strcmp("buckets", indexes->name) != 0) { \
229+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
230+ }
231+ #else
232+ #define VALIDATE_BUCKETS_NAME (indexes ) \
233+ do { \
234+ } while (0);
235+ #endif
236+
237+ #define DEFINE_BUCKET_STATS_HANDLER (NAME , MEMBER ) \
238+ static umf_result_t CTL_READ_HANDLER(NAME, perBucket)( \
239+ void *ctx, umf_ctl_query_source_t source, void *arg, size_t size, \
240+ umf_ctl_index_utlist_t *indexes) { \
241+ (void)source; \
242+ \
243+ disjoint_pool_t *pool = (disjoint_pool_t *)ctx; \
244+ if (arg == NULL || size != sizeof(size_t)) { \
245+ LOG_ERR("arg is NULL or size is not sizeof(size_t)"); \
246+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
247+ } \
248+ \
249+ VALIDATE_BUCKETS_NAME(indexes); \
250+ if (strcmp(#MEMBER, "size") != 0 && !pool->params.pool_trace) { \
251+ LOG_ERR("pool trace is disabled, cannot read " #NAME); \
252+ return UMF_RESULT_ERROR_NOT_SUPPORTED; \
253+ } \
254+ \
255+ size_t idx; \
256+ idx = *(size_t *)indexes->arg; \
257+ \
258+ if (idx >= pool->buckets_num) { \
259+ LOG_ERR("bucket id %zu is out of range [0, %zu)", idx, \
260+ pool->buckets_num); \
261+ return UMF_RESULT_ERROR_INVALID_ARGUMENT; \
262+ } \
263+ \
264+ bucket_t *bucket = pool->buckets[idx]; \
265+ *(size_t *)arg = bucket->MEMBER; \
266+ \
267+ return UMF_RESULT_SUCCESS; \
268+ }
269+
270+ DEFINE_BUCKET_STATS_HANDLER (alloc_num , alloc_count )
271+ DEFINE_BUCKET_STATS_HANDLER (alloc_pool_num , alloc_pool_count )
272+ DEFINE_BUCKET_STATS_HANDLER (free_num , free_count )
273+ DEFINE_BUCKET_STATS_HANDLER (curr_slabs_in_use , curr_slabs_in_use )
274+ DEFINE_BUCKET_STATS_HANDLER (curr_slabs_in_pool , curr_slabs_in_pool )
275+ DEFINE_BUCKET_STATS_HANDLER (max_slabs_in_use , max_slabs_in_use )
276+ DEFINE_BUCKET_STATS_HANDLER (max_slabs_in_pool , max_slabs_in_pool )
277+
278+ static const umf_ctl_node_t CTL_NODE (stats , perBucket )[] = {
279+ CTL_LEAF_RO (alloc_num , perBucket ),
280+ CTL_LEAF_RO (alloc_pool_num , perBucket ),
281+ CTL_LEAF_RO (free_num , perBucket ),
282+ CTL_LEAF_RO (curr_slabs_in_use , perBucket ),
283+ CTL_LEAF_RO (curr_slabs_in_pool , perBucket ),
284+ CTL_LEAF_RO (max_slabs_in_use , perBucket ),
285+ CTL_LEAF_RO (max_slabs_in_pool , perBucket ),
286+ CTL_NODE_END ,
287+ };
288+
289+ // Not a counter; but it is read exactly like other per-bucket stats, so we can use macro.
290+ DEFINE_BUCKET_STATS_HANDLER (size , size )
291+
292+ #undef DEFINE_BUCKET_STATS_HANDLER
293+
294+ static const umf_ctl_node_t CTL_NODE (buckets )[] = {
295+ CTL_LEAF_RO (count ), CTL_LEAF_RO (size , perBucket ),
296+ CTL_CHILD (stats , perBucket ), CTL_NODE_END };
297+
298+ static int bucket_id_parser (const void * arg , void * dest , size_t dest_size ) {
299+ size_t * out = (size_t * )dest ;
300+ assert (out );
301+
302+ if (arg == NULL ) {
303+ * out = SIZE_MAX ;
304+ return 1 ; // node n
305+ }
306+
307+ int ret = ctl_arg_unsigned (arg , dest , dest_size );
308+ if (ret ) {
309+ * out = SIZE_MAX ;
310+ return 1 ;
311+ }
312+
313+ return 0 ;
314+ }
315+
316+ static const struct ctl_argument CTL_ARG (buckets ) = {
317+ sizeof (size_t ),
318+ {{0 , sizeof (size_t ), CTL_ARG_TYPE_UNSIGNED_LONG_LONG , bucket_id_parser },
319+ CTL_ARG_PARSER_END }};
153320
154321static void initialize_disjoint_ctl (void ) {
155322 CTL_REGISTER_MODULE (& disjoint_ctl_root , stats );
156- // CTL_REGISTER_MODULE(&disjoint_ctl_root, name);
323+ CTL_REGISTER_MODULE (& disjoint_ctl_root , buckets );
324+ // TODO: this is hack. Need some way to register module as node with argument
325+ disjoint_ctl_root .root [disjoint_ctl_root .first_free - 1 ].arg =
326+ & CTL_ARG (buckets );
157327}
158328
159329umf_result_t disjoint_pool_ctl (void * hPool ,
0 commit comments