xref: /aosp_15_r20/external/autotest/client/site_tests/hardware_SAT/hardware_SAT.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Lint as: python2, python3
2# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import logging, re, struct, sys, time
7
8from autotest_lib.client.bin import test, utils
9from autotest_lib.client.common_lib import error
10
11def memory_channel_args_snb_bdw(channel_modules):
12    """Add arguments for memory testing.
13    Works on sandybridge, ivybridge, broadwell. Maybe others?
14
15    @param channel_modules: channel names.
16    """
17
18    with open('/proc/bus/pci/00/00.0', 'r', 0) as fd:
19        fd.seek(0x48)
20        mchbar = struct.unpack('=I', fd.read(4))[0]
21    if not mchbar & 1:
22        raise error.TestError('Host Memory Mapped Register Range not enabled.')
23    mchbar &= ~1
24
25    with open('/dev/mem', 'r', 0) as fd:
26        fd.seek(mchbar + 0x5000)
27        mad_chnl = struct.unpack('=I', fd.read(4))[0]
28        fd.seek(mchbar + 0x5024)
29        channel_hash = struct.unpack('=I', fd.read(4))[0]
30
31    if (mad_chnl >> 4) & 3 != 2:
32        raise error.TestError('This test does not support triple-channel mode.')
33    if mad_chnl & 3 == 0 and (mad_chnl >> 2) & 3 == 1:
34        channel_order = [0, 1]
35    elif mad_chnl & 3 == 1 and (mad_chnl >> 2) & 3 == 0:
36        logging.warning('Non-default memory channel configuration... please '
37                     'double-check that this is correct and intended.')
38        channel_order = [1, 0]
39    else:
40        raise error.TestError('Invalid channel configuration: %x' % mad_chnl)
41
42    if not channel_hash & (1 << 23):
43        logging.warning('Memory channel_hash deactivated... going with cache-line '
44                     'sized ping-pong as a wild guess.')
45        channel_hash = 1
46    channel_hash = (channel_hash & 0x3FFF) << 6
47
48    return (' --memory_channel %s --memory_channel %s --channel_hash 0x%x'
49            ' --channel_width 64' % (
50                    ','.join(channel_modules[channel_order[0]]),
51                    ','.join(channel_modules[channel_order[1]]),
52                    channel_hash))
53
54
55class hardware_SAT(test.test):
56    """Run SAT."""
57
58    version = 1
59
60
61    def run_once(self, seconds=60, free_memory_fraction=0.95, wait_secs=0,
62                 disk_thread=True):
63        '''
64        Args:
65          free_memory_fraction: Fraction of free memory (as determined by
66            utils.freememtotal()) to use.
67          wait_secs: time to wait in seconds before executing stressapptest.
68          disk_thread: also stress disk using -f argument of stressapptest.
69        '''
70        assert free_memory_fraction > 0
71        assert free_memory_fraction < 1
72
73        # Wait other parallel tests memory usage to settle to a stable value, so
74        # stressapptest will not claim too much memory.
75        if wait_secs:
76            time.sleep(wait_secs)
77
78        # Allow shmem access to all of memory. This is used for 32 bit
79        # access to > 1.4G. Virtual address space limitation prevents
80        # directly mapping the memory.
81        utils.run('mount -o remount,size=100% /dev/shm')
82        cpus = max(utils.count_cpus(), 1)
83        mbytes = max(int(utils.freememtotal() * free_memory_fraction / 1024),
84                     512)
85        # Even though shared memory allows us to go past the 1.4G
86        # limit, ftruncate still limits us to 2G max on 32 bit systems.
87        if sys.maxsize < 2**32 and mbytes > 2047:
88            mbytes = 2047
89        # SAT should use as much memory as possible, while still
90        # avoiding OOMs and allowing the kernel to run, so that
91        # the maximum amoun tof memory can be tested.
92        args = ' -M %d' % mbytes  # megabytes to test
93        # The number of seconds under test can be chosen to fit into
94        # manufacturing or test flow. 60 seconds gives several
95        # passes and several patterns over each memory location
96        # and should catch clearly fautly memeory. 4 hours
97        # is an effective runin test, to catch lower frequency errors.
98        args += ' -s %d' % seconds  # seconds to run
99        # One memory copy thread per CPU should keep the memory bus
100        # as saturated as possible, while keeping each CPU busy as well.
101        args += ' -m %d' % cpus  # memory copy threads.
102        # SSE copy and checksum increases the rate at which the CPUs
103        # can drive memory, as well as stressing the CPU.
104        args += ' -W'  # Use SSE optimizatin in memory threads.
105        # File IO threads allow stressful transactions over the
106        # south bridge and SATA, as well as potentially finding SSD
107        # or disk cache problems. Two threads ensure multiple
108        # outstanding transactions to the disk, if supported.
109        if disk_thread:
110            args += ' -f sat.diskthread.a'  # disk thread
111            args += ' -f sat.diskthread.b'
112
113        if utils.get_board() == 'link':
114            args += memory_channel_args_snb_bdw([
115                    ['U1', 'U2', 'U3', 'U4'],
116                    ['U6', 'U5', 'U7', 'U8']])  # yes, U6 is actually before U5
117
118        if utils.get_board() == 'samus':
119            args += memory_channel_args_snb_bdw([
120                    ['U11', 'U12'],
121                    ['U13', 'U14']])
122
123        # 'stressapptest' is provided by dev-util/stressapptest, pre-installed
124        # in test images.
125        sat = utils.run('stressapptest' + args)
126        logging.debug(sat.stdout)
127        if not re.search('Status: PASS', sat.stdout):
128            raise error.TestFail(sat.stdout)
129