GithubHelp home page GithubHelp logo

jhawthorn / vernier Goto Github PK

View Code? Open in Web Editor NEW
745.0 15.0 15.0 369 KB

๐Ÿ“ next generation CRuby profiler

Home Page: https://vernier.prof/

License: MIT License

Ruby 53.45% Shell 0.09% C++ 45.69% C 0.76%
flamegraph memory-profiler profiler ruby cpu-profiler

vernier's Introduction

Vernier

Next-generation Ruby 3.2.1+ sampling profiler. Tracks multiple threads, GVL activity, GC pauses, idle time, and more.

Screenshot 2024-02-29 at 22 47 43

Examples

Livestreamed demo: Pairin' with Aaron (YouTube)

Sidekiq jobs from Mastodon (time, threaded) : https://share.firefox.dev/44jZRf3

Puma web requests from Mastodon (time, threaded) : https://share.firefox.dev/48FOTnF

Rails benchmark - lobste.rs (time) : https://share.firefox.dev/3Ld89id

require "irb" (retained memory) : https://share.firefox.dev/3DhLsFa

Installation

Vernier requires Ruby version 3.2.1 or greater

gem "vernier", "~> 1.0"

Usage

The output can be viewed in the web app at https://vernier.prof or locally using the profile-viewer gem (both are lightly customized versions of the firefox profiler frontend, which profiles are also compatible with).

  • Flame Graph: Shows proportionally how much time is spent within particular stack frames. Frames are grouped together, which means that x-axis / left-to-right order is not meaningful.
  • Stack Chart: Shows the stack at each sample with the x-axis representing time and can be read left-to-right.

Time

Command line

The easiest way to record a program or script is via the CLI

$ vernier run -- ruby -e 'sleep 1'
starting profiler with interval 500
#<Vernier::Result 1.001589 seconds, 1 threads, 2002 samples, 1 unique>
written to /tmp/profile20240328-82441-gkzffc.vernier.json

Block of code

Vernier.profile(out: "time_profile.json") do
  some_slow_method
end

Alternatively you can use the aliases Vernier.run and Vernier.trace.

Start and stop

Vernier.start_profile(out: "time_profile.json")

some_slow_method

# some other file

some_other_slow_method

Vernier.stop_profile

Retained memory

Block of code

Record a flamegraph of all retained allocations from loading irb.

ruby -r vernier -e 'Vernier.trace_retained(out: "irb_profile.json") { require "irb" }'

Retained-memory flamegraphs must be interpreted a little differently than a typical profiling flamegraph. In a retained-memory flamegraph, the x-axis represents a proportion of memory in bytes, not time or samples The topmost boxes on the y-axis represent the retained objects, with their stacktrace below; their width represents the percentage of overall retained memory each object occupies.

Options

Option Description
mode The sampling mode to use. One of :wall, :retained or :custom. Default is :wall.
out The file to write the profile to.
interval The sampling interval in microseconds. Default is 500. Only available in :wall mode.
allocation_sample_rate The allocation sampling interval in number of allocations. Default is 0 (disabled). Only available in :wall mode.
gc Initiate a full and immediate garbage collection cycle before profiling. Default is true. Only available in :retained mode.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/jhawthorn/vernier. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

Resources

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Vernier project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

vernier's People

Contributors

benoittgt avatar bensheldon avatar casperisfine avatar chaelcodes avatar dalehamel avatar davidteren avatar jhawthorn avatar joshuay03 avatar smortex avatar technicalpickles avatar tenderlove avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vernier's Issues

Integrate with rack-mini-profiler

An easy way to get profiling data from a running web server is to have a Rack middleware, which wraps the current request in a profile and returns the profile of the request instead of the original body.

At work we use a custom middleware for this, but for other projects I really like https://github.com/MiniProfiler/rack-mini-profiler

We could propose Vernier support is added to rack-mini-profiler (I don't know if they're open to it), or make our own middleware (would avoid needing to install an extra gem), or both!

README should mention low overhead

Hello, this is more a question than an issue but there is nothing related to the performance overhead added by vernier on a ruby program, did someone made a benchmark or something like that already ?

Vernier.trace_retained: fails on missing keywords

Hi!

First of all, thanks for developing this amazing tool ๐Ÿš€ I am trying to use it, I managed to get Vernier.trace example to work,
but the trace_retained isn't working for me:

 โฏ ruby -r vernier -e 'Vernier.trace_retained(out: "irb_profile.json") { require "irb" }'
/Users/yosi/.rvm/gems/ruby-3.2.2/gems/vernier-0.3.0/lib/vernier/output/firefox.rb:160:in `initialize': missing keywords: :name, :timestamps, :sample_categories, :started_at (ArgumentError)
        from /Users/yosi/.rvm/gems/ruby-3.2.2/gems/vernier-0.3.0/lib/vernier/output/firefox.rb:104:in `new'
        from /Users/yosi/.rvm/gems/ruby-3.2.2/gems/vernier-0.3.0/lib/vernier/output/firefox.rb:104:in `block in data'
        from /Users/yosi/.rvm/gems/ruby-3.2.2/gems/vernier-0.3.0/lib/vernier/output/firefox.rb:102:in `each'
        from /Users/yosi/.rvm/gems/ruby-3.2.2/gems/vernier-0.3.0/lib/vernier/output/firefox.rb:102:in `map'
        from /Users/yosi/.rvm/gems/ruby-3.2.2/gems/vernier-0.3.0/lib/vernier/output/firefox.rb:102:in `data'
        from /Users/yosi/.rvm/gems/ruby-3.2.2/gems/vernier-0.3.0/lib/vernier/output/firefox.rb:92:in `output'
        from /Users/yosi/.rvm/gems/ruby-3.2.2/gems/vernier-0.3.0/lib/vernier/result.rb:24:in `to_gecko'
        from /Users/yosi/.rvm/gems/ruby-3.2.2/gems/vernier-0.3.0/lib/vernier/result.rb:28:in `write'
        from /Users/yosi/.rvm/gems/ruby-3.2.2/gems/vernier-0.3.0/lib/vernier.rb:44:in `trace_retained'
        from -e:1:in `<main>'

~
 โฏ ruby -v
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin22]

Single thread profiling?

Now that Ruby 3.3 supports thread-specific profiling, I would love to see Vernier add support for this so I can show people how to profile a single job in production.

A Sidekiq middleware like this might work:

class JobProfiler
  include Sidekiq::ServerMiddleware

  def call(_worker, job, _queue, &block)
    return yield unless job["profile"]

    jid = job["jid"]
    klass = job["class"]
    Vernier.trace(out: "/tmp/#{klass}-#{jid}.profile.json", mode: :thread, &block)
  end
end
Sidekiq.configure_server do |config|
  config.server_middleware.add JobProfiler
end
$ irb
> SomeJob.set(profile: true).perform_async

You'd just need to add support for mode: :thread or similar.

Epic: Library/framework integrations

One cool feature of Vernier (and the firefox profiler we use as a viewer) is that it supports tracing via "markers", which record events which happened during the profile.

When Aaron and I showcased Vernier, we cheated (slightly) and added some small hooks to trace Rails and Sidekiq. I do something pretty similar in examples/rails.rb.

Vernier.trace(out: "rails.json") do |collector|
  ActiveSupport::Notifications.monotonic_subscribe do |name, start, finish, id, payload|
    collector.add_marker(
      name:,
      start: (start * 1_000_000_000).to_i,
      finish: (finish * 1_000_000_000).to_i,
    )
  end

That's simple enough, it subscribes to every ActiveSupport::Notifications topic and forwards them, but it doesn't provide as much information as it could and it doesn't happen by default.

Let's do this better and automatically detect and instrumenting popular libraries!

Tasks

[bug] Segfaults? Seem to be related to GC (ruby 3.2.0, 3.2.2, 3.3.0-preview2)(vernier 0.3.0)

In trying to set up a vernier backend for https://github.com/Shopify/app_profiler, I noticed that randomly the unit tests will segfault and dump core. Here is the (heavily wip) branch, which was at this revision when producing these issues.

I examined a core (from ruby 3.2.0) and it came back with this:

#0  RB_FL_TEST_RAW (flags=<optimized out>, obj=<optimized out>) at ./include/ruby/internal/special_consts.h:313
#1  RB_FL_ANY_RAW (flags=<optimized out>, obj=<optimized out>) at ./include/ruby/internal/fl_type.h:552
#2  rb_array_const_ptr_transient (a=<optimized out>) at ./include/ruby/internal/core/rarray.h:390
#3  RARRAY_AREF (i=<optimized out>, ary=<optimized out>) at internal/array.h:160
#4  pathobj_path (pathobj=140537640272480) at /usr/local/src/ruby-3.2.0/vm_core.h:332
#5  rb_iseq_path (iseq=0x7fd17c9fa948) at iseq.c:1205
#6  0x00007fd17d6cbb71 in rb_source_location (pline=0x556d3df43e5c) at vm.c:1723
#7  rb_source_location_cstr (pline=pline@entry=0x556d3df43e5c) at vm.c:1734
#8  0x00007fd17d4e1641 in rb_bug_for_fatal_signal (default_sighandler=0x0, sig=sig@entry=11, ctx=ctx@entry=0x556d3df43f80,
    fmt=fmt@entry=0x7fd17d73d591 "Segmentation fault at %p") at error.c:810
#9  0x00007fd17d6397fd in sigsegv (sig=11, info=0x556d3df440b0, ctx=0x556d3df43f80) at signal.c:964
#10 <signal handler called>
#11 0x00007fd17d50445e in rb_during_gc () at gc.c:10997
#12 0x00007fd1776d464e in RawSample::sample (this=0x7fd174f62de0) at vernier.cc:308
#13 LiveSample::sample_current_thread (this=0x7fd174f62de0) at vernier.cc:355
#14 GlobalSignalHandler::signal_handler (sig=<optimized out>, sinfo=<optimized out>, ucontext=<optimized out>) at vernier.cc:1161
#15 <signal handler called>
#16 0x00007fd177adbe59 in OPENSSL_strcasecmp (s1=0x7fd177c6ce91 "8-cfb", s2=0x7fd177c6ce91 "8-cfb") at ../crypto/o_str.c:349
#17 0x00007fd177ad1435 in getrn (lh=lh@entry=0x556d3e942f10, data=0x7fff16844f20, rhash=rhash@entry=0x7fff16844ee0) at ../crypto/lhash/lhash.c:359
#18 0x00007fd177ad1c43 in OPENSSL_LH_delete (lh=0x556d3e942f10, data=<optimized out>) at ../crypto/lhash/lhash.c:169
#19 0x00007fd177af2975 in lh_OBJ_NAME_delete (d=0x7fff16844f20, lh=<optimized out>) at ../crypto/objects/obj_local.h:12
#20 OBJ_NAME_remove (type=<optimized out>, name=0x7fd177c6ce8b "aes-128-cfb") at ../crypto/objects/o_names.c:257
#21 OBJ_NAME_remove (name=0x7fd177c6ce8b "aes-128-cfb", type=<optimized out>) at ../crypto/objects/o_names.c:243
#22 0x00007fd177ad1e4c in doall_util_fn (arg=0x0, func_arg=0x0, func=0x7fd177af29f0 <names_lh_free_doall>, use_arg=0, lh=0x556d3e942f10) at ../crypto/lhash/lhash.c:231
#23 OPENSSL_LH_doall (lh=0x556d3e942f10, func=0x7fd177af29f0 <names_lh_free_doall>) at ../crypto/lhash/lhash.c:239
#24 0x00007fd177af2bb4 in lh_OBJ_NAME_doall (doall=0x7fd177af29f0 <names_lh_free_doall>, lh=0x556d3e942f10) at ../crypto/objects/obj_local.h:12
#25 OBJ_NAME_cleanup (type=2) at ../crypto/objects/o_names.c:379
#26 0x00007fd177ae499a in evp_cleanup_int () at ../crypto/evp/names.c:156
#27 OPENSSL_cleanup () at ../crypto/init.c:432
#28 OPENSSL_cleanup () at ../crypto/init.c:338
#29 0x00007fd17d0de495 in __run_exit_handlers (status=0, listp=0x7fd17d2b2838 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true, run_dtors=run_dtors@entry=true)
    at ./stdlib/exit.c:113
#30 0x00007fd17d0de610 in __GI_exit (status=<optimized out>) at ./stdlib/exit.c:143
#31 0x00007fd17d0c2d97 in __libc_start_call_main (main=main@entry=0x556d3c603120 <main>, argc=argc@entry=8, argv=argv@entry=0x7fff16845158)
    at ../sysdeps/nptl/libc_start_call_main.h:74
#32 0x00007fd17d0c2e40 in __libc_start_main_impl (main=0x556d3c603120 <main>, argc=8, argv=0x7fff16845158, init=<optimized out>, fini=<optimized out>,
    rtld_fini=<optimized out>, stack_end=0x7fff16845148) at ../csu/libc-start.c:392
#33 0x0000556d3c6031d5 in _start ()

Something during GC? This one seems to happen fairly frequently.

I examined another one:

#0  __pthread_kill_implementation (no_tid=0, signo=6, threadid=140569982527040) at ./nptl/pthread_kill.c:44
#1  __pthread_kill_internal (signo=6, threadid=140569982527040) at ./nptl/pthread_kill.c:78
#2  __GI___pthread_kill (threadid=140569982527040, signo=signo@entry=6) at ./nptl/pthread_kill.c:89
#3  0x00007fd909f60476 in __GI_raise (sig=sig@entry=6) at ../sysdeps/posix/raise.c:26
#4  0x00007fd909f467f3 in __GI_abort () at ./stdlib/abort.c:79
#5  0x00007fd90a2c9054 in die () at error.c:776
#6  rb_bug_for_fatal_signal (default_sighandler=0x0, sig=sig@entry=11, ctx=ctx@entry=0x5623abf6e400, fmt=fmt@entry=0x7fd90a5c2591 "Segmentation fault at %p") at error.c:817
#7  0x00007fd90a4be7fd in sigsegv (sig=11, info=0x5623abf6e530, ctx=0x5623abf6e400) at signal.c:964
#8  <signal handler called>
#9  VM_ENV_FLAGS (flag=<optimized out>, ep=<optimized out>) at /usr/local/src/ruby-3.2.0/vm_core.h:1344
#10 VM_FRAME_CFRAME_P (cfp=<optimized out>) at /usr/local/src/ruby-3.2.0/vm_core.h:1341
#11 VM_FRAME_RUBYFRAME_P (cfp=<optimized out>) at /usr/local/src/ruby-3.2.0/vm_core.h:1350
#12 rb_profile_frames (start=0, limit=2048, buff=0x7fd8ffbf6de0, lines=0x7fd8ffbfade0) at vm_backtrace.c:1587
#13 0x00007fd9045546a4 in RawSample::sample (this=0x7fd8ffbf6de0) at vernier.cc:313
#14 LiveSample::sample_current_thread (this=0x7fd8ffbf6de0) at vernier.cc:355
#15 GlobalSignalHandler::signal_handler (sig=<optimized out>, sinfo=<optimized out>, ucontext=<optimized out>) at vernier.cc:1161
#16 <signal handler called>
#17 0x00007fd90a50dd36 in thread_start_func_2 (th=<optimized out>, stack_start=<optimized out>) at thread.c:676
#18 0x00007fd90a50ea64 in thread_start_func_1 (th_ptr=<optimized out>) at /usr/local/src/ruby-3.2.0/thread_pthread.c:1170
#19 0x00007fd909fb2ac3 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#20 0x00007fd90a044a40 in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

This is very peculiar, as it seems to happen within rb_profile_frames, suggesting a ruby bug itself? It is much more rare, however.

I'm not really doing anything fancy, just starting and stopping a collector as per vernier's own test cases.

[BUG] pthread_kill failed when running vernier through Sidekiq

Hello! Really excited to use vernier! I gave it a go yesterday by integrating it into a Sidekiq middleware and unfortunately the Sidekiq process is crashing with the following error in the middle of (some) jobs:

[BUG] pthread_kill failed
ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin23]

-- C level backtrace information -------------------------------------------
/Users/dima/.rvm/rubies/ruby-3.2.2/lib/libruby.3.2.dylib(rb_vm_bugreport+0x9a0) [0x10332f110]
/Users/dima/.rvm/rubies/ruby-3.2.2/lib/libruby.3.2.dylib(rb_bug_without_die+0x15c) [0x1031699e8]
/Users/dima/.rvm/rubies/ruby-3.2.2/lib/libruby.3.2.dylib(rb_bug+0x1c) [0x103446880]
/Users/dima/.rvm/gems/[email protected]/bundler/gems/vernier-0c3f6dd66236/lib/vernier/vernier.bundle(_ZN19GlobalSignalHandler13record_sampleER10LiveSampleP17_opaque_pthread_t+0x64) [0x129e1ef4c]
/Users/dima/.rvm/gems/[email protected]/bundler/gems/vernier-0c3f6dd66236/lib/vernier/vernier.bundle(_ZN13TimeCollector17sample_thread_runEv) [0x129e1ec60]
/Users/dima/.rvm/gems/[email protected]/bundler/gems/vernier-0c3f6dd66236/lib/vernier/vernier.bundle(_ZN13TimeCollector19sample_thread_entryEPv) [0x129e1e578]
/usr/lib/system/libsystem_pthread.dylib(_pthread_start+0x88) [0x189b92034]

I tried generating a backtrace from a core dump, though I'm not sure it's more helpful than the above:

* thread #71
    frame #0: 0x0000000189b5a0dc libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x0000000189b91cc0 libsystem_pthread.dylib`pthread_kill + 288
    frame #2: 0x0000000189a9da40 libsystem_c.dylib`abort + 180
    frame #3: 0x0000000103169ae8 libruby.3.2.dylib`die at error.c:776:5
    frame #4: 0x0000000103446884 libruby.3.2.dylib`rb_bug(fmt=<unavailable>) at error.c:800:5
    frame #5: 0x0000000129e1ef4c vernier.bundle`GlobalSignalHandler::record_sample(this=0x0000000129e2c368, sample=0x00000002cb080f78, pthread_id=0x00000002b1187000) at vernier.cc:1156:17
  * frame #6: 0x0000000129e1ec60 vernier.bundle`TimeCollector::sample_thread_run(this=0x000000029b6ac8d0) at vernier.cc:1239:58
    frame #7: 0x0000000129e1e578 vernier.bundle`TimeCollector::sample_thread_entry(arg=0x000000029b6ac8d0) at vernier.cc:1275:20
    frame #8: 0x0000000189b92034 libsystem_pthread.dylib`_pthread_start + 136

As an aside, with YJIT enabled it crashes even faster, but that's a separate issue probably.

Let me know if I can provide any additional information, will be happy to.

Docs: example profiler output

Would be very helpful for those evaluating using this project if you could just take an example JSON file and throw it into the firefox profile viewer.

Use alternative semaphore on macos

macos is warning that sem_init is deprecated ๐Ÿ™„. It might be worth trying an alternative (which is still valid to use in a async-signal-safe context) dispatch_semaphore_t maybe?

Segfault on Ruby 3.3 with `RUBY_MN_THREADS=1`

Probably not a huge surprise, but vernier segfaults if run with MaNy threads turned on. I've compiled Ruby source locally and the following test.rb can trigger it:

require "net/http"
require "vernier"

uri = "https://www.google.com"

Vernier.trace(out: "../time_profile.json") do
  5.times.map do
    Thread.new { Net::HTTP.get(URI(uri)) }
  end.map(&:join)
end

Without RUBY_MN_THREADS=1, it runs fine. With it, I just get a generic Segmentation fault. Run with gdb-ruby I get:

Thread 4 "test.rb:9" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xffff7219f120 (LWP 29637)]
0x0000aaaaea8f45c4 in thread_profile_frames (ec=0x0, start=0, limit=2048, buff=0xffff929a8850, lines=0xffff929ac850)
    at ../vm_backtrace.c:1591
1591	    const rb_control_frame_t *cfp = ec->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(ec);

Happy to provide more info and steps if there's interest. But I can also understand if there's no interest in supporting such a nascent feature.

vernier.prof compare interface doesn't respect tilde

[feat] :cpu mode for on-CPU collection?

Is it feasible to add a :cpu mode similar to what stackprof supports?

Looking at the code, it appears vernier's approach of simply sleeping between samples would not lend itself to this:

vernier/ext/vernier/vernier.cc

Lines 1253 to 1261 in fe8e509

next_sample_schedule += interval;
if (next_sample_schedule < sample_complete) {
//fprintf(stderr, "fell behind by %ius\n", (sample_complete - next_sample_schedule).microseconds());
next_sample_schedule = sample_complete + interval;
}
TimeStamp sleep_time = next_sample_schedule - sample_complete;
TimeStamp::Sleep(sleep_time);

stackprof makes use of setitimer syscall to have the OS provide this faculty for it, and receives SIGPROF only when the elapsed time actually on the CPU has passed.

Perhaps this is an intentional decision on the part of vernier to avoid needing to deal with signal safety?

Perhaps an alternative approach could be to approximate this by having vernier wake up, check the amount of time on-CPU since last interval, and sleep unless it has met the desired interval threshold? Eg, say we want 10ms intervals on CPU before taking a sample, perhaps we could sleep for 1ms of wall time, accumulate the on-CPU delta, and go back to sleep until the threshold is hit?

Explicit selection of threads in firefox output

The firefox profiler makes a guess at which threads to hide and which to have selected by default. Currently we let it do this.

When profiling is started from a non-main thread it's probably best to pre-select that thread, assuming that the user wanted to profile something in that thread (though there are certainly cases that doesn't make sense, so we may want to adjust that heuristic).

Store options given to collector in the result

Eg:

vernier/ext/vernier/vernier.cc

Lines 1482 to 1503 in dc16edf

static VALUE collector_new(VALUE self, VALUE mode, VALUE options) {
BaseCollector *collector;
if (mode == sym("retained")) {
collector = new RetainedCollector();
} else if (mode == sym("custom")) {
collector = new CustomCollector();
} else if (mode == sym("wall")) {
VALUE intervalv = rb_hash_aref(options, sym("interval"));
TimeStamp interval;
if (NIL_P(intervalv)) {
interval = TimeStamp::from_microseconds(500);
} else {
interval = TimeStamp::from_microseconds(NUM2UINT(intervalv));
}
collector = new TimeCollector(interval);
} else {
rb_raise(rb_eArgError, "invalid mode");
}
VALUE obj = TypedData_Wrap_Struct(self, &rb_collector_type, collector);
rb_funcall(obj, rb_intern("initialize"), 1, mode);
return obj;
}

Can the mode and interval passed to the collector be added to Result (perhaps in Result.meta hash?) so that we can determine after the fact what the parameters were for the profile?

So something like:

collector = Vernier::Collector.new(:wall, interval: 1000)
collector.start
foo
result = collector.stop
assert_equal :wall, result.meta[:mode] 
assert_equal 1000, result.meta[:interval]

Segfault on Thread

Maybe I'm doing smth wrong, but the simplest script with Vernier segfaults for me if I use Thread:

require 'vernier'

Vernier.trace(out: 'profile.json') do
  Thread.new { sleep 1 }.join # works fine without it
end

vernier 0.30
Ruby 3.2.0

[BUG] Segmentation fault at 0x0000000000000020
ruby 3.2.0 (2022-12-25 revision a528908271) [x86_64-linux]

-- Control frame information -----------------------------------------------


-- Machine register context ------------------------------------------------
 RIP: 0x00007f55ec391de9 RBP: 0x0000000000000800 RSP: 0x00007f55dff305e0
 RAX: 0x0000000000000000 RBX: 0x0000000000000000 RCX: 0x00007f55e6acfe00
 RDX: 0x0000000000000000 RDI: 0x00007f55ec66df90 RSI: 0x0000000000000800
  R8: 0x0000000000000000  R9: 0x0000000000000000 R10: 0x0000000000000000
 R11: 0x0000000000000286 R12: 0x0000000000000000 R13: 0xffffffffffffffc0
 R14: 0x00007f55e6acfe00 R15: 0x0000000000000000 EFL: 0x0000000000010203

-- C level backtrace information -------------------------------------------
/home/marek/.rbenv/versions/3.2.0/lib/libruby.so.3.2(rb_print_backtrace+0x11) [0x7f55ec393bd4] vm_dump.c:785
/home/marek/.rbenv/versions/3.2.0/lib/libruby.so.3.2(rb_vm_bugreport) vm_dump.c:1080
/home/marek/.rbenv/versions/3.2.0/lib/libruby.so.3.2(rb_bug_for_fatal_signal+0xf4) [0x7f55ec18da74] error.c:813
/home/marek/.rbenv/versions/3.2.0/lib/libruby.so.3.2(sigsegv+0x4d) [0x7f55ec2e5e7d] signal.c:964
/lib/x86_64-linux-gnu/libpthread.so.0(__restore_rt+0x0) [0x7f55ebe7f420]
/home/marek/.rbenv/versions/3.2.0/lib/libruby.so.3.2(VM_ENV_FLAGS+0x0) [0x7f55ec391de9] vm_backtrace.c:1586
/home/marek/.rbenv/versions/3.2.0/lib/libruby.so.3.2(VM_FRAME_CFRAME_P) vm_core.h:1341
/home/marek/.rbenv/versions/3.2.0/lib/libruby.so.3.2(VM_FRAME_RUBYFRAME_P) vm_core.h:1350
/home/marek/.rbenv/versions/3.2.0/lib/libruby.so.3.2(rb_profile_frames) vm_backtrace.c:1587
/home/marek/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/vernier-0.3.0/lib/vernier/vernier.so(0x7f55e6d03272) [0x7f55e6d03272]
/home/marek/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/vernier-0.3.0/lib/vernier/vernier.so(_ZN19GlobalSignalHandler14signal_handlerEiP9siginfo_tPv) (null):0
/lib/x86_64-linux-gnu/libpthread.so.0(__restore_rt+0x0) [0x7f55ebe7f420]
/home/marek/.rbenv/versions/3.2.0/lib/libruby.so.3.2(thread_start_func_2+0x1f7) [0x7f55ec332be7] thread.c:676
/home/marek/.rbenv/versions/3.2.0/lib/libruby.so.3.2(thread_start_func_1+0xf0) [0x7f55ec3339d0] thread_pthread.c:1170
/lib/x86_64-linux-gnu/libpthread.so.0(start_thread+0xd9) [0x7f55ebe73609]
/lib/x86_64-linux-gnu/libc.so.6(clone+0x43) [0x7f55ebd98133]

Trace Ruby allocations

The firefox profiler viewer can show allocations as well as time spent. Recording both time and allocations should allow for a single profile run to contain all the information users should need from their application ๐Ÿ˜Š.

`Encoding::UndefinedConversionError` when writing to gz

When profiling our app's boot-time, I typically use rails runner true as a gauge. I'm trying to run that with vernier run, but seeing errors:

$ DISABLE_SPRING=1 bundle exec vernier run -- bin/rails runner true
starting profiler with interval 500
/Users/josh.nichols/.rbenv/versions/3.3.1/lib/ruby/gems/3.3.0/gems/vernier-1.0.0/lib/vernier/result.rb:46:in `write': "\x8B" from ASCII-8BIT to UTF-8 (Encoding::UndefinedConversionError)
	from /Users/josh.nichols/.rbenv/versions/3.3.1/lib/ruby/gems/3.3.0/gems/vernier-1.0.0/lib/vernier/result.rb:46:in `write'
	from /Users/josh.nichols/.rbenv/versions/3.3.1/lib/ruby/gems/3.3.0/gems/vernier-1.0.0/lib/vernier/autorun.rb:34:in `stop'
	from /Users/josh.nichols/.rbenv/versions/3.3.1/lib/ruby/gems/3.3.0/gems/vernier-1.0.0/lib/vernier/autorun.rb:45:in `at_exit'
	from /Users/josh.nichols/.rbenv/versions/3.3.1/lib/ruby/gems/3.3.0/gems/vernier-1.0.0/lib/vernier/autorun.rb:66:in `block in <top (required)>'

I also tried DISABLE_SPRING=1 bundle exec vernier run -- bundle exec rails runner true to bundle exec it, with the same error

Details

  • Vernier 1.0.0
  • Ruby 3.3.1

Add custom markers

Hi ๐Ÿ‘‹๐Ÿป
It's it possible to add custom markers in Market Chart?

It looks like it possible use add_marker method, but here's no any example of using it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.