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 +4 -4
- data/ext/vernier/vernier.cc +45 -33
- data/lib/vernier/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: da42588d9f2409a9d82a79439014490ecd81f00cb74c975267d6568a6e343c46
|
4
|
+
data.tar.gz: 921543f2b8cfec4e5803c4a47c8953df1acff567b88ddce2e1a65faad9e7c895
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a674536e944ef26f2db5893821d9d643fc8f651d45b7a72923ae9ab7c01f270431f0e5fadea76e3bb3feeabe30edde203b520310cbbbae6a53f03edb148db570
|
7
|
+
data.tar.gz: 1f39e9f04a2fd1c80525a72ce27aca6e8d614dfa9a4ba9f9721beff08f11a41431f6690c6215f0592dcc7923e49e516a4a0ddb812b493820877ceca81b4373ab
|
data/ext/vernier/vernier.cc
CHANGED
@@ -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
|
783
|
+
unique_ptr<MarkerTable> markers;
|
784
784
|
|
785
|
-
|
785
|
+
std::string name;
|
786
786
|
|
787
|
-
|
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
|
-
|
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 =
|
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
|
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 &
|
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.
|
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
|
-
|
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
|
-
|
1236
|
-
|
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
|
1315
|
+
for (auto& marker: thread->markers->list) {
|
1311
1316
|
VALUE ary = marker.to_array();
|
1312
|
-
RARRAY_ASET(ary, 0, thread
|
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 &
|
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 (
|
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
|
1526
|
+
thread->samples.write_result(hash);
|
1515
1527
|
|
1516
|
-
rb_hash_aset(threads, thread
|
1517
|
-
rb_hash_aset(hash, sym("tid"), ULL2NUM(thread
|
1518
|
-
rb_hash_aset(hash, sym("started_at"), ULL2NUM(thread
|
1519
|
-
if (!thread
|
1520
|
-
rb_hash_aset(hash, sym("stopped_at"), ULL2NUM(thread
|
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
|
1534
|
+
rb_hash_aset(hash, sym("name"), rb_str_new(thread->name.data(), thread->name.length()));
|
1523
1535
|
|
1524
1536
|
}
|
1525
1537
|
|
data/lib/vernier/version.rb
CHANGED
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.
|
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-
|
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.
|
70
|
+
rubygems_version: 3.5.3
|
71
71
|
signing_key:
|
72
72
|
specification_version: 4
|
73
73
|
summary: An experimental profiler
|