Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/zabbix/zabbix.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksejs Sestakovs <aleksejs.sestakovs@zabbix.com>2020-05-15 01:32:09 +0300
committerAleksejs Sestakovs <aleksejs.sestakovs@zabbix.com>2020-05-15 01:37:27 +0300
commit5ac71244c018842cc51f205a69a0243f93199326 (patch)
tree3b2d3e185678002ad65caacb496bedd2cc091de5
parent5cca80d8801f8c82b9be2722738dd8170cf14cd8 (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-18391
-rw-r--r--include/perfmon.h1
-rw-r--r--include/sysinfo.h2
-rw-r--r--src/libs/zbxsysinfo/win32/pdhmon.c132
-rw-r--r--src/libs/zbxsysinfo/win32/win32.c2
-rw-r--r--src/libs/zbxwin32/perfmon.c28
-rw-r--r--src/zabbix_agent/perfstat.c257
-rw-r--r--src/zabbix_agent/perfstat.h2
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