diff options
author | Gerald Combs <gerald@wireshark.org> | 2017-11-14 15:58:32 -0800 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2017-11-16 06:11:55 +0000 |
commit | ac1d52aff5bdf74600ddc2f8f06ceccf9d2037a6 (patch) | |
tree | f36410bffc6f0a13a2562e5b2b9d548636c67ecf | |
parent | 665eb78729c91b4056b3e58af4407f51df603f55 (diff) |
Register protocols and handoffs in separate threads.
Instead of interleaving protocol registrations and status callbacks in
the main thread, move protocol registrations to a worker thread. Do the
same with protocol handoffs. This *should* be safe since the status
callbacks only update the UI.
This reduces startup time by about 200ms on my laptop:
Run OS Thread? Time
1 macOS N 340 ms
2 macOS N 260 ms
3 macOS N 252 ms
4 macOS Y 147 ms
5 macOS Y 146 ms
6 macOS Y 142 ms
7 Win 7 N 80 samples
8 Win 7 N 56 samples
9 Win 7 N 75 samples
10 Win 7 Y 31 samples
11 Win 7 Y 2 samples
12 Win 7 Y 0 samples
macOS was sampled using Instruments. Windows 7 was sampled using the
Visual Studio 2015 profiler.
We should do the same thing with our capture and tap event loops, but
that will likely require quite a bit more work.
Change-Id: Iac9a81d8f71668f5979b524744a03f6d80aee893
Reviewed-on: https://code.wireshark.org/review/24447
Reviewed-by: Gerald Combs <gerald@wireshark.org>
Petri-Dish: Gerald Combs <gerald@wireshark.org>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r-- | register.h | 32 | ||||
-rwxr-xr-x | tools/make-dissector-reg.py | 88 | ||||
-rw-r--r-- | ui/qt/splash_overlay.cpp | 28 |
3 files changed, 116 insertions, 32 deletions
diff --git a/register.h b/register.h index deaa9cf3ed..6ace1e49d8 100644 --- a/register.h +++ b/register.h @@ -24,19 +24,43 @@ typedef enum { RA_DISSECTORS, /* Initializing dissectors */ RA_LISTENERS, /* Tap listeners */ RA_EXTCAP, /* extcap register preferences */ - RA_REGISTER, /* Built-in register */ - RA_PLUGIN_REGISTER, /* Plugin register */ - RA_HANDOFF, /* Built-in handoff */ - RA_PLUGIN_HANDOFF, /* Plugin handoff */ + RA_REGISTER, /* Built-in dissector registration */ + RA_PLUGIN_REGISTER, /* Plugin dissector registration */ + RA_HANDOFF, /* Built-in dissector handoff */ + RA_PLUGIN_HANDOFF, /* Plugin dissector handoff */ RA_LUA_PLUGINS, /* Lua plugin register */ RA_LUA_DEREGISTER, /* Lua plugin deregister */ RA_PREFERENCES, /* Module preferences */ RA_INTERFACES /* Local interfaces */ } register_action_e; +#define RA_BASE_COUNT (RA_INTERFACES - 3) // RA_EXTCAP, RA_LUA_PLUGINS, RA_LUA_DEREGISTER + typedef void (*register_cb)(register_action_e action, const char *message, gpointer client_data); +/** Call each dissector's protocol registration routine. + * + * Each routine is called in alphabetical order from a worker thread. + * Registration routines might call any number of routines which are not + * thread safe, such as wmem_alloc. Callbacks should handle themselves + * accordingly. + * + * @param register_cb Callback routine which is called for each protocol. + * Messages have the format "proto_register_XXX". + * @param client_data Data pointer for the callback. + */ WS_DLL_PUBLIC void register_all_protocols(register_cb cb, gpointer client_data); + +/** Call each dissector's protocol handoff routine. + * + * Each routine is called from a worker thread. Registration routines + * might call any number of routines which are not thread safe, such as + * wmem_alloc. Callbacks should handle themselves accordingly. + * + * @param register_cb Callback routine which is called for each protocol. + * Messages have the format "proto_reg_handoff_XXX". + * @param client_data Data pointer for the callback. + */ WS_DLL_PUBLIC void register_all_protocol_handoffs(register_cb cb, gpointer client_data); extern void register_all_tap_listeners(void); WS_DLL_PUBLIC gulong register_count(void); diff --git a/tools/make-dissector-reg.py b/tools/make-dissector-reg.py index 7b4c2962e6..dadb27b17b 100755 --- a/tools/make-dissector-reg.py +++ b/tools/make-dissector-reg.py @@ -211,7 +211,9 @@ WS_DLL_PUBLIC_DEF const gchar plugin_release[] = VERSION_RELEASE; else: reg_code += """ #include "register.h" +#include "ws_attributes.h" +#include <glib.h> """ for symbol in regs['proto_reg']: @@ -227,19 +229,61 @@ plugin_register (void) """ else: reg_code += """ -#define CALLBACK_REGISTER(proto, data) \\ - if (cb) cb(RA_REGISTER, proto, data) +static const char *cur_cb_name = NULL; +//static GMutex register_cb_mtx; +static GAsyncQueue *register_cb_done_q; + +#define CB_WAIT_TIME (150 * 1000) // microseconds + +static void set_cb_name(const char *proto) { + // g_mutex_lock(register_cb_mtx); + cur_cb_name = proto; + // g_mutex_unlock(register_cb_mtx); +} + +static void *register_all_protocols_worker(void *arg _U_); void register_all_protocols(register_cb cb, gpointer cb_data) { + const char *cb_name; + register_cb_done_q = g_async_queue_new(); + gboolean called_back = FALSE; + +#if GLIB_CHECK_VERSION(2,31,0) + g_thread_new("register_all_protocols_worker", ®ister_all_protocols_worker, NULL); +#else + g_thread_create(®ister_all_protocols_worker, TRUE, FALSE, NULL); +#endif + while (!g_async_queue_timeout_pop(register_cb_done_q, CB_WAIT_TIME)) { + // g_mutex_lock(register_cb_mtx); + cb_name = cur_cb_name; + // g_mutex_unlock(register_cb_mtx); + if (cb && cb_name) { + cb(RA_REGISTER, cb_name, cb_data); + called_back = TRUE; + } + } + if (cb && !called_back) { + cb(RA_REGISTER, "Registration finished", cb_data); + } +} + +void +*register_all_protocols_worker(void *arg _U_) +{ """ for symbol in regs['proto_reg']: if registertype != "plugin" and registertype != "plugin_wtap": - reg_code += " CALLBACK_REGISTER(\"%s\", cb_data);\n" % (symbol) + reg_code += " set_cb_name(\"%s\");\n" % (symbol) reg_code += " %s();\n" % (symbol) +if registertype != "plugin" and registertype != "plugin_wtap": + reg_code += """ + g_async_queue_push(register_cb_done_q, GINT_TO_POINTER(TRUE)); + return NULL; +""" reg_code += "}\n\n" @@ -258,19 +302,51 @@ plugin_reg_handoff(void) """ else: reg_code += """ -#define CALLBACK_HANDOFF(proto, data) \\ - if (cb) cb(RA_HANDOFF, proto, data) +static void *register_all_protocol_handoffs_worker(void *arg _U_); void register_all_protocol_handoffs(register_cb cb, gpointer cb_data) { + cur_cb_name = NULL; + const char *cb_name; + gboolean called_back = FALSE; + +#if GLIB_CHECK_VERSION(2,31,0) + g_thread_new("register_all_protocol_hadoffss_worker", ®ister_all_protocol_handoffs_worker, NULL); +#else + g_thread_create(®ister_all_protocol_handoffs_worker, TRUE, FALSE, NULL); +#endif + while (!g_async_queue_timeout_pop(register_cb_done_q, CB_WAIT_TIME)) { + // g_mutex_lock(register_cb_mtx); + cb_name = cur_cb_name; + // g_mutex_unlock(register_cb_mtx); + if (cb && cb_name) { + cb(RA_HANDOFF, cb_name, cb_data); + called_back = TRUE; + } + } + if (cb && !called_back) { + cb(RA_HANDOFF, "Registration finished", cb_data); + } + + g_async_queue_unref(register_cb_done_q); +} + +void +*register_all_protocol_handoffs_worker(void *arg _U_) +{ """ for symbol in regs['handoff_reg']: if registertype != "plugin" and registertype != "plugin_wtap": - reg_code += " CALLBACK_HANDOFF(\"%s\", cb_data);\n" % (symbol) + reg_code += " set_cb_name(\"%s\");\n" % (symbol) reg_code += " %s();\n" % (symbol) +if registertype != "plugin" and registertype != "plugin_wtap": + reg_code += """ + g_async_queue_push(register_cb_done_q, GINT_TO_POINTER(TRUE)); + return NULL; +""" reg_code += "}\n" if registertype == "plugin": diff --git a/ui/qt/splash_overlay.cpp b/ui/qt/splash_overlay.cpp index af1a76503e..3399bea6d8 100644 --- a/ui/qt/splash_overlay.cpp +++ b/ui/qt/splash_overlay.cpp @@ -40,11 +40,6 @@ // Uncomment to slow the update progress //#define THROTTLE_STARTUP 1 -/* - * Update frequency for the splash screen, given in milliseconds. - */ -static int info_update_freq_ = 100; - void splash_update(register_action_e action, const char *message, void *) { emit wsApp->registerUpdate(action, message); } @@ -58,17 +53,14 @@ SplashOverlay::SplashOverlay(QWidget *parent) : { so_ui_->setupUi(this); - // 6 for: - // dissectors, listeners, registering plugins, handingoff plugins, - // preferences, and interfaces - int register_add = 6; + int register_max = RA_BASE_COUNT; #ifdef HAVE_LUA - register_add += wslua_count_plugins(); /* get count of lua plugins */ + register_max++; #endif #ifdef HAVE_EXTCAP - register_add += extcap_count() + 1; /* Count of extcap binaries + registration message */ + register_max++; #endif - so_ui_->progressBar->setMaximum((int)register_count() + register_add); + so_ui_->progressBar->setMaximum(register_max); elapsed_timer_.start(); QColor bg = QColor(tango_aluminium_6); @@ -97,12 +89,6 @@ SplashOverlay::SplashOverlay(QWidget *parent) : "}" )); -#ifndef THROTTLE_STARTUP - // Check for a remote connection - if (display_is_remote()) - info_update_freq_ = 1000; -#endif - connect(wsApp, SIGNAL(splashUpdate(register_action_e,const char*)), this, SLOT(splashUpdate(register_action_e,const char*))); } @@ -133,10 +119,8 @@ void SplashOverlay::splashUpdate(register_action_e action, const char *message) ThrottleThread::msleep(10); #endif - register_cur_++; - if (last_action_ == action && elapsed_timer_.elapsed() < info_update_freq_ && register_cur_ != so_ui_->progressBar->maximum()) { - /* Only update every splash_register_freq milliseconds */ - return; + if (last_action_ != action) { + register_cur_++; } last_action_ = action; |