class Vernier::Output::Firefox
github.com/firefox-devtools/profiler/blob/main/src/types/profile.js<br>https://profiler.firefox.com/
def counter_data
def counter_data profile.hooks.flat_map do |hook| if hook.respond_to?(:firefox_counters) hook.firefox_counters end end.compact end
def data
def data #markers_by_thread = profile.markers.group_by { |marker| marker[0] } threads = profile.threads.map do |ruby_thread_id, thread_info| #markers = markers_by_thread[ruby_thread_id] || [] Thread.new( ruby_thread_id, profile, @categorizer, #markers: markers, **thread_info, ) end { meta: { interval: 1, # FIXME: memory vs wall startTime: profile.started_at / 1_000_000.0, #endTime: (profile.timestamps&.max || 0) / 1_000_000.0, processType: 0, product: "Ruby/Vernier", stackwalk: 1, version: 28, preprocessedProfileVersion: 48, symbolicated: true, markerSchema: marker_schema, sampleUnits: { time: "ms", eventDelay: "ms", threadCPUDelta: "µs" }, # FIXME: memory vs wall categories: @categorizer.categories.map do |category| { name: category.name, color: category.color, subcategories: category.subcategories.map(&:name) } end, sourceCodeIsNotOnSearchfox: true, initialVisibleThreads: threads.each_index.to_a, initialSelectedThreads: Array(threads.find_index(&:is_start)), vernierUserMetadata: profile.meta[:user_metadata], extra: [ label: "User-Supplied Metadata", entries: profile.meta[:user_metadata].map do |k, v| { label: k, format: "string", value: v } end ] }, counters: counter_data, libs: [], threads: threads.map(&:data) } end
def initialize(profile)
def initialize(profile) @profile = profile @categorizer = Categorizer.new end
def marker_schema
def marker_schema hook_additions = profile.hooks.flat_map do |hook| if hook.respond_to?(:firefox_marker_schema) hook.firefox_marker_schema end end.compact [ { name: "THREAD_RUNNING", display: [ "marker-chart" ], data: [ { label: "Description", value: "The thread has acquired the GVL and is executing" } ] }, { name: "THREAD_STALLED", display: [ "marker-chart" ], data: [ { label: "Description", value: "The thread is ready, but stalled waiting for the GVL to be available" } ] }, { name: "THREAD_SUSPENDED", display: [ "marker-chart" ], data: [ { label: "Description", value: "The thread has voluntarily released the GVL (ex. to sleep, for I/O, waiting on a lock)" } ] }, { name: "GC_PAUSE", display: [ "marker-chart", "marker-table", "timeline-overview" ], tooltipLabel: "{marker.name} - {marker.data.state}", data: [ { label: "Description", value: "All threads are paused as GC is performed" }, { key: "state", format: "string" }, { key: "gc_by", format: "string" }, ] }, { name: "FIBER_SWITCH", display: [ "marker-chart", "marker-table", "timeline-overview" ], tooltipLabel: "{marker.name} - {marker.data.fiber_id}", data: [ { label: "Description", value: "Switch running Fiber" }, { key: "fiber_id", format: "integer" }, ] }, *hook_additions ] end
def output(gzip: false)
def output(gzip: false) result = ::JSON.fast_generate(data) if gzip require "zlib" result = Zlib.gzip(result) end result end