# # Copyright (C) 2016 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # import sys SVG_CANVAS_WIDTH = 1124 SVG_NODE_HEIGHT = 17 FONT_SIZE = 12 def hash_to_float(string): return hash(string) / float(sys.maxint) def getLegacyColor(method) : r = 175 + int(50 * hash_to_float(reversed(method))) g = 60 + int(180 * hash_to_float(method)) b = 60 +int(55 * hash_to_float(reversed(method))) return (r,g,b) def getDSOColor(method) : r = 170 + int(80 * hash_to_float(reversed(method))) g = 180 +int(70 * hash_to_float((method))) b = 170 + int(80 * hash_to_float(reversed(method))) return (r,g,b) def getHeatColor(callsite, num_samples) : r = 245 + 10* (1- float(callsite.num_samples)/ num_samples) g = 110 + 105* (1-float(callsite.num_samples)/ num_samples) b = 100 return (r,g,b) def createSVGNode(callsite, depth, f, num_samples, height, color_scheme, nav): x = float(callsite.offset)/float(num_samples)*SVG_CANVAS_WIDTH y = height - (depth * SVG_NODE_HEIGHT) - SVG_NODE_HEIGHT width = float(callsite.num_samples) /float(num_samples) * SVG_CANVAS_WIDTH method = callsite.method.replace(">", ">").replace("<", "<") if (width <= 0) : return if color_scheme == "dso": r, g, b = getDSOColor(callsite.dso) elif color_scheme == "legacy": r, g, b = getLegacyColor(method) else: r, g, b = getHeatColor(callsite, num_samples) r_border = (r - 50) if r_border < 0: r_border = 0 g_border = (g - 50) if g_border < 0: g_border = 0 b_border = (b - 50) if (b_border < 0): b_border = 0 f.write( ' \n\ %s | %s (%d samples: %3.2f%%)\n \ \n \ \n \ \n' % (callsite.id, ','.join(str(x) for x in nav), method, callsite.dso, callsite.num_samples, callsite.num_samples/float(num_samples) * 100, x, y, x, y, width , width, r, g, b, r, g, b, r_border, g_border, b_border, x+2, y+12, FONT_SIZE)) def renderSVGNodes(flamegraph, depth, f, num_samples, height, color_scheme): for i, callsite in enumerate(flamegraph.callsites): # Prebuild navigation target for wasd if i == 0: left_index = 0 else: left_index = flamegraph.callsites[i-1].id if i == len(flamegraph.callsites)-1: right_index = 0 else: right_index = flamegraph.callsites[i+1].id up_index = 0 max_up = 0 for upcallsite in callsite.callsites: if upcallsite.num_samples > max_up: max_up = upcallsite.num_samples up_index = upcallsite.id # up, left, down, right nav = [up_index, left_index,flamegraph.id,right_index] createSVGNode(callsite, depth, f, num_samples, height, color_scheme, nav) # Recurse down renderSVGNodes(callsite, depth+1, f, num_samples, height, color_scheme) def renderSearchNode(f): f.write( ' \ Search\n' % (SVG_CANVAS_WIDTH - 95, SVG_CANVAS_WIDTH - 80) ) def renderUnzoomNode(f): f.write( '