differentialFlamegraph.tsx 2.7 KB

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