Fix bug in fio scenario 35/1635/2
authorhoujingwen <houjingwen@huawei.com>
Wed, 16 Sep 2015 11:19:15 +0000 (11:19 +0000)
committerhoujingwen <houjingwen@huawei.com>
Thu, 24 Sep 2015 03:24:44 +0000 (11:24 +0800)
1) when duration>3600s in fio.yaml, ssh time out
2) sometimes the latency value in test result is null
3) update plot.py, fit for code update in fio.py
4) small bug in file.py (result output dump)

Add --output-format=json in default args, so fio command
can return json format data.

JIRA: YARDSTICK-143

Change-Id: Ie02977b8c9f11986a1eed66896b84d18db3d2211
Signed-off-by: houjingwen <houjingwen@huawei.com>
samples/fio.yaml
tests/unit/benchmark/scenarios/storage/fio_sample_output.json [new file with mode: 0644]
tests/unit/benchmark/scenarios/storage/test_fio.py
yardstick/benchmark/scenarios/storage/fio.py
yardstick/benchmark/scenarios/storage/fio_benchmark.bash
yardstick/dispatcher/file.py
yardstick/plot/plotter.py

index 44444c7..083c575 100644 (file)
@@ -2,48 +2,13 @@
 # Sample benchmark task config file
 # measure storage performance using fio
 #
-# For this sample just like running the command below on the test vm and 
+# For this sample just like running the command below on the test vm and
 # getting benchmark info back to the yardstick.
 #
-# sudo fio -filename=/home/ec2-user/data.raw -bs=4k -ipdepth=1 -rw=write \
+# sudo fio -filename=/home/ec2-user/data.raw -bs=4k -ipdepth=1 -rw=rw \
 #          -ramp_time=10 -runtime=60 -name=yardstick-fio -ioengine=libaio \
 #          -direct=1 -group_reporting -numjobs=1 -time_based \
-#          --output=yardstick-fio.log
-#
-# When the above fio command done, the yardstick-fio.log file will contain 
-# information like below and the benchmark script will take iops, throughput 
-# and latency info marked with "" to create json style output.
-#
-# yardstick-fio: (g=0): rw=write, bs=4K-4K/4K-4K/4K-4K, ioengine=libaio, iodepth=1
-# fio-2.1.3
-# Starting 1 process
-#
-# yardstick-fio: (groupid=0, jobs=1): err= 0: pid=1421: Mon Jul  6 01:25:41 2015
-#   write: io=1985.4MB, bw=33882KB/s, iops="8470", runt= 60001msec
-#     slat (usec): min=6, max=15049, avg=10.29, stdev=19.42
-#     clat (usec): min=1, max=18517, avg=105.68, stdev=37.76
-#      lat ("usec"): min=85, max=18528, avg="116.30", stdev=43.57
-#     clat percentiles (usec):
-#      |  1.00th=[   83],  5.00th=[   85], 10.00th=[   87], 20.00th=[   88],
-#      | 30.00th=[   90], 40.00th=[   93], 50.00th=[   98], 60.00th=[  102],
-#      | 70.00th=[  110], 80.00th=[  124], 90.00th=[  137], 95.00th=[  149],
-#      | 99.00th=[  173], 99.50th=[  181], 99.90th=[  203], 99.95th=[  290],
-#      | 99.99th=[  604]
-#     bw (KB  /s): min=    0, max=39816, per=99.26%, avg=33631.46, stdev=4369.58
-#     lat (usec) : 2=0.01%, 50=0.01%, 100=55.44%, 250=44.50%, 500=0.02%
-#     lat (usec) : 750=0.04%, 1000=0.01%
-#     lat (msec) : 2=0.01%, 4=0.01%, 10=0.01%, 20=0.01%
-#   cpu          : usr=4.09%, sys=16.38%, ctx=604931, majf=0, minf=27
-#   IO depths    : 1=118.9%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
-#      submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
-#      complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
-#      issued    : total=r=0/w=508237/d=0, short=r=0/w=0/d=0
-#
-# Run status group 0 (all jobs):
-#   WRITE: io=1985.4MB, aggrb="33881KB/s", minb=33881KB/s, maxb=33881KB/s, mint=60001msec, maxt=60001msec
-#
-# Disk stats (read/write):
-#   vda: ios=0/604235, merge=0/211, ticks=0/61964, in_queue=61804, util=86.25%
+#          --output-format=json
 
 schema: "yardstick:task:0.1"
 
@@ -54,7 +19,7 @@ scenarios:
     filename: /home/ec2-user/data.raw
     bs: 4k
     iodepth: 1
-    rw: write
+    rw: rw
     ramp_time: 10
   host: fio.demo
   runner:
diff --git a/tests/unit/benchmark/scenarios/storage/fio_sample_output.json b/tests/unit/benchmark/scenarios/storage/fio_sample_output.json
new file mode 100644 (file)
index 0000000..4c75018
--- /dev/null
@@ -0,0 +1 @@
+{"jobs": [{"trim": {"io_bytes": 0, "slat": {"max": 0, "mean": 0.0, "stddev": 0.0, "min": 0}, "bw_max": 0, "bw_mean": 0.0, "iops": 0, "bw": 0, "lat": {"max": 0, "mean": 0.0, "stddev": 0.0, "min": 0}, "bw_agg": 0.0, "clat": {"max": 0, "mean": 0.0, "percentile": {"70.000000": 0, "5.000000": 0, "50.000000": 0, "99.990000": 0, "30.000000": 0, "10.000000": 0, "99.000000": 0, "0.00": 0, "90.000000": 0, "95.000000": 0, "60.000000": 0, "40.000000": 0, "20.000000": 0, "99.900000": 0, "99.950000": 0, "1.000000": 0, "99.500000": 0, "80.000000": 0}, "stddev": 0.0, "min": 0}, "runtime": 0, "bw_min": 0, "bw_dev": 0.0}, "latency_us": {"10": 0.01, "750": 0.03, "20": 0.0, "50": 0.02, "2": 0.01, "4": 0.01, "100": 0.75, "250": 88.37, "500": 10.72, "1000": 0.01}, "latency_ms": {"10": 0.01, "750": 0.0, "20": 0.01, ">=2000": 0.0, "50": 0.01, "2000": 0.0, "2": 0.07, "4": 0.01, "100": 0.0, "250": 0.01, "500": 0.0, "1000": 0.01}, "read": {"io_bytes": 839056, "slat": {"max": 1990, "mean": 18.14, "stddev": 15.4, "min": 0}, "bw_max": 10328, "bw_mean": 8721.27, "iops": 20972, "bw": 83888, "lat": {"max": 776676, "mean": 236.8, "stddev": 4668.12, "min": 45}, "bw_agg": 8721.27, "clat": {"max": 776663, "mean": 217.79, "percentile": {"70.000000": 199, "5.000000": 119, "50.000000": 175, "99.990000": 15168, "30.000000": 155, "10.000000": 131, "99.000000": 342, "0.00": 0, "90.000000": 247, "95.000000": 278, "60.000000": 185, "40.000000": 165, "20.000000": 145, "99.900000": 820, "99.950000": 1272, "1.000000": 96, "99.500000": 370, "80.000000": 217}, "stddev": 4667.79, "min": 0}, "runtime": 10002, "bw_min": 4, "bw_dev": 2178.08}, "majf": 0, "ctx": 490590, "minf": 87, "jobname": "yardstick-fio", "write": {"io_bytes": 841992, "slat": {"max": 2594, "mean": 19.78, "stddev": 16.25, "min": 0}, "bw_max": 10472, "bw_mean": 8464.0, "iops": 21045, "bw": 84182, "lat": {"max": 776709, "mean": 233.55, "stddev": 3115.46, "min": 64}, "bw_agg": 8464.0, "clat": {"max": 776685, "mean": 212.87, "percentile": {"70.000000": 211, "5.000000": 135, "50.000000": 187, "99.990000": 3536, "30.000000": 169, "10.000000": 145, "99.000000": 358, "0.00": 0, "90.000000": 258, "95.000000": 290, "60.000000": 197, "40.000000": 177, "20.000000": 159, "99.900000": 756, "99.950000": 1288, "1.000000": 114, "99.500000": 382, "80.000000": 229}, "stddev": 3115.23, "min": 0}, "runtime": 10002, "bw_min": 4, "bw_dev": 2584.23}, "iodepth_level": {"16": 0.0, "32": 0.0, "1": 111.92, "2": 0.0, "4": 0.0, ">=64": 0.0, "8": 0.0}, "usr_cp": 2.87, "error": 0, "sys_cp": 12.37, "groupid": 0}], "fio version": "fio-2.1.3", "disk_util": [{"aggr_write_ticks": 42020, "read_merges": 0, "name": "dm-0", "write_ios": 233547, "aggr_write_ios": 235129, "aggr_read_ticks": 42576, "read_ios": 233492, "util": 97.22, "read_ticks": 42096, "aggr_write_merge": 0, "write_merges": 0, "aggr_in_queue": 84524, "aggr_read_ios": 235224, "aggr_util": 96.96, "aggr_read_merges": 0, "in_queue": 83732, "write_ticks": 41468}, {"read_merges": 0, "name": "vda", "write_ios": 235129, "read_ios": 235224, "util": 96.96, "read_ticks": 42576, "write_merges": 0, "in_queue": 84524, "write_ticks": 42020}]}
index 54f493e..45e8a94 100644 (file)
@@ -14,6 +14,7 @@
 import mock
 import unittest
 import json
+import os
 
 from yardstick.benchmark.scenarios.storage import fio
 
@@ -34,7 +35,7 @@ class FioTestCase(unittest.TestCase):
         options = {
             'filename': "/home/ec2-user/data.raw",
             'bs': "4k",
-            'rw': "write",
+            'rw': "rw",
             'ramp_time': 10
         }
         args = {'options': options}
@@ -50,19 +51,21 @@ class FioTestCase(unittest.TestCase):
         options = {
             'filename': "/home/ec2-user/data.raw",
             'bs': "4k",
-            'rw': "write",
+            'rw': "rw",
             'ramp_time': 10
         }
         args = {'options': options}
         p.client = mock_ssh.SSH()
 
-        sample_output = '{"read_bw": "N/A", "write_lat": "407.08usec", \
-            "read_iops": "N/A", "write_bw": "9507KB/s", \
-            "write_iops": "2376", "read_lat": "N/A"}'
+        sample_output = self._read_sample_output()
         mock_ssh.SSH().execute.return_value = (0, sample_output, '')
 
         result = p.run(args)
-        expected_result = json.loads(sample_output)
+
+        expected_result = '{"read_bw": 83888, "read_iops": 20972,' \
+            '"read_lat": 236.8, "write_bw": 84182, "write_iops": 21045,'\
+            '"write_lat": 233.55}'
+        expected_result = json.loads(expected_result)
         self.assertEqual(result, expected_result)
 
     def test_fio_unsuccessful_script_error(self, mock_ssh):
@@ -71,7 +74,7 @@ class FioTestCase(unittest.TestCase):
         options = {
             'filename': "/home/ec2-user/data.raw",
             'bs': "4k",
-            'rw': "write",
+            'rw': "rw",
             'ramp_time': 10
         }
         args = {'options': options}
@@ -80,6 +83,12 @@ class FioTestCase(unittest.TestCase):
         mock_ssh.SSH().execute.return_value = (1, '', 'FOOBAR')
         self.assertRaises(RuntimeError, p.run, args)
 
+    def _read_sample_output(self):
+        curr_path = os.path.dirname(os.path.abspath(__file__))
+        output = os.path.join(curr_path, 'fio_sample_output.json')
+        with open(output) as f:
+            sample_output = f.read()
+        return sample_output
 
 def main():
     unittest.main()
index d369516..42f1591 100644 (file)
@@ -17,7 +17,7 @@ LOG = logging.getLogger(__name__)
 
 
 class Fio(base.Scenario):
-    """Execute fio benchmark on host
+    """Execute fio benchmark in a host
 
   Parameters
     filename - file name for fio workload
@@ -73,8 +73,9 @@ class Fio(base.Scenario):
 
     def run(self, args):
         """execute the benchmark"""
-        default_args = "-ioengine=libaio -direct=1 " \
-            "-group_reporting -numjobs=1 -time_based"
+        default_args = "-ioengine=libaio -direct=1 -group_reporting " \
+            "-numjobs=1 -time_based --output-format=json"
+        result = {}
 
         if not self.setup_done:
             self.setup()
@@ -97,21 +98,32 @@ class Fio(base.Scenario):
         else:
             runtime = 30
 
-        args = "-filename=%s -bs=%s -iodepth=%s -rw=%s -ramp_time=%s " \
-               "-runtime=%s -name=%s" \
-               % (filename, bs, iodepth, rw, ramp_time, runtime, name)
-        cmd = "sudo bash fio.sh %s %s %s" \
-              % (filename, args, default_args)
+        cmd_args = "-filename=%s -bs=%s -iodepth=%s -rw=%s -ramp_time=%s " \
+                   "-runtime=%s -name=%s %s" \
+                   % (filename, bs, iodepth, rw, ramp_time, runtime, name,
+                      default_args)
+        cmd = "sudo bash fio.sh %s %s" % (filename, cmd_args)
         LOG.debug("Executing command: %s", cmd)
-        status, stdout, stderr = self.client.execute(cmd)
+        # Set timeout, so that the cmd execution does not exit incorrectly
+        # when the test run time is last long
+        timeout = int(ramp_time) + int(runtime) + 600
+        status, stdout, stderr = self.client.execute(cmd, timeout=timeout)
         if status:
             raise RuntimeError(stderr)
 
-        data = json.loads(stdout)
+        raw_data = json.loads(stdout)
+
+        # The bandwidth unit is KB/s, and latency unit is us
+        result["read_bw"] = raw_data["jobs"][0]["read"]["bw"]
+        result["read_iops"] = raw_data["jobs"][0]["read"]["iops"]
+        result["read_lat"] = raw_data["jobs"][0]["read"]["lat"]["mean"]
+        result["write_bw"] = raw_data["jobs"][0]["write"]["bw"]
+        result["write_iops"] = raw_data["jobs"][0]["write"]["iops"]
+        result["write_lat"] = raw_data["jobs"][0]["write"]["lat"]["mean"]
 
         # TODO: add sla check
 
-        return data
+        return result
 
 
 def _test():
@@ -133,8 +145,9 @@ def _test():
         "filename": "/home/ec2-user/data.raw",
         "bs": "4k",
         "iodepth": "1",
-        "rw": "write",
-        "ramp_time": 10,
+        "rw": "rw",
+        "ramp_time": 1,
+        "duration": 10
     }
     args = {"options": options}
 
index 0fa319d..2ef7f49 100644 (file)
@@ -15,7 +15,6 @@ set -e
 FIO_FILENAME=$1
 shift
 OPTIONS="$@"
-OUTPUT_FILE="yardstick-fio.log"
 
 # setup data file for fio
 setup()
@@ -25,43 +24,10 @@ setup()
     fi
 }
 
-# run fio test
+# run fio test and write json format result to stdout
 run_test()
 {
-    fio $OPTIONS --output=$OUTPUT_FILE
-}
-
-# write the result to stdout in json format
-output_json()
-{
-    read_bw=$(grep "READ.*aggrb"  $OUTPUT_FILE | awk -F [=\ ,] '{printf $9}')
-    write_bw=$(grep "WRITE.*aggrb" $OUTPUT_FILE | awk -F [=\ ,] '{printf $8}')
-    eval $(grep -e '\ lat.*stdev' -e "read.*iops" -e "write.*iops" -e "trim.*iops" $OUTPUT_FILE | sed 'N;s/\n/ /g' | grep read | awk -F [=\ ,\(\)] '{printf("read_iops=%s; read_lat_unit=%s; read_lat=%s", $12, $24, $33)}')
-    eval $(grep -e '\ lat.*stdev' -e "read.*iops" -e "write.*iops" -e "trim.*iops" $OUTPUT_FILE | sed 'N;s/\n/ /g' | grep write | awk -F [=\ ,\(\)] '{printf("write_iops=%s; write_lat_unit=%s; write_lat=%s", $11, $23, $32)}')
-
-    read_bw=${read_bw:-N/A}
-    write_bw=${write_bw:-N/A}
-    read_iops=${read_iops:-N/A}
-    write_iops=${write_iops:-N/A}
-    if [ "x$read_lat" = "x" ]; then
-        read_lat="N/A"
-    else
-        read_lat=$read_lat$read_lat_unit
-    fi
-    if [ "x$write_lat" = "x" ]; then
-        write_lat="N/A"
-    else
-        write_lat=$write_lat$write_lat_unit
-    fi
-
-    echo -e "{ \
-        \"read_bw\":\"$read_bw\", \
-        \"write_bw\":\"$write_bw\", \
-        \"read_iops\":\"$read_iops\", \
-        \"write_iops\":\"$write_iops\", \
-        \"read_lat\":\"$read_lat\", \
-        \"write_lat\":\"$write_lat\" \
-    }"
+    fio $OPTIONS
 }
 
 # main entry
@@ -71,10 +37,7 @@ main()
     setup
 
     # run the test
-    run_test >/dev/null
-
-    # output result
-    output_json
+    run_test
 }
 
 main
index 7c644f8..dc39f15 100644 (file)
@@ -8,6 +8,7 @@
 ##############################################################################
 
 import logging
+import json
 
 from yardstick.dispatcher.base import Base as DispatchBase
 
@@ -50,4 +51,4 @@ class FileDispatcher(DispatchBase):
 
     def record_result_data(self, data):
         if self.log:
-            self.log.info(data)
+            self.log.info(json.dumps(data))
index f3fb75d..0455386 100644 (file)
@@ -213,16 +213,16 @@ class Plotter(object):
             is_rw_type = rw_types[i] == "rw" or rw_types[i] == "randrw"
 
             if is_r_type or is_rw_type:
-                # Remove trailing 'usec' and convert to float
+                # Convert to float
                 data['read_lat'] = \
-                    [r['benchmark']['data']['read_lat'][:-4] for r in records]
+                    [r['benchmark']['data']['read_lat'] for r in records]
                 data['read_lat'] = \
                     [float(i) for i in data['read_lat']]
-                # Remove trailing 'KB/s' and convert to float
+                # Convert to int
                 data['read_bw'] = \
-                    [r['benchmark']['data']['read_bw'][:-4] for r in records]
+                    [r['benchmark']['data']['read_bw'] for r in records]
                 data['read_bw'] =  \
-                    [float(i) for i in data['read_bw']]
+                    [int(i) for i in data['read_bw']]
                 # Convert to int
                 data['read_iops'] = \
                     [r['benchmark']['data']['read_iops'] for r in records]
@@ -231,14 +231,14 @@ class Plotter(object):
 
             if is_w_type or is_rw_type:
                 data['write_lat'] = \
-                    [r['benchmark']['data']['write_lat'][:-4] for r in records]
+                    [r['benchmark']['data']['write_lat'] for r in records]
                 data['write_lat'] = \
                     [float(i) for i in data['write_lat']]
 
                 data['write_bw'] = \
-                    [r['benchmark']['data']['write_bw'][:-4] for r in records]
+                    [r['benchmark']['data']['write_bw'] for r in records]
                 data['write_bw'] = \
-                    [float(i) for i in data['write_bw']]
+                    [int(i) for i in data['write_bw']]
 
                 data['write_iops'] = \
                     [r['benchmark']['data']['write_iops'] for r in records]