lib/roku_builder/plugins/profiler.rb in roku_builder-4.1.0 vs lib/roku_builder/plugins/profiler.rb in roku_builder-4.2.0
- old
+ new
@@ -5,35 +5,98 @@
# Scene Graph Profiler
class Profiler < Util
extend Plugin
def self.commands
- {profile: {device: true}}
+ {
+ profile: {device: true},
+ sgperf: {device: true},
+ devlog: {device: true}
+ }
end
def self.parse_options(parser:, options:)
parser.separator "Commands:"
parser.on("--profile COMMAND", "Run various profiler options") do |c|
options[:profile] = c
end
+ parser.on("--sgperf", "Run scenegraph profiler") do
+ options[:sgperf] = true
+ end
+ parser.on("--devlog FUNCTION [TYPE]", "Run scenegraph profiler") do |f, t|
+ options[:devlog] = t || "rendezvous"
+ options[:devlog_function] = f
+ end
end
# Run the profiler commands
# @param command [Symbol] The profiler command to run
def profile(options:)
+ @connection = nil
case options[:profile].to_sym
when :stats
print_stats
when :all
print_all_nodes
+ when :roots
+ print_root_nodes
when :images
print_image_information
+ when :memmory
+ print_memmory_usage
when :textures
print_texture_information
+ else
+ print_nodes_by_id(options[:profile])
end
+ @connection.close if @connection
end
+ def sgperf(options:)
+ telnet_config ={
+ 'Host' => @roku_ip_address,
+ 'Port' => 8080
+ }
+ @connection = Net::Telnet.new(telnet_config)
+ @connection.puts("sgperf clear\n")
+ @connection.puts("sgperf start\n")
+ start_reg = /thread/
+ end_reg = /#{SecureRandom.uuid}/
+ prev_lines = 0
+ begin
+ while true
+ lines = get_command_response(command: "sgperf report", start_reg: start_reg,
+ end_reg: end_reg, ignore_warnings: true)
+ results = []
+ lines.each do |line|
+ match = /thread node calls: create\s*(\d*) \+ op\s*(\d*)\s*@\s*(\d*\.\d*)% rendezvous/.match(line)
+ results.push([match[1].to_i, match[2].to_i, match[3].to_f])
+ end
+ print "\r" + ("\e[A\e[K"*prev_lines)
+ prev_lines = 0
+ results.each_index do |i|
+ line = results[i]
+ if line[0] > 0 or line[1] > 0 or options[:verbose]
+ prev_lines += 1
+ puts "Thread #{i}: c:#{line[0]} u:#{line[1]} r:#{line[2]}%"
+ end
+ end
+ end
+ rescue SystemExit, Interrupt
+ @connection.close if @connection
+ end
+ end
+
+ def devlog(options:)
+ telnet_config ={
+ 'Host' => @roku_ip_address,
+ 'Port' => 8080
+ }
+ connection = Net::Telnet.new(telnet_config)
+ connection.puts("enhanced_dev_log #{options[:devlog]} #{options[:devlog_function]}\n")
+ end
+
private
# Print the node stats
def print_stats
end_reg = /<\/All_Nodes>/
@@ -65,49 +128,77 @@
start_reg = /<All_Nodes>/
end_reg = /<\/All_Nodes>/
lines = get_command_response(command: "sgnodes all", start_reg: start_reg, end_reg: end_reg)
lines.each {|line| print line}
end
+ def print_root_nodes
+ start_reg = /<Root_Nodes>/
+ end_reg = /<\/Root_Nodes>/
+ lines = get_command_response(command: "sgnodes roots", start_reg: start_reg, end_reg: end_reg)
+ lines.each {|line| print line}
+ end
+ def print_nodes_by_id(id)
+ start_reg = /<#{id}>/
+ end_reg = /<\/#{id}>/
+ lines = get_command_response(command: "sgnodes #{id}", start_reg: start_reg, end_reg: end_reg)
+ lines.each {|line| print line}
+ end
def print_image_information
start_reg = /RoGraphics instance/
end_reg = /Available memory/
lines = get_command_response(command: "r2d2_bitmaps", start_reg: start_reg, end_reg: end_reg)
+ lines = sort_image_lines(lines)
lines.each {|line| print line}
end
+ def print_memmory_usage
+ start_reg = /RoGraphics instance/
+ end_reg = /Available memory/
+ begin
+ while true
+ lines = get_command_response(command: "r2d2_bitmaps", start_reg: start_reg, end_reg: end_reg, ignore_warnings: true)
+ memmory_data = get_memmory_data(lines)
+ print_memmory_data(memmory_data)
+ sleep 1
+ end
+ rescue SystemExit, Interrupt
+ #Exit
+ end
+ end
def print_texture_information
start_reg = /\*+/
end_reg = /#{SecureRandom.uuid}/
lines = get_command_response(command: "loaded_textures", start_reg: start_reg, end_reg: end_reg)
lines.each {|line| print line}
end
# Retrive list of all nodes
# @return [Array<String>] Array of lines
- def get_command_response(command:, start_reg:, end_reg:, unique: false)
+ def get_command_response(command:, start_reg:, end_reg:, unique: false, ignore_warnings: false)
waitfor_config = {
'Match' => /.+/,
- 'Timeout' => 5
+ 'Timeout' => 1
}
- telnet_config ={
- 'Host' => @roku_ip_address,
- 'Port' => 8080
- }
+ unless @connection
+ telnet_config ={
+ 'Host' => @roku_ip_address,
+ 'Port' => 8080
+ }
+ @connection = Net::Telnet.new(telnet_config)
+ end
- connection = Net::Telnet.new(telnet_config)
-
@lines = []
@all_txt = ""
@begun = false
@done = false
- connection.puts("#{command}\n")
+ @connection.puts("#{command}\n")
while not @done
begin
- connection.waitfor(waitfor_config) do |txt|
+ @connection.waitfor(waitfor_config) do |txt|
handle_text(txt: txt, start_reg: start_reg, end_reg: end_reg, unique: unique)
end
rescue Net::ReadTimeout
- @logger.warn "Timed out reading profiler information"
+ @logger.warn "Timed out reading profiler information" unless ignore_warnings
@done = true
end
end
@lines
end
@@ -120,17 +211,65 @@
def handle_text(txt:, start_reg:, end_reg:, unique:)
@all_txt += txt
while line = @all_txt.slice!(/^.*\n/) do
if line =~ start_reg
@begun = true
+ @done = false
@lines = [] if unique
end
@lines.push(line) if @begun
if line =~ end_reg
@begun = false
@done = true
end
end
+ end
+
+ def sort_image_lines(lines)
+ new_lines = []
+ line = lines.shift
+ while line != nil
+ reg = /0x[^\s]+\s+\d+\s+\d+\s+\d+\s+\d+/
+ line_data = []
+ while line =~ reg
+ line_data.push({line: line, size: line.split[4].to_i})
+ line = lines.shift
+ end
+ line_data.sort! {|a, b| b[:size] <=> a[:size]}
+ line_data.each {|data| new_lines.push(data[:line])}
+ new_lines.push(line)
+ line = lines.shift
+ end
+ return new_lines
+ end
+
+ def get_memmory_data(lines)
+ data = {}
+ line = lines.shift
+ while line != nil
+ first_match = /RoGraphics instance (0x.*)/.match(line)
+ if first_match
+ while line != nil
+ usage_match = /Available memory (\d*) used (\d*) max (\d*)/.match(line)
+ if usage_match
+ data[first_match[1]] = [usage_match[1].to_i, usage_match[2].to_i, usage_match[3].to_i]
+ break
+ end
+ line = lines.shift
+ end
+ end
+ line = lines.shift
+ end
+ return data
+ end
+
+ def print_memmory_data(data)
+ @prev_lines ||= 0
+ print "\r" + ("\e[A\e[K"*@prev_lines)
+ data.each_key do |key|
+ print "#{key}: #{(data[key][1]*100)/data[key][2]}%\n"
+ end
+ @prev_lines = data.count
end
end
RokuBuilder.register_plugin(Profiler)
end