Skip to content
This repository was archived by the owner on Dec 3, 2019. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/prober.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ static const char usage_str[] =
"Common Options:\n"
#ifdef ENABLE_THREADS
" --threads Enable multi-threading support\n"
" --only=IDENT Only trace a thread identified by IDENT (requires --threads)\n"
" -d, --dump Dump stacks from all threads (implies --threads)\n"
#else
" -d, --dump Dump the current interpreter stack\n"
Expand Down Expand Up @@ -189,6 +190,7 @@ int Prober::ParseOpts(int argc, char **argv) {
{"seconds", required_argument, 0, 's'},
#if ENABLE_THREADS
{"threads", no_argument, 0, 'L'},
{"only", required_argument, 0, 'i'},
#endif
{"no-line-numbers", no_argument, 0, 'n'},
{"output", required_argument, 0, 'o'},
Expand Down Expand Up @@ -238,7 +240,10 @@ int Prober::ParseOpts(int argc, char **argv) {
std::cout << PYFLAME_VERSION_STR << "\n\n" << usage_str;
return 0;
break;
#ifdef ENABLE_THREADS
#if ENABLE_THREADS
case 'i':
thread_id_ = std::stoul(optarg);
break;
case 'L':
enable_threads_ = true;
break;
Expand Down Expand Up @@ -309,6 +314,11 @@ int Prober::ParseOpts(int argc, char **argv) {
std::cerr << "WARNING: Specifying a PID to trace without -p is deprecated; "
"see Pyflame issue #99 for details.\n";
}
if (thread_id_ > 0 && !enable_threads_) {
std::cerr << "Option --only requires --threads.\n";
std::cerr << usage_str;
return 1;
}
interval_ = ToMicroseconds(sample_rate_);
return -1;
}
Expand Down Expand Up @@ -416,7 +426,9 @@ int Prober::ProbeLoop(const PyFrob &frobber, std::ostream *out) {
}

for (const auto &thread : threads) {
call_stacks.push_back({now, thread.frames()});
if (thread_id_ == 0 || thread.id() == thread_id_) {
call_stacks.push_back({now, thread.frames()});
}
}

if (check_end && (now + interval_ >= end)) {
Expand Down
2 changes: 2 additions & 0 deletions src/prober.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Prober {
include_ts_(false),
include_line_number_(true),
enable_threads_(false),
thread_id_(0),
seconds_(1),
sample_rate_(0.01) {}
Prober(const Prober &other) = delete;
Expand All @@ -63,6 +64,7 @@ class Prober {
bool include_ts_;
bool include_line_number_;
bool enable_threads_;
unsigned long thread_id_;
double seconds_;
double sample_rate_;
std::chrono::microseconds interval_;
Expand Down
25 changes: 25 additions & 0 deletions tests/test_end_to_end.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import subprocess
import sys
import time
import threading

IDLE_RE = re.compile(r'^\(idle\) \d+$')
FLAMEGRAPH_RE = re.compile(
Expand Down Expand Up @@ -637,3 +638,27 @@ def test_no_line_numbers(dijkstra):
for line in lines:
assert_flamegraph(
line, allow_idle=True, line_re=FLAMEGRAPH_NONUMBER_RE)


def test_only():
should_stop = False

def infinite_sleeper():
while not should_stop:
time.sleep(0.01)

thread = threading.Thread(target=infinite_sleeper)
thread.daemon = True
thread.start()

proc = subprocess.Popen(
[path_to_pyflame(), '-p',
str(os.getpid()), '--seconds=1',
'--threads', '--only=' + str(thread.ident)],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
out, err = communicate(proc)
assert not err
assert proc.returncode == 0
assert 'test_only' not in out