differentialFlamegraph.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import {ColorChannels, FlamegraphTheme} from './flamegraph/flamegraphTheme';
  2. import {relativeChange} from './units/units';
  3. import {Flamegraph} from './flamegraph';
  4. import {FlamegraphFrame} from './flamegraphFrame';
  5. function countFrameOccurences(
  6. frames: ReadonlyArray<FlamegraphFrame>
  7. ): Map<string, number> {
  8. const counts = new Map<string, number>();
  9. for (const frame of frames) {
  10. const key = frame.frame.name + (frame.frame.file ? frame.frame.file : '');
  11. if (counts.has(key)) {
  12. counts.set(key, counts.get(key)! + 1);
  13. } else {
  14. counts.set(key, 1);
  15. }
  16. }
  17. return counts;
  18. }
  19. export class DifferentialFlamegraph extends Flamegraph {
  20. colors: Map<string, ColorChannels> = new Map();
  21. fromToDiff: Map<string, number> = new Map();
  22. toCount: Map<string, number> = new Map();
  23. fromCount: Map<string, number> = new Map();
  24. static Diff(
  25. from: Flamegraph, // Reference chart is the one we compare the new flamegraph with
  26. to: Flamegraph,
  27. theme: FlamegraphTheme
  28. ): DifferentialFlamegraph {
  29. const differentialFlamegraph = new DifferentialFlamegraph(
  30. to.profile,
  31. to.profileIndex,
  32. {inverted: from.inverted, leftHeavy: from.leftHeavy}
  33. );
  34. const fromCounts = countFrameOccurences(from.frames);
  35. const toCounts = countFrameOccurences(to.frames);
  36. const countDiff: Map<string, number> = new Map();
  37. const colorMap: Map<string, ColorChannels> =
  38. differentialFlamegraph.colors ?? new Map();
  39. for (const frame of to.frames) {
  40. const key = frame.frame.name + (frame.frame.file ? frame.frame.file : '');
  41. // If we already diffed this frame, skip it
  42. if (countDiff.has(key)) {
  43. continue;
  44. }
  45. const fromCount = fromCounts.get(key);
  46. const toCount = toCounts.get(key);
  47. let diff = 0;
  48. let color: number[] = [];
  49. if (toCount === undefined) {
  50. throw new Error(`Missing count for frame ${key}, this should never happen`);
  51. }
  52. if (fromCount === undefined) {
  53. diff = 1;
  54. color = [...theme.COLORS.DIFFERENTIAL_INCREASE, 1];
  55. } else if (toCount > fromCount) {
  56. diff = relativeChange(toCount, fromCount);
  57. color = [...theme.COLORS.DIFFERENTIAL_INCREASE, diff];
  58. } else if (fromCount > toCount) {
  59. diff = relativeChange(toCount, fromCount);
  60. color = [...theme.COLORS.DIFFERENTIAL_DECREASE, Math.abs(diff)];
  61. } else {
  62. countDiff.set(key, diff);
  63. continue;
  64. }
  65. countDiff.set(key, diff);
  66. colorMap.set(key, color as ColorChannels);
  67. }
  68. differentialFlamegraph.fromToDiff = countDiff;
  69. differentialFlamegraph.toCount = toCounts;
  70. differentialFlamegraph.fromCount = fromCounts;
  71. differentialFlamegraph.colors = colorMap;
  72. return differentialFlamegraph;
  73. }
  74. }