1#!/usr/bin/python
2# -*- coding: utf-8 -*-
3"""
4Auxiliary script used to allocate memory on guests.
5
6@copyright: 2008-2009 Red Hat Inc.
7@author: Jiri Zupka (jzupka@redhat.com)
8"""
9
10
11import os, array, sys, random, copy, tempfile, datetime, math
12
13PAGE_SIZE = 4096 # machine page size
14
15TMPFS_OVERHEAD = 0.0022 # overhead on 1MB of write data
16
17
18class MemFill(object):
19    """
20    Fills guest memory according to certain patterns.
21    """
22    def __init__(self, mem, static_value, random_key):
23        """
24        Constructor of MemFill class.
25
26        @param mem: Amount of test memory in MB.
27        @param random_key: Seed of random series used for fill up memory.
28        @param static_value: Value used to fill all memory.
29        """
30        if (static_value < 0 or static_value > 255):
31            print ("FAIL: Initialization static value"
32                   "can be only in range (0..255)")
33            return
34
35        self.tmpdp = tempfile.mkdtemp()
36        ret_code = os.system("mount -o size=%dM tmpfs %s -t tmpfs" %
37                             ((mem+math.ceil(mem*TMPFS_OVERHEAD)),
38                             self.tmpdp))
39        if ret_code != 0:
40            if os.getuid() != 0:
41                print ("FAIL: Unable to mount tmpfs "
42                       "(likely cause: you are not root)")
43            else:
44                print "FAIL: Unable to mount tmpfs"
45        else:
46            self.f = tempfile.TemporaryFile(prefix='mem', dir=self.tmpdp)
47            self.allocate_by = 'L'
48            self.npages = ((mem * 1024 * 1024) / PAGE_SIZE)
49            self.random_key = random_key
50            self.static_value = static_value
51            print "PASS: Initialization"
52
53
54    def __del__(self):
55        if os.path.ismount(self.tmpdp):
56            self.f.close()
57            os.system("umount %s" % (self.tmpdp))
58
59
60    def compare_page(self, original, inmem):
61        """
62        Compare pages of memory and print the differences found.
63
64        @param original: Data that was expected to be in memory.
65        @param inmem: Data in memory.
66        """
67        for ip in range(PAGE_SIZE / original.itemsize):
68            if (not original[ip] == inmem[ip]): # find which item is wrong
69                originalp = array.array("B")
70                inmemp = array.array("B")
71                originalp.fromstring(original[ip:ip+1].tostring())
72                inmemp.fromstring(inmem[ip:ip+1].tostring())
73                for ib in range(len(originalp)): # find wrong byte in item
74                    if not (originalp[ib] == inmemp[ib]):
75                        position = (self.f.tell() - PAGE_SIZE + ip *
76                                    original.itemsize + ib)
77                        print ("Mem error on position %d wanted 0x%Lx and is "
78                               "0x%Lx" % (position, originalp[ib], inmemp[ib]))
79
80
81    def value_page(self, value):
82        """
83        Create page filled by value.
84
85        @param value: String we want to fill the page with.
86        @return: return array of bytes size PAGE_SIZE.
87        """
88        a = array.array("B")
89        for i in range((PAGE_SIZE / a.itemsize)):
90            try:
91                a.append(value)
92            except:
93                print "FAIL: Value can be only in range (0..255)"
94        return a
95
96
97    def random_page(self, seed):
98        """
99        Create page filled by static random series.
100
101        @param seed: Seed of random series.
102        @return: Static random array series.
103        """
104        random.seed(seed)
105        a = array.array(self.allocate_by)
106        for i in range(PAGE_SIZE / a.itemsize):
107            a.append(random.randrange(0, sys.maxint))
108        return a
109
110
111    def value_fill(self, value=None):
112        """
113        Fill memory page by page, with value generated with value_page.
114
115        @param value: Parameter to be passed to value_page. None to just use
116                what's on the attribute static_value.
117        """
118        self.f.seek(0)
119        if value is None:
120            value = self.static_value
121        page = self.value_page(value)
122        for pages in range(self.npages):
123            page.tofile(self.f)
124        print "PASS: Mem value fill"
125
126
127    def value_check(self, value=None):
128        """
129        Check memory to see if data is correct.
130
131        @param value: Parameter to be passed to value_page. None to just use
132                what's on the attribute static_value.
133        @return: if data in memory is correct return PASS
134                else print some wrong data and return FAIL
135        """
136        self.f.seek(0)
137        e = 2
138        failure = False
139        if value is None:
140            value = self.static_value
141        page = self.value_page(value)
142        for pages in range(self.npages):
143            pf = array.array("B")
144            pf.fromfile(self.f, PAGE_SIZE / pf.itemsize)
145            if not (page == pf):
146                failure = True
147                self.compare_page(page, pf)
148                e = e - 1
149                if e == 0:
150                    break
151        if failure:
152            print "FAIL: value verification"
153        else:
154            print "PASS: value verification"
155
156
157    def static_random_fill(self, n_bytes_on_end=PAGE_SIZE):
158        """
159        Fill memory by page with static random series with added special value
160        on random place in pages.
161
162        @param n_bytes_on_end: how many bytes on the end of page can be changed.
163        @return: PASS.
164        """
165        self.f.seek(0)
166        page = self.random_page(self.random_key)
167        random.seed(self.random_key)
168        p = copy.copy(page)
169
170        t_start = datetime.datetime.now()
171        for pages in range(self.npages):
172            rand = random.randint(((PAGE_SIZE / page.itemsize) - 1) -
173                                  (n_bytes_on_end / page.itemsize),
174                                  (PAGE_SIZE/page.itemsize) - 1)
175            p[rand] = pages
176            p.tofile(self.f)
177            p[rand] = page[rand]
178
179        t_end = datetime.datetime.now()
180        delta = t_end - t_start
181        milisec = delta.microseconds / 1e3 + delta.seconds * 1e3
182        print "PASS: filling duration = %Ld ms" % milisec
183
184
185    def static_random_verify(self, n_bytes_on_end=PAGE_SIZE):
186        """
187        Check memory to see if it contains correct contents.
188
189        @return: if data in memory is correct return PASS
190                else print some wrong data and return FAIL.
191        """
192        self.f.seek(0)
193        e = 2
194        page = self.random_page(self.random_key)
195        random.seed(self.random_key)
196        p = copy.copy(page)
197        failure = False
198        for pages in range(self.npages):
199            rand = random.randint(((PAGE_SIZE/page.itemsize) - 1) -
200                                  (n_bytes_on_end/page.itemsize),
201                                  (PAGE_SIZE/page.itemsize) - 1)
202            p[rand] = pages
203            pf = array.array(self.allocate_by)
204            pf.fromfile(self.f, PAGE_SIZE / pf.itemsize)
205            if not (p == pf):
206                failure = True
207                self.compare_page(p, pf)
208                e = e - 1
209                if e == 0:
210                    break
211            p[rand] = page[rand]
212        if failure:
213            print "FAIL: Random series verification"
214        else:
215            print "PASS: Random series verification"
216
217
218def die():
219    """
220    Quit allocator.
221    """
222    exit(0)
223
224
225def main():
226    """
227    Main (infinite) loop of allocator.
228    """
229    print "PASS: Start"
230    end = False
231    while not end:
232        str = raw_input()
233        exec str
234
235
236if __name__ == "__main__":
237    main()
238