fixes
diff --git a/wally/report.py b/wally/report.py
index 260c031..e24e7b6 100644
--- a/wally/report.py
+++ b/wally/report.py
@@ -4,6 +4,7 @@
 
 import wally
 from wally import charts
+from wally.statistic import round_3_digit
 from wally.utils import parse_creds, ssize_to_b
 from wally.suits.io.results_loader import process_disk_info
 from wally.meta_info import total_lab_info, collect_lab_data
@@ -12,11 +13,27 @@
 logger = logging.getLogger("wally.report")
 
 
+class DiskInfo(object):
+    def __init__(self):
+        self.direct_iops_r_max = 0
+        self.direct_iops_w_max = 0
+        self.rws4k_10ms = 0
+        self.rws4k_30ms = 0
+        self.rws4k_100ms = 0
+        self.bw_write_max = 0
+        self.bw_read_max = 0
+
+
 def render_hdd_html(dest, info, lab_description):
     very_root_dir = os.path.dirname(os.path.dirname(wally.__file__))
     templ_dir = os.path.join(very_root_dir, 'report_templates')
     templ_file = os.path.join(templ_dir, "report_hdd.html")
     templ = open(templ_file, 'r').read()
+
+    for name in info.__dict__:
+        if not name.startswith('__'):
+            info.__dict__[name] = round_3_digit(info.__dict__[name])
+
     report = templ.format(lab_info=lab_description, **info.__dict__)
     open(dest, 'w').write(report)
 
@@ -26,6 +43,11 @@
     templ_dir = os.path.join(very_root_dir, 'report_templates')
     templ_file = os.path.join(templ_dir, "report_ceph.html")
     templ = open(templ_file, 'r').read()
+
+    for name, val in info.__dict__.items():
+        if not name.startswith('__') and isinstance(val, (int, long, float)):
+            setattr(info, name, round_3_digit(val))
+
     report = templ.format(lab_info=lab_description, **info.__dict__)
     open(dest, 'w').write(report)
 
@@ -92,7 +114,8 @@
         chart_data.sort(key=lambda x: x.raw['concurence'])
 
         lat = [x.lat for x in chart_data]
-        concurence = [x.raw['concurence'] for x in chart_data]
+        vm_count = x.meta['testnodes_count']
+        concurence = [x.raw['concurence'] * vm_count for x in chart_data]
 
         if use_bw:
             data = [x.bw for x in chart_data]
@@ -106,17 +129,6 @@
         io_chart(desc, concurence, lat, data, data_dev, name, fname)
 
 
-class DiskInfo(object):
-    def __init__(self):
-        self.direct_iops_r_max = 0
-        self.direct_iops_w_max = 0
-        self.rws4k_10ms = 0
-        self.rws4k_30ms = 0
-        self.rws4k_100ms = 0
-        self.bw_write_max = 0
-        self.bw_read_max = 0
-
-
 def get_disk_info(processed_results):
     di = DiskInfo()
     rws4k_iops_lat_th = []
diff --git a/wally/sensors_utils.py b/wally/sensors_utils.py
index 1e9e898..20135b6 100644
--- a/wally/sensors_utils.py
+++ b/wally/sensors_utils.py
@@ -38,9 +38,9 @@
 
             if 'testnode' in source2roles_map.get(source_id, []):
                 sum_io_q = 0
-                data_store.update(rep_time,
-                                  {"testnodes:io": sum_io_q},
-                                  add=True)
+                data_store.update_values(rep_time,
+                                         {"testnodes:io": sum_io_q},
+                                         add=True)
     except Exception:
         logger.exception("Error in sensors thread")
     logger.info("Sensors thread exits")
@@ -66,10 +66,7 @@
                     monitor_url = node.monitor_url
                 else:
                     ip = node.get_ip()
-                    if ip == '127.0.0.1':
-                        ext_ip = '127.0.0.1'
-                    else:
-                        ext_ip = utils.get_ip_for_target(ip)
+                    ext_ip = utils.get_ip_for_target(ip)
                     monitor_url = receiver_url.format(ip=ext_ip)
 
                 source2roles_map[node.get_conn_id()] = node.roles
diff --git a/wally/suits/io/ceph.cfg b/wally/suits/io/ceph.cfg
index 085153f..7a84872 100644
--- a/wally/suits/io/ceph.cfg
+++ b/wally/suits/io/ceph.cfg
@@ -8,8 +8,9 @@
 filename={FILENAME}
 NUM_ROUNDS=7
 
-NUMJOBS={% 1, 5, 10, 15, 20, 30, 40, 80, 120 %}
-NUMJOBS_SHORT={% 1, 5, 10, 15, 20, 30, 40 %}
+NUMJOBS_LARGE={% 1, 5, 10, 15, 20, 30, 40, 80, 120 %}
+NUMJOBS_NORM={% 1, 5, 10, 15, 20, 30, 40 %}
+NUMJOBS_SHORT={% 1, 5, 10 %}
 
 size=30G
 ramp_time=30
@@ -22,7 +23,7 @@
 blocksize=4k
 rw=randwrite
 sync=1
-numjobs={NUMJOBS}
+numjobs={NUMJOBS_NORM}
 
 # ---------------------------------------------------------------------
 # direct write
@@ -41,7 +42,7 @@
 blocksize=4k
 rw=randread
 direct=1
-numjobs={NUMJOBS}
+numjobs={NUMJOBS_NORM}
 
 # ---------------------------------------------------------------------
 # this is essentially sequential read openration
@@ -60,4 +61,4 @@
 blocksize=1m
 rw=write
 direct=1
-numjobs={NUMJOBS}
+numjobs={NUMJOBS_NORM}
diff --git a/wally/suits/io/results_loader.py b/wally/suits/io/results_loader.py
index 3b50bf7..102fe4c 100644
--- a/wally/suits/io/results_loader.py
+++ b/wally/suits/io/results_loader.py
@@ -9,16 +9,16 @@
 PerfInfo = collections.namedtuple('PerfInfo',
                                   ('name',
                                    'bw', 'iops', 'dev',
-                                   'lat', 'lat_dev', 'raw'))
+                                   'lat', 'lat_dev', 'raw',
+                                   'meta'))
 
 
-def split_and_add(data, block_count):
-    assert len(data) % block_count == 0
-    res = [0] * (len(data) // block_count)
+def split_and_add(data, block_size):
+    assert len(data) % block_size == 0
+    res = [0] * block_size
 
-    for i in range(block_count):
-        for idx, val in enumerate(data[i::block_count]):
-            res[idx] += val
+    for idx, val in enumerate(data):
+        res[idx % block_size] += val
 
     return res
 
@@ -30,13 +30,22 @@
             pass
 
         vm_count = pre_result['__test_meta__']['testnodes_count']
-
         for name, results in pre_result['res'].items():
-            bw, bw_dev = med_dev(split_and_add(results['bw'], vm_count))
-            iops, iops_dev = med_dev(split_and_add(results['iops'], vm_count))
+            assert len(results['bw']) % vm_count == 0
+            block_count = len(results['bw']) // vm_count
+
+            # print
+            # print name, block_count
+            # print results['bw']
+            # print split_and_add(results['bw'], block_count)
+
+            bw, bw_dev = med_dev(split_and_add(results['bw'], block_count))
+            iops, iops_dev = med_dev(split_and_add(results['iops'],
+                                                   block_count))
             lat, lat_dev = med_dev(results['lat'])
             dev = bw_dev / float(bw)
-            data[name] = PerfInfo(name, bw, iops, dev, lat, lat_dev, results)
+            data[name] = PerfInfo(name, bw, iops, dev, lat, lat_dev, results,
+                                  pre_result['__test_meta__'])
     return data
 
 
diff --git a/wally/utils.py b/wally/utils.py
index dcc03cb..36601cd 100644
--- a/wally/utils.py
+++ b/wally/utils.py
@@ -10,6 +10,19 @@
 logger = logging.getLogger("wally")
 
 
+def is_ip(data):
+    if data.count('.') != 3:
+        return False
+
+    try:
+        for part in map(int, data.split('.')):
+            if part > 255 or part < 0:
+                raise ValueError()
+    except ValueError:
+        return False
+    return True
+
+
 def parse_creds(creds):
     # parse user:passwd@host
     user, passwd_host = creds.split(":", 1)
@@ -91,10 +104,11 @@
 
 
 def get_ip_for_target(target_ip):
-    if not re.match("[0-9]+\.[0-9]+\.[0-9]+\.[0-9]$", target_ip):
+    if not is_ip(target_ip):
         target_ip = socket.gethostbyname(target_ip)
 
-    if target_ip in ('localhost', '127.0.0.1', '127.0.1.1'):
+    first_dig = map(int, target_ip.split("."))
+    if first_dig == 127:
         return '127.0.0.1'
 
     cmd = 'ip route get to'.split(" ") + [target_ip]