Hello,

Matt, I think you may have missed the punchline in my original email.
Kopete is waking up over 30 times per second whenever it is running.
This places a non-negligable amount of load on the system to the
extent that you can see some slowdown when attempting to run other CPU
intensive tasks ( such as playing multimedia content ).  I imagine
that it would also have a measurable effect on battery life.

Attached is a patch for KDE 3.5 SVN which fixes the worst offender.
This enables the smooth scrolling timers when any events are received
by the list-view's scrollbar and disables the timers as soon as the
scrollbar comes to rest ( the scrollbar is treated as being 'at rest'
if none of its elements are currently being pressed and if the
scrollbar's value changed by less than one unit in the current
animation step )

It also fixes a mistake in the code where a double is used to store
the ID of a timer returned by a call to QObject::startTimer( ).

Regards,
Robert.

On 28/03/07, Matt Rogers <[EMAIL PROTECTED]> wrote:
On Sunday 25 March 2007 11:11, Robert Knight wrote:
> Hello,
>
> I noticed by chance that Kopete (using KDE 3.5.6) was using several %
> of CPU time, despite
> there being no chat windows open and no accounts running.
>
> I traced the Kopete process using strace and it seems that Kopete is
> waking up almost continuously, though it ought to be idle (or at
> least, with minimal, infrequent activity).
>
> A little more investigative debugging with GDB and it seems that
> Kopete is waking up every 30 milliseconds as the timer used to handle
> smooth scrolling in the contact list view is fired.  That timer is
> started in Kopete::UI::ListView::ListView::setSmoothScrolling() and
> never subsequently disabled.  Relevant code is
> libkopete/ui/kopetelistview.cpp lines 324-338.
>
> To find out what object the timers belonged to I put a breakpoint on
> QEventLoop::activateTimers.  When the breakpoint is reached, there is
> a timerList variable available which is a list of pointers to
> TimerInfo instances which contain information about the timers to be
> fired.  Each TimerInfo instance has an 'obj' variable which is a
> pointer to the QObject that owns the timer.  So to get the class name
> of the object which owns the timer I ran the following when the
> breakpoint was hit:
>
> print timerList->first()->obj->metaObject()->className()
>
> To demonstrate, start Kopete, disconnect from all accounts and close
> any chat windows,
> get the process id of the kopete process, and attach to it using
> "strace -p <kopete process id>".  You can see that gettimeofday is
> being called continuously.  Comment out the calls to startTimer() in
> the setSmoothScrolling() method mentioned above and re-run Kopete and
> trace again with strace.  Kopete now wakes up far less frequently.
>
> A possible solution would be to enable the timer only whilst scrolling
> is in progress if possible and then disable at as soon as the list
> stops scrolling, although I am not very familiar with this code -
> better ideas welcomed.
>
> Regards,
> Robert.

yup, kopete abuses timers quite a bit. However, we don't intend to fix this
until KDE 4.x. Thanks for your work though.
--
Matt

_______________________________________________
kopete-devel mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/kopete-devel



Index: libkopete/kopeteaway.cpp
===================================================================
--- libkopete/kopeteaway.cpp	(revision 646242)
+++ libkopete/kopeteaway.cpp	(working copy)
@@ -188,7 +188,7 @@
 	}
 	
 	// init the timer
-	d->timer = new QTimer(this, "AwayTimer");
+    d->timer = new QTimer(this, "AwayTimer");
 	connect(d->timer, SIGNAL(timeout()), this, SLOT(slotTimerTimeout()));
 	d->timer->start(4000);
 
Index: libkopete/ui/kopetelistview.cpp
===================================================================
--- libkopete/ui/kopetelistview.cpp	(revision 646242)
+++ libkopete/ui/kopetelistview.cpp	(working copy)
@@ -33,6 +33,7 @@
 
 #include <utility>
 #include <memory>
+#include <math.h>
 
 namespace Kopete {
 namespace UI {
@@ -101,7 +102,7 @@
 	//! The status of smooth scrolling, enabled or disabled.
 	bool smoothScrollingEnabled;
 	//! This will be the QTimer's ID which will be updating smooth scrolling animation.
-	double smoothScrollingTimer;
+	int smoothScrollingTimer;
 	//! The time interval which the smooth scrolling will be updated.
 	double smoothScrollingTimerInterval;
 	//! This will be the target scroll bar position. Note that this value is in the sense of contents height in
@@ -324,17 +325,12 @@
 	{
 		// Intercept scrollbar's events
 		verticalScrollBar()->installEventFilter( this );
-		// Install the timer
-		d->smoothScrollingTimer = startTimer( (int)d->smoothScrollingTimerInterval );
 		// If we want to enable smooth scrolling when item has changed with keypresses etc, we need this
 		connect( this, SIGNAL( currentChanged( QListViewItem* ) ), this, SLOT( slotCurrentChanged(QListViewItem*) ) );
 		// Disable autoscroll, we will do it the smooth way.
 		d->smoothScrollDragAutoScroll = dragAutoScroll();
 		setDragAutoScroll( false );
-		// Init the timers to simulate continuous press
-		d->continuousLinePressTimer = startTimer( d->continuousLinePressTimerInterval );
-		d->continuousPagePressTimer = startTimer( d->continuousPagePressTimerInterval );
-		
+				
 	}
 	else	// If disabled
 	{
@@ -342,21 +338,61 @@
 		verticalScrollBar()->removeEventFilter( this );
 		// Restore line/page step sizes
 		verticalScrollBar()->setLineStep( d->smoothScrollingLineStep );
-		// Kill the already started timer
-		killTimer( (int)d->smoothScrollingTimer );
-		d->smoothScrollingTimer = 0;
 		// We don't need to list currentChanged anymore
 		disconnect( this, SIGNAL( currentChanged( QListViewItem* ) ), this, SLOT( slotCurrentChanged(QListViewItem*) ) );
 		// Restore the autoscroll
 		setDragAutoScroll( d->smoothScrollDragAutoScroll );
 		// Kill the continuous press timers
-		killTimer( d->continuousLinePressTimer  );
-		d->continuousLinePressTimer = 0;
-		killTimer( d->continuousPagePressTimer  );
-		d->continuousPagePressTimer = 0;
+		setSmoothScrollTimersEnabled(false);		
 	}
 }
 
+void ListView::setSmoothScrollTimersEnabled(bool enableTimers)
+{
+	if ( enableTimers )
+	{
+		//kdDebug() << "smooth scrolling timers enabled" << endl;
+
+		// for each of the three timers used to manage smooth scrolling, check
+		// whether they are already enabled and if not, start them.
+
+		if ( d->smoothScrollingTimer == 0 )
+			d->smoothScrollingTimer = startTimer( (int)d->smoothScrollingTimerInterval );
+		
+		// start the timers to simulate continuous press
+		if ( d->continuousLinePressTimer == 0 )
+			d->continuousLinePressTimer = startTimer( d->continuousLinePressTimerInterval );
+		
+		if ( d->continuousPagePressTimer == 0 )
+			d->continuousPagePressTimer = startTimer( d->continuousPagePressTimerInterval );
+	}
+	else
+	{
+		//kdDebug() << "smooth scrolling timers disabled" << endl;
+
+		// for each of the three timers used to manage smooth scrolling, check 
+		// whether they are already disabled and if not, kill them.
+
+		if ( d->smoothScrollingTimer != 0 )
+		{
+			killTimer( d->smoothScrollingTimer );
+			d->smoothScrollingTimer = 0;
+		}
+
+		if ( d->continuousLinePressTimer != 0 )
+		{
+			killTimer( d->continuousLinePressTimer );
+			d->continuousLinePressTimer = 0;
+		}
+
+		if ( d->continuousPagePressTimer != 0 )
+		{
+			killTimer( d->continuousPagePressTimer );
+			d->continuousPagePressTimer = 0;
+		}
+	}
+}
+
 bool ListView::smoothScrolling() const
 {
 	return d->smoothScrollingEnabled;
@@ -385,6 +421,7 @@
 		setVScrollBarMode( AlwaysOff );
 		// Start the timer to handle auto-hide
 		killTimer( d->scrollAutoHideTimer );
+		
 		d->scrollAutoHideTimer = startTimer( 1000 );
 	}
 	else
@@ -445,8 +482,23 @@
 		double offset = static_cast<double>( ( d->targetScrollBarValue - d->metaScrollBarCurrentValue ) / d->scrollBarAccelerationConstant );
 		// Add the offset to our meta current value, this is the desired precise value
 		d->metaScrollBarCurrentValue += offset;
-		// Cast it to integer and update the vertical scroll bar value
-		verticalScrollBar()->setValue( static_cast<int>( d->metaScrollBarCurrentValue ) );
+
+		const int newValue = static_cast<int>( d->metaScrollBarCurrentValue );
+	    if ( verticalScrollBar()->value() != newValue )		
+		{
+			// Cast it to integer and update the vertical scroll bar value
+			verticalScrollBar()->setValue( newValue ); 
+		}
+		else
+		{
+			// the scrollbar has reached its rest position, if no parts of the scrollbar
+			// are currently being pressed then the animation has finished and the 
+			// timers can be disabled
+			if ( d->pressedControl == QStyle::SC_None )
+			{
+				setSmoothScrollTimersEnabled(false);
+			}
+		}
 	}
 	else if( e->timerId() == d->continuousLinePressTimer )
 	{
@@ -518,6 +570,11 @@
 {
 	if( o == verticalScrollBar() ) // Event's to scroll bar
 	{
+		// if the scroll bar receives any events ensure that the timers needed to manage
+		// the animations are enabled.
+		// the timers will be disabled when the scrollbar reaches a rest position
+		setSmoothScrollTimersEnabled(true);
+
 		// Our scroll bar
 		QScrollBar *bar = static_cast<QScrollBar*>(o);
 		if( e->type() == QEvent::Wheel )
Index: libkopete/ui/kopetelistview.h
===================================================================
--- libkopete/ui/kopetelistview.h	(revision 646242)
+++ libkopete/ui/kopetelistview.h	(working copy)
@@ -135,13 +135,22 @@
 	 * This will manage the smooth scrolling animation, continuous presses to the scrollbars.
 	 */
 	virtual void timerEvent( QTimerEvent *e );
-	
+
 	/**
 	 * To make smooth scrolling work well, we need extensive event intercepting.
 	 * This event filter is suppposed to achive that.
 	 */
 	virtual bool eventFilter( QObject *o, QEvent *e );
 
+	/**
+	 * Enables or disables the timers used to control the smooth scrolling timers.
+	 * 
+	 * It is safe to call setSmoothScrollTimersEnabled(true) even if the timers are
+	 * already enabled and setSmoothScrollTimersEnabled(false) even if the timers are
+	 * already disabled.
+	 */
+	void setSmoothScrollTimersEnabled(bool enableTimers);
+
 private slots:
 	void slotContextMenu(KListView*,QListViewItem *item, const QPoint &point );
 	void slotDoubleClicked( QListViewItem *item );
_______________________________________________
kopete-devel mailing list
[email protected]
https://mail.kde.org/mailman/listinfo/kopete-devel

Reply via email to