weightedtree

package
v0.0.0-...-9cd7082 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2023 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Types and functions for traversing weighted trees in 'heaviest-first' order -- the next node visited is always the node with the 'highest' total weight whose parent has also been visited.

A weighted tree is comprised of TreeNodes, each of which has a path of ScopeIDs indicating its location in the tree and a set of child TreeNodes. Except for the root TreeNode, each TreeNode has a ScopeID (the last element in its path). TreeNodes must conform to tree constraints:

  • the root TreeNode's path is empty;
  • a non-root TreeNode's path must be its parent's path with its own ScopeID appended at the end;
  • all children of a single TreeNode must have distinct ScopeIDs.

'Highest' is determined by a provided comparator, and may be arbitrary (and of course may actually be 'lowest'.)

Walk(TreeNode, Compare, WalkOptions...) traverses the specified TreeNode in 'heaviest-first' order (as determined by the provided Compare function), and with the walk limited by the provided WalkOptions. It returns a slice of traversal root SubtreeNodes representing a view on the tree. Each SubtreeNode corresponds to a single TreeNode, and includes that TreeNode and its Path, and the SubtreeNode's parent and children. Note that, due to node elision via ElidePrefix and ElideTreeNodes (see below), given a SubtreeNode SN corresponding to TreeNode TN, SN's parent and children may not correspond to TN's parent and children.

A variety of traversal options are supported, including:

  • PathPrefix(ids...): specify ids... as a traversal path prefix. When one or more path prefix is defined, then traversals only begin from specified path prefixes. If multiple path prefixes are defined, then a prefix tree is constructed from their union, and traversal begins from the leaves of that tree.
  • ElidePrefix(): elide non-leaf nodes in specified prefixes. If at least one path prefix is specified and ElidePrefix is not, SubtreeNodes lying within a specified path prefix are returned with Prefix=true.
  • MaxDepth(n): do not traverse deeper than n nodes from a specified path prefix.
  • MaxNodes(n): do not return more than n non-prefix nodes.
  • FilterTreeNodes(func(TreeNode) bool): only traverse nodes for which the specified filter function returns true.
  • ElideTreeNodes(func(TreeNode) bool): Traverse normally, but only return SubtreeNodes for TreeNodes for which the specified filter function returns true.

Subtrees returned from Walk() may be rapidly constructed into the TraceViz data format with SubtreeNode.BuildResponse().

Package weightedtree provides structural helpers for defining weighted tree data. Given a DataBuilder db, a new Tree may be constructed via:

tree := New(db, renderSettings, properties...)

Trees may also be annotated with additional properties, via:

tree.With(properties...)

A tree has one or more root nodes, defined via:

root := tree.Node(selfMagnitude, properties...)

And nodes may have other nodes as children:

child := root.Node(selfMagnitude, properties...)

Each node's self-magnitude is provided at its creation; a node's total- magnitude is computed as the sum of its self-magnitude and the total- magnitude of all its children. Generally, a node's displayed width is proportional to its total-magnitude.

Arbitrary payloads may be composed into trees under Nodes, via

payload.New(node)

which allocate the payload and return its *util.DataBuilder. See payload.go for more detail.

Encoded into the TraceViz data model, a tree is:

tree

properties
  * render settings definition
  * <decorators>
children
  * repeated root nodes

node

properties
   * selfMagnitudeKEy: self magnitude
	 * <decorators>
children
	 * repeated nodes and payloads

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Compare

type Compare func(a, b TreeNode) (int, error)

Compare compares two arbitrary TreeNodes, returning <0, 0, or >0 if the first compares less than, equal to, or greater than the second. It may return an error if some relationship invariant between the two is not met.

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node represents a node within a Tree.

func (*Node) Node

func (n *Node) Node(selfMagnitude float64, properties ...util.PropertyUpdate) *Node

Node creates and returns a new child node with the specified magnitude beneath the receiver.

func (*Node) Payload

func (n *Node) Payload() util.DataBuilder

Payload creates and returns a DataBuilder that can be used to attach arbitrary structured information to the receiving Node.

func (*Node) With

func (n *Node) With(properties ...util.PropertyUpdate) *Node

With applies a set of properties to the receiving Node, returning that Node to facilitate chaining.

type NodeCallback

type NodeCallback func(inputNode *SubtreeNode, outputNode util.DataBuilder)

NodeCallback describes a callback invoked on each SubtreeNode in an invocation of SubtreeNode.BuildResponse.

type RenderSettings

type RenderSettings struct {
	// The height of a frame in pixels.
	FrameHeightPx int64
}

RenderSettings is a collection of rendering settings for trees.

func (*RenderSettings) Define

func (rs *RenderSettings) Define() util.PropertyUpdate

Define applies the receiver as a set of properties.

type ScopeID

type ScopeID uint

ScopeID is the unique ID of a scope. The same scope may appear at multiple places throughout a tree.

type SubtreeNode

type SubtreeNode struct {
	// Parent is set to this node's parent SubtreeNode.  It is nil if this
	// SubtreeNode corresponds to a root TreeNode, and may be nil for
	// SubtreeNodes corresponding to non-root TreeNodes, if scopes are elided.
	Parent *SubtreeNode
	// Prefix is true if this SubtreeNode lies within (but not at the leaf of) a
	// traversal prefix path as specified by PrefixPath().  If the traversal
	// options include ElidePrefix(), prefix nodes are elided.
	Prefix bool
	// Path is set to this node's full path.  It is empty if this SubtreeNode
	// corresponds to the tree root.
	Path []ScopeID
	// The TreeNode corresponding to this SubtreeNode.
	TreeNode TreeNode
	// The children of this SubtreeNode.
	Children []*SubtreeNode
}

SubtreeNode is a node on a traversal subtree returned by Walk. Every SubtreeNode corresponds directly to a TreeNode, which it includes as a member field.

func Walk

func Walk(tn TreeNode, compare Compare, opts ...WalkOption) (*SubtreeNode, error)

Walk returns the subtree of tree rooted at the provided TreeNode, traversed with the provided walk options. The entire traversed subtree, modulo prefix nodes (if ElidePrefix is specified) and any nodes elided by ElideScopeIDs, is constructed and returned, so Walk is unsuitable for very large traversals; it should return visualizable quantities of data. Note that zero SubtreeNodes may be returned if all TreeNodes are filtered out, and more than one SubtreeNodes may be returned if TreeNodes are elided. An invocation of Walk with no nodes elided or filtered out will always return a slice containing one SubtreeNode, corresponding to the provided TreeNode.

Walk is thread-compatible; if Path() and Children() are thread-safe for tn and all its descendants, Walk is thread-safe.

func (*SubtreeNode) BuildResponse

func (sn *SubtreeNode) BuildResponse(db util.DataBuilder, nodeCallback NodeCallback)

BuildResponse builds a TraceViz response tree mirroring the subtree rooted at the receiver, with the provided DataBuilder representing the receiver. BuildResponse assembles the structure of the tree but sets no properties; instead, node properties (and response node children apart from the receiver's tree structure) may be set using the supplied callback, which is invoked once for every SubtreeNode in the receiver's subtree with that SubtreeNode and its corresponding response DataBuilder node.

type Tree

type Tree struct {
	// contains filtered or unexported fields
}

Tree represents a tree of hierarchical, weighted data, such as the aggregated callstacks presented in a flame chart.

func New

func New(db util.DataBuilder, renderSettings *RenderSettings, properties ...util.PropertyUpdate) *Tree

New returns a new Tree populating the provided data builder.

func (*Tree) Node

func (t *Tree) Node(selfMagnitude float64, properties ...util.PropertyUpdate) *Node

Node creates and returns a new root node with the specified magnitude in the tree.

func (*Tree) With

func (t *Tree) With(properties ...util.PropertyUpdate) *Tree

With applies a set of properties to the receiving Tree, returning that Tree to facilitate chaining.

type TreeNode

type TreeNode interface {
	// The path of this node.  It:
	//  * must be empty for the tree root;
	//  * must be unique for all nodes in the tree;
	//  * must, for a child C of parent P, be P.Path() with a single scope ID
	//    appended at the end.  That ScopeID is the node's unique scope ID.
	// During Walk, Path() is cached, so it may be dynamically computed.
	Path() []ScopeID
	// The children of this node with the specified scope IDs.  If no scope IDs
	// are provided, all children should be returned.  Requested scope IDs
	// without corresponding children should just be dropped.
	Children(...ScopeID) ([]TreeNode, error)
}

TreeNode represents a node of a weighted tree.

type TreeNodeFilterFunc

type TreeNodeFilterFunc func(TreeNode) bool

TreeNodeFilterFunc defines a callback implementing a TreeNode filter, and returning true for nodes that satisfy that filter.

type WalkOption

type WalkOption func(wo *walkOptions) error

WalkOption specifies an option configuring a tree traversal.

func ElidePrefix

func ElidePrefix() WalkOption

ElidePrefix specifies whether nodes lying on specified prefix paths are included in the traversal response. If not provided, such prefix nodes will be included, but will be marked with Prefix=true. The root is never elided. Defaults to true.

func ElideTreeNodes

func ElideTreeNodes(f TreeNodeFilterFunc) WalkOption

ElideTreeNodes elides traversed nodes based on a provided TreeNode filter. Elided nodes are traversed normally, but do not result in output SubTreeNodes.

func FilterTreeNodes

func FilterTreeNodes(f TreeNodeFilterFunc) WalkOption

FilterTreeNodes filters the traversal based on a provided TreeNode filter. This can be used to dynamically react to viewport size: a TreeNode may be constructed using the viewport width in pixels (e.g., as a TraceViz DataQuery parameter) and the width of the Tree's root node to ensure that only frames that will render at or above a minimum pixel width are returned.

func MaxDepth

func MaxDepth(maxDepth uint) WalkOption

MaxDepth specifies the maximum depth (or path length) that a walk may traverse, as counted from the most proximate specified prefix (so that nodes at different absolute depths may be returned if they have different- length prefixes). Defaults to no limit.

func MaxNodes

func MaxNodes(maxNodes uint) WalkOption

MaxNodes specifies the maximum number of non-prefix nodes that a walk may traverse. Defaults to no limit.

func PathPrefix

func PathPrefix(path ...ScopeID) WalkOption

PathPrefix specifies a path prefix from which a walk should begin. If the traversal was invoked without ElidePrefix(), the nodes on the prefix path are returned, and marked with Prefix=true. PathPrefix may be specified multiple times, in which case the traversal will choose the next largest descendant of any specified prefix at each step, but if one specified PathPrefix is itself a prefix of another specified PathPrefix, only the more specific (=longer) one will apply. All nodes lying on any specified path prefix will be included in the response and marked with Prefix=true, even those whose children are not traversed, unless ElidePrefix() is also specified. Defaults to the empty path, i.e., no prefix.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL