text-stats: Add JSON output mode in chrome://tracing format

This allows the whole trace to be captured and then loaded into chrome://tracing or https://ui.perfetto.dev
This commit is contained in:
rdb 2022-01-30 00:36:37 +01:00
parent f6322d8c93
commit fb7a2d7a13
4 changed files with 72 additions and 10 deletions

View File

@ -22,9 +22,10 @@
* *
*/ */
TextMonitor:: TextMonitor::
TextMonitor(TextStats *server, std::ostream *outStream, bool show_raw_data ) : PStatMonitor(server) { TextMonitor(TextStats *server, std::ostream *outStream, bool show_raw_data, bool json) : PStatMonitor(server) {
_outStream = outStream; //[PECI] _outStream = outStream; //[PECI]
_show_raw_data = show_raw_data; _show_raw_data = show_raw_data;
_json = json;
} }
/** /**
@ -73,6 +74,30 @@ got_bad_version(int client_major, int client_minor,
<< server_major << "." << server_minor << ".\n"; << server_major << "." << server_minor << ".\n";
} }
/**
* Called whenever a new Thread definition is received from the client.
* Generally, the client will send all of its threads over shortly after
* connecting, but there's no guarantee that they will all be received before
* the first frames are received. The monitor should be prepared to accept
* new Thread definitions midstream.
*/
void TextMonitor::
new_thread(int thread_index) {
if (_json) {
const PStatClientData *client_data = get_client_data();
int pid = get_client_pid();
if (pid < 0) {
pid = _dummy_pid;
}
(*_outStream)
<< "{\"name\":\"thread_name\",\"ph\":\"M\",\"pid\":" << pid
<< ",\"tid\":" << thread_index << ",\"args\":{\"name\":\""
<< client_data->get_thread_name(thread_index) << "\"}},\n";
}
}
/** /**
* Called as each frame's data is made available. There is no gurantee the * Called as each frame's data is made available. There is no gurantee the
* frames will arrive in order, or that all of them will arrive at all. The * frames will arrive in order, or that all of them will arrive at all. The
@ -84,12 +109,29 @@ new_data(int thread_index, int frame_number) {
PStatView &view = get_view(thread_index); PStatView &view = get_view(thread_index);
const PStatThreadData *thread_data = view.get_thread_data(); const PStatThreadData *thread_data = view.get_thread_data();
if (frame_number == thread_data->get_latest_frame_number()) { view.set_to_frame(frame_number);
view.set_to_frame(frame_number);
if (view.all_collectors_known()) { if (true) {
const PStatClientData *client_data = get_client_data(); const PStatClientData *client_data = get_client_data();
if (_json) {
int pid = get_client_pid();
if (pid < 0) {
pid = _dummy_pid;
}
const PStatFrameData &frame_data = thread_data->get_frame(frame_number);
int num_events = frame_data.get_num_events();
for (int i = 0; i < num_events; ++i) {
int collector_index = frame_data.get_time_collector(i);
(*_outStream)
<< "{\"name\":\"" << client_data->get_collector_fullname(collector_index)
<< "\",\"ts\":" << (uint64_t)(frame_data.get_time(i) * 1000000)
<< ",\"ph\":\"" << (frame_data.is_start(i) ? 'B' : 'E') << "\""
<< ",\"tid\":" << thread_index << ",\"pid\":" << pid << "},\n";
}
}
else {
(*_outStream) << "\rThread " (*_outStream) << "\rThread "
<< client_data->get_thread_name(thread_index) << client_data->get_thread_name(thread_index)
<< " frame " << frame_number << ", " << " frame " << frame_number << ", "
@ -149,6 +191,7 @@ new_data(int thread_index, int frame_number) {
void TextMonitor:: void TextMonitor::
lost_connection() { lost_connection() {
nout << "Lost connection.\n"; nout << "Lost connection.\n";
++_dummy_pid;
} }
/** /**

View File

@ -29,7 +29,7 @@ class TextStats;
*/ */
class TextMonitor : public PStatMonitor { class TextMonitor : public PStatMonitor {
public: public:
TextMonitor(TextStats *server, std::ostream *outStream, bool show_raw_data); TextMonitor(TextStats *server, std::ostream *outStream, bool show_raw_data, bool json = false);
TextStats *get_server(); TextStats *get_server();
virtual std::string get_monitor_name(); virtual std::string get_monitor_name();
@ -37,6 +37,7 @@ public:
virtual void got_hello(); virtual void got_hello();
virtual void got_bad_version(int client_major, int client_minor, virtual void got_bad_version(int client_major, int client_minor,
int server_major, int server_minor); int server_major, int server_minor);
virtual void new_thread(int thread_index);
virtual void new_data(int thread_index, int frame_number); virtual void new_data(int thread_index, int frame_number);
virtual void lost_connection(); virtual void lost_connection();
virtual bool is_thread_safe(); virtual bool is_thread_safe();
@ -47,6 +48,8 @@ public:
private: private:
std::ostream *_outStream; //[PECI] std::ostream *_outStream; //[PECI]
bool _show_raw_data; bool _show_raw_data;
bool _json;
int _dummy_pid = 0;
}; };
#include "textMonitor.I" #include "textMonitor.I"

View File

@ -50,6 +50,11 @@ TextStats() {
"time per collector.", "time per collector.",
&TextStats::dispatch_none, &_show_raw_data, nullptr); &TextStats::dispatch_none, &_show_raw_data, nullptr);
add_option
("j", "", 0,
"Output data in JSON format.",
&TextStats::dispatch_none, &_json, nullptr);
add_option add_option
("o", "filename", 0, ("o", "filename", 0,
"Filename where to print. If not given then stderr is being used.", "Filename where to print. If not given then stderr is being used.",
@ -66,7 +71,7 @@ TextStats() {
PStatMonitor *TextStats:: PStatMonitor *TextStats::
make_monitor() { make_monitor() {
return new TextMonitor(this, _outFile, _show_raw_data); return new TextMonitor(this, _outFile, _show_raw_data, _json);
} }
@ -87,13 +92,23 @@ run() {
nout << "Listening for connections.\n"; nout << "Listening for connections.\n";
if (_got_outputFileName) { if (_got_outputFileName) {
_outFile = new std::ofstream(_outputFileName.c_str(), std::ios::out); _outFile = new std::ofstream(_outputFileName.c_str(), std::ios::out | std::ios::trunc);
} else { } else {
_outFile = &(nout); _outFile = &(nout);
} }
if (_json) {
(*_outFile) << "[\n";
}
main_loop(&user_interrupted); main_loop(&user_interrupted);
nout << "Exiting.\n"; nout << "Exiting.\n";
if (_json) {
// Remove the last comma.
_outFile->seekp(-3, std::ios::cur);
(*_outFile) << "\n]\n";
}
} }

View File

@ -37,6 +37,7 @@ public:
private: private:
int _port; int _port;
bool _show_raw_data; bool _show_raw_data;
bool _json = false;
// [PECI] // [PECI]
bool _got_outputFileName; bool _got_outputFileName;