-
Notifications
You must be signed in to change notification settings - Fork 16
/
Copy pathlinkmapCompare.rb
324 lines (262 loc) · 10.8 KB
/
linkmapCompare.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
#用法 ruby linkmapCompare.rb xxx-linkmap.txt yyy-linkmap.txt 即可以同目录下生成一个结果的json文件
require 'json'
class LinkMapParser
def buildResultWithSymbols(symbols)
result = ""
for symbol in symbols
result = result + symbol["size"].to_s + "\t" + symbol["file"].split("/")[-1] + "\r\n"
end
return result
end
def symbolMapFromContent(content)
symbolMap = Hash.new()
lines = content.split("\n")
reachFiles = false
reachSymbols = false
reachSections = false
hasPrintMap = false
for line in lines
if line.start_with?("#")
if line.start_with?("# Object files:")
reachFiles = true
elsif line.start_with?("# Sections:")
reachSections = true
elsif line.start_with?("# Symbols:")
reachSymbols = true
end
else
if reachFiles == true && reachSections == false && reachSymbols == false
range = line.rindex("]")
if range != nil
symModel = Hash.new()
symModel["file"] = line[range+1,line.length - range-1]
key = line[0,range+1]
symbolMap[key] = symModel
end
elsif reachFiles == true && reachSections == true && reachSymbols == true
if !hasPrintMap
# puts(JSON.pretty_generate(symbolMap).gsub(":", " =>"))
hasPrintMap = true
end
symbolsArray = line.split("\t")
if symbolsArray.count == 3
fileKeyAndName = symbolsArray[2]
#16进制转换
size = symbolsArray[1].to_i(16)
range = fileKeyAndName.index("]")
if range != nil
key = fileKeyAndName[0,range+1]
symbol = symbolMap[key]
if symbol != nil
if symbol["size"] == nil
symbol["size"] = 0
end
symbol["size"] = (size + symbol["size"])
else
puts(key + "未找到")
end
end
end
end
end
end
return symbolMap
end
def openContent(linkMapPath)
fileContent = File.read(linkMapPath).unpack('C*').pack('U*')
puts("开始解析原始linkmap文件...")
objectString = "# Object files:"
if !fileContent.include?(objectString)
puts("link map file 文件有误" + "Obj")
return
end
symbolString = "# Symbols:"
if !fileContent.include?(symbolString)
puts("link map file 文件有误" + "Symbol")
return
end
if !fileContent.include?("# Path:")
puts("link map file 文件有误" + "Path")
return
end
symbolMap = symbolMapFromContent(fileContent)
sortedSymbols = Array.new()
for key in symbolMap.keys
sortedSymbols.push(symbolMap[key])
end
#根据大小排序
sortedSymbols = sortedSymbols.sort_by {|hashObj| hashObj["size"]}.reverse
resultSymbols = buildResultWithSymbols(sortedSymbols)
puts("解析原始linkmap文件完成...")
return resultSymbols
end
end
class LibrarySizeAlaysizer
def prettyFormatClassResult(oriHash)
for libName in oriHash.keys
if libName != " DiffResult"
libHash = oriHash[libName]
finalArrayValue = Array.new()
for clsName in libHash.keys
clsHash = libHash[clsName]
resultString = ""
for resultKey in clsHash.keys
resultString = resultString + resultKey + " => " + clsHash[resultKey] + " "
end
simpleHash = Hash.new
simpleHash[clsName] = resultString
finalArrayValue.push(simpleHash)
end
oriHash[libName] = finalArrayValue
end
end
end
def alyTotalSize(sizeHash,versionOld,versionNew)
diffSizeArray = Array.new()
for libName in sizeHash.keys
libDiffSize = 0;
libOldSize = 0;
libNewSize = 0;
for clsName in sizeHash[libName].keys
diffSize = sizeHash[libName][clsName]["大小差值"]
oldSize = sizeHash[libName][clsName][versionOld]
newSize = sizeHash[libName][clsName][versionNew]
libDiffSize += diffSize.to_i
libOldSize += oldSize.to_i
libNewSize += newSize.to_i
end
libHash = Hash.new()
libHash["组件名"] = libName;
libHash["原大小"] = libOldSize
libHash["目前大小"] = libNewSize
libHash["diffSize"] = libDiffSize
diffSizeArray.push(libHash)
end
sizeHash[" DiffResult"] = (diffSizeArray.sort_by {|hashObj| hashObj["diffSize"] }).reverse
end
def parseAndCompareDatas(firsFileContent,secondFileContent,appVersionString1,appVersionString2)
versionsHash1 = getAllVersionHash(firsFileContent)
versionsHash2 = getAllVersionHash(secondFileContent)
puts("开始比较两个版本linkmap文件各库的大小")
compareResultHash = Hash.new()
for libraryName in versionsHash1.keys
libraryHash = versionsHash1[libraryName]
for className in libraryHash.keys
if compareResultHash[libraryName] == nil
compareResultHash[libraryName] = Hash.new()
end
if compareResultHash[libraryName][className] == nil
compareResultHash[libraryName][className] = Hash.new()
end
if versionsHash2[libraryName] == nil
versionsHash2[libraryName] = Hash.new()
end
if versionsHash2[libraryName][className] == nil
versionsHash2[libraryName][className] = "0"
end
libSize1 = versionsHash1[libraryName][className]
libSize2 = versionsHash2[libraryName][className] ? versionsHash2[libraryName][className] : "0"
tmpHash = Hash.new()
if libSize1 != libSize2
tmpHash[appVersionString1] = libSize1
tmpHash[appVersionString2] = libSize2
# puts(libSize2)
#计算两者差值
size1 = libSize1
size2 = libSize2
tmpHash["大小差值"] = (size2.to_i - size1.to_i).to_s
compareResultHash[libraryName][className] = tmpHash
end
end
end
for libraryName in versionsHash2.keys
libraryHash = versionsHash2[libraryName]
for className in libraryHash.keys
if compareResultHash[libraryName] == nil
compareResultHash[libraryName] = Hash.new()
end
if compareResultHash[libraryName][className] == nil
libSize2 = versionsHash2[libraryName][className]
tmpHash = Hash.new()
tmpHash[appVersionString1] = "空"
tmpHash[appVersionString2] = libSize2
tmpHash["大小差值"] = libSize2
compareResultHash[libraryName][className] = tmpHash
end
end
end
removeEmtpyKeys(compareResultHash)
alyTotalSize(compareResultHash,appVersionString1,appVersionString2)
prettyFormatClassResult(compareResultHash)
resultIncreamentText = JSON.pretty_generate(compareResultHash.sort.to_h)
resultLogPath = __dir__ + "/libSizeCompareResult.json"
if !Dir.exists?(resultLogPath)
File.new(resultLogPath,'w')
end
File.open(resultLogPath, "w") do |f|
f.write(resultIncreamentText)
end
puts("分析完成,结果已经保存到=>" + resultLogPath)
end
def removeEmtpyKeys(hashObj)
for libName in hashObj.keys
libHash = hashObj[libName]
for clsName in libHash.keys
versionsHash = hashObj[libName][clsName]
if versionsHash.keys.count == 0
libHash.delete(clsName)
end
end
end
for libName in hashObj.keys
if hashObj[libName].keys.count == 0
hashObj.delete(libName)
end
end
end
def prettyPutsHash(hashContent)
putContent = JSON.pretty_generate(hashContent).gsub(":", " =>")
puts(putContent)
end
def mainLibraryName(libName)
if libName.include?("(")
return libName.split("(")[0]
end
return libName
end
def libraryClassName(libName)
if libName.include?("(")
return libName.split("(")[1].gsub(".o)","")
end
return libName
end
def getAllVersionHash(fileContents)
hashContents = Hash.new()
lines = fileContents.split("\n")
for line in lines
libContents = line.split(" ")
#前面的库名
libName = libContents[1].split("(")[0]
#类名
className = libraryClassName(libContents[1])
libSize = libContents[0]
if hashContents[libName] == nil
classVersionHash = Hash.new()
classVersionHash[className] = libSize
hashContents[libName] = classVersionHash
else
hashContents[libName][className] = libSize
end
end
return hashContents
end
end
parser = LinkMapParser.new
libCompareAly = LibrarySizeAlaysizer.new
linkMapPathFirst = ARGV[0]
linkMapPathSecond = ARGV[1]
libUsageFirst = parser.openContent(linkMapPathFirst)
libUsageSecond = parser.openContent(linkMapPathSecond)
appVersionString1 = linkMapPathFirst.split("/")[-1].split("-")[0]
appVersionString2 = linkMapPathSecond.split("/")[-1].split("-")[0]
libCompareAly.parseAndCompareDatas(libUsageFirst,libUsageSecond,appVersionString1,appVersionString2)