[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