master
py 130 lines 4.03 KB
Raw
1 #!/usr/bin/env python3
2 #
3 # validate-memory-counts.py: check we instrumented memory properly
4 #
5 # This program takes two inputs:
6 # - the mem plugin output
7 # - the memory binary output
8 #
9 # Copyright (C) 2024 Linaro Ltd
10 #
11 # SPDX-License-Identifier: GPL-2.0-or-later
12
13 import sys
14 from argparse import ArgumentParser
15
16 def extract_counts(path):
17 """
18 Load the output from path and extract the lines containing:
19
20 Test data start: 0x40214000
21 Test data end: 0x40218001
22 Test data read: 2522280
23 Test data write: 262111
24
25 From the stream of data. Extract the values for use in the
26 validation function.
27 """
28 start_address = None
29 end_address = None
30 read_count = 0
31 write_count = 0
32 with open(path, 'r') as f:
33 for line in f:
34 if line.startswith("Test data start:"):
35 start_address = int(line.split(':')[1].strip(), 16)
36 elif line.startswith("Test data end:"):
37 end_address = int(line.split(':')[1].strip(), 16)
38 elif line.startswith("Test data read:"):
39 read_count = int(line.split(':')[1].strip())
40 elif line.startswith("Test data write:"):
41 write_count = int(line.split(':')[1].strip())
42 return start_address, end_address, read_count, write_count
43
44
45 def parse_plugin_output(path, start, end):
46 """
47 Load the plugin output from path in the form of:
48
49 Region Base, Reads, Writes, Seen all
50 0x0000000040004000, 31093, 0, false
51 0x0000000040214000, 2522280, 278579, true
52 0x0000000040000000, 137398, 0, false
53 0x0000000040210000, 54727397, 33721956, false
54
55 And extract the ranges that match test data start and end and
56 return the results.
57 """
58 total_reads = 0
59 total_writes = 0
60 seen_all = False
61
62 with open(path, 'r') as f:
63 next(f) # Skip the header
64 for line in f:
65
66 if line.startswith("Region Base"):
67 continue
68
69 parts = line.strip().split(', ')
70 if len(parts) != 4:
71 continue
72
73 region_base = int(parts[0], 16)
74 reads = int(parts[1])
75 writes = int(parts[2])
76
77 if start <= region_base < end: # Checking if within range
78 total_reads += reads
79 total_writes += writes
80 seen_all = parts[3] == "true"
81
82 return total_reads, total_writes, seen_all
83
84 def main() -> None:
85 """
86 Process the arguments, injest the program and plugin out and
87 verify they match up and report if they do not.
88 """
89 parser = ArgumentParser(description="Validate memory instrumentation")
90 parser.add_argument('test_output',
91 help="The output from the test itself")
92 parser.add_argument('plugin_output',
93 help="The output from memory plugin")
94 parser.add_argument('--bss-cleared',
95 action='store_true',
96 help='Assume bss was cleared (and adjusts counts).')
97
98 args = parser.parse_args()
99
100 # Extract counts from memory binary
101 start, end, exp_reads, exp_writes = extract_counts(args.test_output)
102
103 # Some targets clear BSS before running but the test doesn't know
104 # that so we adjust it by the size of the test region.
105 if args.bss_cleared:
106 exp_writes += 16384
107
108 if start is None or end is None:
109 print("Failed to test_data boundaries from output.")
110 sys.exit(1)
111
112 # Parse plugin output
113 preads, pwrites, seen_all = parse_plugin_output(args.plugin_output,
114 start, end)
115
116 if not seen_all:
117 print("Fail: didn't instrument all accesses to test_data.")
118 sys.exit(1)
119
120 # Compare and report
121 if preads == exp_reads and pwrites == exp_writes:
122 sys.exit(0)
123 else:
124 print("Fail: The memory reads and writes count does not match.")
125 print(f"Expected Reads: {exp_reads}, Actual Reads: {preads}")
126 print(f"Expected Writes: {exp_writes}, Actual Writes: {pwrites}")
127 sys.exit(1)
128
129 if __name__ == "__main__":
130 main()