parseThread parses a Threadz profile and returns a new Profile.
(b []byte)
| 838 | |
| 839 | // parseThread parses a Threadz profile and returns a new Profile. |
| 840 | func parseThread(b []byte) (*Profile, error) { |
| 841 | s := bufio.NewScanner(bytes.NewBuffer(b)) |
| 842 | // Skip past comments and empty lines seeking a real header. |
| 843 | for s.Scan() && isSpaceOrComment(s.Text()) { |
| 844 | } |
| 845 | |
| 846 | line := s.Text() |
| 847 | if m := threadzStartRE.FindStringSubmatch(line); m != nil { |
| 848 | // Advance over initial comments until first stack trace. |
| 849 | for s.Scan() { |
| 850 | if line = s.Text(); isMemoryMapSentinel(line) || strings.HasPrefix(line, "-") { |
| 851 | break |
| 852 | } |
| 853 | } |
| 854 | } else if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 { |
| 855 | return nil, errUnrecognized |
| 856 | } |
| 857 | |
| 858 | p := &Profile{ |
| 859 | SampleType: []*ValueType{{Type: "thread", Unit: "count"}}, |
| 860 | PeriodType: &ValueType{Type: "thread", Unit: "count"}, |
| 861 | Period: 1, |
| 862 | } |
| 863 | |
| 864 | locs := make(map[uint64]*Location) |
| 865 | // Recognize each thread and populate profile samples. |
| 866 | for !isMemoryMapSentinel(line) { |
| 867 | if strings.HasPrefix(line, "---- no stack trace for") { |
| 868 | break |
| 869 | } |
| 870 | if t := threadStartRE.FindStringSubmatch(line); len(t) != 4 { |
| 871 | return nil, errUnrecognized |
| 872 | } |
| 873 | |
| 874 | var addrs []uint64 |
| 875 | var err error |
| 876 | line, addrs, err = parseThreadSample(s) |
| 877 | if err != nil { |
| 878 | return nil, err |
| 879 | } |
| 880 | if len(addrs) == 0 { |
| 881 | // We got a --same as previous threads--. Bump counters. |
| 882 | if len(p.Sample) > 0 { |
| 883 | s := p.Sample[len(p.Sample)-1] |
| 884 | s.Value[0]++ |
| 885 | } |
| 886 | continue |
| 887 | } |
| 888 | |
| 889 | var sloc []*Location |
| 890 | for i, addr := range addrs { |
| 891 | // Addresses from stack traces point to the next instruction after |
| 892 | // each call. Adjust by -1 to land somewhere on the actual call |
| 893 | // (except for the leaf, which is not a call). |
| 894 | if i > 0 { |
| 895 | addr-- |
| 896 | } |
| 897 | loc := locs[addr] |
searching dependent graphs…