7
7
#include < sys/wait.h>
8
8
#include < libduck/FormatStream.h>
9
9
#include < libduck/Args.h>
10
+ #include < libduck/Socket.h>
10
11
#include < ctime>
11
12
13
+ constexpr int debugd_port = 59336 ;
14
+ constexpr const char * debugd_start = " DEBUGD\n PROFILE\n " ;
15
+
12
16
using namespace Debug ;
13
17
using Duck::OutputStream;
14
18
15
19
int pid;
16
20
int interval = 10 ;
17
21
int duration = 5000 ;
22
+ bool remote = false ;
18
23
std::string filename;
19
24
20
25
struct Thread {
@@ -23,6 +28,43 @@ struct Thread {
23
28
std::vector<std::vector<size_t >> stacks;
24
29
};
25
30
31
+ Duck::Result output_profile (
32
+ Duck::OutputStream& stream,
33
+ std::map<size_t , AddressInfo>& symbols,
34
+ std::vector<Duck::Ptr<Thread>>& threads) {
35
+ for (auto & thread : threads){
36
+ for (auto & stk : thread->stacks ) {
37
+ stream << " thread " << thread->tid << " ;" ;
38
+ for (size_t i = stk.size (); i > 0 ; i--) {
39
+ auto pos = stk[i - 1 ];
40
+ auto info = symbols.find (pos);
41
+ if (info == symbols.end ()) {
42
+ auto info_res = thread->debugger .info_at (pos);
43
+ if (info_res.is_error ())
44
+ symbols[pos] = {" ???" , pos, nullptr };
45
+ else
46
+ symbols[pos] = info_res.value ();
47
+ info = symbols.find (pos);
48
+ }
49
+
50
+ auto & symbol = info->second ;
51
+ if (!symbol.object )
52
+ stream % " ?? @ {#x}" % symbol.symbol_offset ;
53
+ else if (symbol.symbol_name == " __syscall_trap__" )
54
+ stream << " <kernel>" ;
55
+ else
56
+ stream % " {} @ {}" % symbol.symbol_name % symbol.object ->name ;
57
+
58
+ if (i != 1 )
59
+ stream << " ;" ;
60
+ }
61
+ stream << " 1\n " ;
62
+ }
63
+ }
64
+
65
+ return Duck::Result::SUCCESS;
66
+ }
67
+
26
68
Duck::Result profile () {
27
69
auto proc = TRY (Sys::Process::get (pid));
28
70
@@ -58,44 +100,41 @@ Duck::Result profile() {
58
100
Duck::println (" Done! Symbolicating and dumping..." );
59
101
std::map<size_t , AddressInfo> symbols;
60
102
61
- if (filename.empty ())
62
- filename = " profile-" + proc.name () + " -" + std::to_string (std::time (nullptr )) + " .txt" ;
63
- auto out = TRY (Duck::File::open (filename, " w" ));
64
- Duck::FileOutputStream stream {out};
65
-
66
- for (auto & thread : threads) {
67
- for (auto & stk : thread->stacks ) {
68
- stream << " thread " << thread->tid << " ;" ;
69
- for (size_t i = stk.size (); i > 0 ; i--) {
70
- auto pos = stk[i - 1 ];
71
- auto info = symbols.find (pos);
72
- if (info == symbols.end ()) {
73
- auto info_res = thread->debugger .info_at (pos);
74
- if (info_res.is_error ())
75
- symbols[pos] = {" ???" , pos, nullptr };
76
- else
77
- symbols[pos] = info_res.value ();
78
- info = symbols.find (pos);
79
- }
80
-
81
- auto & symbol = info->second ;
82
- if (!symbol.object )
83
- stream % " ?? @ {#x}" % symbol.symbol_offset ;
84
- else if (symbol.symbol_name == " __syscall_trap__" )
85
- stream << " <kernel>" ;
86
- else
87
- stream % " {} @ {}" % symbol.symbol_name % symbol.object ->name ;
88
-
89
- if (i != 1 )
90
- stream << " ;" ;
91
- }
92
- stream << " 1\n " ;
103
+ if (remote) {
104
+ // Collect into StringOutputStream
105
+ Duck::StringOutputStream stream;
106
+ TRYRES (output_profile (stream, symbols, threads));
107
+
108
+ // Connect to socket
109
+ Duck::print (" Connecting to debug daemon... " , debugd_port);
110
+ fflush (stdout);
111
+ auto sock = TRY (Duck::Socket::open (Duck::Socket::Inet, Duck::Socket::Stream, Duck::Socket::TCP));
112
+ TRYRES (sock.connect ({10 , 0 , 2 , 2 }, debugd_port));
113
+
114
+ // Write to socket
115
+ Duck::print (" Sending... " );
116
+ fflush (stdout);
117
+
118
+ TRYRES (sock.send (debugd_start, strlen (debugd_start)));
119
+ for (size_t i = 0 ; i < stream.string ().length () + 1 ; i += 1024 ) {
120
+ auto len = std::min ((size_t ) 1024 , stream.string ().length () + 1 - i);
121
+ TRYRES (sock.send (stream.string ().c_str () + i, len));
93
122
}
123
+
124
+ Duck::println (" Sent!" );
125
+ sock.close ();
126
+ } else {
127
+ // Write to file
128
+ if (filename.empty ())
129
+ filename = " profile-" + proc.name () + " -" + std::to_string (std::time (nullptr )) + " .txt" ;
130
+ auto out = TRY (Duck::File::open (filename, " w" ));
131
+ Duck::FileOutputStream fs {out};
132
+ TRYRES (output_profile (fs, symbols, threads));
133
+ out.close ();
134
+ Duck::println (" Done! Saved to {}." , filename);
94
135
}
95
136
96
- out.close ();
97
137
98
- Duck::println (" Done! Saved to {}." , filename);
99
138
return Duck::Result::SUCCESS;
100
139
}
101
140
@@ -105,6 +144,7 @@ int main(int argc, char** argv) {
105
144
args.add_named (interval, " i" , " interval" , " The interval with which to sample, in ms. (Default: 10)" );
106
145
args.add_named (duration, " d" , " duration" , " The duration to sample for, in ms. (Default: 5000)" );
107
146
args.add_named (filename, " o" , " output" , " The output file." );
147
+ args.add_flag (remote, " r" , " remote" , " Sends the output to a remote debug server." );
108
148
args.parse (argc, argv);
109
149
110
150
auto res = profile ();
0 commit comments