1f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidouimport os, logging
2f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
3f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidoufrom autotest_lib.client.bin import utils
4f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidoufrom autotest_lib.client.common_lib import error, autotemp
5f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidoufrom autotest_lib.client.cros import power_status
6f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidoufrom autotest_lib.client.cros import storage as storage_mod
7f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
8f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
9f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidouclass hardware_MultiReaderPowerConsumption(storage_mod.StorageTester):
10f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    version = 1
11f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    _files_to_delete = []
12f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    _ramdisk_path = None
13f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    _storage = None
14f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
15f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
16f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    def initialize(self):
17f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        super(hardware_MultiReaderPowerConsumption, self).initialize()
18f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
19f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # Make sure we're not on AC power
20f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self.status = power_status.get_status()
21f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        if self.status.on_ac():
22f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            raise error.TestNAError(
23f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                  'This test needs to be run with the AC power offline')
24f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
25f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
26f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    def cleanup(self):
27f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # Remove intermediate files
28f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        for path in self._files_to_delete:
29f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            utils.system('rm -f %s' % path)
30f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
31f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        if self._storage and os.path.ismount(self._storage['mountpoint']):
32f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            self.scanner.umount_volume(storage_dict=self._storage)
33f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
34f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        if self._ramdisk_path and os.path.ismount(self._ramdisk_path.name):
35f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            umount_ramdisk(self._ramdisk_path.name)
36f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            self._ramdisk_path.clean()
37f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
38f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        super(hardware_MultiReaderPowerConsumption, self).cleanup()
39f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
40f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
41f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    def readwrite_test(self, path, size, delete_file=False):
42f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        """Heavy-duty random read/write test. Run `dd` & `tail -f` in parallel
43f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
44f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        The random write is done by writing a file from /dev/urandom into the
45f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        given location, while the random read is done by concurrently reading
46f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        that file.
47f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
48f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        @param path: The directory that will create the test file.
49f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        @param size: Size of the test file, in MiB.
50f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        @param delete_file: Flag the file to be deleted on test exit.
51f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou               Otherwise file deletion won't be performed.
52f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        """
53f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # Calculate the parameters for dd
54f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        size = 1024*1024*size
55f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        blocksize = 8192
56f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
57f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # Calculate the filename and full path, flag to delete if needed
58f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        filename = 'tempfile.%d.delete-me' % size
59f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        pathfile = os.path.join(path, filename)
60f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        if delete_file:
61f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            self._files_to_delete.append(pathfile)
62f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
63f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        pid = os.fork() # We need to run two processes in parallel
64f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        if pid:
65f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            # parent
66f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            utils.BgJob('tail -f %s --pid=%s > /dev/null'
67f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                        % (pathfile, pid))
68f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            # Reap the dd child so that tail does not wait for the zombie
69f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            os.waitpid(pid, 0)
70f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        else:
71f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            # child
72f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            utils.system('dd if=/dev/urandom of=%s bs=%d count=%s'
73f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                         % (pathfile, blocksize, (size//blocksize)))
74f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            # A forked child is exiting here, so we really do want os._exit:
75f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            os._exit(0)
76f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
77f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
78f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    def run_once(self, ramdisk_size=513, file_size=512, drain_limit=1.05,
79f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                 volume_filter={'bus': 'usb'}):
80f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        """Test card reader CPU power consumption to be within acceptable
81f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        range while performing random r/w
82f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
83f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        The random r/w is performed in the readwrite_test() method, by
84f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        concurrently running `dd if=/dev/urandom` and `tail -f`. It is run once
85f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        on a ramdisk with the SD card mounted, then on the SD card with the
86f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        ramdisk unmounted, and then on the SD card with the ramdisk unmounted.
87f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        The measured values are then reported.
88f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
89f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        @param ramdisk_size: Size of ramdisk (in MiB).
90f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        @param file_size: Size of test file (in MiB).
91f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        @param volume_filter: Where to find the card reader.
92f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        @param drain_limit: maximum ratio between the card reader
93f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                            energy consumption and each of the two
94f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                            ramdisk read/write test energy consumption
95f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                            values. 1.00 means the card reader test may
96f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                            not consume more energy than either ramdisk
97f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                            test, 0.9 means it may consume no more than
98f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                            90% of the ramdisk value, and so forth.
99f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        """
100f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # Switch to VT2 so the screen turns itself off automatically instead of
101f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # dimming, in order to reduce the battery consuption caused by other
102f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # variables.
103f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        utils.system('chvt 2')
104f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
105f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        logging.debug('STEP 1: ensure SD card is inserted and mounted')
106f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self._storage = self.wait_for_device(volume_filter, cycles=1,
107f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                                             mount_volume=True)[0]
108f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
109f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        logging.debug('STEP 2: mount the ramdisk')
110f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self._ramdisk_path = autotemp.tempdir(unique_id='ramdisk',
111f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                                              dir=self.tmpdir)
112f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        mount_ramdisk(self._ramdisk_path.name, ramdisk_size)
113f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
114f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # Read current charge, as well as maximum charge.
115f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self.status.refresh()
116f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        max_charge = self.status.battery[0].charge_full_design
117f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        initial_charge = self.status.battery[0].charge_now
118f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
119f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        logging.debug('STEP 3: perform heavy-duty read-write test on ramdisk')
120f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self.readwrite_test(self._ramdisk_path.name, file_size)
121f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # Read current charge (reading A)
122f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self.status.refresh()
123f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        charge_A = self.status.battery[0].charge_now
124f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
125f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        logging.debug('STEP 4: unmount ramdisk')
126f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        umount_ramdisk(self._ramdisk_path.name)
127f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
128f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        logging.debug('STEP 5: perform identical read write test on SD card')
129f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self.readwrite_test(self._storage['mountpoint'], file_size,
130f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                            delete_file=True)
131f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # Read current charge (reading B)
132f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self.status.refresh()
133f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        charge_B = self.status.battery[0].charge_now
134f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
135f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        logging.debug('STEP 6: unmount card')
136f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self.scanner.umount_volume(storage_dict=self._storage, args='-f -l')
137f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
138f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        logging.debug('STEP 7: perform ramdisk test again')
139f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        mount_ramdisk(self._ramdisk_path.name, ramdisk_size)
140f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self.readwrite_test(self._ramdisk_path.name, file_size)
141f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # Read current charge (reading C)
142f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        self.status.refresh()
143f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        charge_C = self.status.battery[0].charge_now
144f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
145f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        # Compute the results
146f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        ramdisk_plus = initial_charge - charge_A
147f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        sd_card_solo = charge_A - charge_B
148f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        ramdisk_solo = charge_B - charge_C
149f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
150f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        sd_card_drain_ratio_a = (sd_card_solo / ramdisk_plus)
151f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        sd_card_drain_ratio_b = (sd_card_solo / ramdisk_solo)
152f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
153f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        msg = None
154f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        if sd_card_drain_ratio_a > drain_limit:
155f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            msg = ('Card reader drain exceeds mounted baseline by > %f (%f)'
156f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                   % (drain_limit, sd_card_drain_ratio_a))
157f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        elif sd_card_drain_ratio_b > drain_limit:
158f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            msg = ('Card reader drain exceeds unmounted baseline by > %f (%f)'
159f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou                   % (drain_limit, sd_card_drain_ratio_b))
160f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
161f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        if msg:
162f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            raise error.TestError(msg)
163f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou        else:
164f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            fmt = 'Card reader drain ratio Ok: mounted %f; unmounted %f'
165f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou            logging.info(fmt % (sd_card_drain_ratio_a, sd_card_drain_ratio_b))
166f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
167f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
168f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidoudef mount_ramdisk(path, size):
169f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    utils.system('mount -t tmpfs none %s -o size=%sm' % (path, size))
170f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
171f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
172f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidoudef umount_ramdisk(path):
173f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    """Umount ramdisk mounted at |path|
174f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou
175f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    @param path: the mountpoint for the mountd RAM disk
176f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    """
177f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    utils.system('rm -rf %s/*' % path)
178f445f429e77e00e37819e06d31de6e2a76c8ab80Vivia Nikolaidou    utils.system('umount -f -l %s' % path)
179