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(TextStats *server, std::ostream *outStream, bool show_raw_data ) : PStatMonitor(server) {
_outStream = outStream; //[PECI]
_show_raw_data = show_raw_data;
TextMonitor(TextStats *server, std::ostream *outStream, bool show_raw_data, bool json) : PStatMonitor(server) {
_outStream = outStream; //[PECI]
_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";
}
/**
* 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
* 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);
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()) {
const PStatClientData *client_data = get_client_data();
if (true) {
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 "
<< client_data->get_thread_name(thread_index)
<< " frame " << frame_number << ", "
@ -149,6 +191,7 @@ new_data(int thread_index, int frame_number) {
void TextMonitor::
lost_connection() {
nout << "Lost connection.\n";
++_dummy_pid;
}
/**

View File

@ -29,7 +29,7 @@ class TextStats;
*/
class TextMonitor : public PStatMonitor {
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();
virtual std::string get_monitor_name();
@ -37,6 +37,7 @@ public:
virtual void got_hello();
virtual void got_bad_version(int client_major, int client_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 lost_connection();
virtual bool is_thread_safe();
@ -47,6 +48,8 @@ public:
private:
std::ostream *_outStream; //[PECI]
bool _show_raw_data;
bool _json;
int _dummy_pid = 0;
};
#include "textMonitor.I"

View File

@ -50,6 +50,11 @@ TextStats() {
"time per collector.",
&TextStats::dispatch_none, &_show_raw_data, nullptr);
add_option
("j", "", 0,
"Output data in JSON format.",
&TextStats::dispatch_none, &_json, nullptr);
add_option
("o", "filename", 0,
"Filename where to print. If not given then stderr is being used.",
@ -66,7 +71,7 @@ TextStats() {
PStatMonitor *TextStats::
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";
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 {
_outFile = &(nout);
}
if (_json) {
(*_outFile) << "[\n";
}
main_loop(&user_interrupted);
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:
int _port;
bool _show_raw_data;
bool _json = false;
// [PECI]
bool _got_outputFileName;