Browse Source

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

rdb 3 years ago
parent
commit
706c354b02

+ 1 - 1
pandatool/src/gtk-stats/gtkStats.cxx

@@ -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();

+ 77 - 8
pandatool/src/gtk-stats/gtkStatsServer.cxx

@@ -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,10 +55,54 @@ GtkStatsServer() {
 #endif
   _last_session.set_binary();
 
+  create_window();
+}
 
-  _time_units = 0;
+/**
+ * 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;
 
-  create_window();
+      // 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.
  */

+ 8 - 4
pandatool/src/gtk-stats/gtkStatsServer.h

@@ -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

+ 9 - 9
pandatool/src/win-stats/winStats.cxx

@@ -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);
 }

+ 56 - 13
pandatool/src/win-stats/winStatsServer.cxx

@@ -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);

+ 8 - 4
pandatool/src/win-stats/winStatsServer.h

@@ -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;