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>
This commit is contained in:
Gerald Combs 2017-11-14 15:58:32 -08:00 committed by Anders Broman
parent 665eb78729
commit ac1d52aff5
3 changed files with 116 additions and 32 deletions

View File

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

View File

@ -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", &register_all_protocols_worker, NULL);
#else
g_thread_create(&register_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", &register_all_protocol_handoffs_worker, NULL);
#else
g_thread_create(&register_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":

View File

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