@@ -42,7 +42,7 @@ pub struct GenerateArgs {
4242 /// Output JSON file
4343 output : Option < PathBuf > ,
4444 #[ argp( switch, short = 'd' ) ]
45- /// Deduplicate global and weak symbols
45+ /// Deduplicate global and weak symbols (runs single-threaded)
4646 deduplicate : bool ,
4747}
4848
@@ -64,9 +64,12 @@ pub struct ChangesArgs {
6464#[ derive( Debug , Clone , Default , serde:: Serialize , serde:: Deserialize ) ]
6565struct Report {
6666 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 ,
7073 total_functions : u32 ,
7174 matched_functions : u32 ,
7275 matched_functions_percent : f32 ,
@@ -77,8 +80,10 @@ struct Report {
7780struct ReportUnit {
7881 name : String ,
7982 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 ,
8287 total_functions : u32 ,
8388 matched_functions : u32 ,
8489 #[ serde( skip_serializing_if = "Option::is_none" ) ]
@@ -87,11 +92,12 @@ struct ReportUnit {
8792 module_name : Option < String > ,
8893 #[ serde( skip_serializing_if = "Option::is_none" ) ]
8994 module_id : Option < u32 > ,
90- functions : Vec < ReportFunction > ,
95+ sections : Vec < ReportItem > ,
96+ functions : Vec < ReportItem > ,
9197}
9298
9399#[ derive( Debug , Clone , Default , serde:: Serialize , serde:: Deserialize ) ]
94- struct ReportFunction {
100+ struct ReportItem {
95101 name : String ,
96102 #[ serde( skip_serializing_if = "Option::is_none" ) ]
97103 demangled_name : Option < String > ,
@@ -160,21 +166,29 @@ fn generate(args: GenerateArgs) -> Result<()> {
160166 report. units = units. into_iter ( ) . flatten ( ) . collect ( ) ;
161167 }
162168 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 ;
166174 report. total_functions += unit. total_functions ;
167175 report. matched_functions += unit. matched_functions ;
168176 }
169- if report. total_size == 0 {
177+ if report. total_code == 0 {
170178 report. fuzzy_match_percent = 100.0 ;
171179 } else {
172- report. fuzzy_match_percent /= report. total_size as f32 ;
180+ report. fuzzy_match_percent /= report. total_code as f32 ;
173181 }
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 {
175189 100.0
176190 } 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
178192 } ;
179193 report. matched_functions_percent = if report. total_functions == 0 {
180194 100.0
@@ -216,7 +230,6 @@ fn report_object(
216230 }
217231 _ => { }
218232 }
219- // println!("Checking {}", object.name());
220233 let target = object
221234 . target_path
222235 . as_ref ( )
@@ -240,11 +253,37 @@ fn report_object(
240253 ..Default :: default ( )
241254 } ;
242255 let obj = target. as_ref ( ) . or ( base. as_ref ( ) ) . unwrap ( ) ;
256+
243257 let obj_diff = result. left . as_ref ( ) . or ( result. right . as_ref ( ) ) . unwrap ( ) ;
244258 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 => ( ) ,
247285 }
286+
248287 for ( symbol, symbol_diff) in section. symbols . iter ( ) . zip ( & section_diff. symbols ) {
249288 if symbol. size == 0 {
250289 continue ;
@@ -267,11 +306,11 @@ fn report_object(
267306 }
268307 } ) ;
269308 unit. fuzzy_match_percent += match_percent * symbol. size as f32 ;
270- unit. total_size += symbol. size ;
309+ unit. total_code += symbol. size ;
271310 if match_percent == 100.0 {
272- unit. matched_size += symbol. size ;
311+ unit. matched_code += symbol. size ;
273312 }
274- unit. functions . push ( ReportFunction {
313+ unit. functions . push ( ReportItem {
275314 name : symbol. name . clone ( ) ,
276315 demangled_name : symbol. demangled_name . clone ( ) ,
277316 size : symbol. size ,
@@ -284,10 +323,10 @@ fn report_object(
284323 unit. total_functions += 1 ;
285324 }
286325 }
287- if unit. total_size == 0 {
326+ if unit. total_code == 0 {
288327 unit. fuzzy_match_percent = 100.0 ;
289328 } else {
290- unit. fuzzy_match_percent /= unit. total_size as f32 ;
329+ unit. fuzzy_match_percent /= unit. total_code as f32 ;
291330 }
292331 Ok ( Some ( unit) )
293332}
@@ -302,9 +341,12 @@ struct Changes {
302341#[ derive( Debug , Clone , Default , PartialEq , serde:: Serialize , serde:: Deserialize ) ]
303342struct ChangeInfo {
304343 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 ,
308350 total_functions : u32 ,
309351 matched_functions : u32 ,
310352 matched_functions_percent : f32 ,
@@ -314,9 +356,12 @@ impl From<&Report> for ChangeInfo {
314356 fn from ( report : & Report ) -> Self {
315357 Self {
316358 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 ,
320365 total_functions : report. total_functions ,
321366 matched_functions : report. matched_functions ,
322367 matched_functions_percent : report. matched_functions_percent ,
@@ -328,12 +373,19 @@ impl From<&ReportUnit> for ChangeInfo {
328373 fn from ( value : & ReportUnit ) -> Self {
329374 Self {
330375 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 {
334379 100.0
335380 } 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
337389 } ,
338390 total_functions : value. total_functions ,
339391 matched_functions : value. matched_functions ,
@@ -351,24 +403,25 @@ struct ChangeUnit {
351403 name : String ,
352404 from : Option < ChangeInfo > ,
353405 to : Option < ChangeInfo > ,
354- functions : Vec < ChangeFunction > ,
406+ sections : Vec < ChangeItem > ,
407+ functions : Vec < ChangeItem > ,
355408}
356409
357410#[ derive( Debug , Clone , Default , serde:: Serialize , serde:: Deserialize ) ]
358- struct ChangeFunction {
411+ struct ChangeItem {
359412 name : String ,
360- from : Option < ChangeFunctionInfo > ,
361- to : Option < ChangeFunctionInfo > ,
413+ from : Option < ChangeItemInfo > ,
414+ to : Option < ChangeItemInfo > ,
362415}
363416
364417#[ derive( Debug , Clone , Default , PartialEq , serde:: Serialize , serde:: Deserialize ) ]
365- struct ChangeFunctionInfo {
418+ struct ChangeItemInfo {
366419 fuzzy_match_percent : f32 ,
367420 size : u64 ,
368421}
369422
370- impl From < & ReportFunction > for ChangeFunctionInfo {
371- fn from ( value : & ReportFunction ) -> Self {
423+ impl From < & ReportItem > for ChangeItemInfo {
424+ fn from ( value : & ReportItem ) -> Self {
372425 Self { fuzzy_match_percent : value. fuzzy_match_percent , size : value. size }
373426 }
374427}
@@ -382,54 +435,18 @@ fn changes(args: ChangesArgs) -> Result<()> {
382435 units : vec ! [ ] ,
383436 } ;
384437 for prev_unit in & previous. units {
385- let prev_unit_info = ChangeInfo :: from ( prev_unit) ;
386438 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) ;
387443 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- }
428444 if !functions. is_empty ( ) || !matches ! ( & curr_unit_info, Some ( v) if v == & prev_unit_info) {
429445 changes. units . push ( ChangeUnit {
430446 name : prev_unit. name . clone ( ) ,
431447 from : Some ( prev_unit_info) ,
432448 to : curr_unit_info,
449+ sections,
433450 functions,
434451 } ) ;
435452 }
@@ -440,15 +457,8 @@ fn changes(args: ChangesArgs) -> Result<()> {
440457 name : curr_unit. name . clone ( ) ,
441458 from : None ,
442459 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 ) ,
452462 } ) ;
453463 }
454464 }
@@ -466,6 +476,63 @@ fn changes(args: ChangesArgs) -> Result<()> {
466476 Ok ( ( ) )
467477}
468478
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+
469536fn read_report ( path : & Path ) -> Result < Report > {
470537 serde_json:: from_reader ( BufReader :: new (
471538 File :: open ( path) . with_context ( || format ! ( "Failed to open {}" , path. display( ) ) ) ?,
0 commit comments