diff options
author | Aleksejs Sestakovs <aleksejs.sestakovs@zabbix.com> | 2020-05-15 01:32:09 +0300 |
---|---|---|
committer | Aleksejs Sestakovs <aleksejs.sestakovs@zabbix.com> | 2020-05-15 01:37:27 +0300 |
commit | 5ac71244c018842cc51f205a69a0243f93199326 (patch) | |
tree | 3b2d3e185678002ad65caacb496bedd2cc091de5 | |
parent | 5cca80d8801f8c82b9be2722738dd8170cf14cd8 (diff) |
...G...... [ZBXNEXT-1839] added LLD for perf_counter
* commit '776fb0b127d18e5836cc7b304836148ef394e527':
...G...... [ZBXNEXT-1839] fixed to get object indices from registry
...G...... [ZBXNEXT-1839] added length check
...G...... [ZBXNEXT-1839] fixed to accept objects English names case insensitive
...G...... [ZBXNEXT-1839] code formatting
...G...... [ZBXNEXT-1839] fixed deadlock
...G...... [ZBXNEXT-1839] fixed memory leak
...G...... [ZBXNEXT-1839] removed object index
...G...... [ZBXNEXT-1839] changed instance duplication check
...G...... [ZBXNEXT-1839] fixed memory leak
...G...... [ZBXNEXT-1839] fixed loc_name size
...G...... [ZBXNEXT-1839] fixed object_num reset
...G...... [ZBXNEXT-1839] code formatting
...G...... [ZBXNEXT-1839] renamed key to perf_instance.discovery
...G...... [ZBXNEXT-1839] added throttling
...G...... [ZBXNEXT-1839] fixed compilation error
...G...... [ZBXNEXT-1839] changed key name to perf_instance.get
...G...... [ZBXNEXT-1839] changed to use PdhEnumObjects to get object list
...G...... [ZBXNEXT-1839] added LLD for perf_counter
(cherry picked from commit 727a8a3303694ce77724dfbc8902a24d5a0adf00)
-rw-r--r-- | ChangeLog.d/feature/ZBXNEXT-1839 | 1 | ||||
-rw-r--r-- | include/perfmon.h | 1 | ||||
-rw-r--r-- | include/sysinfo.h | 2 | ||||
-rw-r--r-- | src/libs/zbxsysinfo/win32/pdhmon.c | 132 | ||||
-rw-r--r-- | src/libs/zbxsysinfo/win32/win32.c | 2 | ||||
-rw-r--r-- | src/libs/zbxwin32/perfmon.c | 28 | ||||
-rw-r--r-- | src/zabbix_agent/perfstat.c | 257 | ||||
-rw-r--r-- | src/zabbix_agent/perfstat.h | 2 |
8 files changed, 406 insertions, 19 deletions
diff --git a/ChangeLog.d/feature/ZBXNEXT-1839 b/ChangeLog.d/feature/ZBXNEXT-1839 new file mode 100644 index 00000000000..c03872f7070 --- /dev/null +++ b/ChangeLog.d/feature/ZBXNEXT-1839 @@ -0,0 +1 @@ +...G...... [ZBXNEXT-1839] added LLD for perf_counter; thanks to Ryan Armstrong for the patch (asestakovs) diff --git a/include/perfmon.h b/include/perfmon.h index 767fdc724fd..52b1c704269 100644 --- a/include/perfmon.h +++ b/include/perfmon.h @@ -91,6 +91,7 @@ int check_counter_path(char *counterPath, int convert_from_numeric); int init_builtin_counter_indexes(void); DWORD get_builtin_object_index(zbx_builtin_counter_ref_t ref); DWORD get_builtin_counter_index(zbx_builtin_counter_ref_t ref); +wchar_t *get_all_counter_names(HKEY reg_key, wchar_t *reg_value_name); #define get_builtin_object_name(ctr) get_counter_name(get_builtin_object_index(ctr)) #define get_builtin_counter_name(ctr) get_counter_name(get_builtin_counter_index(ctr)) diff --git a/include/sysinfo.h b/include/sysinfo.h index 635a8421441..c6eeb1b6897 100644 --- a/include/sysinfo.h +++ b/include/sysinfo.h @@ -289,6 +289,8 @@ int VM_MEMORY_SIZE(AGENT_REQUEST *request, AGENT_RESULT *result); int USER_PERF_COUNTER(AGENT_REQUEST *request, AGENT_RESULT *result); int PERF_COUNTER(AGENT_REQUEST *request, AGENT_RESULT *result); int PERF_COUNTER_EN(AGENT_REQUEST *request, AGENT_RESULT *result); +int PERF_INSTANCE_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result); +int PERF_INSTANCE_DISCOVERY_EN(AGENT_REQUEST *request, AGENT_RESULT *result); int SERVICE_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result); int SERVICE_INFO(AGENT_REQUEST *request, AGENT_RESULT *result); int SERVICE_STATE(AGENT_REQUEST *request, AGENT_RESULT *result); diff --git a/src/libs/zbxsysinfo/win32/pdhmon.c b/src/libs/zbxsysinfo/win32/pdhmon.c index 00cfe7bf69d..eb27d1faca9 100644 --- a/src/libs/zbxsysinfo/win32/pdhmon.c +++ b/src/libs/zbxsysinfo/win32/pdhmon.c @@ -21,6 +21,8 @@ #include "sysinfo.h" #include "threads.h" #include "perfstat.h" +#include "zbxjson.h" +#include "zbxalgo.h" #include "log.h" int USER_PERF_COUNTER(AGENT_REQUEST *request, AGENT_RESULT *result) @@ -129,3 +131,133 @@ int PERF_COUNTER_EN(AGENT_REQUEST *request, AGENT_RESULT *result) { return perf_counter_ex(__func__, request, result, PERF_COUNTER_LANG_EN); } + +int perf_instance_discovery_ex(const char *function, AGENT_REQUEST *request, AGENT_RESULT *result, + zbx_perf_counter_lang_t lang) +{ + char *tmp; + wchar_t *object_name = NULL; + DWORD cnt_len = 0, inst_len = 0; + struct zbx_json j; + PDH_STATUS status; + int ret = SYSINFO_RET_FAIL; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", function); + + if (1 < request->nparam) + { + SET_MSG_RESULT(result, zbx_strdup(NULL, "Too many parameters.")); + goto err; + } + + tmp = get_rparam(request, 0); + + if (NULL == tmp || '\0' == *tmp) + { + SET_MSG_RESULT(result, zbx_strdup(NULL, "Invalid first parameter.")); + goto err; + } + + if (PERF_COUNTER_LANG_EN == lang) + { + if (NULL == (object_name = get_object_name_local(tmp))) + { + SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain object's localized name.")); + goto err; + } + } + else + object_name = zbx_utf8_to_unicode(tmp); + + if (SUCCEED != refresh_object_cache()) + { + SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot refresh object cache.")); + goto err; + } + + if (PDH_CSTATUS_NO_OBJECT == (status = PdhEnumObjectItems(NULL, NULL, object_name, NULL, &cnt_len, NULL, + &inst_len, PERF_DETAIL_WIZARD, 0))) + { + SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot find object.")); + goto err; + } + else if (PDH_MORE_DATA != status) + { + SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain required buffer size.")); + goto err; + } + + if (0 == inst_len) + { + SET_MSG_RESULT(result, zbx_strdup(NULL, "Object does not support variable instances.")); + goto err; + } + + zbx_json_initarray(&j, ZBX_JSON_STAT_BUF_LEN); + + if (2 < inst_len) + { + wchar_t *cnt_list, *inst_list, *instance; + zbx_vector_str_t instances, instances_uniq; + int i; + + cnt_list = zbx_malloc(NULL, sizeof(wchar_t) * cnt_len); + inst_list = zbx_malloc(NULL, sizeof(wchar_t) * inst_len); + + if (ERROR_SUCCESS != PdhEnumObjectItems(NULL, NULL, object_name, cnt_list, &cnt_len, inst_list, + &inst_len, PERF_DETAIL_WIZARD, 0)) + { + SET_MSG_RESULT(result, zbx_strdup(NULL, "Cannot obtain object instances.")); + zbx_json_free(&j); + zbx_free(cnt_list); + zbx_free(inst_list); + goto err; + } + + zbx_vector_str_create(&instances); + + for (instance = inst_list; L'\0' != *instance; instance += wcslen(instance) + 1) + zbx_vector_str_append(&instances, zbx_unicode_to_utf8(instance)); + + zbx_vector_str_create(&instances_uniq); + zbx_vector_str_append_array(&instances_uniq, instances.values, instances.values_num); + + zbx_vector_str_sort(&instances_uniq, ZBX_DEFAULT_STR_COMPARE_FUNC); + zbx_vector_str_uniq(&instances_uniq, ZBX_DEFAULT_STR_COMPARE_FUNC); + + for (i = 0; i < instances_uniq.values_num; i++) + { + zbx_json_addobject(&j, NULL); + zbx_json_addstring(&j, "{#INSTANCE}", instances_uniq.values[i], ZBX_JSON_TYPE_STRING); + zbx_json_close(&j); + } + + zbx_vector_str_clear_ext(&instances, zbx_str_free); + zbx_vector_str_destroy(&instances); + zbx_vector_str_destroy(&instances_uniq); + + zbx_free(cnt_list); + zbx_free(inst_list); + } + + zbx_json_close(&j); + SET_STR_RESULT(result, zbx_strdup(NULL, j.buffer)); + zbx_json_free(&j); + ret = SYSINFO_RET_OK; +err: + zbx_free(object_name); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", function); + + return ret; +} + +int PERF_INSTANCE_DISCOVERY(AGENT_REQUEST *request, AGENT_RESULT *result) +{ + return perf_instance_discovery_ex(__func__, request, result, PERF_COUNTER_LANG_DEFAULT); +} + +int PERF_INSTANCE_DISCOVERY_EN(AGENT_REQUEST *request, AGENT_RESULT *result) +{ + return perf_instance_discovery_ex(__func__, request, result, PERF_COUNTER_LANG_EN); +} diff --git a/src/libs/zbxsysinfo/win32/win32.c b/src/libs/zbxsysinfo/win32/win32.c index cc8eba08d83..0a3535b35cf 100644 --- a/src/libs/zbxsysinfo/win32/win32.c +++ b/src/libs/zbxsysinfo/win32/win32.c @@ -61,6 +61,8 @@ ZBX_METRIC parameters_specific[] = {"services", CF_HAVEPARAMS, SERVICES, NULL}, {"perf_counter", CF_HAVEPARAMS, PERF_COUNTER, "\\System\\Processes"}, {"perf_counter_en", CF_HAVEPARAMS, PERF_COUNTER_EN, "\\System\\Processes"}, + {"perf_instance.discovery", CF_HAVEPARAMS, PERF_INSTANCE_DISCOVERY, "Processor"}, + {"perf_instance_en.discovery", CF_HAVEPARAMS, PERF_INSTANCE_DISCOVERY_EN, "Processor"}, {"proc_info", CF_HAVEPARAMS, PROC_INFO, "svchost.exe"}, {"__UserPerfCounter", CF_HAVEPARAMS, USER_PERF_COUNTER, ""}, diff --git a/src/libs/zbxwin32/perfmon.c b/src/libs/zbxwin32/perfmon.c index a5b9a49b181..28f8174bd4f 100644 --- a/src/libs/zbxwin32/perfmon.c +++ b/src/libs/zbxwin32/perfmon.c @@ -322,28 +322,30 @@ DWORD get_builtin_counter_index(zbx_builtin_counter_ref_t counter_ref) /****************************************************************************** * * - * Function: get_all_counter_eng_names * + * Function: get_all_counter_names * * * - * Purpose: helper function for init_builtin_counter_indexes() * + * Purpose: function to read counter names/help from registry * * * - * Parameters: reg_value_name - [IN] name of the registry value * + * Parameters: reg_key - [IN] registry key * + * reg_value_name - [IN] name of the registry value * * * * Return value: wchar_t* buffer with list of strings on success, * * NULL on failure * * * - * Comments: This function should be normally called with L"Counter" * - * parameter. It returns a list of null-terminated string pairs. * - * Last string is followed by an additional null-terminator. * - * The return buffer must be freed by the caller. * + * Comments: This function should be normally called with reg_key parameter * + * set to HKEY_PERFORMANCE_NLSTEXT (localized names) or * + * HKEY_PERFORMANCE_TEXT (English names); and reg_value_name * + * parameter set to L"Counter" parameter. It returns a list of * + * null-terminated string pairs. Last string is followed by * + * an additional null-terminator. The return buffer must be freed * + * by the caller. * * * ******************************************************************************/ -static wchar_t *get_all_counter_eng_names(wchar_t *reg_value_name) +wchar_t *get_all_counter_names(HKEY reg_key, wchar_t *reg_value_name) { wchar_t *buffer = NULL; DWORD buffer_size = 0; LSTATUS status = ERROR_SUCCESS; - /* this registry key guaranteed to hold english counter texts even in localized Win versions */ - static HKEY reg_key = HKEY_PERFORMANCE_TEXT; zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); @@ -504,9 +506,9 @@ out: * * * Function: init_builtin_counter_indexes * * * - * Purpose: scans registry key with all performance counter English names * + * Purpose: Scans registry key with all performance counter English names * * and obtains system-dependent PDH counter indexes for further * - * use by corresponding items * + * use by corresponding items. * * * * Return value: SUCCEED/FAIL * * * @@ -524,7 +526,7 @@ int init_builtin_counter_indexes(void) /* Get buffer holding a list of performance counter indexes and English counter names. */ /* L"Counter" stores names, L"Help" stores descriptions ("Help" is not used). */ - if (NULL == (counter_base = eng_names = get_all_counter_eng_names(L"Counter"))) + if (NULL == (counter_base = eng_names = get_all_counter_names(HKEY_PERFORMANCE_TEXT, L"Counter"))) { ret = FAIL; goto out; diff --git a/src/zabbix_agent/perfstat.c b/src/zabbix_agent/perfstat.c index a41ba4931d6..2a9a32dcb37 100644 --- a/src/zabbix_agent/perfstat.c +++ b/src/zabbix_agent/perfstat.c @@ -25,19 +25,32 @@ #include "mutexs.h" #include "sysinfo.h" -#define UNSUPPORTED_REFRESH_PERIOD 600 +#define UNSUPPORTED_REFRESH_PERIOD 600 +#define OBJECT_CACHE_REFRESH_INTERVAL 60 +#define NAMES_UPDATE_INTERVAL 60 + +struct object_name_ref +{ + char *eng_name; + wchar_t *loc_name; +}; typedef struct { zbx_perf_counter_data_t *pPerfCounterList; PDH_HQUERY pdh_query; - time_t nextcheck; /* refresh time of not supported counters */ + time_t nextcheck; /* refresh time of not supported counters */ + time_t lastrefresh_objects; /* last refresh time of object cache */ + time_t lastupdate_names; /* last update time of object names */ } ZBX_PERF_STAT_DATA; static ZBX_PERF_STAT_DATA ppsd; static zbx_mutex_t perfstat_access = ZBX_MUTEX_NULL; +static struct object_name_ref *object_names = NULL; +static int object_num = 0; + #define LOCK_PERFCOUNTERS zbx_mutex_lock(perfstat_access) #define UNLOCK_PERFCOUNTERS zbx_mutex_unlock(perfstat_access) @@ -185,6 +198,148 @@ static void extend_perf_counter_interval(zbx_perf_counter_data_t *counter, int i counter->interval = interval; } +static void free_object_names(void) +{ + int i; + + for (i = 0; i < object_num; i++) + { + zbx_free(object_names[i].eng_name); + zbx_free(object_names[i].loc_name); + } + + zbx_free(object_names); + object_num = 0; +} + +/****************************************************************************** + * * + * Function: set_object_names * + * * + * Purpose: obtains PDH object localized names and associates them with * + * English names, to be used by perf_instance_en.discovery * + * * + * Return value: SUCCEED/FAIL * + * * + ******************************************************************************/ +static int set_object_names(void) +{ + wchar_t *names_eng, *names_loc, *eng_name, *loc_name, *objects, *object, *p_eng = NULL, *p_loc = NULL; + DWORD sz = 0; + PDH_STATUS pdh_status; + BOOL refresh; + int ret = FAIL; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + LOCK_PERFCOUNTERS; + + if (ppsd.lastupdate_names + NAMES_UPDATE_INTERVAL >= time(NULL)) + { + ret = SUCCEED; + goto out; + } + + if (ppsd.lastrefresh_objects + OBJECT_CACHE_REFRESH_INTERVAL > time(NULL)) + refresh = FALSE; + else + refresh = TRUE; + + if (PDH_MORE_DATA != (pdh_status = PdhEnumObjects(NULL, NULL, NULL, &sz, PERF_DETAIL_WIZARD, refresh))) + { + zabbix_log(LOG_LEVEL_ERR, "cannot obtain required buffer size: %s", + strerror_from_module(pdh_status, L"PDH.DLL")); + goto out; + } + + if (TRUE == refresh) + ppsd.lastrefresh_objects = time(NULL); + + if (NULL == (p_eng = names_eng = get_all_counter_names(HKEY_PERFORMANCE_TEXT, L"Counter")) || + NULL == (p_loc = names_loc = get_all_counter_names(HKEY_PERFORMANCE_NLSTEXT, L"Counter"))) + { + goto out; + } + + /* skip fields with number of records */ + names_eng += wcslen(names_eng) + 1; + names_eng += wcslen(names_eng) + 1; + names_loc += wcslen(names_loc) + 1; + names_loc += wcslen(names_loc) + 1; + + objects = zbx_malloc(NULL, (++sz) * sizeof(wchar_t)); + + if (ERROR_SUCCESS != (pdh_status = PdhEnumObjects(NULL, NULL, objects, &sz, PERF_DETAIL_WIZARD, FALSE))) + { + zabbix_log(LOG_LEVEL_ERR, "cannot obtain objects list: %s", + strerror_from_module(pdh_status, L"PDH.DLL")); + zbx_free(objects); + goto out; + } + + free_object_names(); + + for (object = objects; L'\0' != *object; object += sz) + { + DWORD idx_eng, idx_loc; + + sz = (DWORD)wcslen(object) + 1; + object_names = zbx_realloc(object_names, sizeof(struct object_name_ref) * (object_num + 1)); + + object_names[object_num].eng_name = NULL; + object_names[object_num].loc_name = zbx_malloc(NULL, sizeof(wchar_t) * sz); + memcpy(object_names[object_num].loc_name, object, sizeof(wchar_t) * sz); + + /* For some objects the localized name might be missing and PdhEnumObjects() will return English */ + /* name instead. In that case for localized name use name returned by PdhEnumObjects() if such name */ + /* exists in English names registry (HKEY_PERFORMANCE_TEXT). */ + + idx_loc = 0; + + for (loc_name = names_loc; L'\0' != *loc_name; loc_name += wcslen(loc_name) + 1) + { + DWORD idx; + + idx = (DWORD)_wtoi(loc_name); + loc_name += wcslen(loc_name) + 1; + + if (0 == wcscmp(object, loc_name)) + { + idx_loc = idx; + break; + } + } + + for (eng_name = names_eng; L'\0' != *eng_name; eng_name += wcslen(eng_name) + 1) + { + idx_eng = (DWORD)_wtoi(eng_name); + eng_name += wcslen(eng_name) + 1; + + if (idx_loc == idx_eng || + (0 == idx_loc && 0 == wcscmp(object_names[object_num].loc_name, eng_name))) + { + object_names[object_num].eng_name = zbx_unicode_to_utf8(eng_name); + break; + } + } + + object_num++; + } + + zbx_free(objects); + ppsd.lastupdate_names = time(NULL); + ret = SUCCEED; +out: + zbx_free(p_eng); + zbx_free(p_loc); + + UNLOCK_PERFCOUNTERS; + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + /****************************************************************************** * * * Comments: counter is removed from the collector and * @@ -230,8 +385,6 @@ static void free_perf_counter_list(void) { zbx_perf_counter_data_t *cptr; - LOCK_PERFCOUNTERS; - while (NULL != ppsd.pPerfCounterList) { cptr = ppsd.pPerfCounterList; @@ -242,8 +395,6 @@ static void free_perf_counter_list(void) zbx_free(cptr->value_array); zbx_free(cptr); } - - UNLOCK_PERFCOUNTERS; } /****************************************************************************** @@ -301,6 +452,8 @@ int init_perf_collector(zbx_threadedness_t threadedness, char **error) } ppsd.nextcheck = time(NULL) + UNSUPPORTED_REFRESH_PERIOD; + ppsd.lastrefresh_objects = 0; + ppsd.lastupdate_names = 0; if (SUCCEED != init_builtin_counter_indexes()) { @@ -308,6 +461,12 @@ int init_perf_collector(zbx_threadedness_t threadedness, char **error) goto out; } + if (SUCCEED != set_object_names()) + { + *error = zbx_strdup(*error, "cannot initialize object names"); + goto out; + } + ret = SUCCEED; out: zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); @@ -334,7 +493,12 @@ void free_perf_collector(void) PdhCloseQuery(ppsd.pdh_query); ppsd.pdh_query = NULL; + LOCK_PERFCOUNTERS; + free_perf_counter_list(); + free_object_names(); + + UNLOCK_PERFCOUNTERS; zbx_mutex_destroy(&perfstat_access); } @@ -664,3 +828,84 @@ out: return ret; } + +int refresh_object_cache(void) +{ + DWORD sz = 0; + int ret = SUCCEED; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + LOCK_PERFCOUNTERS; + + if (ppsd.lastrefresh_objects + OBJECT_CACHE_REFRESH_INTERVAL < time(NULL)) + { + if (PDH_MORE_DATA != PdhEnumObjects(NULL, NULL, NULL, &sz, PERF_DETAIL_WIZARD, TRUE)) + { + ret = FAIL; + goto out; + } + + ppsd.lastrefresh_objects = time(NULL); + } +out: + UNLOCK_PERFCOUNTERS; + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s():%s", __func__, zbx_result_string(ret)); + + return ret; +} + +static wchar_t *get_object_name(char *eng_name) +{ + wchar_t *loc_name = NULL; + int i; + size_t len; + + LOCK_PERFCOUNTERS; + + len = strlen(eng_name); + + for (i = 0; i < object_num; i++) + { + if (NULL != object_names[i].eng_name && len == strlen(object_names[i].eng_name) && + 0 == zbx_strncasecmp(object_names[i].eng_name, eng_name, len)) + { + size_t sz; + + sz = (wcslen(object_names[i].loc_name) + 1) * sizeof(wchar_t); + loc_name = zbx_malloc(NULL, sz); + memcpy(loc_name, object_names[i].loc_name, sz); + break; + } + } + + UNLOCK_PERFCOUNTERS; + + return loc_name; +} + +/****************************************************************************** + * * + * Function: get_object_name_local * + * * + * Purpose: get localized name of the object * + * * + * Parameters: eng_name - [IN] english name * + * * + * Returns: localized name of the object * + * * + ******************************************************************************/ +wchar_t *get_object_name_local(char *eng_name) +{ + wchar_t *name; + + zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __func__); + + if (NULL == (name = get_object_name(eng_name)) && SUCCEED == set_object_names()) + name = get_object_name(eng_name); + + zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __func__); + + return name; +} diff --git a/src/zabbix_agent/perfstat.h b/src/zabbix_agent/perfstat.h index 424cdf214ce..f9b4aaab421 100644 --- a/src/zabbix_agent/perfstat.h +++ b/src/zabbix_agent/perfstat.h @@ -45,5 +45,7 @@ int get_perf_counter_value_by_name(const char *name, double *value, char **error int get_perf_counter_value_by_path(const char *counterpath, int interval, zbx_perf_counter_lang_t lang, double *value, char **error); int get_perf_counter_value(zbx_perf_counter_data_t *counter, int interval, double *value, char **error); +int refresh_object_cache(void); +wchar_t *get_object_name_local(char *eng_name); #endif |