[packagekit] packagekit: Branch 'master'
Richard Hughes
hughsient at kemper.freedesktop.org
Tue Oct 23 03:08:09 PDT 2007
src/Makefile.am | 4
src/pk-backend.c | 15 +-
src/pk-self-test.c | 2
src/pk-time.c | 353 +++++++++++++++++++++++++++++++++++++++++++++++++++++
src/pk-time.h | 61 +++++++++
5 files changed, 428 insertions(+), 7 deletions(-)
New commits:
commit 908971cfa380b3ed8995c75223d314ec101a71b6
Author: Richard Hughes <richard at hughsie.com>
Date: Tue Oct 23 11:05:31 2007 +0100
add the PkTime module to monitor the elapsed time and also to guess the completion time
diff --git a/src/Makefile.am b/src/Makefile.am
index 6b17868..16fc2c8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -46,6 +46,8 @@ packagekitd_SOURCES = \
pk-backend.c \
pk-backend.h \
pk-security.h \
+ pk-time.h \
+ pk-time.c \
pk-conf.c \
pk-conf.h \
pk-spawn.c \
@@ -126,6 +128,8 @@ pk_self_test_SOURCES = \
pk-inhibit.c \
pk-backend.h \
pk-backend.c \
+ pk-time.h \
+ pk-time.c \
pk-spawn.h \
pk-spawn.c \
pk-conf.h \
diff --git a/src/pk-backend.c b/src/pk-backend.c
index dc189b4..fc16ccf 100644
--- a/src/pk-backend.c
+++ b/src/pk-backend.c
@@ -46,6 +46,7 @@
#include "pk-marshal.h"
#include "pk-enum.h"
#include "pk-spawn.h"
+#include "pk-time.h"
#include "pk-inhibit.h"
#include "pk-thread-list.h"
@@ -70,7 +71,7 @@ struct _PkBackendPrivate
gchar *xcached_parameter;
gchar *xcached_value;
PkExitEnum exit;
- GTimer *timer;
+ PkTime *time;
PkSpawn *spawn;
gboolean is_killable;
gboolean during_initialize;
@@ -609,6 +610,9 @@ pk_backend_change_percentage (PkBackend *backend, guint percentage)
/* save in case we need this from coldplug */
backend->priv->last_percentage = percentage;
+ /* needed for time remaining calculation */
+ pk_time_add_data (backend->priv->time, percentage);
+
pk_debug ("emit percentage-changed %i", percentage);
g_signal_emit (backend, signals [PK_BACKEND_PERCENTAGE_CHANGED], 0, percentage);
return TRUE;
@@ -1611,10 +1615,7 @@ pk_backend_get_filters (PkBackend *backend)
guint
pk_backend_get_runtime (PkBackend *backend)
{
- gdouble time;
- time = g_timer_elapsed (backend->priv->timer, NULL);
- time *= 1000;
- return (guint) time;
+ return pk_time_get_elapsed (backend->priv->time);
}
/**
@@ -1648,7 +1649,6 @@ pk_backend_finalize (GObject *object)
g_free (backend->priv->name);
g_free (backend->priv->last_package);
pk_backend_unload (backend);
- g_timer_destroy (backend->priv->timer);
g_free (backend->priv->xcached_package_id);
g_free (backend->priv->xcached_transaction_id);
@@ -1664,6 +1664,7 @@ pk_backend_finalize (GObject *object)
/* remove any inhibit, it's okay to call this function when it's not needed */
pk_inhibit_remove (backend->priv->inhibit, backend);
+ g_object_unref (backend->priv->time);
g_object_unref (backend->priv->inhibit);
g_object_unref (backend->priv->network);
@@ -1771,7 +1772,6 @@ static void
pk_backend_init (PkBackend *backend)
{
backend->priv = PK_BACKEND_GET_PRIVATE (backend);
- backend->priv->timer = g_timer_new ();
backend->priv->assigned = FALSE;
backend->priv->is_killable = FALSE;
backend->priv->set_error = FALSE;
@@ -1793,6 +1793,7 @@ pk_backend_init (PkBackend *backend)
backend->priv->role = PK_ROLE_ENUM_UNKNOWN;
backend->priv->status = PK_STATUS_ENUM_UNKNOWN;
backend->priv->exit = PK_EXIT_ENUM_SUCCESS;
+ backend->priv->time = pk_time_new ();
backend->priv->inhibit = pk_inhibit_new ();
backend->priv->network = pk_network_new ();
backend->priv->thread_list = pk_thread_list_new ();
diff --git a/src/pk-self-test.c b/src/pk-self-test.c
index 1102b89..b8fa478 100644
--- a/src/pk-self-test.c
+++ b/src/pk-self-test.c
@@ -30,6 +30,7 @@ void libst_inhibit (LibSelfTest *test);
void libst_spawn (LibSelfTest *test);
void libst_thread_list (LibSelfTest *test);
void libst_transaction_list (LibSelfTest *test);
+void libst_time (LibSelfTest *test);
int
main (int argc, char **argv)
@@ -44,6 +45,7 @@ main (int argc, char **argv)
pk_debug_init (TRUE);
/* tests go here */
+ libst_time (&test);
libst_conf (&test);
libst_inhibit (&test);
libst_spawn (&test);
diff --git a/src/pk-time.c b/src/pk-time.c
new file mode 100644
index 0000000..2b525cf
--- /dev/null
+++ b/src/pk-time.c
@@ -0,0 +1,353 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#include <sys/wait.h>
+#include <fcntl.h>
+
+#include <glib/gi18n.h>
+
+#include "pk-debug.h"
+#include "pk-time.h"
+#include "pk-marshal.h"
+
+static void pk_time_class_init (PkTimeClass *klass);
+static void pk_time_init (PkTime *time);
+static void pk_time_finalize (GObject *object);
+
+#define PK_TIME_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PK_TYPE_TIME, PkTimePrivate))
+#define PK_TIME_AVERAGE_MIN 2
+#define PK_TIME_AVERAGE_MAX 5
+#define PK_TIME_VALUE_MIN 5*1000
+#define PK_TIME_VALUE_MAX 60*60*1000
+
+struct PkTimePrivate
+{
+ gboolean finished;
+ GPtrArray *array;
+ GTimer *timer;
+};
+
+typedef struct {
+ guint percentage;
+ guint time;
+} PkTimeItem;
+
+G_DEFINE_TYPE (PkTime, pk_time, G_TYPE_OBJECT)
+
+/**
+ * pk_time_get_elapsed:
+ *
+ * Returns time running in ms
+ **/
+guint
+pk_time_get_elapsed (PkTime *time)
+{
+ gdouble elapsed;
+
+ g_return_val_if_fail (time != NULL, 0);
+ g_return_val_if_fail (PK_IS_TIME (time), 0);
+
+ elapsed = g_timer_elapsed (time->priv->timer, NULL);
+ elapsed *= 1000;
+ return (guint) elapsed;
+}
+
+/**
+ * pk_time_get_remaining:
+ **/
+static gfloat
+pk_time_get_gradient (PkTimeItem *item1, PkTimeItem *item2)
+{
+ gfloat dy;
+ gfloat dx;
+ dy = (gfloat) (item1->percentage - item2->percentage);
+ dx = (gfloat) (item1->time - item2->time);
+ return dy/dx;
+}
+
+/**
+ * pk_time_get_remaining:
+ **/
+guint
+pk_time_get_remaining (PkTime *time)
+{
+ guint i;
+ guint averaged = 0;
+ guint length;
+ gfloat grad;
+ gfloat grad_ave = 0.0f;
+ gfloat estimated;
+ guint percentage_left;
+ guint elapsed;
+ PkTimeItem *item;
+ PkTimeItem *item_prev;
+
+ g_return_val_if_fail (time != NULL, 0);
+ g_return_val_if_fail (PK_IS_TIME (time), 0);
+
+ length = time->priv->array->len;
+ if (length < 2) {
+ pk_debug ("array too small");
+ return 0;
+ }
+
+ /* get as many as we can */
+ for (i=length-1; i>0; i--) {
+ item_prev = g_ptr_array_index (time->priv->array, i-1);
+ item = g_ptr_array_index (time->priv->array, i);
+ grad = pk_time_get_gradient (item, item_prev);
+ pk_debug ("gradient between %i/%i=%f", i-1, i, grad);
+ if (grad < 0.0001 || grad > 100) {
+ pk_debug ("ignoring gradient");
+ } else {
+ grad_ave += grad;
+ averaged++;
+ if (averaged > PK_TIME_AVERAGE_MAX) {
+ break;
+ }
+ }
+ }
+
+ pk_debug ("averaged %i points", averaged);
+ if (averaged < PK_TIME_AVERAGE_MIN) {
+ pk_debug ("not enough samples for accurate time: %i", averaged);
+ return 0;
+ }
+
+ /* normalise to the number of samples */
+ grad_ave /= averaged;
+ pk_debug ("grad_ave=%f", grad_ave);
+
+ /* just for debugging */
+ elapsed = pk_time_get_elapsed (time);
+ pk_debug ("elapsed=%i", elapsed);
+
+ /* 100 percent to be complete */
+ item = g_ptr_array_index (time->priv->array, length - 1);
+ percentage_left = 100 - item->percentage;
+ pk_debug ("percentage_left=%i", percentage_left);
+ estimated = (gfloat) percentage_left / grad_ave;
+
+ /* turn to ms */
+ pk_debug ("estimated=%f", estimated);
+
+ if (estimated < PK_TIME_VALUE_MIN) {
+ estimated = 0;
+ } else if (estimated > PK_TIME_VALUE_MAX) {
+ estimated = 0;
+ }
+ return (guint) estimated;
+}
+
+/**
+ * pk_time_add_data:
+ **/
+gboolean
+pk_time_add_data (PkTime *time, guint percentage)
+{
+ PkTimeItem *item;
+ gdouble elapsed;
+
+ g_return_val_if_fail (time != NULL, FALSE);
+ g_return_val_if_fail (PK_IS_TIME (time), FALSE);
+
+ /* get runtime in ms */
+ elapsed = g_timer_elapsed (time->priv->timer, NULL);
+ elapsed *= 1000;
+
+ pk_debug ("adding %i at %i (ms)", percentage, (guint) elapsed);
+
+ /* create a new object and add to the array */
+ item = g_new0 (PkTimeItem, 1);
+ item->time = (guint) elapsed;
+ item->percentage = percentage;
+ g_ptr_array_add (time->priv->array, item);
+
+ return TRUE;
+}
+
+/**
+ * pk_time_class_init:
+ * @klass: The PkTimeClass
+ **/
+static void
+pk_time_class_init (PkTimeClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = pk_time_finalize;
+ g_type_class_add_private (klass, sizeof (PkTimePrivate));
+}
+
+/**
+ * pk_time_init:
+ * @time: This class instance
+ **/
+static void
+pk_time_init (PkTime *time)
+{
+ time->priv = PK_TIME_GET_PRIVATE (time);
+ time->priv->array = g_ptr_array_new ();
+ time->priv->timer = g_timer_new ();
+}
+
+/**
+ * pk_time_finalize:
+ * @object: The object to finalize
+ **/
+static void
+pk_time_finalize (GObject *object)
+{
+ PkTime *time;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (PK_IS_TIME (object));
+
+ time = PK_TIME (object);
+ g_return_if_fail (time->priv != NULL);
+ g_ptr_array_free (time->priv->array, TRUE);
+
+ G_OBJECT_CLASS (pk_time_parent_class)->finalize (object);
+}
+
+/**
+ * pk_time_new:
+ *
+ * Return value: a new PkTime object.
+ **/
+PkTime *
+pk_time_new (void)
+{
+ PkTime *time;
+ time = g_object_new (PK_TYPE_TIME, NULL);
+ return PK_TIME (time);
+}
+
+/***************************************************************************
+ *** MAKE CHECK TESTS ***
+ ***************************************************************************/
+#ifdef PK_BUILD_TESTS
+#include <libselftest.h>
+
+void
+libst_time (LibSelfTest *test)
+{
+ PkTime *time = NULL;
+ gboolean ret;
+ guint value;
+
+ if (libst_start (test, "PkTime", CLASS_AUTO) == FALSE) {
+ return;
+ }
+
+ /************************************************************/
+ libst_title (test, "get PkTime object");
+ time = pk_time_new ();
+ if (time != NULL) {
+ libst_success (test, NULL);
+ } else {
+ libst_failed (test, NULL);
+ }
+
+ /************************************************************/
+ libst_title (test, "get elapsed correctly at startup");
+ value = pk_time_get_elapsed (time);
+ if (value < 10) {
+ libst_success (test, "elapsed at startup %i", value);
+ } else {
+ libst_failed (test, "elapsed at startup %i", value);
+ }
+
+ /************************************************************/
+ libst_title (test, "ignore remaining correctly");
+ value = pk_time_get_remaining (time);
+ if (value == 0) {
+ libst_success (test, NULL);
+ } else {
+ libst_failed (test, "got %i, not zero!", value);
+ }
+
+ /************************************************************/
+ g_usleep (1000*1000);
+
+ /************************************************************/
+ libst_title (test, "get elapsed correctly");
+ value = pk_time_get_elapsed (time);
+ if (value > 900 && value < 1100) {
+ libst_success (test, "elapsed ~1000ms: %i", value);
+ } else {
+ libst_failed (test, "elapsed not ~1000ms: %i", value);
+ }
+
+ /************************************************************/
+ libst_title (test, "ignore remaining correctly when not enough entries");
+ value = pk_time_get_remaining (time);
+ if (value == 0) {
+ libst_success (test, NULL);
+ } else {
+ libst_failed (test, "got %i, not zero!", value);
+ }
+
+ /************************************************************/
+ libst_title (test, "make sure we can add data");
+ ret = pk_time_add_data (time, 10);
+ if (ret == TRUE) {
+ libst_success (test, NULL);
+ } else {
+ libst_failed (test, NULL);
+ }
+
+ /************************************************************/
+ libst_title (test, "make sure we can get remaining correctly");
+ value = 20;
+ while (value < 60) {
+ g_usleep (2*1000*1000);
+ pk_time_add_data (time, value);
+ value += 10;
+ }
+ value = pk_time_get_remaining (time);
+ if (value > 9500 && value < 10500) {
+ libst_success (test, NULL);
+ } else {
+ libst_failed (test, "got %i, not ~10000ms", value);
+ }
+
+
+ g_object_unref (time);
+
+ libst_end (test);
+}
+#endif
+
diff --git a/src/pk-time.h b/src/pk-time.h
new file mode 100644
index 0000000..5e0245f
--- /dev/null
+++ b/src/pk-time.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 Richard Hughes <richard at hughsie.com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PK_TIME_H
+#define __PK_TIME_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define PK_TYPE_TIME (pk_time_get_type ())
+#define PK_TIME(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), PK_TYPE_TIME, PkTime))
+#define PK_TIME_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), PK_TYPE_TIME, PkTimeClass))
+#define PK_IS_TIME(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), PK_TYPE_TIME))
+#define PK_IS_TIME_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), PK_TYPE_TIME))
+#define PK_TIME_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), PK_TYPE_TIME, PkTimeClass))
+#define PK_TIME_ERROR (pk_time_error_quark ())
+#define PK_TIME_TYPE_ERROR (pk_time_error_get_type ())
+
+typedef struct PkTimePrivate PkTimePrivate;
+
+typedef struct
+{
+ GObject parent;
+ PkTimePrivate *priv;
+} PkTime;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} PkTimeClass;
+
+GType pk_time_get_type (void);
+PkTime *pk_time_new (void);
+
+gboolean pk_time_add_data (PkTime *time,
+ guint percentage);
+guint pk_time_get_elapsed (PkTime *time);
+guint pk_time_get_remaining (PkTime *time);
+
+G_END_DECLS
+
+#endif /* __PK_TIME_H */
More information about the PackageKit
mailing list