88module Vernier
99 module Output
1010 # https://profiler.firefox.com/
11- # https://github.com/firefox-devtools/profiler/blob/main/src/types/profile.js
11+ # https://github.com/firefox-devtools/profiler/blob/main/src/types/profile.ts
1212 class Firefox
1313 class Categorizer
14+ RAILS_COMPONENTS = %w[ activesupport activemodel activerecord actionview
15+ actionpack activejob actionmailer actioncable
16+ activestorage actionmailbox actiontext railties ]
17+
18+ AVAILABLE_COLORS = %w[ transparent purple green orange yellow lightblue
19+ blue brown magenta red lightred darkgrey grey ]
20+
21+ ORDERED_CATEGORIES = %w[ Kernel Rails gem Ruby ] # This is in the order of preference
22+
1423 attr_reader :categories
24+
1525 def initialize
1626 @categories = [ ]
1727 @categories_by_name = { }
1828
19- add_category ( name : "Ruby" , color : "grey" ) do |c |
20- rails_components = %w[ activesupport activemodel activerecord
21- actionview actionpack activejob actionmailer actioncable
22- activestorage actionmailbox actiontext railties ]
29+ add_category ( name : "Kernel" , color : "magenta" ) do |c |
2330 c . add_subcategory (
24- name : "Rails " ,
25- matcher : gem_path ( * rails_components )
31+ name : "Kernel " ,
32+ matcher : starts_with ( "<internal" )
2633 )
34+ end
35+
36+ add_category ( name : "gem" , color : "lightblue" ) do |c |
2737 c . add_subcategory (
2838 name : "gem" ,
2939 matcher : starts_with ( *Gem . path )
3040 )
41+ end
42+
43+ add_category ( name : "Rails" , color : "red" ) do |c |
44+ RAILS_COMPONENTS . each do |subcategory |
45+ c . add_subcategory (
46+ name : subcategory ,
47+ matcher : gem_path ( subcategory )
48+ )
49+ end
50+ end
51+
52+ add_category ( name : "Ruby" , color : "purple" ) do |c |
3153 c . add_subcategory (
3254 name : "stdlib" ,
3355 matcher : starts_with ( RbConfig ::CONFIG [ "rubylibdir" ] )
3456 )
3557 end
58+
3659 add_category ( name : "Idle" , color : "transparent" )
3760 add_category ( name : "Stalled" , color : "transparent" )
3861
3962 add_category ( name : "GC" , color : "red" )
63+
4064 add_category ( name : "cfunc" , color : "yellow" , matcher : "<cfunc>" )
4165
4266 add_category ( name : "Thread" , color : "grey" )
@@ -69,7 +93,10 @@ def categorize(path)
6993
7094 class Category
7195 attr_reader :idx , :name , :color , :matcher , :subcategories
96+
7297 def initialize ( idx , name :, color :, matcher : nil )
98+ raise ArgumentError , "invalid color: #{ color } " if color && AVAILABLE_COLORS . none? ( color )
99+
73100 @idx = idx
74101 @name = name
75102 @color = color
@@ -315,19 +342,13 @@ def initialize(ruby_thread_id, profile, categorizer, name:, tid:, samples:, weig
315342 func_implementations [ func_idx ]
316343 end
317344
318- cfunc_category = @categorizer . get_category ( "cfunc" )
319- ruby_category = @categorizer . get_category ( "Ruby" )
320345 func_categories , func_subcategories = [ ] , [ ]
321346 filenames . each do |filename |
322- if filename == "<cfunc>"
323- func_categories << cfunc_category
324- func_subcategories << 0
325- else
326- func_categories << ruby_category
327- subcategory = ruby_category . subcategories . detect { |c | c . matches? ( filename ) } &.idx || 0
328- func_subcategories << subcategory
329- end
347+ category , subcategory = categorize_filename ( filename )
348+ func_categories << category
349+ func_subcategories << subcategory
330350 end
351+
331352 @frame_categories = @stack_table_hash [ :frame_table ] . fetch ( :func ) . map do |func_idx |
332353 func_categories [ func_idx ]
333354 end
@@ -336,6 +357,32 @@ def initialize(ruby_thread_id, profile, categorizer, name:, tid:, samples:, weig
336357 end
337358 end
338359
360+ def categorize_filename ( filename )
361+ return cfunc_category_and_subcategory if filename == "<cfunc>"
362+
363+ category , subcategory = find_category_and_subcategory ( filename , Categorizer ::ORDERED_CATEGORIES )
364+ return category , subcategory if subcategory
365+
366+ ruby_category_and_subcategory
367+ end
368+
369+ def cfunc_category_and_subcategory
370+ [ @categorizer . get_category ( "cfunc" ) , 0 ]
371+ end
372+
373+ def ruby_category_and_subcategory
374+ [ @categorizer . get_category ( "Ruby" ) , 0 ]
375+ end
376+
377+ def find_category_and_subcategory ( filename , categories )
378+ categories . each do |category_name |
379+ category = @categorizer . get_category ( category_name )
380+ subcategory = category . subcategories . detect { |c | c . matches? ( filename ) } &.idx
381+ return category , subcategory if subcategory
382+ end
383+ [ nil , nil ]
384+ end
385+
339386 def filter_filenames ( filenames )
340387 filter = FilenameFilter . new
341388 filenames . map do |filename |
0 commit comments