mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-10-18 03:12:52 +02:00
My application (OSTree) has suffered really bad performance degredation recently, and doing some analysis of the problem, I think a lot stems from the recent order of magnitude increase in the default GLib worker threads. OSTree does a *lot* of async I/O (directory enumeration, calling link(), reading/writing files) etc. It very quickly reaches 100 threads, but there is up/down thread churn as threads complete, but process gets I/O bound and thus the threads are starved of work, but then the main thread manages to fill the queue more, suddenly spinning up lots of worker threads again. Now, as this patch forces users to specify, there are several distinct classes of tasks. It basically never makes sense to run more CPU-bound threads than there are CPUs. Spawning 90+ threads to do SHA256 calculation for example is just creating pointless extra contention on a dual-processor system. Therefore, the limit of the thread pool for G_TASK_THREAD_KIND_CPU is the number of processors. Similarly, there's a real limit to how much I/O traffic it makes sense to schedule simultaneously. I need to do more research here - what makes sense for my laptop with 1 magnetic hard drive is likely different from a fast server with RAID on top of SSDs. For the moment, I've chosen to limit I/O bound threads to 4. The limit for _DEFAULT remains 100 - but we can solve this better if we have e.g. a way for tasks to express dependencies, among other things. But for now, with this patch, and OSTree modified to use G_TASK_THREAD_KIND_IO for its rename()/link() threads, I am seeing better performance. https://bugzilla.gnome.org/show_bug.cgi?id=687223
165 lines
7.6 KiB
C
165 lines
7.6 KiB
C
/* GIO - GLib Input, Output and Streaming Library
|
|
*
|
|
* Copyright 2011 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General
|
|
* Public License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
|
|
#error "Only <gio/gio.h> can be included directly."
|
|
#endif
|
|
|
|
#ifndef __G_TASK_H__
|
|
#define __G_TASK_H__
|
|
|
|
#include <gio/giotypes.h>
|
|
|
|
G_BEGIN_DECLS
|
|
|
|
#define G_TYPE_TASK (g_task_get_type ())
|
|
#define G_TASK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_TASK, GTask))
|
|
#define G_TASK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_TASK, GTaskClass))
|
|
#define G_IS_TASK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_TASK))
|
|
#define G_IS_TASK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_TASK))
|
|
#define G_TASK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_TASK, GTaskClass))
|
|
|
|
typedef struct _GTaskClass GTaskClass;
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
GType g_task_get_type (void) G_GNUC_CONST;
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
GTask *g_task_new (gpointer source_object,
|
|
GCancellable *cancellable,
|
|
GAsyncReadyCallback callback,
|
|
gpointer callback_data);
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_report_error (gpointer source_object,
|
|
GAsyncReadyCallback callback,
|
|
gpointer callback_data,
|
|
gpointer source_tag,
|
|
GError *error);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_report_new_error (gpointer source_object,
|
|
GAsyncReadyCallback callback,
|
|
gpointer callback_data,
|
|
gpointer source_tag,
|
|
GQuark domain,
|
|
gint code,
|
|
const char *format,
|
|
...);
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_set_task_data (GTask *task,
|
|
gpointer task_data,
|
|
GDestroyNotify task_data_destroy);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_set_priority (GTask *task,
|
|
gint priority);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_set_scheduling (GTask *task,
|
|
gint glib_priority,
|
|
GTaskThreadKind kind);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_set_check_cancellable (GTask *task,
|
|
gboolean check_cancellable);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_set_source_tag (GTask *task,
|
|
gpointer source_tag);
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gpointer g_task_get_source_object (GTask *task);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gpointer g_task_get_task_data (GTask *task);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gint g_task_get_priority (GTask *task);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
GMainContext *g_task_get_context (GTask *task);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
GCancellable *g_task_get_cancellable (GTask *task);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gboolean g_task_get_check_cancellable (GTask *task);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gpointer g_task_get_source_tag (GTask *task);
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gboolean g_task_is_valid (gpointer result,
|
|
gpointer source_object);
|
|
|
|
|
|
typedef void (*GTaskThreadFunc) (GTask *task,
|
|
gpointer source_object,
|
|
gpointer task_data,
|
|
GCancellable *cancellable);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_run_in_thread (GTask *task,
|
|
GTaskThreadFunc task_func);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_run_in_thread_sync (GTask *task,
|
|
GTaskThreadFunc task_func);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gboolean g_task_set_return_on_cancel (GTask *task,
|
|
gboolean return_on_cancel);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gboolean g_task_get_return_on_cancel (GTask *task);
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_attach_source (GTask *task,
|
|
GSource *source,
|
|
GSourceFunc callback);
|
|
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_return_pointer (GTask *task,
|
|
gpointer result,
|
|
GDestroyNotify result_destroy);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_return_boolean (GTask *task,
|
|
gboolean result);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_return_int (GTask *task,
|
|
gssize result);
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_return_error (GTask *task,
|
|
GError *error);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
void g_task_return_new_error (GTask *task,
|
|
GQuark domain,
|
|
gint code,
|
|
const char *format,
|
|
...) G_GNUC_PRINTF (4, 5);
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gboolean g_task_return_error_if_cancelled (GTask *task);
|
|
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gpointer g_task_propagate_pointer (GTask *task,
|
|
GError **error);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gboolean g_task_propagate_boolean (GTask *task,
|
|
GError **error);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gssize g_task_propagate_int (GTask *task,
|
|
GError **error);
|
|
GLIB_AVAILABLE_IN_2_36
|
|
gboolean g_task_had_error (GTask *task);
|
|
|
|
G_END_DECLS
|
|
|
|
#endif /* __G_TASK_H__ */
|