Home | History | Annotate | Download | only in inferno
      1 #
      2 # Copyright (C) 2016 The Android Open Source Project
      3 #
      4 # Licensed under the Apache License, Version 2.0 (the "License");
      5 # you may not use this file except in compliance with the License.
      6 # You may obtain a copy of the License at
      7 #
      8 #      http://www.apache.org/licenses/LICENSE-2.0
      9 #
     10 # Unless required by applicable law or agreed to in writing, software
     11 # distributed under the License is distributed on an "AS IS" BASIS,
     12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 # See the License for the specific language governing permissions and
     14 # limitations under the License.
     15 #
     16 
     17 class CallSite:
     18     def __init__(self, ip, method, dso):
     19         self.ip = ip
     20         self.method = method
     21         self.dso = dso
     22 
     23 
     24 
     25 class Thread:
     26     def __init__(self, tid):
     27         self.tid = tid
     28         self.samples = []
     29         self.flamegraph = {}
     30         self.num_samples = 0
     31 
     32 
     33     def add_callchain(self, callchain, symbol, sample):
     34         chain = []
     35         self.num_samples += 1
     36         for j in range(callchain.nr):
     37             entry = callchain.entries[callchain.nr - j - 1]
     38             if entry.ip == 0:
     39                 continue
     40             chain.append(CallSite(entry.ip, entry.symbol.symbol_name, entry.symbol.dso_name))
     41 
     42         chain.append(CallSite(sample.ip, symbol.symbol_name, symbol.dso_name))
     43         self.samples.append(chain)
     44 
     45 
     46     def collapse_flamegraph(self):
     47         flamegraph = FlameGraphCallSite("root", "")
     48         flamegraph.id = 0 # This is used for wasd navigation, 0 = not a valid target.
     49         self.flamegraph = flamegraph
     50         for sample in self.samples:
     51             flamegraph = self.flamegraph
     52             for callsite in sample:
     53                flamegraph = flamegraph.get_callsite(callsite.method, callsite.dso)
     54 
     55         # Populate root note.
     56         for node in self.flamegraph.callsites:
     57             self.flamegraph.num_samples += node.num_samples
     58 
     59 
     60 class Process:
     61     def __init__(self, name, pid):
     62         self.name = name
     63         self.pid = pid
     64         self.threads = {}
     65         self.cmd = ""
     66         self.props = {}
     67         self.args = None
     68         self.num_samples = 0
     69 
     70     def get_thread(self, tid):
     71         if (tid not in self.threads.keys()):
     72             self.threads[tid] = Thread(tid)
     73         return self.threads[tid]
     74 
     75 CALLSITE_COUNTER = 0
     76 def get_callsite_id():
     77     global CALLSITE_COUNTER
     78     CALLSITE_COUNTER += 1
     79     toReturn = CALLSITE_COUNTER
     80     return toReturn
     81 
     82 
     83 class FlameGraphCallSite:
     84 
     85     def __init__(self, method, dso):
     86         self.callsites = []
     87         self.method = method
     88         self.dso = dso
     89         self.num_samples = 0
     90         self.offset = 0 # Offset allows position nodes in different branches.
     91         self.id = get_callsite_id()
     92 
     93 
     94     def get_callsite(self, name, dso):
     95         for c in self.callsites:
     96             if c.equivalent(name, dso):
     97                 c.num_samples += 1
     98                 return c
     99         callsite = FlameGraphCallSite(name, dso)
    100         callsite.num_samples = 1
    101         self.callsites.append(callsite)
    102         return callsite
    103 
    104     def equivalent(self, method, dso):
    105         return self.method == method and self.dso == dso
    106 
    107 
    108     def get_max_depth(self):
    109         max = 0
    110         for c in self.callsites:
    111             depth = c.get_max_depth()
    112             if depth > max:
    113                 max = depth
    114         return max +1