pstats: Support for command-line options (session file, port number)

This commit is contained in:
rdb 2022-12-01 15:05:34 +01:00
parent 7e8dfc58ce
commit 706c354b02
6 changed files with 160 additions and 40 deletions

View File

@ -22,7 +22,7 @@ main(int argc, char *argv[]) {
// Create the server window.
GtkStatsServer *server = new GtkStatsServer;
server->new_session();
server->parse_command_line(argc, argv);
// Now get lost in the message loop.
gtk_main();

View File

@ -17,11 +17,36 @@
#include "pStatGraph.h"
#include "config_pstatclient.h"
#include <unistd.h>
/**
*
*/
GtkStatsServer::
GtkStatsServer() {
GtkStatsServer() : _port(pstats_port) {
set_program_brief("GTK+3-based PStats client");
set_program_description
("This is a GUI-based PStats server that listens on a TCP port for a "
"connection from a PStatClient in a Panda3D application. It offers "
"various graphs for showing the timing information sent by the client."
"\n\n"
"The full documentation is available online:\n "
#ifdef HAVE_PYTHON
"https://docs.panda3d.org/" PANDA_ABI_VERSION_STR "/python/optimization/pstats"
#else
"https://docs.panda3d.org/" PANDA_ABI_VERSION_STR "/cpp/optimization/pstats"
#endif
"");
add_option
("p", "port", 0,
"Specify the TCP port to listen for connections on. By default, this "
"is taken from the pstats-port Config variable.",
&ProgramBase::dispatch_int, nullptr, &_port);
add_runline("[-p 5185]");
add_runline("session.pstats");
#ifdef __APPLE__
_last_session = Filename::expand_from(
"$HOME/Library/Caches/Panda3D-" PANDA_ABI_VERSION_STR "/last-session.pstats");
@ -30,12 +55,56 @@ GtkStatsServer() {
#endif
_last_session.set_binary();
_time_units = 0;
create_window();
}
/**
* Does something with the additional arguments on the command line (after all
* the -options have been parsed). Returns true if the arguments are good,
* false otherwise.
*/
bool GtkStatsServer::
handle_args(ProgramBase::Args &args) {
if (args.empty()) {
new_session();
return true;
}
else if (args.size() == 1) {
Filename fn = Filename::from_os_specific(args[0]);
fn.set_binary();
GtkStatsMonitor *monitor = new GtkStatsMonitor(this);
if (!monitor->read(fn)) {
delete monitor;
// If we're not running from the terminal, show a GUI message box.
if (!isatty(STDERR_FILENO)) {
GtkWidget *dialog =
gtk_message_dialog_new(GTK_WINDOW(_window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Failed to load session file: %s", fn.c_str());
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
}
return false;
}
_save_filename = fn;
gtk_widget_set_sensitive(_new_session_menu_item, TRUE);
gtk_widget_set_sensitive(_save_session_menu_item, TRUE);
gtk_widget_set_sensitive(_close_session_menu_item, TRUE);
gtk_widget_set_sensitive(_export_session_menu_item, TRUE);
_monitor = monitor;
return true;
}
else {
nout << "At most one filename may be specified on the command-line.\n";
return false;
}
}
/**
*
*/
@ -97,16 +166,16 @@ new_session() {
return false;
}
if (listen()) {
if (listen(_port)) {
{
std::ostringstream strm;
strm << "PStats Server (listening on port " << pstats_port << ")";
strm << "PStats Server (listening on port " << _port << ")";
std::string title = strm.str();
gtk_window_set_title(GTK_WINDOW(_window), title.c_str());
}
{
std::ostringstream strm;
strm << "Waiting for client to connect on port " << pstats_port << "...";
strm << "Waiting for client to connect on port " << _port << "...";
std::string title = strm.str();
_status_bar_label = gtk_label_new(title.c_str());
gtk_container_add(GTK_CONTAINER(_status_bar), _status_bar_label);
@ -129,7 +198,8 @@ new_session() {
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Unable to open port %d. Try specifying a different port number "
"using pstats-port in your Config file.", pstats_port.get_value());
"using pstats-port in your Config file or the -p option on the "
"command-line.", _port);
gtk_dialog_run(GTK_DIALOG(dialog));
gtk_widget_destroy(dialog);
@ -405,7 +475,6 @@ close_session() {
return true;
}
/**
* Returns the window handle to the server's window.
*/

View File

@ -15,18 +15,21 @@
#define GTKSTATSSERVER_H
#include "pandatoolbase.h"
#include "programBase.h"
#include "pStatServer.h"
#include "gtkStatsMonitor.h"
/**
* The class that owns the main loop, waiting for client connections.
*/
class GtkStatsServer : public PStatServer {
class GtkStatsServer : public PStatServer, public ProgramBase {
public:
GtkStatsServer();
virtual PStatMonitor *make_monitor(const NetAddress &address);
virtual void lost_connection(PStatMonitor *monitor);
virtual bool handle_args(Args &args) override;
virtual PStatMonitor *make_monitor(const NetAddress &address) override;
virtual void lost_connection(PStatMonitor *monitor) override;
bool new_session();
bool open_session();
@ -58,6 +61,7 @@ private:
Filename _last_session;
Filename _save_filename;
int _port = -1;
GtkWidget *_window = nullptr;
GtkAccelGroup *_accel_group = nullptr;
GtkWidget *_menu_bar = nullptr;
@ -70,7 +74,7 @@ private:
GtkWidget *_save_session_menu_item;
GtkWidget *_close_session_menu_item;
GtkWidget *_export_session_menu_item;
int _time_units;
int _time_units = 0;
};
#endif

View File

@ -26,7 +26,7 @@
// Enable common controls version 6, necessary for modern visual styles
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
int main(int argc, char *argv[]) {
// Initialize commctl32.dll.
INITCOMMONCONTROLSEX icc;
icc.dwICC = ICC_WIN95_CLASSES | ICC_STANDARD_CLASSES;
@ -38,7 +38,11 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
// Create the server window.
WinStatsServer *server = new WinStatsServer;
server->new_session();
if (server->parse_command_line(argc, argv, false) == ProgramBase::EC_failure) {
MessageBox(nullptr, "Failed to parse command-line options.",
"PStats Error", MB_OK | MB_ICONEXCLAMATION);
return 1;
}
// Now get lost in the Windows message loop.
MSG msg;
@ -54,13 +58,9 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
retval = GetMessage(&msg, nullptr, 0, 0);
}
return (0);
return 0;
}
// WinMain() is the correct way to start a Windows-only application, but it is
// sometimes more convenient during development to use main() instead, which
// doesn't squelch the stderr output.
int main(int argc, char *argv[]) {
return WinMain(nullptr, nullptr, nullptr, 0);
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
return main(__argc, __argv);
}

View File

@ -28,17 +28,14 @@ const char *const WinStatsServer::_window_class_name = "server";
*
*/
WinStatsServer::
WinStatsServer() {
WinStatsServer() : _port(pstats_port) {
set_program_brief("Windows PStats client");
add_option("p", "port", 0, "", &ProgramBase::dispatch_int, nullptr, &_port);
_last_session = Filename::expand_from(
"$USER_APPDATA/Panda3D-" PANDA_ABI_VERSION_STR "/last-session.pstats");
_last_session.set_binary();
_window = 0;
_menu_bar = 0;
_options_menu = 0;
_time_units = 0;
// Create the fonts used for rendering the UI.
NONCLIENTMETRICS metrics = {0};
metrics.cbSize = sizeof(NONCLIENTMETRICS);
@ -51,6 +48,52 @@ WinStatsServer() {
create_window();
}
/**
* Does something with the additional arguments on the command line (after all
* the -options have been parsed). Returns true if the arguments are good,
* false otherwise.
*/
bool WinStatsServer::
handle_args(ProgramBase::Args &args) {
if (args.empty()) {
new_session();
return true;
}
else if (args.size() == 1) {
Filename fn = Filename::from_os_specific(args[0]);
fn.set_binary();
WinStatsMonitor *monitor = new WinStatsMonitor(this);
if (!monitor->read(fn)) {
delete monitor;
std::ostringstream stream;
stream << "Failed to load session file: " << fn;
std::string str = stream.str();
MessageBox(_window, str.c_str(), "PStats Error",
MB_OK | MB_ICONEXCLAMATION);
return true;
}
// Enable the "New Session", "Save Session" and "Close Session" menu items.
MENUITEMINFO mii;
memset(&mii, 0, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STATE;
mii.fState = MFS_ENABLED;
SetMenuItemInfoA(_session_menu, MI_session_new, FALSE, &mii);
SetMenuItemInfoA(_session_menu, MI_session_save, FALSE, &mii);
SetMenuItemInfoA(_session_menu, MI_session_close, FALSE, &mii);
SetMenuItemInfoA(_session_menu, MI_session_export_json, FALSE, &mii);
_monitor = monitor;
return true;
}
else {
nout << "At most one filename may be specified on the command-line.\n";
return false;
}
}
/**
*
*/
@ -112,16 +155,16 @@ new_session() {
return false;
}
if (listen()) {
if (listen(_port)) {
{
std::ostringstream strm;
strm << "PStats Server (listening on port " << pstats_port << ")";
strm << "PStats Server (listening on port " << _port << ")";
std::string title = strm.str();
SetWindowTextA(_window, title.c_str());
}
{
std::ostringstream strm;
strm << "Waiting for client to connect on port " << pstats_port << "...";
strm << "Waiting for client to connect on port " << _port << "...";
std::string title = strm.str();
int part = -1;
SendMessage(_status_bar, SB_SETPARTS, 1, (LPARAM)&part);
@ -155,9 +198,9 @@ new_session() {
std::ostringstream stream;
stream
<< "Unable to open port " << pstats_port
<< ". Try specifying a different\n"
<< "port number using pstats-port in your Config file.";
<< "Unable to open port " << _port << ". Try specifying a different "
<< "port number using pstats-port in your Config file or the -p option on "
<< "the command-line.";
std::string str = stream.str();
MessageBox(_window, str.c_str(), "PStats Error",
MB_OK | MB_ICONEXCLAMATION);

View File

@ -15,18 +15,21 @@
#define WINSTATSSERVER_H
#include "pandatoolbase.h"
#include "programBase.h"
#include "pStatServer.h"
#include "winStatsMonitor.h"
/**
* The class that owns the main loop, waiting for client connections.
*/
class WinStatsServer : public PStatServer {
class WinStatsServer : public PStatServer, public ProgramBase {
public:
WinStatsServer();
virtual PStatMonitor *make_monitor(const NetAddress &address);
virtual void lost_connection(PStatMonitor *monitor);
virtual bool handle_args(Args &args) override;
virtual PStatMonitor *make_monitor(const NetAddress &address) override;
virtual void lost_connection(PStatMonitor *monitor) override;
bool new_session();
bool open_session();
@ -60,13 +63,14 @@ private:
Filename _last_session;
int _port = -1;
HWND _window = 0;
HMENU _menu_bar = 0;
HMENU _session_menu = 0;
HMENU _options_menu = 0;
HWND _status_bar;
POINT _client_origin;
int _time_units;
int _time_units = 0;
int _pixel_scale;
HFONT _font;