diff --git a/ChangeLog.d/feature/ZBXNEXT-10119 b/ChangeLog.d/feature/ZBXNEXT-10119
new file mode 100644
index 00000000000..8cf83ae6a27
--- /dev/null
+++ b/ChangeLog.d/feature/ZBXNEXT-10119
@@ -0,0 +1 @@
+.......PS. [ZBXNEXT-10119] improved preprocessing diagnostics by highlighting top item IDs with the longest processing times (vso)
diff --git a/include/zbxpreproc.h b/include/zbxpreproc.h
index 18b20f9e2e6..9eb2f1baeac 100644
--- a/include/zbxpreproc.h
+++ b/include/zbxpreproc.h
@@ -66,6 +66,7 @@ typedef struct
 	zbx_pp_task_state_t	state;
 	zbx_uint64_t		itemid;
 	zbx_uint64_t		hostid;
+	zbx_uint64_t		time_ms;
 	void			*data;
 }
 zbx_pp_task_t;
@@ -118,11 +119,14 @@ void	zbx_preprocess_item_value(zbx_uint64_t itemid, zbx_uint64_t hostid, unsigne
 void	zbx_preprocessor_flush(void);
 int	zbx_preprocessor_get_diag_stats(zbx_uint64_t *preproc_num, zbx_uint64_t *pending_num,
 		zbx_uint64_t *finished_num, zbx_uint64_t *sequences_num, zbx_uint64_t *queued_num,
-		zbx_uint64_t *queued_sz, zbx_uint64_t *direct_num, zbx_uint64_t *direct_sz, char **error);
+		zbx_uint64_t *queued_sz, zbx_uint64_t *direct_num, zbx_uint64_t *direct_sz, zbx_uint64_t *history_sz,
+		char **error);
 int	zbx_preprocessor_get_top_sequences(int limit, zbx_vector_pp_top_stats_ptr_t *stats, char **error);
 int	zbx_preprocessor_get_top_peak(int limit, zbx_vector_pp_top_stats_ptr_t *stats, char **error);
 int	zbx_preprocessor_get_top_values_num(int limit, zbx_vector_pp_top_stats_ptr_t *stats, char **error);
 int	zbx_preprocessor_get_top_values_size(int limit, zbx_vector_pp_top_stats_ptr_t *stats, char **error);
+int	zbx_preprocessor_get_top_time_ms(int limit, zbx_vector_pp_top_stats_ptr_t *stats, char **error);
+int	zbx_preprocessor_get_top_total_ms(int limit, zbx_vector_pp_top_stats_ptr_t *stats, char **error);
 int	zbx_preprocessor_test(unsigned char value_type, const char *value, const zbx_timespec_t *ts,
 		unsigned char state, const zbx_vector_pp_step_ptr_t *steps, zbx_vector_pp_result_ptr_t *results,
 		zbx_pp_history_t *history, char **error);
diff --git a/include/zbxpreprocbase.h b/include/zbxpreprocbase.h
index cf6c85913f0..9785b32686d 100644
--- a/include/zbxpreprocbase.h
+++ b/include/zbxpreprocbase.h
@@ -56,6 +56,7 @@ void			zbx_pp_history_cache_release(zbx_pp_history_cache_t *history_cache);
 zbx_pp_history_t	*zbx_pp_history_cache_history_acquire(zbx_pp_history_cache_t *history_cache);
 void			zbx_pp_history_cache_history_set_and_release(zbx_pp_history_cache_t *history_cache,
 				zbx_pp_history_t *history_in, zbx_pp_history_t *history_out);
+zbx_uint64_t		zbx_pp_history_cache_history_size(zbx_pp_history_cache_t *history_cache);
 
 typedef enum
 {
@@ -100,6 +101,8 @@ typedef struct
 
 	zbx_uint64_t		values_num;
 	zbx_uint64_t		values_sz;
+	zbx_uint64_t		time_ms;
+	zbx_uint64_t		total_ms;
 }
 zbx_pp_item_preproc_t;
 
diff --git a/include/zbxtimekeeper.h b/include/zbxtimekeeper.h
index 325dc3bbbbd..3a82992926f 100644
--- a/include/zbxtimekeeper.h
+++ b/include/zbxtimekeeper.h
@@ -68,7 +68,7 @@ zbx_timekeeper_t	*zbx_timekeeper_create_ext(int units_num, zbx_timekeeper_sync_t
 zbx_timekeeper_t	*zbx_timekeeper_create(int units_num, zbx_timekeeper_sync_t *sync);
 void	zbx_timekeeper_free(zbx_timekeeper_t *timekeeper);
 
-void	zbx_timekeeper_update(zbx_timekeeper_t *timekeeper, int index, unsigned char state);
+zbx_uint64_t		zbx_timekeeper_update(zbx_timekeeper_t *timekeeper, int index, unsigned char state);
 void	zbx_timekeeper_collect(zbx_timekeeper_t *timekeeper);
 
 int	zbx_timekeeper_get_stat(zbx_timekeeper_t *timekeeper, int unit_index, int count, unsigned char aggr_func,
diff --git a/include/zbxvariant.h b/include/zbxvariant.h
index f2cee5f1e1b..be8f0984840 100644
--- a/include/zbxvariant.h
+++ b/include/zbxvariant.h
@@ -74,6 +74,7 @@ int		zbx_variant_convert(zbx_variant_t *value, int type);
 const char	*zbx_get_variant_type_desc(unsigned char type);
 const char	*zbx_variant_value_desc(const zbx_variant_t *value);
 const char	*zbx_variant_type_desc(const zbx_variant_t *value);
+zbx_uint64_t	zbx_variant_size(const zbx_variant_t *value);
 
 int		zbx_variant_compare(const zbx_variant_t *value1, const zbx_variant_t *value2);
 
diff --git a/src/libs/zbxdiag/diag.c b/src/libs/zbxdiag/diag.c
index 4db200fd44e..f56e0cf6c1d 100644
--- a/src/libs/zbxdiag/diag.c
+++ b/src/libs/zbxdiag/diag.c
@@ -537,7 +537,7 @@ static void	diag_prepare_default_request(struct zbx_json *j, unsigned int flags)
 	if (0 != (flags & (1 << ZBX_DIAGINFO_PREPROCESSING)))
 	{
 		diag_add_section_request(j, ZBX_DIAG_PREPROCESSING, "peak", "sequences", "values_num", "values_sz",
-				NULL);
+				"time_ms", "total_ms", NULL);
 	}
 
 	if (0 != (flags & (1 << ZBX_DIAGINFO_LLD)))
@@ -750,6 +750,8 @@ static void	diag_log_preprocessing(struct zbx_json_parse *jp, char **out, size_t
 	diag_log_top_view(jp, "top.peak", "$.top.peak", out, out_alloc, out_offset);
 	diag_log_top_view(jp, "top.values_num", "$.top.values_num", out, out_alloc, out_offset);
 	diag_log_top_view(jp, "top.values_sz", "$.top.values_sz", out, out_alloc, out_offset);
+	diag_log_top_view(jp, "top.time_ms", "$.top.time_ms", out, out_alloc, out_offset);
+	diag_log_top_view(jp, "top.total_ms", "$.top.total_ms", out, out_alloc, out_offset);
 
 	zbx_strlog_alloc(LOG_LEVEL_INFORMATION, out, out_alloc, out_offset, "==");
 }
diff --git a/src/libs/zbxpreproc/pp_diag.c b/src/libs/zbxpreproc/pp_diag.c
index af5ad0e9d24..4bcc924efce 100644
--- a/src/libs/zbxpreproc/pp_diag.c
+++ b/src/libs/zbxpreproc/pp_diag.c
@@ -75,11 +75,12 @@ int	zbx_diag_add_preproc_info(const struct zbx_json_parse *jp, struct zbx_json *
 		if (0 != (fields & ZBX_DIAG_PREPROC_SIMPLE))
 		{
 			zbx_uint64_t	preproc_num, pending_num, finished_num, sequences_num, queued_num, queued_sz,
-					direct_num, direct_sz;
+					direct_num, direct_sz, history_sz;
 
 			time1 = zbx_time();
 			if (FAIL == (ret = zbx_preprocessor_get_diag_stats(&preproc_num, &pending_num, &finished_num,
-					&sequences_num, &queued_num, &queued_sz, &direct_num, &direct_sz, error)))
+					&sequences_num, &queued_num, &queued_sz, &direct_num, &direct_sz,
+					&history_sz, error)))
 			{
 				goto out;
 			}
@@ -97,6 +98,7 @@ int	zbx_diag_add_preproc_info(const struct zbx_json_parse *jp, struct zbx_json *
 				zbx_json_adduint64(json, "queued size", queued_sz);
 				zbx_json_adduint64(json, "direct count", direct_num);
 				zbx_json_adduint64(json, "direct size", direct_sz);
+				zbx_json_adduint64(json, "history size", history_sz);
 			}
 		}
 
@@ -132,6 +134,16 @@ int	zbx_diag_add_preproc_info(const struct zbx_json_parse *jp, struct zbx_json *
 					zbx_get_top_cb = zbx_preprocessor_get_top_values_size;
 					name = "values_sz";
 				}
+				else if (0 == strcmp(map->name, "time_ms"))
+				{
+					zbx_get_top_cb = zbx_preprocessor_get_top_time_ms;
+					name = "time_ms";
+				}
+				else if (0 == strcmp(map->name, "total_ms"))
+				{
+					zbx_get_top_cb = zbx_preprocessor_get_top_total_ms;
+					name = "total_ms";
+				}
 				else
 				{
 					*error = zbx_dsprintf(*error, "Unsupported top field: %s", map->name);
diff --git a/src/libs/zbxpreproc/pp_manager.c b/src/libs/zbxpreproc/pp_manager.c
index e89362760bb..8d26b5090ee 100644
--- a/src/libs/zbxpreproc/pp_manager.c
+++ b/src/libs/zbxpreproc/pp_manager.c
@@ -439,6 +439,9 @@ static void	pp_manager_queue_value_task_result(zbx_pp_manager_t *manager, zbx_pp
 	zbx_pp_task_value_t	*d = (zbx_pp_task_value_t *)PP_TASK_DATA(task);
 	zbx_pp_item_t		*item;
 
+	d->preproc->time_ms = task->time_ms;
+	d->preproc->total_ms += task->time_ms;
+
 	if (ZBX_VARIANT_NONE == d->result.type)
 		return;
 
@@ -480,6 +483,8 @@ static zbx_pp_task_t	*pp_manager_queue_dependent_task_result(zbx_pp_manager_t *m
 	zbx_pp_task_t		*task_value = d->primary;
 	zbx_pp_task_value_t	*dp = (zbx_pp_task_value_t *)PP_TASK_DATA(task_value);
 
+	d->primary->time_ms = task->time_ms;
+
 	pp_manager_queue_value_task_result(manager, d->primary);
 	pp_manager_queue_dependents(manager, d->preproc, dp->um_handle, task_value->itemid, &dp->result, dp->ts, d->cache);
 
@@ -506,6 +511,8 @@ static zbx_pp_task_t	*pp_manager_requeue_next_sequence_task(zbx_pp_manager_t *ma
 
 	if (SUCCEED == zbx_list_pop(&d_seq->tasks, (void **)&task))
 	{
+		task->time_ms = task_seq->time_ms;
+
 		switch (task->type)
 		{
 			case ZBX_PP_TASK_VALUE:
@@ -677,7 +684,7 @@ static void	zbx_pp_manager_get_sequence_stats(zbx_pp_manager_t *manager, zbx_vec
 	pp_task_queue_get_sequence_stats(&manager->queue, stats);
 }
 
-static void	zbx_pp_manager_get_values_stats(zbx_pp_manager_t *manager, int is_num,
+static void	zbx_pp_manager_get_num_stats(zbx_pp_manager_t *manager, int request,
 		zbx_vector_pp_top_stats_ptr_t *stats)
 {
 	zbx_hashset_iter_t	iter;
@@ -693,7 +700,21 @@ static void	zbx_pp_manager_get_values_stats(zbx_pp_manager_t *manager, int is_nu
 		if (NULL ==  item->preproc)
 			continue;
 
-		num = 0 == is_num ? (zbx_int64_t)item->preproc->values_sz : (zbx_int64_t)item->preproc->values_num;
+		switch (request)
+		{
+			case ZBX_IPC_PREPROCESSOR_TOP_VALUES_NUM:
+				num =  (zbx_int64_t)item->preproc->values_num;
+				break;
+			case ZBX_IPC_PREPROCESSOR_TOP_VALUES_SZ:
+				num = (zbx_int64_t)item->preproc->values_sz;
+				break;
+			case ZBX_IPC_PREPROCESSOR_TOP_TOTAL_MS:
+				num = (zbx_int64_t)(item->preproc->total_ms);
+				break;
+			case ZBX_IPC_PREPROCESSOR_TOP_TIME_MS:
+			default:
+				num = (zbx_int64_t)(item->preproc->time_ms);
+		}
 
 		if (0 == num)
 			continue;
@@ -1068,6 +1089,25 @@ static void	preprocessor_flush_tasks(zbx_pp_manager_t *manager, zbx_vector_pp_ta
 	}
 }
 
+static zbx_uint64_t	zbx_pp_manager_items_history_size(zbx_pp_manager_t *manager)
+{
+	zbx_hashset_iter_t	iter;
+	zbx_pp_item_t		*item;
+	zbx_uint64_t		history_size = 0;
+
+	zbx_hashset_iter_reset(&manager->items, &iter);
+
+	while (NULL != (item = (zbx_pp_item_t *)zbx_hashset_iter_next(&iter)))
+	{
+		if (NULL ==  item->preproc)
+			continue;
+
+		history_size += zbx_pp_history_cache_history_size(item->preproc->history_cache);
+	}
+
+	return history_size;
+}
+
 /******************************************************************************
  *                                                                            *
  * Purpose: respond to diagnostic information request                         *
@@ -1076,13 +1116,14 @@ static void	preprocessor_flush_tasks(zbx_pp_manager_t *manager, zbx_vector_pp_ta
 static void	preprocessor_reply_diag_info(zbx_pp_manager_t *manager, zbx_ipc_client_t *client,
 		zbx_uint64_t queued_num, zbx_uint64_t queued_sz, zbx_uint64_t direct_num, zbx_uint64_t direct_sz)
 {
-	zbx_uint64_t	preproc_num, pending_num, finished_num, sequences_num;
+	zbx_uint64_t	preproc_num, pending_num, finished_num, sequences_num, history_sz;
 	unsigned char	*data;
 	zbx_uint32_t	data_len;
 
+	history_sz = zbx_pp_manager_items_history_size(manager);
 	zbx_pp_manager_get_diag_stats(manager, &preproc_num, &pending_num, &finished_num, &sequences_num);
 	data_len = zbx_preprocessor_pack_diag_stats(&data, preproc_num, pending_num, finished_num, sequences_num,
-			queued_num, queued_sz, direct_num, direct_sz);
+			queued_num, queued_sz, direct_num, direct_sz, history_sz);
 
 	zbx_ipc_client_send(client, ZBX_IPC_PREPROCESSOR_DIAG_STATS_RESULT, data, data_len);
 
@@ -1148,6 +1189,7 @@ static void	zbx_pp_manager_items_preproc_values_stats_reset(zbx_pp_manager_t *ma
 
 		item->preproc->values_num = 0;
 		item->preproc->values_sz = 0;
+		item->preproc->total_ms = 0;
 	}
 }
 
@@ -1174,12 +1216,10 @@ static void	preprocessor_reply_top_stats(zbx_pp_manager_t *manager, zbx_ipc_clie
 
 	if (ZBX_IPC_PREPROCESSOR_TOP_SEQUENCES == code)
 		zbx_pp_manager_get_sequence_stats(manager, &stats);
-	else if (ZBX_IPC_PREPROCESSOR_TOP_VALUES_NUM == code)
-		zbx_pp_manager_get_values_stats(manager, 1, &stats);
-	else if (ZBX_IPC_PREPROCESSOR_TOP_VALUES_SZ == code)
-		zbx_pp_manager_get_values_stats(manager, 0, &stats);
-	else
+	else if (ZBX_IPC_PREPROCESSOR_TOP_PEAK == code)
 		zbx_pp_manager_items_preproc_peak(manager, &stats);
+	else
+		zbx_pp_manager_get_num_stats(manager, code, &stats);
 
 	if (limit > stats.values_num)
 		limit = stats.values_num;
@@ -1413,6 +1453,8 @@ ZBX_THREAD_ENTRY(zbx_pp_manager_thread, args)
 				case ZBX_IPC_PREPROCESSOR_TOP_PEAK:
 				case ZBX_IPC_PREPROCESSOR_TOP_VALUES_NUM:
 				case ZBX_IPC_PREPROCESSOR_TOP_VALUES_SZ:
+				case ZBX_IPC_PREPROCESSOR_TOP_TIME_MS:
+				case ZBX_IPC_PREPROCESSOR_TOP_TOTAL_MS:
 					preprocessor_reply_top_stats(manager, client, message, message->code);
 					break;
 				case ZBX_IPC_PREPROCESSOR_USAGE_STATS:
diff --git a/src/libs/zbxpreproc/pp_protocol.c b/src/libs/zbxpreproc/pp_protocol.c
index 27ba8ec6c78..c9eb19f0246 100644
--- a/src/libs/zbxpreproc/pp_protocol.c
+++ b/src/libs/zbxpreproc/pp_protocol.c
@@ -491,7 +491,8 @@ zbx_uint32_t	zbx_preprocessor_pack_test_result(unsigned char **data, const zbx_p
  ******************************************************************************/
 zbx_uint32_t	zbx_preprocessor_pack_diag_stats(unsigned char **data, zbx_uint64_t preproc_num,
 		zbx_uint64_t pending_num, zbx_uint64_t finished_num, zbx_uint64_t sequences_num,
-		zbx_uint64_t queued_num, zbx_uint64_t queued_sz, zbx_uint64_t direct_num, zbx_uint64_t direct_sz)
+		zbx_uint64_t queued_num, zbx_uint64_t queued_sz, zbx_uint64_t direct_num, zbx_uint64_t direct_sz,
+		zbx_uint64_t history_sz)
 {
 	unsigned char	*ptr;
 	zbx_uint32_t	data_len = 0;
@@ -504,6 +505,7 @@ zbx_uint32_t	zbx_preprocessor_pack_diag_stats(unsigned char **data, zbx_uint64_t
 	zbx_serialize_prepare_value(data_len, queued_sz);
 	zbx_serialize_prepare_value(data_len, direct_num);
 	zbx_serialize_prepare_value(data_len, direct_sz);
+	zbx_serialize_prepare_value(data_len, history_sz);
 
 	*data = (unsigned char *)zbx_malloc(NULL, data_len);
 
@@ -515,7 +517,8 @@ zbx_uint32_t	zbx_preprocessor_pack_diag_stats(unsigned char **data, zbx_uint64_t
 	ptr += zbx_serialize_value(ptr, queued_num);
 	ptr += zbx_serialize_value(ptr, queued_sz);
 	ptr += zbx_serialize_value(ptr, direct_num);
-	(void)zbx_serialize_value(ptr, direct_sz);
+	ptr += zbx_serialize_value(ptr, direct_sz);
+	(void)zbx_serialize_value(ptr, history_sz);
 
 	return data_len;
 }
@@ -772,7 +775,7 @@ void	zbx_preprocessor_unpack_test_result(zbx_vector_pp_result_ptr_t *results, zb
  ******************************************************************************/
 void	zbx_preprocessor_unpack_diag_stats(zbx_uint64_t *preproc_num, zbx_uint64_t *pending_num,
 		zbx_uint64_t *finished_num, zbx_uint64_t *sequences_num, zbx_uint64_t *queued_num,
-		zbx_uint64_t *queued_sz, zbx_uint64_t *direct_num, zbx_uint64_t *direct_sz,
+		zbx_uint64_t *queued_sz, zbx_uint64_t *direct_num, zbx_uint64_t *direct_sz, zbx_uint64_t *history_sz,
 		const unsigned char *data)
 {
 	const unsigned char	*offset = data;
@@ -784,7 +787,8 @@ void	zbx_preprocessor_unpack_diag_stats(zbx_uint64_t *preproc_num, zbx_uint64_t
 	offset += zbx_deserialize_value(offset, queued_num);
 	offset += zbx_deserialize_value(offset, queued_sz);
 	offset += zbx_deserialize_value(offset, direct_num);
-	(void)zbx_deserialize_value(offset, direct_sz);
+	offset += zbx_deserialize_value(offset, direct_sz);
+	(void)zbx_deserialize_value(offset, history_sz);
 }
 
 /******************************************************************************
@@ -1201,7 +1205,8 @@ out:
  ******************************************************************************/
 int	zbx_preprocessor_get_diag_stats(zbx_uint64_t *preproc_num, zbx_uint64_t *pending_num,
 		zbx_uint64_t *finished_num, zbx_uint64_t *sequences_num, zbx_uint64_t *queued_num,
-		zbx_uint64_t *queued_sz, zbx_uint64_t *direct_num, zbx_uint64_t *direct_sz, char **error)
+		zbx_uint64_t *queued_sz, zbx_uint64_t *direct_num, zbx_uint64_t *direct_sz, zbx_uint64_t *history_sz,
+		char **error)
 {
 	unsigned char	*result;
 
@@ -1212,7 +1217,7 @@ int	zbx_preprocessor_get_diag_stats(zbx_uint64_t *preproc_num, zbx_uint64_t *pen
 	}
 
 	zbx_preprocessor_unpack_diag_stats(preproc_num, pending_num, finished_num, sequences_num, queued_num,
-			queued_sz, direct_num, direct_sz, result);
+			queued_sz, direct_num, direct_sz, history_sz, result);
 	zbx_free(result);
 
 	return SUCCEED;
@@ -1286,6 +1291,26 @@ int	zbx_preprocessor_get_top_values_size(int limit, zbx_vector_pp_top_stats_ptr_
 	return preprocessor_get_top_view(limit, stats, error, ZBX_IPC_PREPROCESSOR_TOP_VALUES_SZ);
 }
 
+/******************************************************************************
+ *                                                                            *
+ * Purpose: get the top N items by the elapsed time                           *
+ *                                                                            *
+ ******************************************************************************/
+int	zbx_preprocessor_get_top_time_ms(int limit, zbx_vector_pp_top_stats_ptr_t *stats, char **error)
+{
+	return preprocessor_get_top_view(limit, stats, error, ZBX_IPC_PREPROCESSOR_TOP_TIME_MS);
+}
+
+/******************************************************************************
+ *                                                                            *
+ * Purpose: get the top N items by the total elapsed time                     *
+ *                                                                            *
+ ******************************************************************************/
+int	zbx_preprocessor_get_top_total_ms(int limit, zbx_vector_pp_top_stats_ptr_t *stats, char **error)
+{
+	return preprocessor_get_top_view(limit, stats, error, ZBX_IPC_PREPROCESSOR_TOP_TOTAL_MS);
+}
+
 /******************************************************************************
  *                                                                            *
  * Purpose: get preprocessing manager diagnostic statistics                   *
diff --git a/src/libs/zbxpreproc/pp_protocol.h b/src/libs/zbxpreproc/pp_protocol.h
index e81191f2d81..30335615778 100644
--- a/src/libs/zbxpreproc/pp_protocol.h
+++ b/src/libs/zbxpreproc/pp_protocol.h
@@ -36,6 +36,8 @@
 #define ZBX_IPC_PREPROCESSOR_SIZE			10011
 #define ZBX_IPC_PREPROCESSOR_TOP_VALUES_NUM		10012
 #define ZBX_IPC_PREPROCESSOR_TOP_VALUES_SZ		10013
+#define ZBX_IPC_PREPROCESSOR_TOP_TIME_MS		10014
+#define ZBX_IPC_PREPROCESSOR_TOP_TOTAL_MS		10015
 
 /* item value data used in preprocessing manager */
 typedef struct
@@ -75,14 +77,15 @@ void	zbx_preprocessor_unpack_test_result(zbx_vector_pp_result_ptr_t *results, zb
 
 zbx_uint32_t	zbx_preprocessor_pack_diag_stats(unsigned char **data, zbx_uint64_t preproc_num,
 		zbx_uint64_t pending_num, zbx_uint64_t finished_num, zbx_uint64_t sequences_num,
-		zbx_uint64_t queued_num, zbx_uint64_t queued_sz, zbx_uint64_t direct_num, zbx_uint64_t direct_sz);
+		zbx_uint64_t queued_num, zbx_uint64_t queued_sz, zbx_uint64_t direct_num, zbx_uint64_t direct_sz,
+		zbx_uint64_t history_size);
 
 zbx_uint32_t	zbx_preprocessor_pack_values_stats(unsigned char **data, zbx_uint64_t queued_num,
 		zbx_uint64_t queued_sz, zbx_uint64_t direct_num, zbx_uint64_t direct_sz, zbx_uint64_t enqueued_num);
 
 void	zbx_preprocessor_unpack_diag_stats(zbx_uint64_t *preproc_num, zbx_uint64_t *pending_num,
 		zbx_uint64_t *finished_num, zbx_uint64_t *sequences_num, zbx_uint64_t *queued_num,
-		zbx_uint64_t *queued_sz, zbx_uint64_t *direct_num, zbx_uint64_t *direct_sz,
+		zbx_uint64_t *queued_sz, zbx_uint64_t *direct_num, zbx_uint64_t *direct_sz, zbx_uint64_t *history_sz,
 		const unsigned char *data);
 
 void	zbx_preprocessor_unpack_values_stats(zbx_uint64_t *queued_num, zbx_uint64_t *queued_sz,
diff --git a/src/libs/zbxpreproc/pp_worker.c b/src/libs/zbxpreproc/pp_worker.c
index e6323eed7fe..5044fb8c562 100644
--- a/src/libs/zbxpreproc/pp_worker.c
+++ b/src/libs/zbxpreproc/pp_worker.c
@@ -161,7 +161,7 @@ static void	*pp_worker_entry(void *args)
 					break;
 			}
 
-			zbx_timekeeper_update(worker->timekeeper, worker->id - 1, ZBX_PROCESS_STATE_IDLE);
+			in->time_ms = zbx_timekeeper_update(worker->timekeeper, worker->id - 1, ZBX_PROCESS_STATE_IDLE);
 
 			pp_task_queue_lock(queue);
 			pp_task_queue_push_finished(queue, in);
diff --git a/src/libs/zbxpreprocbase/pp_history.c b/src/libs/zbxpreprocbase/pp_history.c
index c2ecd6eb505..89bc7567508 100644
--- a/src/libs/zbxpreprocbase/pp_history.c
+++ b/src/libs/zbxpreprocbase/pp_history.c
@@ -219,3 +219,22 @@ void	zbx_pp_history_cache_history_set_and_release(zbx_pp_history_cache_t *histor
 
 	pthread_mutex_unlock(&history_cache->lock);
 }
+
+zbx_uint64_t	zbx_pp_history_cache_history_size(zbx_pp_history_cache_t *history_cache)
+{
+	zbx_uint64_t	history_size = 0;
+
+	if (NULL == history_cache)
+		return 0;
+
+	pthread_mutex_lock(&history_cache->lock);
+
+	if (NULL != history_cache->history)
+	{
+		for (int i = 0; i < history_cache->history->step_history.values_num; i++)
+			history_size += zbx_variant_size(&history_cache->history->step_history.values[i].value);
+	}
+	pthread_mutex_unlock(&history_cache->lock);
+
+	return history_size;
+}
diff --git a/src/libs/zbxpreprocbase/pp_item.c b/src/libs/zbxpreprocbase/pp_item.c
index b20e25b0ff8..984b25282b5 100644
--- a/src/libs/zbxpreprocbase/pp_item.c
+++ b/src/libs/zbxpreprocbase/pp_item.c
@@ -50,6 +50,8 @@ zbx_pp_item_preproc_t	*zbx_pp_item_preproc_create(zbx_uint64_t hostid, unsigned
 
 	preproc->values_num = 0;
 	preproc->values_sz = 0;
+	preproc->time_ms = 0;
+	preproc->total_ms = 0;
 
 	preproc->mode = ZBX_PP_PROCESS_PARALLEL;
 
diff --git a/src/libs/zbxtimekeeper/timekeeper.c b/src/libs/zbxtimekeeper/timekeeper.c
index 4a86e2e8265..ba41a248df6 100644
--- a/src/libs/zbxtimekeeper/timekeeper.c
+++ b/src/libs/zbxtimekeeper/timekeeper.c
@@ -269,13 +269,13 @@ void	zbx_timekeeper_free(zbx_timekeeper_t *timekeeper)
  *           once per half timekeeper delay interval.                         *
  *                                                                            *
  ******************************************************************************/
-void	zbx_timekeeper_update(zbx_timekeeper_t *timekeeper, int index, unsigned char state)
+zbx_uint64_t	zbx_timekeeper_update(zbx_timekeeper_t *timekeeper, int index, unsigned char state)
 {
 	zbx_timekeeper_unit_t	*unit;
-	clock_t			ticks;
+	clock_t			ticks, elapsed;
 
 	if (0 > index || index >= timekeeper->units_num)
-		return;
+		return 0;
 
 	unit = timekeeper->units + index;
 
@@ -283,7 +283,7 @@ void	zbx_timekeeper_update(zbx_timekeeper_t *timekeeper, int index, unsigned cha
 	{
 		zabbix_log(LOG_LEVEL_WARNING, "cannot get process times: %s", zbx_strerror(errno));
 		unit->cache.state = state;
-		return;
+		return 0;
 	}
 
 	if (0 == unit->cache.ticks_flush)
@@ -291,11 +291,12 @@ void	zbx_timekeeper_update(zbx_timekeeper_t *timekeeper, int index, unsigned cha
 		unit->cache.ticks_flush = ticks;
 		unit->cache.state = state;
 		unit->cache.ticks = ticks;
-		return;
+		return 0;
 	}
 
 	/* update process statistics in local cache */
-	unit->cache.counter[unit->cache.state] += (zbx_uint64_t)(ticks - unit->cache.ticks);
+	elapsed = (ticks - unit->cache.ticks);
+	unit->cache.counter[unit->cache.state] += (zbx_uint64_t)elapsed;
 
 	if (ZBX_TIMEKEEPER_FLUSH_DELAY < (double)(ticks - unit->cache.ticks_flush) / (double)timekeeper->ticks_per_sec)
 	{
@@ -327,6 +328,8 @@ void	zbx_timekeeper_update(zbx_timekeeper_t *timekeeper, int index, unsigned cha
 	/* update local timekeeper cache */
 	unit->cache.state = state;
 	unit->cache.ticks = ticks;
+
+	return (double)(elapsed * 1000) / (double)timekeeper->ticks_per_sec;
 }
 
 /******************************************************************************
diff --git a/src/libs/zbxvariant/variant.c b/src/libs/zbxvariant/variant.c
index f5cf81d4c3d..deb76da6dc1 100644
--- a/src/libs/zbxvariant/variant.c
+++ b/src/libs/zbxvariant/variant.c
@@ -418,6 +418,42 @@ const char	*zbx_variant_type_desc(const zbx_variant_t *value)
 	return zbx_get_variant_type_desc(value->type);
 }
 
+zbx_uint64_t	zbx_variant_size(const zbx_variant_t *value)
+{
+	zbx_uint64_t	size = 0;
+	zbx_uint32_t	size32;
+
+	switch (value->type)
+	{
+		case ZBX_VARIANT_STR:
+			size = strlen(value->data.str) + 1;
+			break;
+		case ZBX_VARIANT_BIN:
+			memcpy(&size32, value->data.bin, sizeof(size32));
+			size = size32;
+			break;
+		case ZBX_VARIANT_ERR:
+			size = strlen(value->data.err);
+			break;
+		case ZBX_VARIANT_VECTOR:
+			if (NULL != value->data.vector)
+			{
+				int	i;
+
+				size += sizeof(zbx_vector_var_t);
+				for (i = 0; i < value->data.vector->values_num; i++)
+					size += zbx_variant_size(&value->data.vector->values[i]);
+
+				size += sizeof(zbx_variant_t) * (value->data.vector->values_alloc - i);
+			}
+			break;
+		default:
+			break;
+	}
+
+	return size + sizeof(zbx_variant_t);
+}
+
 /******************************************************************************
  *                                                                            *
  * Purpose: compares two variant values when at least one is empty (having    *
