@@ -42,7 +42,7 @@ pub struct GenerateArgs {
42
42
/// Output JSON file
43
43
output : Option < PathBuf > ,
44
44
#[ argp( switch, short = 'd' ) ]
45
- /// Deduplicate global and weak symbols
45
+ /// Deduplicate global and weak symbols (runs single-threaded)
46
46
deduplicate : bool ,
47
47
}
48
48
@@ -64,9 +64,12 @@ pub struct ChangesArgs {
64
64
#[ derive( Debug , Clone , Default , serde:: Serialize , serde:: Deserialize ) ]
65
65
struct Report {
66
66
fuzzy_match_percent : f32 ,
67
- total_size : u64 ,
68
- matched_size : u64 ,
69
- matched_size_percent : f32 ,
67
+ total_code : u64 ,
68
+ matched_code : u64 ,
69
+ matched_code_percent : f32 ,
70
+ total_data : u64 ,
71
+ matched_data : u64 ,
72
+ matched_data_percent : f32 ,
70
73
total_functions : u32 ,
71
74
matched_functions : u32 ,
72
75
matched_functions_percent : f32 ,
@@ -77,8 +80,10 @@ struct Report {
77
80
struct ReportUnit {
78
81
name : String ,
79
82
fuzzy_match_percent : f32 ,
80
- total_size : u64 ,
81
- matched_size : u64 ,
83
+ total_code : u64 ,
84
+ matched_code : u64 ,
85
+ total_data : u64 ,
86
+ matched_data : u64 ,
82
87
total_functions : u32 ,
83
88
matched_functions : u32 ,
84
89
#[ serde( skip_serializing_if = "Option::is_none" ) ]
@@ -87,11 +92,12 @@ struct ReportUnit {
87
92
module_name : Option < String > ,
88
93
#[ serde( skip_serializing_if = "Option::is_none" ) ]
89
94
module_id : Option < u32 > ,
90
- functions : Vec < ReportFunction > ,
95
+ sections : Vec < ReportItem > ,
96
+ functions : Vec < ReportItem > ,
91
97
}
92
98
93
99
#[ derive( Debug , Clone , Default , serde:: Serialize , serde:: Deserialize ) ]
94
- struct ReportFunction {
100
+ struct ReportItem {
95
101
name : String ,
96
102
#[ serde( skip_serializing_if = "Option::is_none" ) ]
97
103
demangled_name : Option < String > ,
@@ -160,21 +166,29 @@ fn generate(args: GenerateArgs) -> Result<()> {
160
166
report. units = units. into_iter ( ) . flatten ( ) . collect ( ) ;
161
167
}
162
168
for unit in & report. units {
163
- report. fuzzy_match_percent += unit. fuzzy_match_percent * unit. total_size as f32 ;
164
- report. total_size += unit. total_size ;
165
- report. matched_size += unit. matched_size ;
169
+ report. fuzzy_match_percent += unit. fuzzy_match_percent * unit. total_code as f32 ;
170
+ report. total_code += unit. total_code ;
171
+ report. matched_code += unit. matched_code ;
172
+ report. total_data += unit. total_data ;
173
+ report. matched_data += unit. matched_data ;
166
174
report. total_functions += unit. total_functions ;
167
175
report. matched_functions += unit. matched_functions ;
168
176
}
169
- if report. total_size == 0 {
177
+ if report. total_code == 0 {
170
178
report. fuzzy_match_percent = 100.0 ;
171
179
} else {
172
- report. fuzzy_match_percent /= report. total_size as f32 ;
180
+ report. fuzzy_match_percent /= report. total_code as f32 ;
173
181
}
174
- report. matched_size_percent = if report. total_size == 0 {
182
+
183
+ report. matched_code_percent = if report. total_code == 0 {
184
+ 100.0
185
+ } else {
186
+ report. matched_code as f32 / report. total_code as f32 * 100.0
187
+ } ;
188
+ report. matched_data_percent = if report. total_data == 0 {
175
189
100.0
176
190
} else {
177
- report. matched_size as f32 / report. total_size as f32 * 100.0
191
+ report. matched_data as f32 / report. total_data as f32 * 100.0
178
192
} ;
179
193
report. matched_functions_percent = if report. total_functions == 0 {
180
194
100.0
@@ -216,7 +230,6 @@ fn report_object(
216
230
}
217
231
_ => { }
218
232
}
219
- // println!("Checking {}", object.name());
220
233
let target = object
221
234
. target_path
222
235
. as_ref ( )
@@ -240,11 +253,37 @@ fn report_object(
240
253
..Default :: default ( )
241
254
} ;
242
255
let obj = target. as_ref ( ) . or ( base. as_ref ( ) ) . unwrap ( ) ;
256
+
243
257
let obj_diff = result. left . as_ref ( ) . or ( result. right . as_ref ( ) ) . unwrap ( ) ;
244
258
for ( section, section_diff) in obj. sections . iter ( ) . zip ( & obj_diff. sections ) {
245
- if section. kind != ObjSectionKind :: Code {
246
- continue ;
259
+ let section_match_percent = section_diff. match_percent . unwrap_or_else ( || {
260
+ // Support cases where we don't have a target object,
261
+ // assume complete means 100% match
262
+ if object. complete == Some ( true ) {
263
+ 100.0
264
+ } else {
265
+ 0.0
266
+ }
267
+ } ) ;
268
+ unit. sections . push ( ReportItem {
269
+ name : section. name . clone ( ) ,
270
+ demangled_name : None ,
271
+ fuzzy_match_percent : section_match_percent,
272
+ size : section. size ,
273
+ address : section. virtual_address ,
274
+ } ) ;
275
+
276
+ match section. kind {
277
+ ObjSectionKind :: Data | ObjSectionKind :: Bss => {
278
+ unit. total_data += section. size ;
279
+ if section_match_percent == 100.0 {
280
+ unit. matched_data += section. size ;
281
+ }
282
+ continue ;
283
+ }
284
+ ObjSectionKind :: Code => ( ) ,
247
285
}
286
+
248
287
for ( symbol, symbol_diff) in section. symbols . iter ( ) . zip ( & section_diff. symbols ) {
249
288
if symbol. size == 0 {
250
289
continue ;
@@ -267,11 +306,11 @@ fn report_object(
267
306
}
268
307
} ) ;
269
308
unit. fuzzy_match_percent += match_percent * symbol. size as f32 ;
270
- unit. total_size += symbol. size ;
309
+ unit. total_code += symbol. size ;
271
310
if match_percent == 100.0 {
272
- unit. matched_size += symbol. size ;
311
+ unit. matched_code += symbol. size ;
273
312
}
274
- unit. functions . push ( ReportFunction {
313
+ unit. functions . push ( ReportItem {
275
314
name : symbol. name . clone ( ) ,
276
315
demangled_name : symbol. demangled_name . clone ( ) ,
277
316
size : symbol. size ,
@@ -284,10 +323,10 @@ fn report_object(
284
323
unit. total_functions += 1 ;
285
324
}
286
325
}
287
- if unit. total_size == 0 {
326
+ if unit. total_code == 0 {
288
327
unit. fuzzy_match_percent = 100.0 ;
289
328
} else {
290
- unit. fuzzy_match_percent /= unit. total_size as f32 ;
329
+ unit. fuzzy_match_percent /= unit. total_code as f32 ;
291
330
}
292
331
Ok ( Some ( unit) )
293
332
}
@@ -302,9 +341,12 @@ struct Changes {
302
341
#[ derive( Debug , Clone , Default , PartialEq , serde:: Serialize , serde:: Deserialize ) ]
303
342
struct ChangeInfo {
304
343
fuzzy_match_percent : f32 ,
305
- total_size : u64 ,
306
- matched_size : u64 ,
307
- matched_size_percent : f32 ,
344
+ total_code : u64 ,
345
+ matched_code : u64 ,
346
+ matched_code_percent : f32 ,
347
+ total_data : u64 ,
348
+ matched_data : u64 ,
349
+ matched_data_percent : f32 ,
308
350
total_functions : u32 ,
309
351
matched_functions : u32 ,
310
352
matched_functions_percent : f32 ,
@@ -314,9 +356,12 @@ impl From<&Report> for ChangeInfo {
314
356
fn from ( report : & Report ) -> Self {
315
357
Self {
316
358
fuzzy_match_percent : report. fuzzy_match_percent ,
317
- total_size : report. total_size ,
318
- matched_size : report. matched_size ,
319
- matched_size_percent : report. matched_size_percent ,
359
+ total_code : report. total_code ,
360
+ matched_code : report. matched_code ,
361
+ matched_code_percent : report. matched_code_percent ,
362
+ total_data : report. total_data ,
363
+ matched_data : report. matched_data ,
364
+ matched_data_percent : report. matched_data_percent ,
320
365
total_functions : report. total_functions ,
321
366
matched_functions : report. matched_functions ,
322
367
matched_functions_percent : report. matched_functions_percent ,
@@ -328,12 +373,19 @@ impl From<&ReportUnit> for ChangeInfo {
328
373
fn from ( value : & ReportUnit ) -> Self {
329
374
Self {
330
375
fuzzy_match_percent : value. fuzzy_match_percent ,
331
- total_size : value. total_size ,
332
- matched_size : value. matched_size ,
333
- matched_size_percent : if value. total_size == 0 {
376
+ total_code : value. total_code ,
377
+ matched_code : value. matched_code ,
378
+ matched_code_percent : if value. total_code == 0 {
334
379
100.0
335
380
} else {
336
- value. matched_size as f32 / value. total_size as f32 * 100.0
381
+ value. matched_code as f32 / value. total_code as f32 * 100.0
382
+ } ,
383
+ total_data : value. total_data ,
384
+ matched_data : value. matched_data ,
385
+ matched_data_percent : if value. total_data == 0 {
386
+ 100.0
387
+ } else {
388
+ value. matched_data as f32 / value. total_data as f32 * 100.0
337
389
} ,
338
390
total_functions : value. total_functions ,
339
391
matched_functions : value. matched_functions ,
@@ -351,24 +403,25 @@ struct ChangeUnit {
351
403
name : String ,
352
404
from : Option < ChangeInfo > ,
353
405
to : Option < ChangeInfo > ,
354
- functions : Vec < ChangeFunction > ,
406
+ sections : Vec < ChangeItem > ,
407
+ functions : Vec < ChangeItem > ,
355
408
}
356
409
357
410
#[ derive( Debug , Clone , Default , serde:: Serialize , serde:: Deserialize ) ]
358
- struct ChangeFunction {
411
+ struct ChangeItem {
359
412
name : String ,
360
- from : Option < ChangeFunctionInfo > ,
361
- to : Option < ChangeFunctionInfo > ,
413
+ from : Option < ChangeItemInfo > ,
414
+ to : Option < ChangeItemInfo > ,
362
415
}
363
416
364
417
#[ derive( Debug , Clone , Default , PartialEq , serde:: Serialize , serde:: Deserialize ) ]
365
- struct ChangeFunctionInfo {
418
+ struct ChangeItemInfo {
366
419
fuzzy_match_percent : f32 ,
367
420
size : u64 ,
368
421
}
369
422
370
- impl From < & ReportFunction > for ChangeFunctionInfo {
371
- fn from ( value : & ReportFunction ) -> Self {
423
+ impl From < & ReportItem > for ChangeItemInfo {
424
+ fn from ( value : & ReportItem ) -> Self {
372
425
Self { fuzzy_match_percent : value. fuzzy_match_percent , size : value. size }
373
426
}
374
427
}
@@ -382,54 +435,18 @@ fn changes(args: ChangesArgs) -> Result<()> {
382
435
units : vec ! [ ] ,
383
436
} ;
384
437
for prev_unit in & previous. units {
385
- let prev_unit_info = ChangeInfo :: from ( prev_unit) ;
386
438
let curr_unit = current. units . iter ( ) . find ( |u| u. name == prev_unit. name ) ;
439
+ let sections = process_items ( prev_unit, curr_unit, |u| & u. sections ) ;
440
+ let functions = process_items ( prev_unit, curr_unit, |u| & u. functions ) ;
441
+
442
+ let prev_unit_info = ChangeInfo :: from ( prev_unit) ;
387
443
let curr_unit_info = curr_unit. map ( ChangeInfo :: from) ;
388
- let mut functions = vec ! [ ] ;
389
- if let Some ( curr_unit) = curr_unit {
390
- for prev_func in & prev_unit. functions {
391
- let prev_func_info = ChangeFunctionInfo :: from ( prev_func) ;
392
- let curr_func = curr_unit. functions . iter ( ) . find ( |f| f. name == prev_func. name ) ;
393
- let curr_func_info = curr_func. map ( ChangeFunctionInfo :: from) ;
394
- if let Some ( curr_func_info) = curr_func_info {
395
- if prev_func_info != curr_func_info {
396
- functions. push ( ChangeFunction {
397
- name : prev_func. name . clone ( ) ,
398
- from : Some ( prev_func_info) ,
399
- to : Some ( curr_func_info) ,
400
- } ) ;
401
- }
402
- } else {
403
- functions. push ( ChangeFunction {
404
- name : prev_func. name . clone ( ) ,
405
- from : Some ( prev_func_info) ,
406
- to : None ,
407
- } ) ;
408
- }
409
- }
410
- for curr_func in & curr_unit. functions {
411
- if !prev_unit. functions . iter ( ) . any ( |f| f. name == curr_func. name ) {
412
- functions. push ( ChangeFunction {
413
- name : curr_func. name . clone ( ) ,
414
- from : None ,
415
- to : Some ( ChangeFunctionInfo :: from ( curr_func) ) ,
416
- } ) ;
417
- }
418
- }
419
- } else {
420
- for prev_func in & prev_unit. functions {
421
- functions. push ( ChangeFunction {
422
- name : prev_func. name . clone ( ) ,
423
- from : Some ( ChangeFunctionInfo :: from ( prev_func) ) ,
424
- to : None ,
425
- } ) ;
426
- }
427
- }
428
444
if !functions. is_empty ( ) || !matches ! ( & curr_unit_info, Some ( v) if v == & prev_unit_info) {
429
445
changes. units . push ( ChangeUnit {
430
446
name : prev_unit. name . clone ( ) ,
431
447
from : Some ( prev_unit_info) ,
432
448
to : curr_unit_info,
449
+ sections,
433
450
functions,
434
451
} ) ;
435
452
}
@@ -440,15 +457,8 @@ fn changes(args: ChangesArgs) -> Result<()> {
440
457
name : curr_unit. name . clone ( ) ,
441
458
from : None ,
442
459
to : Some ( ChangeInfo :: from ( curr_unit) ) ,
443
- functions : curr_unit
444
- . functions
445
- . iter ( )
446
- . map ( |f| ChangeFunction {
447
- name : f. name . clone ( ) ,
448
- from : None ,
449
- to : Some ( ChangeFunctionInfo :: from ( f) ) ,
450
- } )
451
- . collect ( ) ,
460
+ sections : process_new_items ( & curr_unit. sections ) ,
461
+ functions : process_new_items ( & curr_unit. functions ) ,
452
462
} ) ;
453
463
}
454
464
}
@@ -466,6 +476,63 @@ fn changes(args: ChangesArgs) -> Result<()> {
466
476
Ok ( ( ) )
467
477
}
468
478
479
+ fn process_items < F : Fn ( & ReportUnit ) -> & Vec < ReportItem > > (
480
+ prev_unit : & ReportUnit ,
481
+ curr_unit : Option < & ReportUnit > ,
482
+ getter : F ,
483
+ ) -> Vec < ChangeItem > {
484
+ let prev_items = getter ( prev_unit) ;
485
+ let mut items = vec ! [ ] ;
486
+ if let Some ( curr_unit) = curr_unit {
487
+ let curr_items = getter ( curr_unit) ;
488
+ for prev_func in prev_items {
489
+ let prev_func_info = ChangeItemInfo :: from ( prev_func) ;
490
+ let curr_func = curr_items. iter ( ) . find ( |f| f. name == prev_func. name ) ;
491
+ let curr_func_info = curr_func. map ( ChangeItemInfo :: from) ;
492
+ if let Some ( curr_func_info) = curr_func_info {
493
+ if prev_func_info != curr_func_info {
494
+ items. push ( ChangeItem {
495
+ name : prev_func. name . clone ( ) ,
496
+ from : Some ( prev_func_info) ,
497
+ to : Some ( curr_func_info) ,
498
+ } ) ;
499
+ }
500
+ } else {
501
+ items. push ( ChangeItem {
502
+ name : prev_func. name . clone ( ) ,
503
+ from : Some ( prev_func_info) ,
504
+ to : None ,
505
+ } ) ;
506
+ }
507
+ }
508
+ for curr_func in curr_items {
509
+ if !prev_items. iter ( ) . any ( |f| f. name == curr_func. name ) {
510
+ items. push ( ChangeItem {
511
+ name : curr_func. name . clone ( ) ,
512
+ from : None ,
513
+ to : Some ( ChangeItemInfo :: from ( curr_func) ) ,
514
+ } ) ;
515
+ }
516
+ }
517
+ } else {
518
+ for prev_func in prev_items {
519
+ items. push ( ChangeItem {
520
+ name : prev_func. name . clone ( ) ,
521
+ from : Some ( ChangeItemInfo :: from ( prev_func) ) ,
522
+ to : None ,
523
+ } ) ;
524
+ }
525
+ }
526
+ items
527
+ }
528
+
529
+ fn process_new_items ( items : & [ ReportItem ] ) -> Vec < ChangeItem > {
530
+ items
531
+ . iter ( )
532
+ . map ( |f| ChangeItem { name : f. name . clone ( ) , from : None , to : Some ( ChangeItemInfo :: from ( f) ) } )
533
+ . collect ( )
534
+ }
535
+
469
536
fn read_report ( path : & Path ) -> Result < Report > {
470
537
serde_json:: from_reader ( BufReader :: new (
471
538
File :: open ( path) . with_context ( || format ! ( "Failed to open {}" , path. display( ) ) ) ?,
0 commit comments