X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvpp-api%2Fpython%2Fvpp_papi%2Fvpp_stats.py;h=8344de0c55ba0f52afce7d587b66c39c21e8c7ee;hb=53fffa1;hp=b84a0e5dc9d49b4a4b07e931e13e446fe538bbc1;hpb=732021070fa0c731896ab3e29f802d3834c72ab7;p=vpp.git diff --git a/src/vpp-api/python/vpp_papi/vpp_stats.py b/src/vpp-api/python/vpp_papi/vpp_stats.py index b84a0e5dc9d..8344de0c55b 100644 --- a/src/vpp-api/python/vpp_papi/vpp_stats.py +++ b/src/vpp-api/python/vpp_papi/vpp_stats.py @@ -2,6 +2,7 @@ from __future__ import print_function from cffi import FFI +import time ffi = FFI() ffi.cdef(""" @@ -13,45 +14,68 @@ typedef struct { typedef enum { STAT_DIR_TYPE_ILLEGAL = 0, - STAT_DIR_TYPE_SCALAR_POINTER, - STAT_DIR_TYPE_VECTOR_POINTER, + STAT_DIR_TYPE_SCALAR_INDEX, STAT_DIR_TYPE_COUNTER_VECTOR_SIMPLE, STAT_DIR_TYPE_COUNTER_VECTOR_COMBINED, STAT_DIR_TYPE_ERROR_INDEX, - STAT_DIR_TYPE_SERIALIZED_NODES, } stat_directory_type_t; -typedef struct { +typedef struct +{ stat_directory_type_t type; - void *value; + union { + uint64_t offset; + uint64_t index; + uint64_t value; + }; + uint64_t offset_vector; + char name[128]; // TODO change this to pointer to "somewhere" } stat_segment_directory_entry_t; -typedef struct { +typedef struct +{ char *name; stat_directory_type_t type; - union { + union + { double scalar_value; uint64_t error_value; - uint64_t *vector_pointer; counter_t **simple_counter_vec; vlib_counter_t **combined_counter_vec; }; } stat_segment_data_t; -typedef struct { - char *name; - stat_segment_directory_entry_t *ep; -} stat_segment_cached_pointer_t; - +typedef struct +{ + uint64_t epoch; + uint64_t in_progress; + uint64_t directory_offset; + uint64_t error_offset; + uint64_t stats_offset; +} stat_segment_shared_header_t; + +typedef struct +{ + uint64_t current_epoch; + stat_segment_shared_header_t *shared_header; + stat_segment_directory_entry_t *directory_vector; + ssize_t memory_size; +} stat_client_main_t; + +stat_client_main_t * stat_client_get(void); +void stat_client_free(stat_client_main_t * sm); +int stat_segment_connect_r (char *socket_name, stat_client_main_t * sm); int stat_segment_connect (char *socket_name); +void stat_segment_disconnect_r (stat_client_main_t * sm); void stat_segment_disconnect (void); -uint8_t **stat_segment_ls (uint8_t **pattern); -stat_segment_data_t *stat_segment_dump (uint8_t ** counter_vec); -/* Collects registered counters */ -stat_segment_cached_pointer_t *stat_segment_register (uint8_t ** counter_vec); -stat_segment_data_t *stat_segment_collect (stat_segment_cached_pointer_t *); +uint32_t *stat_segment_ls_r (uint8_t ** patterns, stat_client_main_t * sm); +uint32_t *stat_segment_ls (uint8_t ** pattern); +stat_segment_data_t *stat_segment_dump_r (uint32_t * stats, stat_client_main_t * sm); +stat_segment_data_t *stat_segment_dump (uint32_t * counter_vec); void stat_segment_data_free (stat_segment_data_t * res); + +double stat_segment_heartbeat_r (stat_client_main_t * sm); double stat_segment_heartbeat (void); int stat_segment_vec_len(void *vec); uint8_t **stat_segment_string_vector(uint8_t **string_vector, char *string); @@ -64,7 +88,8 @@ def make_string_vector(api, strings): if type(strings) is not list: strings = [strings] for s in strings: - vec = api.stat_segment_string_vector(vec, ffi.new("char []", s)) + vec = api.stat_segment_string_vector(vec, ffi.new("char []", + s.encode())) return vec @@ -100,49 +125,87 @@ def combined_counter_vec_list(api, e): def stat_entry_to_python(api, e): + # Scalar index + if e.type == 1: + return e.scalar_value + return None + if e.type == 2: + return simple_counter_vec_list(api, e.simple_counter_vec) if e.type == 3: - return simple_counter_vec_list(e.simple_counter_vec) - if e.type == 4: return combined_counter_vec_list(api, e.combined_counter_vec) - if e.type == 5: + if e.type == 4: return e.error_value return None -class VPPStats: - def __init__(self, socketname='/var/run/stats.sock'): - self.api = ffi.dlopen('libvppapiclient.so') - rv = self.api.stat_segment_connect(socketname) +class VPPStats(object): + def __init__(self, socketname='/var/run/stats.sock', timeout=10): + try: + self.api = ffi.dlopen('libvppapiclient.so') + except Exception: + raise RuntimeError("Could not open: libvppapiclient.so") + self.client = self.api.stat_client_get() + + poll_end_time = time.time() + timeout + while time.time() < poll_end_time: + rv = self.api.stat_segment_connect_r(socketname.encode(), + self.client) + if rv == 0: + break + if rv != 0: raise IOError() def heartbeat(self): - return self.api.stat_segment_heartbeat() + return self.api.stat_segment_heartbeat_r(self.client) def ls(self, patterns): - return self.api.stat_segment_ls(make_string_vector(self.api, patterns)) + return self.api.stat_segment_ls_r(make_string_vector(self.api, + patterns), + self.client) def dump(self, counters): stats = {} - rv = self.api.stat_segment_dump(counters) + rv = self.api.stat_segment_dump_r(counters, self.client) + # Raise exception and retry + if rv == ffi.NULL: + raise IOError() rv_len = self.api.stat_segment_vec_len(rv) for i in range(rv_len): - n = ffi.string(rv[i].name) + n = ffi.string(rv[i].name).decode() e = stat_entry_to_python(self.api, rv[i]) - if e: + if e is not None: stats[n] = e return stats - def dump_str(self, counters_str): - return self.dump(make_string_vector(self.api, counters_str)) + def get_counter(self, name): + retries = 0 + while True: + try: + dir = self.ls(name) + return self.dump(dir).values()[0] + except Exception as e: + if retries > 10: + return None + retries += 1 def disconnect(self): - self.api.stat_segment_disconnect() + self.api.stat_segment_disconnect_r(self.client) + self.api.stat_client_free(self.client) def set_errors(self): '''Return all errors counters > 0''' - error_names = self.ls(['/err/']) - error_counters = self.dump(error_names) + retries = 0 + while True: + try: + error_names = self.ls(['/err/']) + error_counters = self.dump(error_names) + break + except Exception as e: + if retries > 10: + return None + retries += 1 + return {k: error_counters[k] for k in error_counters.keys() if error_counters[k]} @@ -153,9 +216,3 @@ class VPPStats: for k in sorted(error_counters): s += '{:<60}{:>10}\n'.format(k, error_counters[k]) return s - - def register(self): - raise NotImplemented - - def collect(self): - raise NotImplemented