31
31
import java .lang .management .GarbageCollectorMXBean ;
32
32
import java .lang .management .ManagementFactory ;
33
33
import java .nio .file .Path ;
34
+ import java .security .CodeSource ;
34
35
import java .util .ArrayList ;
35
36
import java .util .Collection ;
36
37
import java .util .Comparator ;
75
76
import com .oracle .svm .core .VM ;
76
77
import com .oracle .svm .core .heap .Heap ;
77
78
import com .oracle .svm .core .hub .ClassForNameSupport ;
79
+ import com .oracle .svm .core .hub .DynamicHub ;
78
80
import com .oracle .svm .core .jdk .Resources ;
79
81
import com .oracle .svm .core .option .AccumulatingLocatableMultiOptionValue ;
80
82
import com .oracle .svm .core .option .HostedOptionKey ;
@@ -639,13 +641,50 @@ public void ensureCreationStageEndCompleted() {
639
641
}
640
642
}
641
643
644
+ private record BreakDownClassifier (Package javaPackage , Module javaModule , String location ) {
645
+ static BreakDownClassifier of (Class <?> clazz ) {
646
+ return new BreakDownClassifier (clazz .getPackage (), clazz .getModule (), sourcePath (clazz ));
647
+ }
648
+
649
+ private static String sourcePath (Class <?> clazz ) {
650
+ CodeSource codeSource = clazz .getProtectionDomain ().getCodeSource ();
651
+ if (codeSource != null && codeSource .getLocation () != null ) {
652
+ String path = codeSource .getLocation ().getPath ();
653
+ // Use String API to determine basename of path to handle both / and \.
654
+ return path .substring (Math .max (path .lastIndexOf ('/' ) + 1 , path .lastIndexOf ('\\' ) + 1 ));
655
+ }
656
+ return null ;
657
+ }
658
+
659
+ @ Override
660
+ public String toString () {
661
+ String locationSuffix = location == null ? "" : " (" + Utils .truncateName (location , 14 ) + ")" ;
662
+ return moduleNamePrefix (javaModule ) + Utils .truncateFQN (javaPackage .getName (), 22 ) + locationSuffix ;
663
+ }
664
+
665
+ }
666
+
667
+ static String moduleNamePrefix (Module javaModule ) {
668
+ if (!javaModule .isNamed ()) {
669
+ return "" ;
670
+ }
671
+ if (javaModule .equals (DynamicHub .class .getModule ())) {
672
+ return "VM " ;
673
+ }
674
+ return Utils .truncateFQN (javaModule .getName (), 19 ) + "/" ;
675
+ }
676
+
642
677
private void printBreakdowns () {
643
678
if (!SubstrateOptions .BuildOutputBreakdowns .getValue ()) {
644
679
return ;
645
680
}
646
681
l ().printLineSeparator ();
647
- Map <String , Long > codeBreakdown = CodeBreakdownProvider .getAndClear ();
648
- Iterator <Entry <String , Long >> packagesBySize = codeBreakdown .entrySet ().stream ()
682
+ Map <BreakDownClassifier , Long > codeBreakdown = CodeBreakdownProvider .getAndClear ().entrySet ().stream ()
683
+ .collect (Collectors .groupingBy (
684
+ entry -> BreakDownClassifier .of (entry .getKey ()),
685
+ Collectors .summingLong (entry -> entry .getValue ())));
686
+
687
+ Iterator <Entry <BreakDownClassifier , Long >> packagesBySize = codeBreakdown .entrySet ().stream ()
649
688
.sorted (Entry .comparingByValue (Comparator .reverseOrder ())).iterator ();
650
689
651
690
HeapBreakdownProvider heapBreakdown = HeapBreakdownProvider .singleton ();
@@ -663,10 +702,9 @@ private void printBreakdowns() {
663
702
for (int i = 0 ; i < MAX_NUM_BREAKDOWN ; i ++) {
664
703
String codeSizePart = "" ;
665
704
if (packagesBySize .hasNext ()) {
666
- Entry <String , Long > e = packagesBySize .next ();
667
- String className = Utils .truncateClassOrPackageName (e .getKey ());
668
- codeSizePart = String .format ("%9s %s" , ByteFormattingUtil .bytesToHuman (e .getValue ()), className );
669
- printedCodeBytes += e .getValue ();
705
+ Entry <BreakDownClassifier , Long > entry = packagesBySize .next ();
706
+ codeSizePart = String .format ("%9s %s" , ByteFormattingUtil .bytesToHuman (entry .getValue ()), entry .getKey ());
707
+ printedCodeBytes += entry .getValue ();
670
708
printedCodeItems ++;
671
709
}
672
710
@@ -676,7 +714,7 @@ private void printBreakdowns() {
676
714
String className = e .label .renderToString (linkStrategy );
677
715
// Do not truncate special breakdown items, they can contain links.
678
716
if (e .label instanceof HeapBreakdownProvider .SimpleHeapObjectKindName ) {
679
- className = Utils .truncateClassOrPackageName (className );
717
+ className = Utils .truncateFQN (className );
680
718
}
681
719
long byteSize = e .byteSize ;
682
720
heapSizePart = String .format ("%9s %s" , ByteFormattingUtil .bytesToHuman (byteSize ), className );
@@ -920,9 +958,10 @@ private static OperatingSystemMXBean getOperatingSystemMXBean() {
920
958
return (OperatingSystemMXBean ) ManagementFactory .getOperatingSystemMXBean ();
921
959
}
922
960
923
- private static final class Utils {
961
+ static final class Utils {
924
962
private static final double MILLIS_TO_SECONDS = 1000d ;
925
963
private static final double NANOS_TO_SECONDS = 1000d * 1000d * 1000d ;
964
+ public static final String TRUNCATION_PLACEHOLDER = "~" ;
926
965
927
966
private static double millisToSeconds (double millis ) {
928
967
return millis / MILLIS_TO_SECONDS ;
@@ -937,39 +976,50 @@ private static String getUsedMemory() {
937
976
}
938
977
939
978
private static String stringFilledWith (int size , String fill ) {
940
- return new String ( new char [ size ]). replace ( " \0 " , fill );
979
+ return fill . repeat ( size );
941
980
}
942
981
943
982
private static double toPercentage (long part , long total ) {
944
983
return part / (double ) total * 100 ;
945
984
}
946
985
947
- private static String truncateClassOrPackageName (String classOrPackageName ) {
948
- int classNameLength = classOrPackageName .length ();
949
- int maxLength = CHARACTERS_PER_LINE / 2 - 10 ;
986
+ private static String truncateName (String name , int maxLength ) {
987
+ int length = name .length ();
988
+ if (length <= maxLength ) {
989
+ return name ;
990
+ }
991
+ return TRUNCATION_PLACEHOLDER + name .substring (length - maxLength + TRUNCATION_PLACEHOLDER .length (), length );
992
+ }
993
+
994
+ private static String truncateFQN (String fqn ) {
995
+ return truncateFQN (fqn , CHARACTERS_PER_LINE / 2 - 10 );
996
+ }
997
+
998
+ static String truncateFQN (String fqn , int maxLength ) {
999
+ int classNameLength = fqn .length ();
950
1000
if (classNameLength <= maxLength ) {
951
- return classOrPackageName ;
1001
+ return fqn ;
952
1002
}
953
1003
StringBuilder sb = new StringBuilder ();
954
1004
int currentDot = -1 ;
955
1005
while (true ) {
956
- int nextDot = classOrPackageName .indexOf ('.' , currentDot + 1 );
1006
+ int nextDot = fqn .indexOf ('.' , currentDot + 1 );
957
1007
if (nextDot < 0 ) { // Not more dots, handle the rest and return.
958
- String rest = classOrPackageName .substring (currentDot + 1 );
1008
+ String rest = fqn .substring (currentDot + 1 );
959
1009
int sbLength = sb .length ();
960
1010
int restLength = rest .length ();
961
1011
if (sbLength + restLength <= maxLength ) {
962
1012
sb .append (rest );
963
1013
} else {
964
1014
int remainingSpaceDivBy2 = (maxLength - sbLength ) / 2 ;
965
- sb .append (rest , 0 , remainingSpaceDivBy2 - 1 ).append ("~" ).append (rest , restLength - remainingSpaceDivBy2 , restLength );
1015
+ sb .append (rest , 0 , remainingSpaceDivBy2 - 1 ).append (TRUNCATION_PLACEHOLDER ).append (rest , restLength - remainingSpaceDivBy2 , restLength );
966
1016
}
967
1017
break ;
968
1018
}
969
- sb .append (classOrPackageName .charAt (currentDot + 1 )).append ('.' );
1019
+ sb .append (fqn .charAt (currentDot + 1 )).append ('.' );
970
1020
if (sb .length () + (classNameLength - nextDot ) <= maxLength ) {
971
1021
// Rest fits maxLength, append and return.
972
- sb .append (classOrPackageName .substring (nextDot + 1 ));
1022
+ sb .append (fqn .substring (nextDot + 1 ));
973
1023
break ;
974
1024
}
975
1025
currentDot = nextDot ;
0 commit comments