flamegraphTheme.tsx 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import {
  2. makeColorBucketTheme,
  3. makeColorMap,
  4. makeStackToColor,
  5. } from 'sentry/utils/profiling/colors/utils';
  6. import {FlamegraphFrame} from 'sentry/utils/profiling/flamegraphFrame';
  7. import {Frame} from 'sentry/utils/profiling/frame';
  8. import {darkTheme, lightTheme} from 'sentry/utils/theme';
  9. const MONOSPACE_FONT = `ui-monospace, Menlo, Monaco, 'Cascadia Mono', 'Segoe UI Mono', 'Roboto Mono',
  10. 'Oxygen Mono', 'Ubuntu Monospace', 'Source Code Pro', 'Fira Mono', 'Droid Sans Mono',
  11. 'Courier New', monospace`;
  12. const FRAME_FONT = lightTheme.text.familyMono;
  13. // Luma chroma hue settings
  14. export interface LCH {
  15. C_0: number;
  16. C_d: number;
  17. L_0: number;
  18. L_d: number;
  19. }
  20. // Color can be rgb or rgba. I want to probably eliminate rgb and just use rgba, but we would be allocating 25% more memory,
  21. // and I'm not sure about the impact we'd need. There is a tradeoff between memory and runtime performance checks that I'll need to evaluate at some point.
  22. export type ColorChannels = [number, number, number] | [number, number, number, number];
  23. export interface FlamegraphTheme {
  24. // @TODO, most colors are defined as strings, which is a mistake as we loose a lot of functionality and impose constraints.
  25. // They should instead be defined as arrays of numbers so we can use them with glsl and avoid unnecessary parsing
  26. COLORS: {
  27. BAR_LABEL_FONT_COLOR: string;
  28. COLOR_BUCKET: (t: number, frame?: Frame) => ColorChannels;
  29. COLOR_MAP: (
  30. frames: ReadonlyArray<FlamegraphFrame>,
  31. colorBucket: FlamegraphTheme['COLORS']['COLOR_BUCKET'],
  32. sortByKey?: (a: FlamegraphFrame, b: FlamegraphFrame) => number
  33. ) => Map<FlamegraphFrame['frame']['key'], ColorChannels>;
  34. CURSOR_CROSSHAIR: string;
  35. DIFFERENTIAL_DECREASE: ColorChannels;
  36. DIFFERENTIAL_INCREASE: ColorChannels;
  37. FOCUSED_FRAME_BORDER_COLOR: string;
  38. FRAME_FALLBACK_COLOR: [number, number, number, number];
  39. GRID_FRAME_BACKGROUND_COLOR: string;
  40. GRID_LINE_COLOR: string;
  41. HIGHLIGHTED_LABEL_COLOR: ColorChannels;
  42. HOVERED_FRAME_BORDER_COLOR: string;
  43. LABEL_FONT_COLOR: string;
  44. MINIMAP_POSITION_OVERLAY_BORDER_COLOR: string;
  45. MINIMAP_POSITION_OVERLAY_COLOR: string;
  46. REQUEST_2XX_RESPONSE: string;
  47. REQUEST_4XX_RESPONSE: string;
  48. REQUEST_DNS_TIME: string;
  49. REQUEST_SSL_TIME: string;
  50. REQUEST_TCP_TIME: string;
  51. // Nice color picker for GLSL colors - https://keiwando.com/color-picker/
  52. REQUEST_WAIT_TIME: string;
  53. SAMPLE_TICK_COLOR: ColorChannels;
  54. SEARCH_RESULT_FRAME_COLOR: string;
  55. SELECTED_FRAME_BORDER_COLOR: string;
  56. SPAN_FRAME_BACKGROUND: string;
  57. SPAN_FRAME_BORDER: string;
  58. STACK_TO_COLOR: (
  59. frames: ReadonlyArray<FlamegraphFrame>,
  60. colorMapFn: FlamegraphTheme['COLORS']['COLOR_MAP'],
  61. colorBucketFn: FlamegraphTheme['COLORS']['COLOR_BUCKET']
  62. ) => {
  63. colorBuffer: Array<number>;
  64. colorMap: Map<Frame['key'], ColorChannels>;
  65. };
  66. };
  67. CONFIG: {
  68. HIGHLIGHT_RECURSION: boolean;
  69. };
  70. FONTS: {
  71. FONT: string;
  72. FRAME_FONT: string;
  73. };
  74. SIZES: {
  75. BAR_FONT_SIZE: number;
  76. BAR_HEIGHT: number;
  77. BAR_PADDING: number;
  78. FLAMEGRAPH_DEPTH_OFFSET: number;
  79. FOCUSED_FRAME_BORDER_WIDTH: number;
  80. FRAME_BORDER_WIDTH: number;
  81. GRID_LINE_WIDTH: number;
  82. HOVERED_FRAME_BORDER_WIDTH: number;
  83. INTERNAL_SAMPLE_TICK_LINE_WIDTH: number;
  84. LABEL_FONT_PADDING: number;
  85. LABEL_FONT_SIZE: number;
  86. MINIMAP_HEIGHT: number;
  87. MINIMAP_POSITION_OVERLAY_BORDER_WIDTH: number;
  88. REQUEST_BAR_HEIGHT: number;
  89. REQUEST_DEPTH_OFFSET: number;
  90. REQUEST_FONT_SIZE: number;
  91. // Request
  92. REQUEST_TAIL_HEIGHT: number;
  93. // Spans
  94. SPANS_BAR_HEIGHT: number;
  95. SPANS_DEPTH_OFFSET: number;
  96. SPANS_FONT_SIZE: number;
  97. TIMELINE_HEIGHT: number;
  98. TOOLTIP_FONT_SIZE: number;
  99. };
  100. }
  101. // Luma chroma hue settings for light theme
  102. export const LCH_LIGHT = {
  103. C_0: 0.25,
  104. C_d: 0.2,
  105. L_0: 0.8,
  106. L_d: 0.15,
  107. };
  108. // Luma chroma hue settings for dark theme
  109. export const LCH_DARK = {
  110. C_0: 0.2,
  111. C_d: 0.1,
  112. L_0: 0.2,
  113. L_d: 0.1,
  114. };
  115. export const LightFlamegraphTheme: FlamegraphTheme = {
  116. CONFIG: {
  117. HIGHLIGHT_RECURSION: false,
  118. },
  119. SIZES: {
  120. BAR_FONT_SIZE: 11,
  121. BAR_HEIGHT: 20,
  122. BAR_PADDING: 4,
  123. FLAMEGRAPH_DEPTH_OFFSET: 12,
  124. FOCUSED_FRAME_BORDER_WIDTH: 2,
  125. FRAME_BORDER_WIDTH: 2,
  126. GRID_LINE_WIDTH: 2,
  127. HOVERED_FRAME_BORDER_WIDTH: 1,
  128. INTERNAL_SAMPLE_TICK_LINE_WIDTH: 1,
  129. LABEL_FONT_PADDING: 6,
  130. LABEL_FONT_SIZE: 10,
  131. MINIMAP_HEIGHT: 100,
  132. MINIMAP_POSITION_OVERLAY_BORDER_WIDTH: 2,
  133. REQUEST_BAR_HEIGHT: 14,
  134. REQUEST_DEPTH_OFFSET: 4,
  135. REQUEST_FONT_SIZE: 10,
  136. REQUEST_TAIL_HEIGHT: 8,
  137. SPANS_BAR_HEIGHT: 14,
  138. SPANS_DEPTH_OFFSET: 4,
  139. SPANS_FONT_SIZE: 10,
  140. TIMELINE_HEIGHT: 20,
  141. TOOLTIP_FONT_SIZE: 12,
  142. },
  143. COLORS: {
  144. BAR_LABEL_FONT_COLOR: '#000',
  145. COLOR_BUCKET: makeColorBucketTheme(LCH_LIGHT),
  146. COLOR_MAP: makeColorMap,
  147. CURSOR_CROSSHAIR: '#bbbbbb',
  148. DIFFERENTIAL_DECREASE: [0.309, 0.2058, 0.98],
  149. DIFFERENTIAL_INCREASE: [0.98, 0.2058, 0.4381],
  150. FOCUSED_FRAME_BORDER_COLOR: lightTheme.focus,
  151. FRAME_FALLBACK_COLOR: [0, 0, 0, 0.035],
  152. GRID_FRAME_BACKGROUND_COLOR: 'rgba(255, 255, 255, 0.8)',
  153. GRID_LINE_COLOR: '#e5e7eb',
  154. HIGHLIGHTED_LABEL_COLOR: [255, 255, 0],
  155. HOVERED_FRAME_BORDER_COLOR: 'rgba(0, 0, 0, 0.8)',
  156. LABEL_FONT_COLOR: '#1f233a',
  157. MINIMAP_POSITION_OVERLAY_BORDER_COLOR: 'rgba(0,0,0, 0.2)',
  158. MINIMAP_POSITION_OVERLAY_COLOR: 'rgba(0,0,0,0.1)',
  159. REQUEST_2XX_RESPONSE: 'rgba(218, 231, 209, 1)',
  160. REQUEST_4XX_RESPONSE: 'rgba(255,96, 96, 1)',
  161. REQUEST_DNS_TIME: `rgba(57, 146, 152, 1)`,
  162. REQUEST_SSL_TIME: `rgba(207,84,218, 1)`,
  163. REQUEST_TCP_TIME: `rgba(242, 146,57,1)`,
  164. REQUEST_WAIT_TIME: `rgba(253,252,224, 1)`,
  165. SAMPLE_TICK_COLOR: [255, 0, 0, 0.5],
  166. SEARCH_RESULT_FRAME_COLOR: 'vec4(0.99, 0.70, 0.35, 1.0)',
  167. SELECTED_FRAME_BORDER_COLOR: lightTheme.blue400,
  168. SPAN_FRAME_BACKGROUND: 'rgba(231, 231, 231, 0.5)',
  169. SPAN_FRAME_BORDER: 'rgba(200, 200, 200, 1)',
  170. STACK_TO_COLOR: makeStackToColor([0, 0, 0, 0.035]),
  171. },
  172. FONTS: {
  173. FONT: MONOSPACE_FONT,
  174. FRAME_FONT,
  175. },
  176. };
  177. export const DarkFlamegraphTheme: FlamegraphTheme = {
  178. CONFIG: {
  179. HIGHLIGHT_RECURSION: false,
  180. },
  181. SIZES: {
  182. BAR_FONT_SIZE: 11,
  183. BAR_HEIGHT: 20,
  184. BAR_PADDING: 4,
  185. FLAMEGRAPH_DEPTH_OFFSET: 12,
  186. FOCUSED_FRAME_BORDER_WIDTH: 1,
  187. FRAME_BORDER_WIDTH: 2,
  188. GRID_LINE_WIDTH: 2,
  189. HOVERED_FRAME_BORDER_WIDTH: 1,
  190. INTERNAL_SAMPLE_TICK_LINE_WIDTH: 1,
  191. LABEL_FONT_PADDING: 6,
  192. LABEL_FONT_SIZE: 10,
  193. MINIMAP_HEIGHT: 100,
  194. MINIMAP_POSITION_OVERLAY_BORDER_WIDTH: 2,
  195. REQUEST_BAR_HEIGHT: 14,
  196. REQUEST_DEPTH_OFFSET: 4,
  197. REQUEST_FONT_SIZE: 10,
  198. REQUEST_TAIL_HEIGHT: 8,
  199. SPANS_BAR_HEIGHT: 14,
  200. SPANS_DEPTH_OFFSET: 4,
  201. SPANS_FONT_SIZE: 10,
  202. TIMELINE_HEIGHT: 20,
  203. TOOLTIP_FONT_SIZE: 12,
  204. },
  205. COLORS: {
  206. BAR_LABEL_FONT_COLOR: 'rgb(255 255 255 / 80%)',
  207. COLOR_BUCKET: makeColorBucketTheme(LCH_DARK),
  208. COLOR_MAP: makeColorMap,
  209. CURSOR_CROSSHAIR: '#828285',
  210. DIFFERENTIAL_DECREASE: [0.309, 0.2058, 0.98],
  211. DIFFERENTIAL_INCREASE: [0.98, 0.2058, 0.4381],
  212. FOCUSED_FRAME_BORDER_COLOR: darkTheme.focus,
  213. FRAME_FALLBACK_COLOR: [1, 1, 1, 0.1],
  214. GRID_FRAME_BACKGROUND_COLOR: 'rgba(0, 0, 0, 0.4)',
  215. GRID_LINE_COLOR: '#222227',
  216. HIGHLIGHTED_LABEL_COLOR: [255, 255, 0],
  217. HOVERED_FRAME_BORDER_COLOR: 'rgba(255, 255, 255, 0.8)',
  218. LABEL_FONT_COLOR: 'rgba(255, 255, 255, 0.8)',
  219. MINIMAP_POSITION_OVERLAY_BORDER_COLOR: 'rgba(255,255,255, 0.2)',
  220. MINIMAP_POSITION_OVERLAY_COLOR: 'rgba(255,255,255,0.1)',
  221. REQUEST_2XX_RESPONSE: 'rgba(218, 231, 209, 1)',
  222. REQUEST_4XX_RESPONSE: 'rgba(255,96, 96, 1)',
  223. REQUEST_DNS_TIME: `rgba(57, 146, 152, 1)`,
  224. REQUEST_SSL_TIME: `rgba(207,84,218, 1)`,
  225. REQUEST_TCP_TIME: `rgba(242, 146,57,1)`,
  226. REQUEST_WAIT_TIME: `rgba(253,252,224, 1)`,
  227. SAMPLE_TICK_COLOR: [255, 0, 0, 0.5],
  228. SEARCH_RESULT_FRAME_COLOR: 'vec4(0.99, 0.70, 0.35, 0.7)',
  229. SELECTED_FRAME_BORDER_COLOR: lightTheme.blue400,
  230. SPAN_FRAME_BACKGROUND: 'rgba(232, 232, 232, 0.2)',
  231. SPAN_FRAME_BORDER: '#57575b',
  232. STACK_TO_COLOR: makeStackToColor([1, 1, 1, 0.1]),
  233. },
  234. FONTS: {
  235. FONT: MONOSPACE_FONT,
  236. FRAME_FONT,
  237. },
  238. };