export counters in a memfd segment

also export per-node error counters

directory entries implement object types

Change-Id: I8ce8e0a754e1be9de895c44ed9be6533b4ecef0f
Signed-off-by: Dave Barach <dave@barachs.net>
This commit is contained in:
Dave Barach
2018-06-01 18:52:25 -04:00
parent 59ae61ee75
commit 048a4e5a00
18 changed files with 1221 additions and 32 deletions

View File

@ -5884,7 +5884,8 @@ _(SESSION_RULE_ADD_DEL_REPLY, session_rule_add_del_reply) \
_(SESSION_RULES_DETAILS, session_rules_details) \
_(IP_CONTAINER_PROXY_ADD_DEL_REPLY, ip_container_proxy_add_del_reply) \
_(OUTPUT_ACL_SET_INTERFACE_REPLY, output_acl_set_interface_reply) \
_(QOS_RECORD_ENABLE_DISABLE_REPLY, qos_record_enable_disable_reply)
_(QOS_RECORD_ENABLE_DISABLE_REPLY, qos_record_enable_disable_reply) \
_(MAP_STATS_SEGMENT_REPLY, map_stats_segment_reply)
#define foreach_standalone_reply_msg \
_(SW_INTERFACE_EVENT, sw_interface_event) \
@ -22431,6 +22432,92 @@ api_app_namespace_add_del (vat_main_t * vam)
return ret;
}
static void vl_api_map_stats_segment_reply_t_handler
(vl_api_map_stats_segment_reply_t * mp)
{
#if VPP_API_TEST_BUILTIN == 0
vat_main_t *vam = &vat_main;
ssvm_private_t *ssvmp = &vam->stat_segment;
ssvm_shared_header_t *shared_header;
socket_client_main_t *scm = vam->socket_client_main;
int rv = ntohl (mp->retval);
int my_fd, retval;
clib_error_t *error;
vam->retval = rv;
if (rv != 0)
{
vam->result_ready = 1;
return;
}
/*
* Check the socket for the magic fd
*/
error = vl_sock_api_recv_fd_msg (scm->socket_fd, &my_fd, 5);
if (error)
{
clib_error_report (error);
vam->retval = -99;
vam->result_ready = 1;
return;
}
memset (ssvmp, 0, sizeof (*ssvmp));
ssvmp->fd = my_fd;
/* Note: this closes memfd.fd */
retval = ssvm_slave_init_memfd (ssvmp);
if (retval)
{
clib_warning ("WARNING: segment map returned %d", retval);
vam->retval = -99;
vam->result_ready = 1;
return;
}
else
errmsg ("stat segment mapped OK...");
ASSERT (ssvmp && ssvmp->sh);
/* Pick up the segment lock from the shared memory header */
shared_header = ssvmp->sh;
vam->stat_segment_lockp = (clib_spinlock_t *) (shared_header->opaque[0]);
vam->retval = 0;
vam->result_ready = 1;
#endif
}
static void vl_api_map_stats_segment_reply_t_handler_json
(vl_api_map_stats_segment_reply_t * mp)
{
#if VPP_API_TEST_BUILTIN == 0
vat_main_t *vam = &vat_main;
clib_warning ("not implemented");
vam->retval = -99;
vam->result_ready = 1;
#endif
}
static int
api_map_stats_segment (vat_main_t * vam)
{
#if VPP_API_TEST_BUILTIN == 0
vl_api_map_stats_segment_t *mp;
int ret;
M (MAP_STATS_SEGMENT, mp);
S (mp);
W (ret);
return ret;
#else
errmsg ("api unavailable");
return -99;
#endif
}
static int
api_sock_init_shm (vat_main_t * vam)
{
@ -22956,6 +23043,7 @@ api_qos_record_enable_disable (vat_main_t * vam)
return ret;
}
static int
q_or_quit (vat_main_t * vam)
{
@ -22983,6 +23071,80 @@ comment (vat_main_t * vam)
return 0;
}
static int
statseg (vat_main_t * vam)
{
ssvm_private_t *ssvmp = &vam->stat_segment;
ssvm_shared_header_t *shared_header = ssvmp->sh;
vlib_counter_t **counters;
u64 thread0_index1_packets;
u64 thread0_index1_bytes;
f64 vector_rate, input_rate;
uword *p;
uword *counter_vector_by_name;
if (vam->stat_segment_lockp == 0)
{
errmsg ("Stat segment not mapped...");
return -99;
}
/* look up "/if/rx for sw_if_index 1 as a test */
clib_spinlock_lock (vam->stat_segment_lockp);
counter_vector_by_name = (uword *) shared_header->opaque[1];
p = hash_get_mem (counter_vector_by_name, "/if/rx");
if (p == 0)
{
clib_spinlock_unlock (vam->stat_segment_lockp);
errmsg ("/if/tx not found?");
return -99;
}
/* Fish per-thread vector of combined counters from shared memory */
counters = (vlib_counter_t **) p[0];
if (vec_len (counters[0]) < 2)
{
clib_spinlock_unlock (vam->stat_segment_lockp);
errmsg ("/if/tx vector length %d", vec_len (counters[0]));
return -99;
}
/* Read thread 0 sw_if_index 1 counter */
thread0_index1_packets = counters[0][1].packets;
thread0_index1_bytes = counters[0][1].bytes;
p = hash_get_mem (counter_vector_by_name, "vector_rate");
if (p == 0)
{
clib_spinlock_unlock (vam->stat_segment_lockp);
errmsg ("vector_rate not found?");
return -99;
}
vector_rate = *(f64 *) (p[0]);
p = hash_get_mem (counter_vector_by_name, "input_rate");
if (p == 0)
{
clib_spinlock_unlock (vam->stat_segment_lockp);
errmsg ("input_rate not found?");
return -99;
}
input_rate = *(f64 *) (p[0]);
clib_spinlock_unlock (vam->stat_segment_lockp);
print (vam->ofp, "vector_rate %.2f input_rate %.2f",
vector_rate, input_rate);
print (vam->ofp, "thread 0 sw_if_index 1 rx pkts %lld, bytes %lld",
thread0_index1_packets, thread0_index1_bytes);
return 0;
}
static int
cmd_cmp (void *a1, void *a2)
{
@ -23799,7 +23961,8 @@ _(ip_container_proxy_add_del, "[add|del] <address> <sw_if_index>") \
_(output_acl_set_interface, \
"<intfc> | sw_if_index <nn> [ip4-table <nn>] [ip6-table <nn>]\n" \
" [l2-table <nn>] [del]") \
_(qos_record_enable_disable, "<record-source> <intfc> | sw_if_index <id> [disable]")
_(qos_record_enable_disable, "<record-source> <intfc> | sw_if_index <id> [disable]") \
_(map_stats_segment, "<no-args>")
/* List of command functions, CLI names map directly to functions */
#define foreach_cli_function \
@ -23822,7 +23985,9 @@ _(quit, "usage: quit") \
_(search_node_table, "usage: search_node_table <name>...") \
_(set, "usage: set <variable-name> <value>") \
_(script, "usage: script <file-name>") \
_(statseg, "usage: statseg"); \
_(unset, "usage: unset <variable-name>")
#define _(N,n) \
static void vl_api_##n##_t_handler_uni \
(vl_api_##n##_t * mp) \

View File

@ -209,6 +209,9 @@ typedef struct
ip4_nbr_counter_t **ip4_nbr_counters;
ip6_nbr_counter_t **ip6_nbr_counters;
ssvm_private_t stat_segment;
clib_spinlock_t *stat_segment_lockp;
socket_client_main_t *socket_client_main;
u8 *socket_name;

View File

@ -25,7 +25,6 @@ libvppcom_la_SOURCES += \
vcl/vcl_event.c \
vcl/vppcom.c \
$(libvppinfra_la_SOURCES) \
$(libvlib_la_SOURCES) \
$(libsvm_la_SOURCES) \
$(libvlibmemoryclient_la_SOURCES)

View File

@ -87,13 +87,4 @@ nobase_include_HEADERS += \
vlib/unix/plugin.h \
vlib/unix/unix.h
noinst_PROGRAMS += vlib_unix
vlib_unix_SOURCES = \
examples/vlib/main_stub.c \
examples/vlib/mc_test.c
vlib_unix_LDADD = libvlib.la \
libvppinfra.la -lpthread -lm -ldl -lrt
# vi:syntax=automake

View File

@ -74,15 +74,32 @@ vlib_clear_combined_counters (vlib_combined_counter_main_t * cm)
}
}
void *vlib_stats_push_heap (void) __attribute__ ((weak));
void *
vlib_stats_push_heap (void)
{
return 0;
};
void vlib_stats_pop_heap (void *, void *) __attribute__ ((weak));
void
vlib_stats_pop_heap (void *notused, void *notused2)
{
};
void
vlib_validate_simple_counter (vlib_simple_counter_main_t * cm, u32 index)
{
vlib_thread_main_t *tm = vlib_get_thread_main ();
int i;
void *oldheap = vlib_stats_push_heap ();
vec_validate (cm->counters, tm->n_vlib_mains - 1);
for (i = 0; i < tm->n_vlib_mains; i++)
vec_validate_aligned (cm->counters[i], index, CLIB_CACHE_LINE_BYTES);
vlib_stats_pop_heap (cm, oldheap);
}
void
@ -90,10 +107,13 @@ vlib_validate_combined_counter (vlib_combined_counter_main_t * cm, u32 index)
{
vlib_thread_main_t *tm = vlib_get_thread_main ();
int i;
void *oldheap = vlib_stats_push_heap ();
vec_validate (cm->counters, tm->n_vlib_mains - 1);
for (i = 0; i < tm->n_vlib_mains; i++)
vec_validate_aligned (cm->counters[i], index, CLIB_CACHE_LINE_BYTES);
vlib_stats_pop_heap (cm, oldheap);
}
u32

View File

@ -63,6 +63,7 @@ typedef struct
serialized incrementally. */
char *name; /**< The counter collection's name. */
char *stat_segment_name; /**< Name in stat segment directory */
} vlib_simple_counter_main_t;
/** The number of counters (not the number of per-thread counters) */
@ -183,6 +184,7 @@ typedef struct
vlib_counter_t *value_at_last_serialize; /**< Counter values as of last serialize. */
u32 last_incremental_serialize_index; /**< Last counter index serialized incrementally. */
char *name; /**< The counter collection's name. */
char *stat_segment_name; /**< Name in stat segment directory */
} vlib_combined_counter_main_t;
/** The number of counters (not the number of per-thread counters) */

View File

@ -140,6 +140,19 @@ VLIB_REGISTER_NODE (misc_drop_buffers_node,static) = {
};
/* *INDENT-ON* */
void vlib_stats_register_error_index (u8 *, u64) __attribute__ ((weak));
void
vlib_stats_register_error_index (u8 * notused, u64 notused2)
{
};
void vlib_stats_pop_heap2 (void *, u32, void *) __attribute__ ((weak));
void
vlib_stats_pop_heap2 (void *notused, u32 notused2, void *notused3)
{
};
/* Reserves given number of error codes for given node. */
void
vlib_register_errors (vlib_main_t * vm,
@ -148,6 +161,8 @@ vlib_register_errors (vlib_main_t * vm,
vlib_error_main_t *em = &vm->error_main;
vlib_node_t *n = vlib_get_node (vm, node_index);
uword l;
void *oldheap;
void *vlib_stats_push_heap (void) __attribute__ ((weak));
ASSERT (vlib_get_thread_index () == 0);
@ -169,9 +184,13 @@ vlib_register_errors (vlib_main_t * vm,
clib_memcpy (vec_elt_at_index (em->error_strings_heap, n->error_heap_index),
error_strings, n_errors * sizeof (error_strings[0]));
vec_validate (vm->error_elog_event_types, l - 1);
/* Switch to the stats segment ... */
oldheap = vlib_stats_push_heap ();
/* Allocate a counter/elog type for each error. */
vec_validate (em->counters, l - 1);
vec_validate (vm->error_elog_event_types, l - 1);
/* Zero counters for re-registrations of errors. */
if (n->error_heap_index + n_errors <= vec_len (em->counters_last_clear))
@ -182,6 +201,22 @@ vlib_register_errors (vlib_main_t * vm,
memset (em->counters + n->error_heap_index,
0, n_errors * sizeof (em->counters[0]));
/* Register counter indices in the stat segment directory */
{
int i;
u8 *error_name;
for (i = 0; i < n_errors; i++)
{
error_name = format (0, "/err/%s%c", error_strings[i], 0);
/* Note: error_name consumed by the following call */
vlib_stats_register_error_index (error_name, n->error_heap_index + i);
}
}
/* (re)register the em->counters base address, switch back to main heap */
vlib_stats_pop_heap2 (em->counters, vm->thread_index, oldheap);
{
elog_event_type_t t;
uword i;

View File

@ -1717,6 +1717,12 @@ vlib_main (vlib_main_t * volatile vm, unformat_input_t * input)
goto done;
}
if ((error = vlib_call_init_function (vm, map_stat_segment_init)))
{
clib_error_report (error);
goto done;
}
/* Register static nodes so that init functions may use them. */
vlib_register_all_static_nodes (vm);
@ -1736,6 +1742,24 @@ vlib_main (vlib_main_t * volatile vm, unformat_input_t * input)
goto done;
}
if ((error = vlib_call_init_function (vm, vpe_api_init)))
{
clib_error_report (error);
goto done;
}
if ((error = vlib_call_init_function (vm, vlibmemory_init)))
{
clib_error_report (error);
goto done;
}
if ((error = vlib_call_init_function (vm, map_api_segment_init)))
{
clib_error_report (error);
goto done;
}
/* See unix/main.c; most likely already set up */
if (vm->init_functions_called == 0)
vm->init_functions_called = hash_create (0, /* value bytes */ 0);

View File

@ -459,6 +459,22 @@ vl_mem_api_init (const char *region_name)
return 0;
}
static clib_error_t *
map_api_segment_init (vlib_main_t * vm)
{
api_main_t *am = &api_main;
int rv;
if ((rv = vl_mem_api_init (am->region_name)) < 0)
{
return clib_error_return (0, "vl_mem_api_init (%s) failed",
am->region_name);
}
return 0;
}
VLIB_INIT_FUNCTION (map_api_segment_init);
static void
send_memclnt_keepalive (vl_api_registration_t * regp, f64 now)
{

View File

@ -287,12 +287,6 @@ vl_api_clnt_process (vlib_main_t * vm, vlib_node_runtime_t * node,
uword *event_data = 0;
f64 now;
if ((rv = vl_mem_api_init (am->region_name)) < 0)
{
clib_warning ("memory_api_init returned %d, quitting...", rv);
return 0;
}
if ((error = vl_sock_api_init (vm)))
{
clib_error_report (error);

View File

@ -1250,6 +1250,10 @@ vnet_interface_init (vlib_main_t * vm)
CLIB_CACHE_LINE_BYTES);
im->sw_if_counter_lock[0] = 1; /* should be no need */
/*
* $$$$ add stat segment name(s) if desired
* set xxx.stat_segment_name = "whatever"...
*/
vec_validate (im->sw_if_counters, VNET_N_SIMPLE_INTERFACE_COUNTER - 1);
im->sw_if_counters[VNET_INTERFACE_COUNTER_DROP].name = "drops";
im->sw_if_counters[VNET_INTERFACE_COUNTER_PUNT].name = "punts";

View File

@ -11,7 +11,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
bin_PROGRAMS += bin/vpp
bin_PROGRAMS += bin/vpp
bin_vpp_SOURCES = \
vpp/vnet/main.c \
@ -19,7 +19,8 @@ bin_vpp_SOURCES = \
vpp/app/version.c \
vpp/oam/oam.c \
vpp/oam/oam_api.c \
vpp/stats/stats.c
vpp/stats/stats.c \
vpp/stats/stat_segment.c
bin_vpp_SOURCES += \
vpp/api/api.c \
@ -130,6 +131,20 @@ bin_summary_stats_client_LDADD = \
libvppinfra.la \
-lpthread -lm -lrt
noinst_PROGRAMS += bin/stat_client
bin_stat_client_SOURCES = \
vpp/app/stat_client.c \
vpp/app/stat_client.h
bin_stat_client_LDADD = \
libvlibmemoryclient.la \
libsvm.la \
libvppinfra.la \
-lpthread -lm -lrt
bin_PROGRAMS += bin/vpp_get_metrics
bin_vpp_get_metrics_SOURCES = \

343
src/vpp/app/stat_client.c Normal file

File diff suppressed because it is too large Load Diff

70
src/vpp/app/stat_client.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __included_stat_client_h__
#define __included_stat_client_h__
#include <vlib/vlib.h>
#include <vppinfra/socket.h>
#include <svm/ssvm.h>
#include <vlibapi/api.h>
#include <vlibmemory/api.h>
#include <vlibmemory/socket_api.h>
#include <vlibmemory/socket_client.h>
#include <vpp/stats/stats.h>
typedef struct
{
u64 current_epoch;
/* Cached pointers to scalar quantities, these wont change */
f64 *vector_rate_ptr;
f64 *input_rate_ptr;
volatile int segment_ready;
/*
* Cached pointers to vector quantities,
* MUST invalidate when the epoch changes
*/
vlib_counter_t **intfc_rx_counters;
vlib_counter_t **intfc_tx_counters;
u64 *thread_0_error_counts;
u64 source_address_match_error_index;
/* mapped stats segment object */
ssvm_private_t stat_segment;
/* Socket client object */
socket_client_main_t *socket_client_main;
/* Spinlock for the stats segment */
clib_spinlock_t *stat_segment_lockp;
u8 *socket_name;
} stat_client_main_t;
extern stat_client_main_t stat_client_main;
#endif /* __included_stat_client_h__ */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/

File diff suppressed because it is too large Load Diff

View File

@ -58,6 +58,8 @@ service {
rpc want_udp_encap_stats
returns want_udp_encap_stats_reply
events vnet_udp_encap_counters;
rpc map_stats_segment
returns map_stats_segment_reply;
};
/** \brief Want Stats, enable/disable ALL stats updates
@ -472,6 +474,13 @@ manual_print manual_endian define vnet_udp_encap_counters
vl_api_udp_encap_counter_t c[count];
};
autoreply define map_stats_segment
{
u32 client_index;
u32 context;
};
/*
* Local Variables:
* eval: (c-set-style "gnu")

View File

@ -48,24 +48,25 @@ stats_main_t stats_main;
#define foreach_stats_msg \
_(WANT_STATS, want_stats) \
_(VNET_INTERFACE_SIMPLE_COUNTERS, vnet_interface_simple_counters) \
_(WANT_INTERFACE_SIMPLE_STATS, want_interface_simple_stats) \
_(WANT_INTERFACE_SIMPLE_STATS, want_interface_simple_stats) \
_(VNET_INTERFACE_COMBINED_COUNTERS, vnet_interface_combined_counters) \
_(WANT_INTERFACE_COMBINED_STATS, want_interface_combined_stats) \
_(WANT_INTERFACE_COMBINED_STATS, want_interface_combined_stats) \
_(WANT_PER_INTERFACE_COMBINED_STATS, want_per_interface_combined_stats) \
_(WANT_PER_INTERFACE_SIMPLE_STATS, want_per_interface_simple_stats) \
_(WANT_PER_INTERFACE_SIMPLE_STATS, want_per_interface_simple_stats) \
_(VNET_IP4_FIB_COUNTERS, vnet_ip4_fib_counters) \
_(WANT_IP4_FIB_STATS, want_ip4_fib_stats) \
_(WANT_IP4_FIB_STATS, want_ip4_fib_stats) \
_(VNET_IP6_FIB_COUNTERS, vnet_ip6_fib_counters) \
_(WANT_IP6_FIB_STATS, want_ip6_fib_stats) \
_(WANT_IP6_FIB_STATS, want_ip6_fib_stats) \
_(WANT_IP4_MFIB_STATS, want_ip4_mfib_stats) \
_(WANT_IP6_MFIB_STATS, want_ip6_mfib_stats) \
_(VNET_IP4_NBR_COUNTERS, vnet_ip4_nbr_counters) \
_(WANT_IP4_NBR_STATS, want_ip4_nbr_stats) \
_(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) \
_(WANT_IP6_NBR_STATS, want_ip6_nbr_stats) \
_(VNET_GET_SUMMARY_STATS, vnet_get_summary_stats) \
_(STATS_GET_POLLER_DELAY, stats_get_poller_delay) \
_(WANT_UDP_ENCAP_STATS, want_udp_encap_stats)
_(WANT_IP4_NBR_STATS, want_ip4_nbr_stats) \
_(VNET_IP6_NBR_COUNTERS, vnet_ip6_nbr_counters) \
_(WANT_IP6_NBR_STATS, want_ip6_nbr_stats) \
_(VNET_GET_SUMMARY_STATS, vnet_get_summary_stats) \
_(STATS_GET_POLLER_DELAY, stats_get_poller_delay) \
_(WANT_UDP_ENCAP_STATS, want_udp_encap_stats) \
_(MAP_STATS_SEGMENT, map_stats_segment)
#define vl_msg_name_crc_list
#include <vpp/stats/stats.api.h>
@ -2934,6 +2935,50 @@ stats_memclnt_delete_callback (u32 client_index)
#define vl_api_vnet_ip4_nbr_counters_t_print vl_noop_handler
#define vl_api_vnet_ip6_nbr_counters_t_endian vl_noop_handler
#define vl_api_vnet_ip6_nbr_counters_t_print vl_noop_handler
#define vl_api_map_stats_segment_t_print vl_noop_handler
static void
vl_api_map_stats_segment_t_handler (vl_api_map_stats_segment_t * mp)
{
vl_api_map_stats_segment_reply_t *rmp;
stats_main_t *sm = &stats_main;
ssvm_private_t *ssvmp = &sm->stat_segment;
vl_api_registration_t *regp;
api_main_t *am = &api_main;
clib_file_t *cf;
vl_api_shm_elem_config_t *config = 0;
vl_shmem_hdr_t *shmem_hdr;
int rv = 0;
regp = vl_api_client_index_to_registration (mp->client_index);
if (regp == 0)
{
clib_warning ("API client disconnected");
return;
}
if (regp->registration_type != REGISTRATION_TYPE_SOCKET_SERVER)
rv = VNET_API_ERROR_INVALID_REGISTRATION;
rmp = vl_msg_api_alloc (sizeof (*rmp));
rmp->_vl_msg_id = htons (VL_API_MAP_STATS_SEGMENT_REPLY);
rmp->context = mp->context;
rmp->retval = htonl (rv);
vl_api_send_msg (regp, (u8 *) rmp);
if (rv != 0)
return;
/*
* We need the reply message to make it out the back door
* before we send the magic fd message so force a flush
*/
cf = vl_api_registration_file (regp);
cf->write_function (cf);
/* Send the magic "here's your sign (aka fd)" socket message */
vl_sock_api_send_fd_msg (cf->file_descriptor, ssvmp->fd);
}
static clib_error_t *
stats_init (vlib_main_t * vm)

View File

@ -27,6 +27,7 @@
#include <vlibmemory/api.h>
#include <vlibapi/api_helper_macros.h>
#include <svm/queue.h>
#include <svm/ssvm.h>
typedef struct
{
@ -157,6 +158,15 @@ typedef struct
vpe_client_stats_registration_t **regs_tmp;
vpe_client_registration_t **clients_tmp;
/* statistics segment */
ssvm_private_t stat_segment;
uword *counter_vector_by_name;
clib_spinlock_t *stat_segment_lockp;
/* Pointers to scalar stats maintained by the stat segment process */
f64 *input_rate_ptr;
f64 *vector_rate_ptr;
/* convenience */
vlib_main_t *vlib_main;
vnet_main_t *vnet_main;
@ -166,6 +176,25 @@ typedef struct
extern stats_main_t stats_main;
#define STAT_SEGMENT_OPAQUE_LOCK 0
#define STAT_SEGMENT_OPAQUE_DIR 1
#define STAT_SEGMENT_OPAQUE_EPOCH 2
typedef enum
{
STAT_DIR_TYPE_ILLEGAL = 0,
STAT_DIR_TYPE_SCALAR_POINTER,
STAT_DIR_TYPE_VECTOR_POINTER,
STAT_DIR_TYPE_COUNTER_VECTOR,
STAT_DIR_TYPE_ERROR_INDEX,
} stat_directory_type_t;
typedef struct
{
stat_directory_type_t type;
void *value;
} stat_segment_directory_entry_t;
#endif /* __included_stats_h__ */
/*