diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 25171da8e81e9bc7c61afb01af6990cdbe196a12..4e6a4c6a8bced7b21eb3f5dd8b984d5d5141d510 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -84,7 +84,7 @@ set (server_sources
      iobuf.cc
      coio_buf.cc
      pickle.cc
-     stat.cc
+     rmean.cc
      ipc.cc
      latch.cc
      errinj.cc
diff --git a/src/box/box.cc b/src/box/box.cc
index 6722e32f4df4f749c20f24e7c7c22f9c5561f1e9..c2b87fc305fdec2f1e3f8c962889e4eda677c697 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -36,7 +36,7 @@
 #include "recovery.h"
 #include "relay.h"
 #include "replica.h"
-#include <stat.h>
+#include <rmean.h>
 #include "main.h"
 #include "tuple.h"
 #include "lua/call.h"
@@ -583,7 +583,7 @@ box_free(void)
 		tuple_free();
 		port_free();
 		engine_shutdown();
-		stat_free();
+		rmean_delete(rmean_box);
 	}
 }
 
@@ -615,8 +615,7 @@ box_init(void)
 		   cfg_geti("slab_alloc_maximal"),
 		   cfg_getd("slab_alloc_factor"));
 
-	stat_init();
-	stat_base = stat_register(iproto_type_strs, IPROTO_TYPE_STAT_MAX);
+	rmean_box = rmean_new(iproto_type_strs, IPROTO_TYPE_STAT_MAX);
 
 	engine_init();
 
@@ -678,7 +677,7 @@ box_init(void)
 
 	engine_end_recovery();
 
-	stat_cleanup(stat_base, IPROTO_TYPE_STAT_MAX);
+	rmean_cleanup(rmean_box);
 
 	if (recovery_has_replica(recovery))
 		recovery_follow_replica(recovery);
diff --git a/src/box/iproto.cc b/src/box/iproto.cc
index 0cdb34e22f541bc2b14b96c9bebdca7e5027e1a3..8cfff83417af653b903cbc39f65a115a35aa6b9c 100644
--- a/src/box/iproto.cc
+++ b/src/box/iproto.cc
@@ -50,7 +50,7 @@
 #include "iproto_constants.h"
 #include "user_def.h"
 #include "authentication.h"
-#include "stat.h"
+#include "rmean.h"
 #include "lua/call.h"
 
 /* {{{ iproto_msg - declaration */
@@ -650,12 +650,12 @@ tx_process_msg(struct cmsg *m)
 			break;
 		case IPROTO_CALL:
 			assert(msg->request.type == msg->header.type);
-			stat_collect(stat_base, msg->request.type, 1);
+			rmean_collect(rmean_box, msg->request.type, 1);
 			box_lua_call(&msg->request, out);
 			break;
 		case IPROTO_EVAL:
 			assert(msg->request.type == msg->header.type);
-			stat_collect(stat_base, msg->request.type, 1);
+			rmean_collect(rmean_box, msg->request.type, 1);
 			box_lua_eval(&msg->request, out);
 			break;
 		case IPROTO_AUTH:
diff --git a/src/box/lua/stat.cc b/src/box/lua/stat.cc
index 00b85a415dd04de56481664b956c2980cc8e4e28..7aa56497429d432b4280cad414d1269ee5b04016 100644
--- a/src/box/lua/stat.cc
+++ b/src/box/lua/stat.cc
@@ -32,7 +32,8 @@
 #include "stat.h"
 
 #include <string.h>
-#include <stat.h>
+#include <rmean.h>
+#include <box/request.h>
 
 extern "C" {
 #include <lua.h>
@@ -90,14 +91,14 @@ static int
 lbox_stat_index(struct lua_State *L)
 {
 	luaL_checkstring(L, -1);
-	return stat_foreach(seek_stat_item, L);
+	return rmean_foreach(rmean_box, seek_stat_item, L);
 }
 
 static int
 lbox_stat_call(struct lua_State *L)
 {
 	lua_newtable(L);
-	stat_foreach(set_stat_item, L);
+	rmean_foreach(rmean_box, set_stat_item, L);
 	return 1;
 }
 
diff --git a/src/box/request.cc b/src/box/request.cc
index 12e51f9cc14bc7927abdeda737c7e4d7bd44b782..952a6cf117f150addf7a9b9129fd1d85a47929e6 100644
--- a/src/box/request.cc
+++ b/src/box/request.cc
@@ -42,9 +42,9 @@
 #include <scoped_guard.h>
 #include "user_def.h"
 #include "iproto_constants.h"
-#include "stat.h"
+#include "rmean.h"
 
-int stat_base;
+struct rmean *rmean_box;
 
 enum dup_replace_mode
 dup_replace_mode(uint32_t op)
@@ -251,7 +251,7 @@ process_rw(struct request *request, struct port *port)
 	};
 	request_execute_f fun = execute_map[request->type];
 	assert(fun != NULL);
-	stat_collect(stat_base, request->type, 1);
+	rmean_collect(rmean_box, request->type, 1);
 	try {
 		fun(request, port);
 		port_eof(port);
diff --git a/src/box/request.h b/src/box/request.h
index 606f084e05474dc3803c736da489638763613759..5732e135e08ec66674bec9e0e424ec2e25c380b6 100644
--- a/src/box/request.h
+++ b/src/box/request.h
@@ -35,7 +35,9 @@
 
 struct txn;
 struct port;
-extern int stat_base;
+
+/** box statistics */
+extern struct rmean *rmean_box;
 
 struct request
 {
diff --git a/src/main.cc b/src/main.cc
index 7e5d98b6b19fc2099cee405cdee39663ece8d7c9..1a93791dd413f46a023ff96d7339acaa84ce9b03 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -53,7 +53,7 @@
 #include <crc32.h>
 #include "memory.h"
 #include <say.h>
-#include <stat.h>
+#include <rmean.h>
 #include <limits.h>
 #include "trivia/util.h"
 #include "tt_pthread.h"
diff --git a/src/rmean.cc b/src/rmean.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b16c20a78b5ac9a32377a94a9e97415a8cbe9532
--- /dev/null
+++ b/src/rmean.cc
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2010-2015, Tarantool AUTHORS, please see AUTHORS file.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the
+ *    following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "rmean.h"
+
+#include <say.h>
+
+#include <assoc.h>
+
+
+void
+rmean_collect(struct rmean *rmean, size_t name, int64_t value)
+{
+	rmean->stats[name].value[0] += value;
+	rmean->stats[name].total += value;
+}
+
+int
+rmean_foreach(struct rmean *rmean, rmean_cb cb, void *cb_ctx)
+{
+	for (size_t i = 0; i < rmean->stats_n; i++) {
+		if (rmean->stats[i].name == NULL)
+			continue;
+
+		int diff = 0;
+		for (size_t j = 1; j <= PERF_SECS; j++)
+			diff += rmean->stats[i].value[j];
+		/* value[0] not adds because second isn't over */
+
+		diff /= PERF_SECS;
+
+		int res = cb(rmean->stats[i].name, diff,
+			     rmean->stats[i].total, cb_ctx);
+		if (res != 0)
+			return res;
+	}
+	return 0;
+
+}
+
+void
+rmean_age(ev_loop * /* loop */,
+	 ev_timer *timer, int /* events */)
+{
+	struct rmean *rmean = (struct rmean *) timer->data;
+	if (rmean->stats == NULL)
+		return;
+
+	for (size_t i = 0; i < rmean->stats_n; i++) {
+		if (rmean->stats[i].name == NULL)
+			continue;
+
+		for (int j = PERF_SECS - 1; j >= 0;  j--)
+			rmean->stats[i].value[j + 1] =
+					rmean->stats[i].value[j];
+		rmean->stats[i].value[0] = 0;
+	}
+
+	ev_timer_again(loop(), timer);
+}
+
+void
+rmean_timer_tick(struct rmean *rmean)
+{
+	rmean_age(loop(), &rmean->timer, 0);
+}
+
+struct rmean *
+rmean_new(const char **name, size_t n)
+{
+	struct rmean *rmean = (struct rmean *) realloc(NULL,
+				sizeof(rmean) + sizeof(stats) * (n + 1));
+	if (rmean == NULL)
+		return NULL;
+	memset(rmean, 0, sizeof(rmean) + sizeof(stats) * n);
+	rmean->stats_n = n;
+	rmean->timer.data = (void *)rmean;
+	ev_timer_init(&rmean->timer, rmean_age, 0, 1.);
+	ev_timer_again(loop(), &rmean->timer);
+	for (size_t i = 0; i < n; i++, name++) {
+		rmean->stats[i].name = *name;
+
+		if (*name == NULL)
+			continue;
+	}
+	return rmean;
+}
+
+void
+rmean_delete(struct rmean *rmean)
+{
+	if (rmean) {
+		ev_timer_stop(loop(), &rmean->timer);
+		free(rmean);
+	}
+}
+
+void
+rmean_cleanup(struct rmean *rmean)
+{
+	for (size_t i = 0; i < rmean->stats_n; i++) {
+		for (size_t j = 0; j < PERF_SECS + 1; j++)
+			rmean->stats[i].value[j] = 0;
+		rmean->stats[i].total = 0;
+	}
+}
diff --git a/src/stat.h b/src/rmean.h
similarity index 66%
rename from src/stat.h
rename to src/rmean.h
index 0fc4aa7f15b76c5e94609b8f51e3175351d2421a..5b980b620c06d03694ef658ca9a5b4de54203275 100644
--- a/src/stat.h
+++ b/src/rmean.h
@@ -1,5 +1,5 @@
-#ifndef TARANTOOL_STAT_H_INCLUDED
-#define TARANTOOL_STAT_H_INCLUDED
+#ifndef TARANTOOL_RMEAN_H_INCLUDED
+#define TARANTOOL_RMEAN_H_INCLUDED
 /*
  * Copyright 2010-2015, Tarantool AUTHORS, please see AUTHORS file.
  *
@@ -34,16 +34,33 @@
 #include <stddef.h>
 #include <stdint.h>
 
-void stat_init(void);
-void stat_free(void);
-void stat_cleanup(int base, size_t max_idx);
-int stat_register(const char **name, size_t count);
-extern int stat_max_name_len;
+#include "trivia/util.h"
+#include "fiber.h"
 
-void stat_collect(int base, int name, int64_t value);
+#define PERF_SECS 5
 
-typedef int (*stat_cb)(const char *name, int rps, int64_t total, void *cb_ctx);
+struct stats {
+	const char *name;
+	int64_t value[PERF_SECS + 1];
+	int64_t total;
+};
 
-int stat_foreach(stat_cb cb, void *cb_ctx);
+struct rmean {
+	ev_timer timer;
+	int stats_n;
+	struct stats stats[0];
+};
 
-#endif /* TARANTOOL_STAT_H_INCLUDED */
+struct rmean *rmean_new(const char **name, size_t n);
+void rmean_delete(struct rmean *rmean);
+void rmean_cleanup(struct rmean *rmean);
+
+void rmean_timer_tick(struct rmean *rmean);
+
+void rmean_collect(struct rmean *rmean, size_t name, int64_t value);
+
+typedef int (*rmean_cb)(const char *name, int rps, int64_t total, void *cb_ctx);
+
+int rmean_foreach(struct rmean *rmean, rmean_cb cb, void *cb_ctx);
+
+#endif /* TARANTOOL_RMEAN_H_INCLUDED */
diff --git a/src/stat.cc b/src/stat.cc
deleted file mode 100644
index 5e9ed99548d68e48aae9d66680b220be4bad34b5..0000000000000000000000000000000000000000
--- a/src/stat.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2010-2015, Tarantool AUTHORS, please see AUTHORS file.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- *    copyright notice, this list of conditions and the
- *    following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#include "stat.h"
-
-#include "trivia/util.h"
-#include "fiber.h"
-#include <say.h>
-
-#include <assoc.h>
-
-#define SECS 5
-static ev_timer timer;
-
-struct stats {
-	const char *name;
-	int64_t value[SECS + 1];
-} *stats = NULL;
-static int stats_size = 0;
-static int stats_max = 0;
-static int base = 0;
-int stat_max_name_len = 0;
-
-static void
-stat_recalc_max_name_len()
-{
-	stat_max_name_len = 0;
-	for (unsigned i = 0; i <= stats_max; i++) {
-		if (stats[i].name != NULL)
-			stat_max_name_len = MAX(stat_max_name_len,
-						strlen(stats[i].name));
-	}
-}
-
-int
-stat_register(const char **name, size_t max_idx)
-{
-	int initial_base = base;
-
-	for (int i = 0; i < max_idx; i++, name++, base++) {
-		if (stats_size <= base) {
-			stats_size += 1024;
-			stats = (struct stats *) realloc(stats, sizeof(*stats) * stats_size);
-			if (stats == NULL)
-				abort();
-		}
-
-		stats[base].name = *name;
-
-		if (*name == NULL)
-			continue;
-
-		for (int i = 0; i < SECS + 1; i++)
-			stats[base].value[i] = 0;
-
-		stats_max = base;
-	}
-	stat_recalc_max_name_len();
-
-	return initial_base;
-}
-
-void
-stat_collect(int base, int name, int64_t value)
-{
-	stats[base + name].value[0] += value;
-	stats[base + name].value[SECS] += value;
-}
-
-int
-stat_foreach(stat_cb cb, void *cb_ctx)
-{
-	for (unsigned i = 0; i <= stats_max; i++) {
-		if (stats[i].name == NULL)
-			continue;
-
-		int diff = 0;
-		for (int j = 0; j < SECS; j++)
-			diff += stats[i].value[j];
-
-		diff /= SECS;
-
-		int res = cb(stats[i].name, diff,
-			     stats[i].value[SECS], cb_ctx);
-		if (res != 0)
-			return res;
-	}
-	return 0;
-
-}
-
-void
-stat_age(ev_loop * /* loop */, ev_timer *timer, int /* events */)
-{
-	if (stats == NULL)
-		return;
-
-	for (int i = 0; i <= stats_max; i++) {
-		if (stats[i].name == NULL)
-			continue;
-
-		for (int j = SECS - 2; j >= 0;  j--)
-			stats[i].value[j + 1] = stats[i].value[j];
-		stats[i].value[0] = 0;
-	}
-
-	ev_timer_again(loop(), timer);
-}
-
-void
-stat_init(void)
-{
-	ev_init(&timer, stat_age);
-	timer.repeat = 1.;
-	ev_timer_again(loop(), &timer);
-}
-
-void
-stat_free(void)
-{
-	ev_timer_stop(loop(), &timer);
-	if (stats)
-		free(stats);
-}
-
-void
-stat_cleanup(int base, size_t max_idx)
-{
-	for (int i = base; i < max_idx; i++)
-		for (int j = 0; j < SECS + 1; j++)
-			stats[i].value[j] = 0;
-}
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index f76c65b22a0048e625455f1e683c2f1b1f98e9df..384fc7674ffa4fd93e752fe4cbf54a9ecb3bce75 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -117,3 +117,7 @@ add_executable(reflection_cxx.test reflection_cxx.cc unit.c
 add_executable(csv.test csv.c
     ${CMAKE_SOURCE_DIR}/src/lib/csv/csv.c
 )
+
+add_executable(rmean.test rmean.cc unit.c
+        ${CMAKE_SOURCE_DIR}/src/rmean.cc)
+target_link_libraries(rmean.test core)
diff --git a/test/unit/rmean.cc b/test/unit/rmean.cc
new file mode 100644
index 0000000000000000000000000000000000000000..797d12dda10aef4d266869499a747f8a37090605
--- /dev/null
+++ b/test/unit/rmean.cc
@@ -0,0 +1,63 @@
+#include "rmean.h"
+#include "memory.h"
+#include "unit.h"
+
+int print_stat(const char *name, int rps, int64_t total, void* ctx)
+{
+	printf("%s: rps %d, total %d%c", name, rps, (int)total,
+	       name[2] == '2' ? '\n' : '\t');
+	return 0;
+}
+
+void test_100rps(rmean *st)
+{
+	header();
+	printf("Send 100 requests every second for 10 seconds\n");
+	printf("Calc rps at third and last second\n");
+	for(int i = 0; i < 10; i++) { /* 10 seconds */
+		rmean_collect(st, 0, 100); /* send 100 requests */
+		rmean_timer_tick(st);
+		if (i == 2 || i == 9) /* two checks */
+			rmean_foreach(st, print_stat, NULL);
+	}
+	/* 10 seconds, 1000 in EV1, 100 rps */
+	footer();
+}
+
+void test_mean15rps(rmean *st)
+{
+	header();
+	printf("Send 15 rps on the average, and 3 rps to EV2\n");
+	for(int i = 0; i < 10; i++) { /* 10 seconds */
+		for(int j = 0; j < 15; j++) {
+			rmean_collect(st, 0, 1); /* send 15 requests */
+			if((i * 3 + 2 + j) % 15 == 0)
+				rmean_timer_tick(st);
+		}
+		rmean_collect(st, 1, 3);
+	}
+	rmean_foreach(st, print_stat, NULL);
+	/* 10 seconds, 1000 + 150 in EV1, 15 rps. 30 in EV2, 3 rps*/
+	footer();
+}
+
+int main()
+{
+	printf("Stat. 2 names, timer simulation\n");
+
+	memory_init();
+	fiber_init();
+
+	struct rmean *st;
+	const char *name[] = {"EV1", "EV2"};
+	st = rmean_new(name, 2);
+
+	test_100rps(st);
+	test_mean15rps(st);
+
+	rmean_delete(st);
+
+	fiber_free();
+	memory_free();
+	return 0;
+}
diff --git a/test/unit/rmean.result b/test/unit/rmean.result
new file mode 100644
index 0000000000000000000000000000000000000000..b881d7becdefb36ef887aae88d4bdc380595a76e
--- /dev/null
+++ b/test/unit/rmean.result
@@ -0,0 +1,12 @@
+Stat. 2 names, timer simulation
+	*** test_100rps ***
+Send 100 requests every second for 10 seconds
+Calc rps at third and last second
+EV1: rps 60, total 300	EV2: rps 0, total 0
+EV1: rps 100, total 1000	EV2: rps 0, total 0
+	*** test_100rps: done ***
+ 	*** test_mean15rps ***
+Send 15 rps on the average, and 3 rps to EV2
+EV1: rps 15, total 1150	EV2: rps 3, total 30
+	*** test_mean15rps: done ***
+ 
\ No newline at end of file