vernier 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f552d6fe2d529de743412cbc9975bfbd4ac87b894777a44ce26ef07dddc8e032
4
- data.tar.gz: b9ddcd3e4ce0acb5ac53363e041d1bd9e3a2d4c5bf21b2bbe56c48ed5fef4cdd
3
+ metadata.gz: da42588d9f2409a9d82a79439014490ecd81f00cb74c975267d6568a6e343c46
4
+ data.tar.gz: 921543f2b8cfec4e5803c4a47c8953df1acff567b88ddce2e1a65faad9e7c895
5
5
  SHA512:
6
- metadata.gz: 1b0808ee6ae8e64866e81e7ba8ed4847788421a00517c00e7aacb54c2fdff16287f92eb10132b5802fcb93955c3e4cf1a8fe4cfc97f4a9742a8130341bea75f7
7
- data.tar.gz: 686a7397043be44451cccf9380473cda1e350ee342878ca2428d8bcd6c69aeea36244d15c92e3f998d4b6245c46c37d74ac3aac18ed58c783c288501d0cf7243
6
+ metadata.gz: a674536e944ef26f2db5893821d9d643fc8f651d45b7a72923ae9ab7c01f270431f0e5fadea76e3bb3feeabe30edde203b520310cbbbae6a53f03edb148db570
7
+ data.tar.gz: 1f39e9f04a2fd1c80525a72ce27aca6e8d614dfa9a4ba9f9721beff08f11a41431f6690c6215f0592dcc7923e49e516a4a0ddb812b493820877ceca81b4373ab
@@ -331,7 +331,7 @@ struct RawSample {
331
331
 
332
332
  Frame frame(int i) const {
333
333
  int idx = len - i - 1;
334
- if (idx < 0) throw std::out_of_range("out of range");
334
+ if (idx < 0) throw std::out_of_range("VERNIER BUG: index out of range");
335
335
  const Frame frame = {frames[idx], lines[idx]};
336
336
  return frame;
337
337
  }
@@ -446,7 +446,7 @@ struct FrameList {
446
446
 
447
447
  int stack_index(const RawSample &stack) {
448
448
  if (stack.empty()) {
449
- throw std::runtime_error("empty stack");
449
+ throw std::runtime_error("VERNIER BUG: empty stack");
450
450
  }
451
451
 
452
452
  StackNode *node = &root_stack_node;
@@ -659,8 +659,8 @@ class Marker {
659
659
 
660
660
  class MarkerTable {
661
661
  public:
662
- std::vector<Marker> list;
663
662
  std::mutex mutex;
663
+ std::vector<Marker> list;
664
664
 
665
665
  void record_interval(Marker::Type type, TimeStamp from, TimeStamp to, int stack_index = -1) {
666
666
  const std::lock_guard<std::mutex> lock(mutex);
@@ -780,19 +780,18 @@ class Thread {
780
780
  int stack_on_suspend_idx;
781
781
  SampleTranslator translator;
782
782
 
783
- MarkerTable *markers;
783
+ unique_ptr<MarkerTable> markers;
784
784
 
785
- std::string name;
785
+ std::string name;
786
786
 
787
- // FIXME: don't use pthread at start
787
+ // FIXME: don't use pthread at start
788
788
  Thread(State state, pthread_t pthread_id, VALUE ruby_thread) : pthread_id(pthread_id), ruby_thread(ruby_thread), state(state), stack_on_suspend_idx(-1) {
789
- name = Qnil;
790
789
  ruby_thread_id = rb_obj_id(ruby_thread);
791
- //ruby_thread_id = ULL2NUM(ruby_thread);
790
+ //ruby_thread_id = ULL2NUM(ruby_thread);
792
791
  native_tid = get_native_thread_id();
793
792
  started_at = state_changed_at = TimeStamp::Now();
794
793
  name = "";
795
- markers = new MarkerTable();
794
+ markers = std::make_unique<MarkerTable>();
796
795
 
797
796
  if (state == State::STARTED) {
798
797
  markers->record(Marker::Type::MARKER_GVL_THREAD_STARTED);
@@ -879,15 +878,15 @@ class ThreadTable {
879
878
  public:
880
879
  FrameList &frame_list;
881
880
 
882
- std::vector<Thread> list;
881
+ std::vector<std::unique_ptr<Thread> > list;
883
882
  std::mutex mutex;
884
883
 
885
884
  ThreadTable(FrameList &frame_list) : frame_list(frame_list) {
886
885
  }
887
886
 
888
887
  void mark() {
889
- for (auto &thread : list) {
890
- thread.mark();
888
+ for (const auto &thread : list) {
889
+ thread->mark();
891
890
  }
892
891
  }
893
892
 
@@ -923,7 +922,8 @@ class ThreadTable {
923
922
 
924
923
  //fprintf(stderr, "th %p (tid: %i) from %s to %s\n", (void *)th, native_tid, gvl_event_name(state), gvl_event_name(new_state));
925
924
 
926
- for (auto &thread : list) {
925
+ for (auto &threadptr : list) {
926
+ auto &thread = *threadptr;
927
927
  if (thread_equal(th, thread.ruby_thread)) {
928
928
  if (new_state == Thread::State::SUSPENDED) {
929
929
 
@@ -950,7 +950,7 @@ class ThreadTable {
950
950
  }
951
951
 
952
952
  //fprintf(stderr, "NEW THREAD: th: %p, state: %i\n", th, new_state);
953
- list.emplace_back(new_state, pthread_self(), th);
953
+ list.push_back(std::make_unique<Thread>(new_state, pthread_self(), th));
954
954
  }
955
955
 
956
956
  bool thread_equal(VALUE a, VALUE b) {
@@ -1226,17 +1226,22 @@ class GlobalSignalHandler {
1226
1226
  if (count == 0) clear_signal_handler();
1227
1227
  }
1228
1228
 
1229
- void record_sample(LiveSample &sample, pthread_t pthread_id) {
1229
+ bool record_sample(LiveSample &sample, pthread_t pthread_id) {
1230
1230
  const std::lock_guard<std::mutex> lock(mutex);
1231
1231
 
1232
1232
  assert(pthread_id);
1233
1233
 
1234
1234
  live_sample = &sample;
1235
- if (pthread_kill(pthread_id, SIGPROF)) {
1236
- rb_bug("pthread_kill failed");
1235
+ int rc = pthread_kill(pthread_id, SIGPROF);
1236
+ if (rc) {
1237
+ fprintf(stderr, "VERNIER BUG: pthread_kill of %lu failed (%i)\n", (unsigned long)pthread_id, rc);
1238
+ live_sample = NULL;
1239
+ return false;
1240
+ } else {
1241
+ sample.wait();
1242
+ live_sample = NULL;
1243
+ return true;
1237
1244
  }
1238
- sample.wait();
1239
- live_sample = NULL;
1240
1245
  }
1241
1246
 
1242
1247
  private:
@@ -1307,9 +1312,9 @@ class TimeCollector : public BaseCollector {
1307
1312
  rb_ary_push(list, ary);
1308
1313
  }
1309
1314
  for (auto &thread : threads.list) {
1310
- for (auto& marker: thread.markers->list) {
1315
+ for (auto& marker: thread->markers->list) {
1311
1316
  VALUE ary = marker.to_array();
1312
- RARRAY_ASET(ary, 0, thread.ruby_thread_id);
1317
+ RARRAY_ASET(ary, 0, thread->ruby_thread_id);
1313
1318
  rb_ary_push(list, ary);
1314
1319
  }
1315
1320
  }
@@ -1325,14 +1330,21 @@ class TimeCollector : public BaseCollector {
1325
1330
  TimeStamp sample_start = TimeStamp::Now();
1326
1331
 
1327
1332
  threads.mutex.lock();
1328
- for (auto &thread : threads.list) {
1333
+ for (auto &threadptr : threads.list) {
1334
+ auto &thread = *threadptr;
1335
+
1329
1336
  //if (thread.state == Thread::State::RUNNING) {
1330
1337
  //if (thread.state == Thread::State::RUNNING || (thread.state == Thread::State::SUSPENDED && thread.stack_on_suspend_idx < 0)) {
1331
1338
  if (thread.state == Thread::State::RUNNING) {
1332
1339
  //fprintf(stderr, "sampling %p on tid:%i\n", thread.ruby_thread, thread.native_tid);
1333
- GlobalSignalHandler::get_instance()->record_sample(sample, thread.pthread_id);
1334
-
1335
- if (sample.sample.gc) {
1340
+ bool signal_sent = GlobalSignalHandler::get_instance()->record_sample(sample, thread.pthread_id);
1341
+
1342
+ if (!signal_sent) {
1343
+ // The thread has died. We probably should have caught
1344
+ // that by the GVL instrumentation, but let's try to get
1345
+ // it to a consistent state and stop profiling it.
1346
+ thread.set_state(Thread::State::STOPPED);
1347
+ } else if (sample.sample.gc) {
1336
1348
  // fprintf(stderr, "skipping GC sample\n");
1337
1349
  } else {
1338
1350
  record_sample(sample.sample, sample_start, thread, CATEGORY_NORMAL);
@@ -1465,7 +1477,7 @@ class TimeCollector : public BaseCollector {
1465
1477
  int ret = pthread_create(&sample_thread, NULL, &sample_thread_entry, this);
1466
1478
  if (ret != 0) {
1467
1479
  perror("pthread_create");
1468
- rb_bug("pthread_create");
1480
+ rb_bug("VERNIER: pthread_create failed");
1469
1481
  }
1470
1482
 
1471
1483
  // Set the state of the current Ruby thread to RUNNING, which we know it
@@ -1511,15 +1523,15 @@ class TimeCollector : public BaseCollector {
1511
1523
 
1512
1524
  for (const auto& thread: this->threads.list) {
1513
1525
  VALUE hash = rb_hash_new();
1514
- thread.samples.write_result(hash);
1526
+ thread->samples.write_result(hash);
1515
1527
 
1516
- rb_hash_aset(threads, thread.ruby_thread_id, hash);
1517
- rb_hash_aset(hash, sym("tid"), ULL2NUM(thread.native_tid));
1518
- rb_hash_aset(hash, sym("started_at"), ULL2NUM(thread.started_at.nanoseconds()));
1519
- if (!thread.stopped_at.zero()) {
1520
- rb_hash_aset(hash, sym("stopped_at"), ULL2NUM(thread.stopped_at.nanoseconds()));
1528
+ rb_hash_aset(threads, thread->ruby_thread_id, hash);
1529
+ rb_hash_aset(hash, sym("tid"), ULL2NUM(thread->native_tid));
1530
+ rb_hash_aset(hash, sym("started_at"), ULL2NUM(thread->started_at.nanoseconds()));
1531
+ if (!thread->stopped_at.zero()) {
1532
+ rb_hash_aset(hash, sym("stopped_at"), ULL2NUM(thread->stopped_at.nanoseconds()));
1521
1533
  }
1522
- rb_hash_aset(hash, sym("name"), rb_str_new(thread.name.data(), thread.name.length()));
1534
+ rb_hash_aset(hash, sym("name"), rb_str_new(thread->name.data(), thread->name.length()));
1523
1535
 
1524
1536
  }
1525
1537
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Vernier
4
- VERSION = "0.5.0"
4
+ VERSION = "0.5.1"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vernier
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Hawthorn
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-02-27 00:00:00.000000000 Z
11
+ date: 2024-02-28 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: An experimental profiler
14
14
  email:
@@ -67,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  requirements: []
70
- rubygems_version: 3.4.10
70
+ rubygems_version: 3.5.3
71
71
  signing_key:
72
72
  specification_version: 4
73
73
  summary: An experimental profiler