Hone logo
Hone
Problems

Angular Flame Graph Visualization

This challenge involves building a reusable Angular component that visualizes performance profiling data in the form of a flame graph. Flame graphs are a powerful tool for identifying performance bottlenecks in applications by representing call stacks and their associated costs.

Problem Description

Your task is to create an Angular component that accepts hierarchical performance profiling data and renders it as an interactive flame graph. The component should visually represent the CPU time or memory usage of different functions or code blocks within an application.

Key Requirements:

  • Data Input: The component should accept an array of objects, where each object represents a node in the flame graph. Each node should have at least the following properties:
    • name: A string representing the function or code block name.
    • value: A number representing the cost (e.g., CPU time, memory usage).
    • children: An optional array of child nodes, forming the hierarchy.
  • Visual Representation:
    • Each node should be rendered as a rectangular bar.
    • The width of a bar should be proportional to its value relative to its parent's value or the total value at that level.
    • The color of a bar can be used to differentiate between different types of functions or to indicate depth.
    • The y-axis should represent the call stack depth, with deeper calls appearing higher.
  • Interactivity:
    • Hover: When a user hovers over a bar, a tooltip should appear displaying the name and value of the hovered node, as well as its percentage contribution to its parent.
    • Zoom/Pan (Optional but Recommended): Allow users to zoom into specific sections of the flame graph and pan horizontally to explore details.
  • Responsiveness: The graph should adapt to different screen sizes.
  • Reusability: The component should be designed for easy integration into various Angular applications.

Expected Behavior:

The component should render a hierarchical visualization where wider bars indicate functions that consume more resources. Users should be able to easily identify performance hotspots by observing the widest bars at the top or within specific call stacks.

Edge Cases:

  • Empty Data: Handle cases where no profiling data is provided.
  • Deeply Nested Data: Ensure performance and readability with very deep call stacks.
  • Large Values: Handle very large numerical values for value.
  • Identical Names at Same Level: The visualization should still be distinguishable.

Examples

Example 1:

[
  {
    "name": "root",
    "value": 100,
    "children": [
      {
        "name": "funcA",
        "value": 60,
        "children": [
          { "name": "funcA1", "value": 30 },
          { "name": "funcA2", "value": 30 }
        ]
      },
      {
        "name": "funcB",
        "value": 40,
        "children": [
          { "name": "funcB1", "value": 20 },
          { "name": "funcB2", "value": 20 }
        ]
      }
    ]
  }
]

Output: A flame graph where "root" is the widest bar at the bottom. "funcA" and "funcB" are stacked on top of "root", with "funcA" being wider than "funcB". "funcA1" and "funcA2" are stacked on top of "funcA", and similarly for "funcB". Hovering over "funcA" shows its name, value (60), and percentage of "root" (60%).

Example 2:

[
  {
    "name": "Application",
    "value": 500,
    "children": [
      {
        "name": "UI Rendering",
        "value": 300,
        "children": [
          { "name": "DOM Manipulation", "value": 150 },
          { "name": "Layout Calculation", "value": 100 },
          { "name": "Painting", "value": 50 }
        ]
      },
      {
        "name": "Data Fetching",
        "value": 200,
        "children": [
          { "name": "API Call 1", "value": 100 },
          { "name": "API Call 2", "value": 100 }
        ]
      }
    ]
  }
]

Output: A flame graph where "Application" is the base. "UI Rendering" and "Data Fetching" are stacked on top. "UI Rendering" occupies more horizontal space than "Data Fetching". Within "UI Rendering", "DOM Manipulation" is the widest, followed by "Layout Calculation", and then "Painting". Hovering over "Layout Calculation" would show its name, value (100), and its percentage of "UI Rendering" (33.33%).

Example 3: Edge Case - Flat Data

[
  { "name": "Task1", "value": 50 },
  { "name": "Task2", "value": 70 },
  { "name": "Task3", "value": 30 }
]

Output: A flame graph with three bars at the same depth, representing "Task1", "Task2", and "Task3". The widths are proportional to their values. This would typically be rendered as a single row of bars.

Constraints

  • The input data will be a valid JSON array conforming to the specified structure.
  • value will be a non-negative number.
  • The component should be built using Angular 15+ and TypeScript.
  • Consider performance for graphs with up to 1000 nodes and a maximum depth of 20.
  • The primary rendering library (e.g., D3.js, Chart.js, or pure SVG/Canvas) is up to you, but ensure it's well-integrated into Angular.

Notes

  • Consider how you will map the hierarchical data to a 2D layout. A common approach is to use a "treemap" or "icicle" layout algorithm.
  • Coloring strategies can significantly improve readability. Think about using a color scale based on function type, depth, or value.
  • For interactivity, consider using event listeners and state management within your Angular component.
  • If implementing zoom/pan, libraries like D3.js offer robust solutions.
  • The "root" of the flame graph typically represents the total cost of the profiled operation.
Loading editor...
typescript