Skip to content

Commit f9346fd

Browse files
committedMar 27, 2025·
add ctl to fixed provider
1 parent 2a7b9e6 commit f9346fd

8 files changed

+228
-108
lines changed
 

‎benchmark/benchmark_umf.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ struct provider_interface {
4444
if (state.thread_index() != 0) {
4545
return;
4646
}
47-
umfCtlExec("umf.provider.by_handle.stats.reset", provider, NULL);
47+
umfCtlExec("umf.provider.by_handle.stats.peak_memory.reset", provider,
48+
NULL);
4849
}
4950

5051
void postBench([[maybe_unused]] ::benchmark::State &state) {

‎src/ctl/ctl.c

+11-2
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ umf_result_t umfCtlSet(const char *name, void *ctx, void *arg) {
102102
}
103103

104104
umf_result_t umfCtlExec(const char *name, void *ctx, void *arg) {
105-
if (name == NULL || arg == NULL || ctx == NULL) {
105+
if (name == NULL || ctx == NULL) {
106106
return UMF_RESULT_ERROR_INVALID_ARGUMENT;
107107
}
108108
return ctl_query(NULL, ctx, CTL_QUERY_PROGRAMMATIC, name,
@@ -140,6 +140,7 @@ static const umf_ctl_node_t *ctl_find_node(const umf_ctl_node_t *nodes,
140140
* in the main ctl tree.
141141
*/
142142
while (node_name != NULL) {
143+
char *next_node = strtok_r(NULL, CTL_QUERY_NODE_SEPARATOR, &sptr);
143144
*name_offset = node_name - parse_str;
144145
if (n != NULL && n->type == CTL_NODE_SUBTREE) {
145146
// if a subtree occurs, the subtree handler should be called
@@ -168,6 +169,14 @@ static const umf_ctl_node_t *ctl_find_node(const umf_ctl_node_t *nodes,
168169
if (index_entry && n->type == CTL_NODE_INDEXED) {
169170
break;
170171
} else if (strcmp(n->name, node_name) == 0) {
172+
if (n->type == CTL_NODE_LEAF && next_node != NULL) {
173+
// this is not the last node in the query, so it couldn't be leaf
174+
continue;
175+
}
176+
if (n->type != CTL_NODE_LEAF && next_node == NULL) {
177+
// this is the last node in the query, so it must be a leaf
178+
continue;
179+
}
171180
break;
172181
}
173182
}
@@ -181,7 +190,7 @@ static const umf_ctl_node_t *ctl_find_node(const umf_ctl_node_t *nodes,
181190
}
182191

183192
nodes = n->children;
184-
node_name = strtok_r(NULL, CTL_QUERY_NODE_SEPARATOR, &sptr);
193+
node_name = next_node;
185194
}
186195

187196
umf_ba_global_free(parse_str);
+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright (C) 2025 Intel Corporation
3+
*
4+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
*/
7+
8+
#ifdef UMF_PROVIDER_CTL_STATS_IMPL_H
9+
#error This file should not be included more than once
10+
#else
11+
#define UMF_PROVIDER_CTL_STATS_IMPL_H 1
12+
13+
#ifndef CTL_PROVIDER_TYPE
14+
#error "CTL_PROVIDER_TYPE must be defined"
15+
#endif
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
#include "ctl/ctl.h"
22+
#include "utils/utils_assert.h"
23+
24+
static int CTL_READ_HANDLER(peak_memory)(void *ctx,
25+
umf_ctl_query_source_t source,
26+
void *arg,
27+
umf_ctl_index_utlist_t *indexes,
28+
const char *extra_name,
29+
umf_ctl_query_type_t query_type) {
30+
/* suppress unused-parameter errors */
31+
(void)source, (void)indexes, (void)extra_name, (void)query_type;
32+
33+
size_t *arg_out = arg;
34+
CTL_PROVIDER_TYPE *provider = (CTL_PROVIDER_TYPE *)ctx;
35+
utils_atomic_load_acquire_size_t(&provider->stats.peak_memory, arg_out);
36+
return 0;
37+
}
38+
39+
static int CTL_READ_HANDLER(allocated_memory)(void *ctx,
40+
umf_ctl_query_source_t source,
41+
void *arg,
42+
umf_ctl_index_utlist_t *indexes,
43+
const char *extra_name,
44+
umf_ctl_query_type_t query_type) {
45+
/* suppress unused-parameter errors */
46+
(void)source, (void)indexes, (void)extra_name, (void)query_type;
47+
48+
size_t *arg_out = arg;
49+
CTL_PROVIDER_TYPE *provider = (CTL_PROVIDER_TYPE *)ctx;
50+
utils_atomic_load_acquire_size_t(&provider->stats.allocated_memory,
51+
arg_out);
52+
return 0;
53+
}
54+
55+
static int CTL_RUNNABLE_HANDLER(reset)(void *ctx, umf_ctl_query_source_t source,
56+
void *arg,
57+
umf_ctl_index_utlist_t *indexes,
58+
const char *extra_name,
59+
umf_ctl_query_type_t query_type) {
60+
/* suppress unused-parameter errors */
61+
(void)source, (void)indexes, (void)arg, (void)extra_name, (void)query_type;
62+
63+
CTL_PROVIDER_TYPE *provider = (CTL_PROVIDER_TYPE *)ctx;
64+
size_t allocated;
65+
size_t current_peak;
66+
67+
utils_atomic_load_acquire_size_t(&provider->stats.peak_memory,
68+
&current_peak);
69+
do {
70+
utils_atomic_load_acquire_size_t(&provider->stats.allocated_memory,
71+
&allocated);
72+
} while (!utils_compare_exchange_size_t(&provider->stats.peak_memory,
73+
&current_peak, &allocated));
74+
75+
return 0;
76+
}
77+
78+
static const umf_ctl_node_t CTL_NODE(peak_memory)[] = {CTL_LEAF_RUNNABLE(reset),
79+
CTL_NODE_END};
80+
81+
static const umf_ctl_node_t CTL_NODE(stats)[] = {
82+
CTL_LEAF_RO(allocated_memory), CTL_LEAF_RO(peak_memory),
83+
CTL_CHILD(peak_memory), CTL_LEAF_RUNNABLE(reset), CTL_NODE_END};
84+
85+
static inline void provider_ctl_stats_alloc(CTL_PROVIDER_TYPE *provider,
86+
size_t size) {
87+
size_t allocated =
88+
utils_fetch_and_add_size_t(&provider->stats.allocated_memory, size) +
89+
size;
90+
91+
size_t peak;
92+
utils_atomic_load_acquire_size_t(&provider->stats.peak_memory, &peak);
93+
94+
// If the compare-exchange fails, 'peak' is updated to the current value
95+
// of peak_memory. We then re-check whether allocated is still greater than
96+
// the updated peak value.
97+
while (allocated > peak &&
98+
!utils_compare_exchange_size_t(&provider->stats.peak_memory, &peak,
99+
&allocated)) {
100+
;
101+
}
102+
}
103+
104+
static inline void provider_ctl_stats_free(CTL_PROVIDER_TYPE *provider,
105+
size_t size) {
106+
utils_fetch_and_sub_size_t(&provider->stats.allocated_memory, size);
107+
}
108+
109+
#ifdef __cplusplus
110+
}
111+
#endif
112+
#endif
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (C) 2025 Intel Corporation
3+
*
4+
* Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
5+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
*/
7+
8+
#ifndef UMF_PROVIDER_CTL_STATS_TYPE_H
9+
#define UMF_PROVIDER_CTL_STATS_TYPE_H 1
10+
11+
#include <stddef.h>
12+
13+
#ifdef __cplusplus
14+
extern "C" {
15+
#endif
16+
17+
typedef struct ctl_stats_t {
18+
size_t allocated_memory;
19+
size_t peak_memory;
20+
} ctl_stats_t;
21+
22+
#ifdef __cplusplus
23+
}
24+
#endif
25+
#endif

‎src/provider/provider_fixed_memory.c

+39-3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "base_alloc_global.h"
2121
#include "coarse.h"
2222
#include "libumf.h"
23+
#include "provider_ctl_stats_type.h"
2324
#include "utils_common.h"
2425
#include "utils_concurrency.h"
2526
#include "utils_log.h"
@@ -30,6 +31,7 @@ typedef struct fixed_memory_provider_t {
3031
void *base; // base address of memory
3132
size_t size; // size of the memory region
3233
coarse_t *coarse; // coarse library handle
34+
ctl_stats_t stats;
3335
} fixed_memory_provider_t;
3436

3537
// Fixed Memory provider settings struct
@@ -52,6 +54,17 @@ static __TLS fixed_last_native_error_t TLS_last_native_error;
5254
#define _UMF_FIXED_RESULT_ERROR_PURGE_FORCE_FAILED \
5355
(UMF_FIXED_RESULT_ERROR_PURGE_FORCE_FAILED - UMF_FIXED_RESULT_SUCCESS)
5456

57+
#define CTL_PROVIDER_TYPE fixed_memory_provider_t
58+
#include "provider_ctl_stats_impl.h"
59+
60+
struct ctl *fixed_memory_ctl_root;
61+
static UTIL_ONCE_FLAG ctl_initialized = UTIL_ONCE_FLAG_INIT;
62+
63+
static void initialize_fixed_ctl(void) {
64+
fixed_memory_ctl_root = ctl_new();
65+
CTL_REGISTER_MODULE(fixed_memory_ctl_root, stats);
66+
}
67+
5568
static const char *Native_error_str[] = {
5669
[_UMF_FIXED_RESULT_SUCCESS] = "success",
5770
[_UMF_FIXED_RESULT_ERROR_PURGE_FORCE_FAILED] = "force purging failed"};
@@ -153,7 +166,14 @@ static umf_result_t fixed_alloc(void *provider, size_t size, size_t alignment,
153166
fixed_memory_provider_t *fixed_provider =
154167
(fixed_memory_provider_t *)provider;
155168

156-
return coarse_alloc(fixed_provider->coarse, size, alignment, resultPtr);
169+
umf_result_t ret =
170+
coarse_alloc(fixed_provider->coarse, size, alignment, resultPtr);
171+
172+
if (ret == UMF_RESULT_SUCCESS) {
173+
provider_ctl_stats_alloc(fixed_provider, size);
174+
}
175+
176+
return ret;
157177
}
158178

159179
static void fixed_get_last_native_error(void *provider, const char **ppMessage,
@@ -250,7 +270,22 @@ static umf_result_t fixed_allocation_merge(void *provider, void *lowPtr,
250270
static umf_result_t fixed_free(void *provider, void *ptr, size_t size) {
251271
fixed_memory_provider_t *fixed_provider =
252272
(fixed_memory_provider_t *)provider;
253-
return coarse_free(fixed_provider->coarse, ptr, size);
273+
274+
umf_result_t ret = coarse_free(fixed_provider->coarse, ptr, size);
275+
276+
if (ret == UMF_RESULT_SUCCESS) {
277+
provider_ctl_stats_free(fixed_provider, size);
278+
}
279+
280+
return ret;
281+
}
282+
283+
static umf_result_t fixed_ctl(void *provider, int operationType,
284+
const char *name, void *arg,
285+
umf_ctl_query_type_t query_type) {
286+
utils_init_once(&ctl_initialized, initialize_fixed_ctl);
287+
return ctl_query(fixed_memory_ctl_root, provider, operationType, name,
288+
query_type, arg);
254289
}
255290

256291
static umf_memory_provider_ops_t UMF_FIXED_MEMORY_PROVIDER_OPS = {
@@ -271,7 +306,8 @@ static umf_memory_provider_ops_t UMF_FIXED_MEMORY_PROVIDER_OPS = {
271306
.ipc.get_ipc_handle = NULL,
272307
.ipc.put_ipc_handle = NULL,
273308
.ipc.open_ipc_handle = NULL,
274-
.ipc.close_ipc_handle = NULL};
309+
.ipc.close_ipc_handle = NULL,
310+
.ctl = fixed_ctl};
275311

276312
umf_memory_provider_ops_t *umfFixedMemoryProviderOps(void) {
277313
return &UMF_FIXED_MEMORY_PROVIDER_OPS;

‎src/provider/provider_os_memory.c

+7-98
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ umf_result_t umfOsMemoryProviderParamsSetPartitions(
102102
#include "utils_concurrency.h"
103103
#include "utils_log.h"
104104

105+
#define CTL_PROVIDER_TYPE os_memory_provider_t
106+
#include "provider_ctl_stats_impl.h"
107+
105108
#define NODESET_STR_BUF_LEN 1024
106109

107110
#define TLS_MSG_BUF_LEN 1024
@@ -189,70 +192,6 @@ static int CTL_READ_HANDLER(ipc_enabled)(void *ctx,
189192
return 0;
190193
}
191194

192-
static int CTL_READ_HANDLER(peak_memory)(void *ctx,
193-
umf_ctl_query_source_t source,
194-
void *arg,
195-
umf_ctl_index_utlist_t *indexes,
196-
const char *extra_name,
197-
umf_ctl_query_type_t query_type) {
198-
/* suppress unused-parameter errors */
199-
(void)source, (void)indexes, (void)ctx, (void)extra_name, (void)query_type;
200-
201-
size_t *arg_out = arg;
202-
os_memory_provider_t *os_provider = (os_memory_provider_t *)ctx;
203-
COMPILE_ERROR_ON(sizeof(os_provider->stats.peak_memory) !=
204-
sizeof(uint64_t));
205-
utils_atomic_load_acquire_u64((uint64_t *)&os_provider->stats.peak_memory,
206-
(uint64_t *)arg_out);
207-
return 0;
208-
}
209-
210-
static int CTL_READ_HANDLER(allocated_memory)(void *ctx,
211-
umf_ctl_query_source_t source,
212-
void *arg,
213-
umf_ctl_index_utlist_t *indexes,
214-
const char *extra_name,
215-
umf_ctl_query_type_t query_type) {
216-
/* suppress unused-parameter errors */
217-
(void)source, (void)indexes, (void)ctx, (void)extra_name, (void)query_type;
218-
219-
size_t *arg_out = arg;
220-
os_memory_provider_t *os_provider = (os_memory_provider_t *)ctx;
221-
COMPILE_ERROR_ON(sizeof(os_provider->stats.allocated_memory) !=
222-
sizeof(uint64_t));
223-
COMPILE_ERROR_ON(sizeof(*arg_out) != sizeof(uint64_t));
224-
utils_atomic_load_acquire_u64(
225-
(uint64_t *)&os_provider->stats.allocated_memory, (uint64_t *)arg_out);
226-
return 0;
227-
}
228-
229-
static int CTL_RUNNABLE_HANDLER(reset)(void *ctx, umf_ctl_query_source_t source,
230-
void *arg,
231-
umf_ctl_index_utlist_t *indexes,
232-
const char *extra_name,
233-
umf_ctl_query_type_t query_type) {
234-
/* suppress unused-parameter errors */
235-
(void)source, (void)indexes, (void)arg, (void)extra_name, (void)query_type;
236-
237-
os_memory_provider_t *os_provider = (os_memory_provider_t *)ctx;
238-
size_t allocated;
239-
240-
COMPILE_ERROR_ON(sizeof(os_provider->stats.allocated_memory) !=
241-
sizeof(uint64_t));
242-
COMPILE_ERROR_ON(sizeof(allocated) != sizeof(uint64_t));
243-
244-
utils_atomic_load_acquire_u64(
245-
(uint64_t *)&os_provider->stats.allocated_memory,
246-
(uint64_t *)&allocated);
247-
utils_atomic_store_release_u64((uint64_t *)&os_provider->stats.peak_memory,
248-
(uint64_t)allocated);
249-
250-
return 0;
251-
}
252-
static const umf_ctl_node_t CTL_NODE(stats)[] = {
253-
CTL_LEAF_RO(allocated_memory), CTL_LEAF_RO(peak_memory),
254-
CTL_LEAF_RUNNABLE(reset), CTL_NODE_END};
255-
256195
static const umf_ctl_node_t CTL_NODE(params)[] = {CTL_LEAF_RO(ipc_enabled),
257196
CTL_NODE_END};
258197

@@ -1176,29 +1115,7 @@ static umf_result_t os_alloc(void *provider, size_t size, size_t alignment,
11761115

11771116
*resultPtr = addr;
11781117

1179-
COMPILE_ERROR_ON(sizeof(os_provider->stats.allocated_memory) !=
1180-
sizeof(uint64_t));
1181-
COMPILE_ERROR_ON(sizeof(os_provider->stats.peak_memory) !=
1182-
sizeof(uint64_t));
1183-
COMPILE_ERROR_ON(sizeof(size) != sizeof(uint64_t));
1184-
// TODO: Change to memory_order_relaxed when we will have a proper wrapper
1185-
size_t allocated =
1186-
utils_fetch_and_add_u64(
1187-
(uint64_t *)&os_provider->stats.allocated_memory, (uint64_t)size) +
1188-
size;
1189-
1190-
uint64_t peak;
1191-
utils_atomic_load_acquire_u64((uint64_t *)&os_provider->stats.peak_memory,
1192-
&peak);
1193-
1194-
while (allocated > peak && !utils_compare_exchange_u64(
1195-
(uint64_t *)&os_provider->stats.peak_memory,
1196-
&peak, (uint64_t *)&allocated)) {
1197-
/* If the compare-exchange fails, 'peak' is updated to the current value of peak_memory.
1198-
We then re-check whether allocated is still greater than the updated peak value. */
1199-
;
1200-
}
1201-
1118+
provider_ctl_stats_alloc(os_provider, size);
12021119
return UMF_RESULT_SUCCESS;
12031120

12041121
err_unmap:
@@ -1226,13 +1143,7 @@ static umf_result_t os_free(void *provider, void *ptr, size_t size) {
12261143
return UMF_RESULT_ERROR_MEMORY_PROVIDER_SPECIFIC;
12271144
}
12281145

1229-
COMPILE_ERROR_ON(sizeof(size) != sizeof(uint64_t));
1230-
COMPILE_ERROR_ON(sizeof(os_provider->stats.allocated_memory) !=
1231-
sizeof(uint64_t));
1232-
1233-
// TODO: Change it to memory_order_relaxed when we will have a proper wrapper
1234-
utils_fetch_and_sub_u64((uint64_t *)&os_provider->stats.allocated_memory,
1235-
size);
1146+
provider_ctl_stats_free(os_provider, size);
12361147

12371148
return UMF_RESULT_SUCCESS;
12381149
}
@@ -1530,11 +1441,9 @@ static umf_result_t os_close_ipc_handle(void *provider, void *ptr,
15301441

15311442
static umf_result_t os_ctl(void *hProvider, int operationType, const char *name,
15321443
void *arg, umf_ctl_query_type_t query_type) {
1533-
(void)operationType; // unused
1534-
os_memory_provider_t *os_provider = (os_memory_provider_t *)hProvider;
15351444
utils_init_once(&ctl_initialized, initialize_os_ctl);
1536-
return ctl_query(os_memory_ctl_root, os_provider, CTL_QUERY_PROGRAMMATIC,
1537-
name, query_type, arg);
1445+
return ctl_query(os_memory_ctl_root, hProvider, operationType, name,
1446+
query_type, arg);
15381447
}
15391448

15401449
static umf_memory_provider_ops_t UMF_OS_MEMORY_PROVIDER_OPS = {

‎src/provider/provider_os_memory_internal.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include "utils_common.h"
2323
#include "utils_concurrency.h"
2424

25+
#include "provider_ctl_stats_type.h"
26+
2527
#ifdef __cplusplus
2628
extern "C" {
2729
#endif
@@ -67,10 +69,8 @@ typedef struct os_memory_provider_t {
6769
size_t partitions_weight_sum;
6870

6971
hwloc_topology_t topo;
70-
struct {
71-
size_t allocated_memory;
72-
size_t peak_memory;
73-
} stats;
72+
73+
ctl_stats_t stats;
7474
} os_memory_provider_t;
7575

7676
#ifdef __cplusplus

‎src/utils/utils_concurrency.h

+28
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ using std::memory_order_release;
4040

4141
#endif /* !_WIN32 */
4242

43+
#include "utils_assert.h"
4344
#include "utils_common.h"
4445
#include "utils_sanitizers.h"
4546

@@ -219,6 +220,33 @@ static inline bool utils_compare_exchange_u64(uint64_t *ptr, uint64_t *expected,
219220

220221
#endif // !defined(_WIN32)
221222

223+
static inline void utils_atomic_load_acquire_size_t(size_t *ptr, size_t *out) {
224+
COMPILE_ERROR_ON(sizeof(size_t) != sizeof(uint64_t));
225+
utils_atomic_load_acquire_u64((uint64_t *)ptr, (uint64_t *)out);
226+
}
227+
228+
static inline void utils_atomic_store_release_size_t(size_t *ptr, size_t val) {
229+
COMPILE_ERROR_ON(sizeof(size_t) != sizeof(uint64_t));
230+
utils_atomic_store_release_u64((uint64_t *)ptr, (uint64_t)val);
231+
}
232+
233+
static inline size_t utils_fetch_and_add_size_t(size_t *ptr, size_t val) {
234+
COMPILE_ERROR_ON(sizeof(size_t) != sizeof(uint64_t));
235+
return utils_fetch_and_add_u64((uint64_t *)ptr, (uint64_t)val);
236+
}
237+
238+
static inline size_t utils_fetch_and_sub_size_t(size_t *ptr, size_t val) {
239+
COMPILE_ERROR_ON(sizeof(size_t) != sizeof(uint64_t));
240+
return utils_fetch_and_sub_u64((uint64_t *)ptr, (uint64_t)val);
241+
}
242+
243+
static inline bool utils_compare_exchange_size_t(size_t *ptr, size_t *expected,
244+
size_t *desired) {
245+
COMPILE_ERROR_ON(sizeof(size_t) != sizeof(uint64_t));
246+
return utils_compare_exchange_u64((uint64_t *)ptr, (uint64_t *)expected,
247+
(uint64_t *)desired);
248+
}
249+
222250
#ifdef __cplusplus
223251
}
224252
#endif

0 commit comments

Comments
 (0)
Please sign in to comment.