Browse Source

Handle memory maps generated by logging

If the memory map is generated by logging routines such as glog, they
may include some initial text which confuses the parsing of legacy
mappings. The initial text is the same for all mapping entries,
so detect it on the proc map sentinel and remove it from the mapping
entries.
Raul Silvera 8 years ago
parent
commit
251ad27be0
1 changed files with 36 additions and 22 deletions
  1. 36
    22
      profile/legacy_profile.go

+ 36
- 22
profile/legacy_profile.go View File

509
 			continue
509
 			continue
510
 		}
510
 		}
511
 
511
 
512
-		if sectionTrigger(line) != unrecognizedSection {
512
+		if isMemoryMapSentinel(line) {
513
 			break
513
 			break
514
 		}
514
 		}
515
 
515
 
837
 	if m := threadzStartRE.FindStringSubmatch(line); m != nil {
837
 	if m := threadzStartRE.FindStringSubmatch(line); m != nil {
838
 		// Advance over initial comments until first stack trace.
838
 		// Advance over initial comments until first stack trace.
839
 		for s.Scan() {
839
 		for s.Scan() {
840
-			if line = s.Text(); sectionTrigger(line) != unrecognizedSection || strings.HasPrefix(line, "-") {
840
+			if line = s.Text(); isMemoryMapSentinel(line) || strings.HasPrefix(line, "-") {
841
 				break
841
 				break
842
 			}
842
 			}
843
 		}
843
 		}
853
 
853
 
854
 	locs := make(map[uint64]*Location)
854
 	locs := make(map[uint64]*Location)
855
 	// Recognize each thread and populate profile samples.
855
 	// Recognize each thread and populate profile samples.
856
-	for sectionTrigger(line) == unrecognizedSection {
856
+	for !isMemoryMapSentinel(line) {
857
 		if strings.HasPrefix(line, "---- no stack trace for") {
857
 		if strings.HasPrefix(line, "---- no stack trace for") {
858
 			line = ""
858
 			line = ""
859
 			break
859
 			break
944
 // parseAdditionalSections parses any additional sections in the
944
 // parseAdditionalSections parses any additional sections in the
945
 // profile, ignoring any unrecognized sections.
945
 // profile, ignoring any unrecognized sections.
946
 func parseAdditionalSections(s *bufio.Scanner, p *Profile) error {
946
 func parseAdditionalSections(s *bufio.Scanner, p *Profile) error {
947
-	for sectionTrigger(s.Text()) != memoryMapSection && s.Scan() {
947
+	for !isMemoryMapSentinel(s.Text()) && s.Scan() {
948
 	}
948
 	}
949
 	if err := s.Err(); err != nil {
949
 	if err := s.Err(); err != nil {
950
 		return err
950
 		return err
951
 	}
951
 	}
952
-	return p.parseMemoryMapFromScanner(s)
952
+	return p.ParseMemoryMapFromScanner(s)
953
 }
953
 }
954
 
954
 
955
 // ParseProcMaps parses a memory map in the format of /proc/self/maps.
955
 // ParseProcMaps parses a memory map in the format of /proc/self/maps.
964
 func parseProcMapsFromScanner(s *bufio.Scanner) ([]*Mapping, error) {
964
 func parseProcMapsFromScanner(s *bufio.Scanner) ([]*Mapping, error) {
965
 	var mapping []*Mapping
965
 	var mapping []*Mapping
966
 
966
 
967
+	// If the memory-map sentinel is at column X, assume memory mappings
968
+	// also start at X. This is useful to eliminate logging information.
969
+	offset := memoryMapSentinelOffset(s.Text())
970
+
967
 	var attrs []string
971
 	var attrs []string
968
 	var r *strings.Replacer
972
 	var r *strings.Replacer
969
 	const delimiter = "="
973
 	const delimiter = "="
970
 	for s.Scan() {
974
 	for s.Scan() {
971
-		line := strings.TrimSpace(s.Text())
972
-		if line == "" {
975
+		line := s.Text()
976
+		if len(line) > offset {
977
+			line = line[offset:]
978
+		}
979
+		if line = strings.TrimSpace(line); line == "" {
973
 			continue
980
 			continue
974
 		}
981
 		}
975
 
982
 
1005
 // /proc/self/maps, and overrides the mappings in the current profile.
1012
 // /proc/self/maps, and overrides the mappings in the current profile.
1006
 // It renumbers the samples and locations in the profile correspondingly.
1013
 // It renumbers the samples and locations in the profile correspondingly.
1007
 func (p *Profile) ParseMemoryMap(rd io.Reader) error {
1014
 func (p *Profile) ParseMemoryMap(rd io.Reader) error {
1008
-	return p.parseMemoryMapFromScanner(bufio.NewScanner(rd))
1015
+	return p.ParseMemoryMapFromScanner(bufio.NewScanner(rd))
1009
 }
1016
 }
1010
 
1017
 
1011
-func (p *Profile) parseMemoryMapFromScanner(s *bufio.Scanner) error {
1018
+func (p *Profile) ParseMemoryMapFromScanner(s *bufio.Scanner) error {
1012
 	mapping, err := parseProcMapsFromScanner(s)
1019
 	mapping, err := parseProcMapsFromScanner(s)
1013
 	if err != nil {
1020
 	if err != nil {
1014
 		return err
1021
 		return err
1054
 	return mapping, nil
1061
 	return mapping, nil
1055
 }
1062
 }
1056
 
1063
 
1057
-type sectionType int
1058
-
1059
-const (
1060
-	unrecognizedSection sectionType = iota
1061
-	memoryMapSection
1062
-)
1063
-
1064
-var memoryMapTriggers = []string{
1064
+var memoryMapSentinels = []string{
1065
 	"--- Memory map: ---",
1065
 	"--- Memory map: ---",
1066
 	"MAPPED_LIBRARIES:",
1066
 	"MAPPED_LIBRARIES:",
1067
 }
1067
 }
1068
 
1068
 
1069
-func sectionTrigger(line string) sectionType {
1070
-	for _, trigger := range memoryMapTriggers {
1071
-		if strings.Contains(line, trigger) {
1072
-			return memoryMapSection
1069
+// isMemoryMapSentinel returns true if the string contains one of the
1070
+// known sentinels for memory map information.
1071
+func isMemoryMapSentinel(line string) bool {
1072
+	for _, s := range memoryMapSentinels {
1073
+		if strings.Contains(line, s) {
1074
+			return true
1075
+		}
1076
+	}
1077
+	return false
1078
+}
1079
+
1080
+// memoryMapSentinelOffset returns the index of a known memory map
1081
+// sentinel in the string. If the string does not contain a sentinel,
1082
+// it returns 0.
1083
+func memoryMapSentinelOffset(line string) int {
1084
+	for _, s := range memoryMapSentinels {
1085
+		if i := strings.Index(line, s); i != -1 {
1086
+			return i
1073
 		}
1087
 		}
1074
 	}
1088
 	}
1075
-	return unrecognizedSection
1089
+	return 0
1076
 }
1090
 }
1077
 
1091
 
1078
 func (p *Profile) addLegacyFrameInfo() {
1092
 func (p *Profile) addLegacyFrameInfo() {