1#!/usr/bin/env python
2#
3#   Copyright 2017 - The Android Open Source Project
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16import os
17
18from metrics.metric import Metric
19
20
21class ReadMetric(Metric):
22    """Find read speed of /dev/sda using hdparm
23
24    Attributes:
25      NUM_RUNS: number of times hdparm is run
26    """
27    NUM_RUNS = 3
28    COMMAND = 'for i in {1..%s}; do hdparm -Tt /dev/sda; done'
29    # Fields for response dictionary
30    CACHED_READ_RATE = 'cached_read_rate'
31    BUFFERED_READ_RATE = 'buffered_read_rate'
32
33    def is_privileged(self):
34        """Checks if this module is being ran as the necessary root user.
35
36        Returns:
37            T if being run as root, F if not.
38        """
39
40        return os.getuid() == 0
41
42    def gather_metric(self):
43        """Finds read speed of /dev/sda
44
45        Takes approx 50 seconds to return, runs hdparm 3 times at
46        18 seconds each time to get an average. Should be performed on an
47        inactive system, with no other active processes.
48
49        Returns:
50            A dict with the following fields:
51              cached_read_rate: cached reads in MB/sec
52              buffered_read_rate: buffered disk reads in MB/sec
53        """
54        # Run shell command
55        # Example stdout:
56
57        # /dev/sda:
58        # Timing cached reads:   18192 MB in  2.00 seconds = 9117.49 MB/sec
59        # Timing buffered disk reads: 414 MB in  3.07 seconds = 134.80 MB/sec
60
61        # /dev/sda:
62        # Timing cached reads:   18100 MB in  2.00 seconds = 9071.00 MB/sec
63        # Timing buffered disk reads: 380 MB in  3.01 seconds = 126.35 MB/sec
64
65        # /dev/sda:
66        # Timing cached reads:   18092 MB in  2.00 seconds = 9067.15 MB/sec
67        # Timing buffered disk reads: 416 MB in  3.01 seconds = 138.39 MB/sec
68
69        if not self.is_privileged():
70            return {self.CACHED_READ_RATE: None, self.BUFFERED_READ_RATE: None}
71
72        result = self._shell.run(self.COMMAND % self.NUM_RUNS).stdout
73
74        cached_reads = 0.0
75        buffered_reads = 0.0
76        # Calculate averages
77        for ln in result.splitlines():
78            if ln.startswith(' Timing cached'):
79                cached_reads += float(ln.split()[-2])
80            elif ln.startswith(' Timing buffered'):
81                buffered_reads += float(ln.split()[-2])
82        # Create response dictionary
83        response = {
84            self.CACHED_READ_RATE: cached_reads / self.NUM_RUNS,
85            self.BUFFERED_READ_RATE: buffered_reads / self.NUM_RUNS
86        }
87        return response
88