chaos_detector 0.4.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/detect_chaos +31 -0
- data/lib/chaos_detector.rb +22 -0
- data/lib/chaos_detector/chaos_graphs/chaos_edge.rb +32 -0
- data/lib/chaos_detector/chaos_graphs/chaos_graph.rb +389 -0
- data/lib/chaos_detector/chaos_graphs/domain_metrics.rb +19 -0
- data/lib/chaos_detector/chaos_graphs/domain_node.rb +57 -0
- data/lib/chaos_detector/chaos_graphs/function_node.rb +112 -0
- data/lib/chaos_detector/chaos_graphs/module_node.rb +86 -0
- data/lib/chaos_detector/chaos_utils.rb +57 -0
- data/lib/chaos_detector/graph_theory/appraiser.rb +162 -0
- data/lib/chaos_detector/graph_theory/edge.rb +76 -0
- data/lib/chaos_detector/graph_theory/graph.rb +144 -0
- data/lib/chaos_detector/graph_theory/loop_detector.rb +32 -0
- data/lib/chaos_detector/graph_theory/node.rb +70 -0
- data/lib/chaos_detector/graph_theory/node_metrics.rb +68 -0
- data/lib/chaos_detector/graph_theory/reduction.rb +40 -0
- data/lib/chaos_detector/graphing/directed_graphs.rb +396 -0
- data/lib/chaos_detector/graphing/graphs.rb +129 -0
- data/lib/chaos_detector/graphing/matrix_graphs.rb +101 -0
- data/lib/chaos_detector/navigator.rb +237 -0
- data/lib/chaos_detector/options.rb +51 -0
- data/lib/chaos_detector/stacker/comp_info.rb +42 -0
- data/lib/chaos_detector/stacker/fn_info.rb +44 -0
- data/lib/chaos_detector/stacker/frame.rb +34 -0
- data/lib/chaos_detector/stacker/frame_stack.rb +63 -0
- data/lib/chaos_detector/stacker/mod_info.rb +24 -0
- data/lib/chaos_detector/tracker.rb +276 -0
- data/lib/chaos_detector/utils/core_util.rb +117 -0
- data/lib/chaos_detector/utils/fs_util.rb +49 -0
- data/lib/chaos_detector/utils/lerp_util.rb +20 -0
- data/lib/chaos_detector/utils/log_util.rb +45 -0
- data/lib/chaos_detector/utils/str_util.rb +90 -0
- data/lib/chaos_detector/utils/tensor_util.rb +21 -0
- data/lib/chaos_detector/walkman.rb +214 -0
- metadata +147 -0
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'chaos_detector/options'
|
2
|
+
require 'chaos_detector/navigator'
|
3
|
+
require 'chaos_detector/stacker/frame'
|
4
|
+
require 'chaos_detector/graph_theory/appraiser'
|
5
|
+
require 'chaos_detector/graph_theory/graph'
|
6
|
+
require 'chaos_detector/graphing/directed_graphs'
|
7
|
+
require 'chaos_detector/chaos_graphs/chaos_graph'
|
8
|
+
require 'chaos_detector/utils/str_util'
|
9
|
+
require 'chaos_detector/chaos_utils'
|
10
|
+
|
11
|
+
require_relative 'directed_graphs'
|
12
|
+
require_relative 'matrix_graphs'
|
13
|
+
|
14
|
+
module ChaosDetector
|
15
|
+
module Graphing
|
16
|
+
### Top-level Chaos-detection graphing and rendering
|
17
|
+
class Graphs
|
18
|
+
attr_reader :navigator
|
19
|
+
attr_reader :chaos_graph
|
20
|
+
|
21
|
+
def initialize(options: nil)
|
22
|
+
@options = options || ChaosDetector::Options.new
|
23
|
+
@render_folder = @options.path_with_root(key: :graph_render_folder)
|
24
|
+
# @render_folder = @options.graph_render_folder
|
25
|
+
ChaosDetector::Utils::FSUtil.ensure_dirpath(@render_folder)
|
26
|
+
@navigator = ChaosDetector::Navigator.new(options: @options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def playback(row_range: nil)
|
30
|
+
fn_graph, mod_graph = @navigator.playback(row_range: row_range)
|
31
|
+
@chaos_graph = ChaosDetector::ChaosGraphs::ChaosGraph.new(fn_graph, mod_graph)
|
32
|
+
@chaos_graph.infer_all
|
33
|
+
end
|
34
|
+
|
35
|
+
GRAPH_TYPE_ATTRS = {
|
36
|
+
domain: {
|
37
|
+
# ratio: 'auto',
|
38
|
+
# size: '8, 8',
|
39
|
+
# rankdir: 'TB',
|
40
|
+
# packmode: 'clust'
|
41
|
+
},
|
42
|
+
function: {
|
43
|
+
|
44
|
+
},
|
45
|
+
module: {
|
46
|
+
rankdir: 'TB',
|
47
|
+
packmode: 'clust',
|
48
|
+
ranksep: '1.5',
|
49
|
+
},
|
50
|
+
}
|
51
|
+
|
52
|
+
def adjacency_graph(graph_type, graph: nil, graph_name: 'adj-matrix')
|
53
|
+
the_matrix = ChaosDetector::Graphing::MatrixGraphs.new(chaos_graph, render_folder: @render_folder)
|
54
|
+
graph, appraiser = @chaos_graph.graph_data_for(graph_type: graph_type)
|
55
|
+
matrix = appraiser.adjacency_matrix
|
56
|
+
the_matrix.render_adjacency(matrix, graph_name: graph_name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def render_dep_graph(graph_type, graph: nil, as_cluster: false, domains: false, name: nil, root: true, metrics_table: false)
|
60
|
+
g, _appraiser = chaos_graph.graph_data_for(graph_type: graph_type)
|
61
|
+
rgraph = graph ? graph : g
|
62
|
+
graph_name = name ? name : "#{graph_type}-dep"
|
63
|
+
|
64
|
+
graph_attrs = GRAPH_TYPE_ATTRS[graph_type]
|
65
|
+
|
66
|
+
dgraph = if domains #&& graph_type != :cluster
|
67
|
+
build_domain_dgraph(graph_name, rgraph.nodes, rgraph.edges, graph_attrs: graph_attrs, metrics_table: metrics_table)
|
68
|
+
else
|
69
|
+
build_dgraph(graph_name, rgraph.nodes, rgraph.edges, as_cluster: as_cluster, graph_attrs: graph_attrs, metrics_table: metrics_table)
|
70
|
+
end
|
71
|
+
|
72
|
+
dgraph.rendered_path
|
73
|
+
end
|
74
|
+
|
75
|
+
def render_domain_dep(graph_name: 'domain-dep', domain_graph: nil, metrics_table: false)
|
76
|
+
render_dep_graph(:domain, as_cluster: true, graph: domain_graph, name: graph_name, metrics_table: metrics_table)
|
77
|
+
end
|
78
|
+
|
79
|
+
def render_fn_dep(graph_name: 'fn-dep', function_graph: nil, domains: false, metrics_table: false)
|
80
|
+
render_dep_graph(:function, as_cluster: true, graph: function_graph, domains: domains, name: graph_name, metrics_table: metrics_table)
|
81
|
+
end
|
82
|
+
|
83
|
+
def render_mod_dep(graph_name: 'module-dep', module_graph: nil, domains: false, metrics_table: false)
|
84
|
+
render_dep_graph(:module, graph: module_graph, domains: domains, name: graph_name, metrics_table: metrics_table)
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def build_dgraph(label, nodes, edges, as_cluster: false, render: true, graph_attrs: nil, metrics_table: false)
|
90
|
+
# nodes.each do |n|
|
91
|
+
# p("#{label} Nodes: #{ChaosUtils.decorate(n.title)}")
|
92
|
+
# end
|
93
|
+
|
94
|
+
# edges.each do |e|
|
95
|
+
# p("#{label} Edges: #{ChaosUtils.decorate(e.src_node.title)} -> #{ChaosUtils.decorate(e.dep_node.title)}")
|
96
|
+
# end
|
97
|
+
puts("Building #{label} with as_cluster: #{as_cluster}")
|
98
|
+
dgraph = ChaosDetector::Graphing::DirectedGraphs.new(render_folder: @render_folder)
|
99
|
+
dgraph.create_directed_graph(label, graph_attrs: graph_attrs)
|
100
|
+
dgraph.append_nodes(nodes, as_cluster: as_cluster, metrics_table: metrics_table)
|
101
|
+
dgraph.add_edges(edges)
|
102
|
+
dgraph.render_graph if render
|
103
|
+
dgraph
|
104
|
+
end
|
105
|
+
|
106
|
+
def build_domain_dgraph(graph_name, nodes, edges, render: true, graph_attrs: nil, metrics_table: false)
|
107
|
+
# Add domains as cluster/subgraph nodes:
|
108
|
+
domain_nodes = nodes.map{|node| chaos_graph.domain_node_for(name: node.domain_name) }
|
109
|
+
dgraph = build_dgraph(graph_name, domain_nodes, [], as_cluster: true, render: false, graph_attrs: graph_attrs, metrics_table: metrics_table)
|
110
|
+
|
111
|
+
# Add nodes to domains:
|
112
|
+
dgraph.append_nodes(nodes, metrics_table: false) do |node|
|
113
|
+
chaos_graph.domain_node_for(name: node.domain_name)
|
114
|
+
end
|
115
|
+
dgraph.add_edges(edges)
|
116
|
+
dgraph.render_graph if render
|
117
|
+
dgraph
|
118
|
+
# dgraph.rendered_path
|
119
|
+
|
120
|
+
# fn_nodes = chaos_graph.function_graph.nodes.group_by(&:domain_name)
|
121
|
+
# fn_nodes.map do |dom_nm, fn_nodes|
|
122
|
+
# dom_node = ChaosUtils.aught?(dom_nm) && chaos_graph.domain_node_for(name: dom_nm)
|
123
|
+
# dgraph.add_node_to_parent(fn_node, dom_node)
|
124
|
+
# end
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'ruby-graphviz'
|
3
|
+
require 'rubyvis'
|
4
|
+
|
5
|
+
require 'chaos_detector/utils/str_util'
|
6
|
+
require 'chaos_detector/chaos_utils'
|
7
|
+
|
8
|
+
module ChaosDetector
|
9
|
+
module Graphing
|
10
|
+
class MatrixGraphs
|
11
|
+
CELL_WIDTH = 100
|
12
|
+
NodeStruct = Struct.new(:node_name, :node_value, :group, :index, :link_degree)
|
13
|
+
LinkNodeStruct = Struct.new(:index, :link_degree)
|
14
|
+
LinkStruct = Struct.new(:source, :target, :source_node, :target_node, :value, :link_value, :link_degree)
|
15
|
+
|
16
|
+
def initialize(chaos_graph, render_folder: nil)
|
17
|
+
@chaos_graph = chaos_graph
|
18
|
+
@render_folder = render_folder || 'render'
|
19
|
+
end
|
20
|
+
|
21
|
+
def simple_graph_struct(graph)
|
22
|
+
groupset = graph.nodes.reduce(Set.new()) { |memo, n| memo.add(n.domain_name) }
|
23
|
+
groups = groupset.to_a.sort!
|
24
|
+
|
25
|
+
nodes = graph.nodes.map.with_index do |node, n|
|
26
|
+
group_index = groups.index(node.domain_name)
|
27
|
+
NodeStruct.new(node.title, node.to_k, group_index, n)
|
28
|
+
end
|
29
|
+
|
30
|
+
links = graph.edges.map do |edge|
|
31
|
+
w = edge.weight
|
32
|
+
src = nodes.index(edge.src_node)
|
33
|
+
dep = nodes.index(edge.dep_node)
|
34
|
+
LinkStruct.new(src, dep, LinkNodeStruct.new(0, w), LinkNodeStruct.new(0, w), w, w )
|
35
|
+
end
|
36
|
+
|
37
|
+
[nodes, links]
|
38
|
+
end
|
39
|
+
|
40
|
+
def render_adjacency(matrix, graph_name: 'adj-matrix')
|
41
|
+
|
42
|
+
puts "MATRIX COUNT: #{matrix.row_size} x #{matrix.column_size} = #{matrix.count}"
|
43
|
+
matrix.row_vectors.each{|v| puts v.to_a.inspect}
|
44
|
+
|
45
|
+
# simple_nodes, simple_links = simple_graph_struct(graph)
|
46
|
+
|
47
|
+
w = Math.sqrt(matrix.count) * CELL_WIDTH
|
48
|
+
h = w
|
49
|
+
|
50
|
+
color=Rubyvis::Colors.category19
|
51
|
+
|
52
|
+
vis = Rubyvis::Panel.new() do
|
53
|
+
width w
|
54
|
+
height h
|
55
|
+
top 90
|
56
|
+
left 90
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
# layout_matrix do
|
61
|
+
# nodes simple_nodes
|
62
|
+
# links simple_links
|
63
|
+
# # sort {|a,b| b.group<=>a.group }
|
64
|
+
# directed (true)
|
65
|
+
# link.bar do
|
66
|
+
# fill_style {|l| l.link_value!=0 ?
|
67
|
+
# ((l.target_node.group == l.source_node.group) ? color[l.source_node.group] : "#555") : "#eee"}
|
68
|
+
# antialias(false)
|
69
|
+
# line_width(1)
|
70
|
+
# end
|
71
|
+
# node_label.label do
|
72
|
+
# text_style {|l| color[l.group]}
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
|
76
|
+
# vis
|
77
|
+
# .add(Rubyvis::Layout::Grid)
|
78
|
+
# .rows(matrix.to_a)
|
79
|
+
# .cell
|
80
|
+
# .add(Rubyvis::Bar)
|
81
|
+
# .fill_style(Rubyvis.ramp("white", "black"))
|
82
|
+
# .anchor("center").
|
83
|
+
# .add(Rubyvis::Label)
|
84
|
+
# .text_style(Rubyvis.ramp("black","white"))
|
85
|
+
# .text(lambda{|v| v.is_a?(Numeric) ? ("%0.2f" % v) : v.to_s})
|
86
|
+
|
87
|
+
vis.render();
|
88
|
+
svg = vis.to_svg()
|
89
|
+
|
90
|
+
@rendered_path = File.join(@render_folder, "#{graph_name}.svg").to_s
|
91
|
+
ChaosDetector::Utils::FSUtil.safe_file_write(@rendered_path, content: svg)
|
92
|
+
@rendered_path
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
def log(msg, **opts)
|
97
|
+
ChaosUtils.log_msg(msg, subject: 'MatrixDiagram', **opts)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,237 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require_relative 'options'
|
3
|
+
require_relative 'stacker/mod_info'
|
4
|
+
require_relative 'graph_theory/graph'
|
5
|
+
require_relative 'chaos_graphs/function_node'
|
6
|
+
require_relative 'chaos_graphs/module_node'
|
7
|
+
require_relative 'stacker/frame'
|
8
|
+
require_relative 'walkman'
|
9
|
+
require 'chaos_detector/chaos_utils'
|
10
|
+
|
11
|
+
# The main interface for intercepting tracepoints,
|
12
|
+
# and converting them into recordable and playable
|
13
|
+
# stack/trace frames
|
14
|
+
|
15
|
+
module ChaosDetector
|
16
|
+
class Navigator
|
17
|
+
REGEX_MODULE_UNDECORATE = /#<(Class:)?([a-zA-Z\:]*)(.*)>/.freeze
|
18
|
+
DEFAULT_GROUP = 'default'.freeze
|
19
|
+
FRAME_ACTIONS = [:return].freeze # , :return, :class, :end]
|
20
|
+
|
21
|
+
attr_reader :options
|
22
|
+
attr_reader :domain_hash
|
23
|
+
attr_reader :walkman
|
24
|
+
|
25
|
+
attr_reader :nodes
|
26
|
+
attr_reader :edges
|
27
|
+
|
28
|
+
attr_reader :mod_nodes
|
29
|
+
attr_reader :mod_edges
|
30
|
+
|
31
|
+
def initialize(options:)
|
32
|
+
raise ArgumentError, '#initialize requires options' if options.nil?
|
33
|
+
|
34
|
+
@options = options
|
35
|
+
apply_options
|
36
|
+
end
|
37
|
+
|
38
|
+
### Playback of walkman CSV file:
|
39
|
+
def playback(row_range: nil)
|
40
|
+
log('Chaos playing through navigator. Total lines: ', object: @walkman.count)
|
41
|
+
|
42
|
+
@nodes = Set.new
|
43
|
+
@edges_call = Set.new
|
44
|
+
@edges_ret = Set.new
|
45
|
+
@mod_nodes = Set.new
|
46
|
+
@mod_edges = Set.new
|
47
|
+
@err_nodes = Set.new
|
48
|
+
|
49
|
+
@walkman.playback(row_range: row_range) do |_rownum, frame|
|
50
|
+
perform_node_action(frame)
|
51
|
+
end
|
52
|
+
# log('Found nodes.', object: @nodes.length)
|
53
|
+
|
54
|
+
@walkman.playback(row_range: row_range) do |_rownum, frame|
|
55
|
+
if [:call, :return].include?(frame.event)
|
56
|
+
perform_edge_action(frame)
|
57
|
+
else
|
58
|
+
perform_mod_edge_action(frame)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
edges = merge_edges.to_a
|
63
|
+
# log('Found edges.', object: edges.length)
|
64
|
+
|
65
|
+
@mod_graph = ChaosDetector::GraphTheory::Graph.new(
|
66
|
+
root_node: ChaosDetector::ChaosGraphs::ModuleNode.root_node(force_new: true),
|
67
|
+
nodes: @mod_nodes.to_a,
|
68
|
+
edges: @mod_edges.to_a
|
69
|
+
)
|
70
|
+
|
71
|
+
@fn_graph = ChaosDetector::GraphTheory::Graph.new(
|
72
|
+
root_node: ChaosDetector::ChaosGraphs::FunctionNode.root_node(force_new: true),
|
73
|
+
nodes: @nodes.to_a,
|
74
|
+
edges: edges
|
75
|
+
)
|
76
|
+
|
77
|
+
[@fn_graph, @mod_graph]
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def apply_options
|
83
|
+
@walkman = ChaosDetector::Walkman.new(options: @options)
|
84
|
+
@domain_hash = {}
|
85
|
+
# @options.path_domain_hash && options.path_domain_hash.each do |path, group|
|
86
|
+
# dpath = Pathname.new(path.to_s).cleanpath.to_s
|
87
|
+
# @domain_hash[dpath] = group
|
88
|
+
# end
|
89
|
+
end
|
90
|
+
|
91
|
+
# We merge/reduce edges elsewhere:
|
92
|
+
def merge_edges
|
93
|
+
c = Set.new(@edges_call)
|
94
|
+
r = Set.new(@edges_ret)
|
95
|
+
|
96
|
+
raise 'Call Edges should be Set' unless c.length == @edges_call.length
|
97
|
+
raise 'Ret Edges should be Set' unless r.length == @edges_ret.length
|
98
|
+
|
99
|
+
raise 'Call Edges should be unique' unless @edges_call.uniq.length == @edges_call.length
|
100
|
+
raise 'Call Edges should be unique' unless @edges_ret.uniq.length == @edges_ret.length
|
101
|
+
|
102
|
+
# log('Unique edges in call (n/total)', object: [(c - r).length, c.length])
|
103
|
+
# log('Unique edges in return (n/total)', object: [(r - c).length, r.length])
|
104
|
+
|
105
|
+
# @edges_call.each do |e|
|
106
|
+
# log("edges_call", object: e)
|
107
|
+
# end
|
108
|
+
|
109
|
+
# @edges_ret.each do |e|
|
110
|
+
# log("edges_ret ", object: e)
|
111
|
+
# end
|
112
|
+
|
113
|
+
c.union(r)
|
114
|
+
end
|
115
|
+
|
116
|
+
def fn_node_for(fn_info)
|
117
|
+
return nil unless fn_info&.fn_name
|
118
|
+
|
119
|
+
@nodes.find do |n|
|
120
|
+
n.fn_name == fn_info.fn_name &&
|
121
|
+
n.fn_path == fn_info.fn_path
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def mod_node_for(mod_info)
|
126
|
+
return nil unless mod_info&.mod_name
|
127
|
+
|
128
|
+
@mod_nodes.find do |n|
|
129
|
+
n.mod_name == mod_info.mod_name &&
|
130
|
+
n.mod_path == mod_info.mod_path
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# @return Node matching given frame or create a new one.
|
135
|
+
def fn_node_for_frame(frame)
|
136
|
+
# log("Calling fn_node_for_frame", object: frame)
|
137
|
+
node = fn_node_for(frame.fn_info)
|
138
|
+
|
139
|
+
if node.nil? && frame.event == :call
|
140
|
+
fn_info = frame.fn_info
|
141
|
+
node = ChaosDetector::ChaosGraphs::FunctionNode.new(
|
142
|
+
fn_name: fn_info.fn_name,
|
143
|
+
fn_path: fn_info.fn_path,
|
144
|
+
fn_line: fn_info.fn_line,
|
145
|
+
domain_name: options.domain_from_path(fn_info.fn_path),
|
146
|
+
mod_info: frame.mod_info
|
147
|
+
)
|
148
|
+
@nodes << node
|
149
|
+
end
|
150
|
+
|
151
|
+
node
|
152
|
+
end
|
153
|
+
|
154
|
+
def mod_node_from_info(mod_info)
|
155
|
+
# log("Calling fn_node_for_frame", object: frame)
|
156
|
+
node = mod_node_for(mod_info)
|
157
|
+
|
158
|
+
if node.nil? #&& frame.event == :call
|
159
|
+
node = ChaosDetector::ChaosGraphs::ModuleNode.new(
|
160
|
+
mod_name: mod_info.mod_name,
|
161
|
+
mod_path: mod_info.mod_path,
|
162
|
+
mod_type: mod_info.mod_type,
|
163
|
+
domain_name: options.domain_from_path(mod_info.mod_path)
|
164
|
+
)
|
165
|
+
|
166
|
+
@mod_nodes << node
|
167
|
+
end
|
168
|
+
|
169
|
+
node
|
170
|
+
end
|
171
|
+
|
172
|
+
def edge_for_nodes(src_node, dep_node, edges:, edge_type: :dependent)
|
173
|
+
edge = edges.find do |e|
|
174
|
+
e.src_node == src_node && e.dep_node == dep_node
|
175
|
+
end
|
176
|
+
if edge.nil?
|
177
|
+
edge = ChaosDetector::GraphTheory::Edge.new(src_node, dep_node, edge_type: edge_type)
|
178
|
+
edges << edge
|
179
|
+
end
|
180
|
+
edge
|
181
|
+
end
|
182
|
+
|
183
|
+
def perform_node_action(frame)
|
184
|
+
return unless [:call, :return].include?(frame.event)
|
185
|
+
node = fn_node_for_frame(frame)
|
186
|
+
|
187
|
+
ChaosUtils.with(node && frame.event == :return && frame.fn_info.fn_line) do |fn_line|
|
188
|
+
if !node.fn_line_end.nil? && node.fn_line_end != fn_line
|
189
|
+
end
|
190
|
+
node.fn_line_end = [fn_line, node.fn_line_end.to_i].max
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
|
195
|
+
def perform_edge_action(frame)
|
196
|
+
return unless frame.fn_info && frame.event==:call #&& frame.caller_info
|
197
|
+
|
198
|
+
dest_node = fn_node_for(frame.fn_info)
|
199
|
+
if dest_node.nil?
|
200
|
+
# unless @err_nodes.include?(dest_node)
|
201
|
+
# log "Couldn't find destination node (of #{@nodes.length} / #{@edges_call.length}) on #{frame}"
|
202
|
+
# @err_nodes << dest_node
|
203
|
+
# end
|
204
|
+
return
|
205
|
+
end
|
206
|
+
|
207
|
+
caller_node = fn_node_for(frame.caller_info)
|
208
|
+
if caller_node.nil?
|
209
|
+
caller_node = ChaosDetector::ChaosGraphs::FunctionNode.root_node
|
210
|
+
raise 'Caller node is required (falls back to root).' if caller_node.nil?
|
211
|
+
|
212
|
+
# log("Adding edge to root!")
|
213
|
+
@nodes << caller_node
|
214
|
+
end
|
215
|
+
|
216
|
+
edges = frame.event == :return ? @edges_ret : @edges_call
|
217
|
+
edge_for_nodes(caller_node, dest_node, edges: edges)
|
218
|
+
end
|
219
|
+
|
220
|
+
def perform_mod_edge_action(frame)
|
221
|
+
return unless frame.mod_info && frame.caller_info
|
222
|
+
|
223
|
+
caller_node = mod_node_from_info(frame.caller_info)
|
224
|
+
dest_node = mod_node_from_info(frame.mod_info)
|
225
|
+
edge_for_nodes(dest_node, caller_node, edges: @mod_edges, edge_type: frame.event)
|
226
|
+
end
|
227
|
+
|
228
|
+
def domain_from_path(local_path:)
|
229
|
+
key = domain_hash.keys.find { |k| local_path.start_with?(k) }
|
230
|
+
key ? domain_hash[key] : ChaosDetector::GraphTheory::Node::ROOT_NODE_NAME
|
231
|
+
end
|
232
|
+
|
233
|
+
def log(msg, **opts)
|
234
|
+
ChaosUtils.log_msg(msg, subject: 'Navigator', **opts)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|