vernier 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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