[rkward-cvs] rkward/rkward/rbackend rembedinternal.cpp,1.27,1.28 rembedinternal.h,1.15,1.16 rinterface.cpp,1.37,1.38 rinterface.h,1.21,1.22 rthread.cpp,1.26,1.27 rthread.h,1.19,1.20

Thomas Friedrichsmeier tfry at users.sourceforge.net
Thu Nov 3 15:24:58 UTC 2005


Update of /cvsroot/rkward/rkward/rkward/rbackend
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21971/rkward/rbackend

Modified Files:
	rembedinternal.cpp rembedinternal.h rinterface.cpp 
	rinterface.h rthread.cpp rthread.h 
Log Message:
Significant performance improvements while processing immediate output. 1) Flush output at regular intervals and when needed, instead of always flushing small pieces. 2) setUpdatesEnabled (false) while removing superfluous lines in console/log

Index: rthread.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rthread.h,v
retrieving revision 1.19
retrieving revision 1.20
diff -C2 -d -r1.19 -r1.20
*** rthread.h	2 Nov 2005 21:11:38 -0000	1.19
--- rthread.h	3 Nov 2005 15:24:56 -0000	1.20
***************
*** 108,111 ****
--- 108,114 ----
  	void handleOutput (char *buf, int buf_length);
  
+ /** Flushes current output buffer. Lock the mutex before calling this function! It is called from both threads and is not re-entrant */
+ 	void flushOutput ();
+ 
  /** this function is public for technical reasons, only. Don't use except from REmbedInternal! Called from REmbedInternal when the R backend
  signals a condition. @see REmbedInternal::handleCondition () */
***************
*** 143,146 ****
--- 146,153 ----
  		RCommand *command;
  	};
+ /** current output */
+ 	ROutput *current_output;
+ /** current length of output. Used so we can flush every once in a while, if output becomes too long */
+ 	int out_buf_len;
  protected:
  /** the main loop. See \ref RThread for a more detailed description */

Index: rinterface.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rinterface.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -C2 -d -r1.21 -r1.22
*** rinterface.h	21 Oct 2005 15:23:36 -0000	1.21
--- rinterface.h	3 Nov 2005 15:24:56 -0000	1.22
***************
*** 24,29 ****
  #include "rthread.h"
  
! #define MUTEX_LOCK /*qDebug ("%d", ++RInterface::mutex_counter);*/ RInterface::mutex.lock ();
! #define MUTEX_UNLOCK /*qDebug ("%d", --RInterface::mutex_counter);*/ RInterface::mutex.unlock ();
  
  class RKwatch;
--- 24,35 ----
  #include "rthread.h"
  
! //#define DEBUG_MUTEX
! #ifdef DEBUG_MUTEX
! #define MUTEX_LOCK qDebug ("mutex locks: %d, locked in %s, %s, %d", ++RInterface::mutex_counter, __FILE__, __FUNCTION__, __LINE__); RInterface::mutex.lock ();
! #define MUTEX_UNLOCK qDebug ("mutex locks: %d, unlocked in %s, %s, %d", --RInterface::mutex_counter, __FILE__, __FUNCTION__, __LINE__); RInterface::mutex.unlock ();
! #else
! #define MUTEX_LOCK RInterface::mutex.lock ();
! #define MUTEX_UNLOCK RInterface::mutex.unlock ();
! #endif
  
  class RKwatch;
***************
*** 31,34 ****
--- 37,41 ----
  class RKwardApp;
  struct RCallbackArgs;
+ class QTimer;
  
  /** This class provides the main interface to the R-processor.
***************
*** 71,81 ****
  /** *The* mutex in usein RKWard. This is needed to ensure, the main (GUI) thread, and the backend thread (@see RThread) do not try to access the same data at the same time. Use MUTEX_LOCK and MUTEX_UNLOCK to lock/unlock the mutex. */
  	static QMutex mutex;
! 	//static int mutex_counter;
  
  /** returns the command currently running in the thread. Be careful when using the returned pointer! */
  	RCommand *runningCommand () { return r_thread->current_command; };
  private:
  /** pointer to the RThread */
  	RThread *r_thread;
  /** cancelling the command that is (or seems to be) currently running is tricky: In order to do so, we need to signal an interrupt to the RThread. We need this pointer to find out, when the command has actually been interrupted, and we can resume processing. */
  	RCommand *running_command_canceled;
--- 78,95 ----
  /** *The* mutex in usein RKWard. This is needed to ensure, the main (GUI) thread, and the backend thread (@see RThread) do not try to access the same data at the same time. Use MUTEX_LOCK and MUTEX_UNLOCK to lock/unlock the mutex. */
  	static QMutex mutex;
! #ifdef DEBUG_MUTEX
! 	static int mutex_counter;
! #endif
  
  /** returns the command currently running in the thread. Be careful when using the returned pointer! */
  	RCommand *runningCommand () { return r_thread->current_command; };
+ public slots:
+ /** called periodically to flush output buffer in RThread */
+ 	void flushOutput ();
  private:
  /** pointer to the RThread */
  	RThread *r_thread;
+ /** Timer to trigger flushing output */
+ 	QTimer *flush_timer;
  /** cancelling the command that is (or seems to be) currently running is tricky: In order to do so, we need to signal an interrupt to the RThread. We need this pointer to find out, when the command has actually been interrupted, and we can resume processing. */
  	RCommand *running_command_canceled;

Index: rembedinternal.h
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembedinternal.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -C2 -d -r1.15 -r1.16
*** rembedinternal.h	21 Oct 2005 15:23:36 -0000	1.15
--- rembedinternal.h	3 Nov 2005 15:24:56 -0000	1.16
***************
*** 117,120 ****
--- 117,123 ----
  	virtual void handleOutput (char *buf, int buf_length) = 0;
  
+ /** This gets called, when the console is flushed */
+ 	virtual void flushOutput () = 0;
+ 
  /** This gets called, when R reports warnings/messages. Used to get at warning-output. */
  //	virtual void handleCondition (char **call, int call_length) = 0;

Index: rembedinternal.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rembedinternal.cpp,v
retrieving revision 1.27
retrieving revision 1.28
diff -C2 -d -r1.27 -r1.28
*** rembedinternal.cpp	2 Nov 2005 21:11:38 -0000	1.27
--- rembedinternal.cpp	3 Nov 2005 15:24:56 -0000	1.28
***************
*** 93,97 ****
  
  void RFlushConsole () {
! // we leave this un-implemented on purpose! We simply don't want that sort of thing to be done.
  }
  
--- 93,97 ----
  
  void RFlushConsole () {
! 	REmbedInternal::this_pointer->flushOutput ();
  }
  

Index: rthread.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rthread.cpp,v
retrieving revision 1.26
retrieving revision 1.27
diff -C2 -d -r1.26 -r1.27
*** rthread.cpp	2 Nov 2005 21:11:38 -0000	1.26
--- rthread.cpp	3 Nov 2005 15:24:56 -0000	1.27
***************
*** 31,34 ****
--- 31,35 ----
  #include <qapplication.h>
  
+ #define MAX_BUF_LENGTH 1000
  
  RThread::RThread () : QThread (), REmbedInternal () {
***************
*** 39,42 ****
--- 40,45 ----
  	this_pointer = this;
  	RK_ASSERT (this_pointer);
+ 	current_output = 0;
+ 	out_buf_len = 0;
  }
  
***************
*** 168,171 ****
--- 171,176 ----
  	//		runCommandInternal (".rk.init.handlers ()\n", &dummy);
  		}
+ 
+ 		flushOutput ();
  	}
  
***************
*** 184,195 ****
  	if (!buf_length) return;
  
! 	ROutput *out = new ROutput;
! 	out->type = ROutput::Output;
! 	out->output = QString (buf);
  
! 	current_command->output_list.append (out);
! 	current_command->status |= RCommand::HasOutput;
  
! 	RK_DO (qDebug ("output '%s'", buf), RBACKEND, DL_DEBUG);
  
  // pass a signal to the main thread for real-time update of output
--- 189,221 ----
  	if (!buf_length) return;
  
! 	MUTEX_LOCK;
! 	if (current_output) {
! 		if (current_output->type != ROutput::Output) {
! 			flushOutput ();
! 		}
! 	}
! 	if (!current_output) {	// not an else, might have been set to 0 in the above if
! 		current_output = new ROutput;
! 		current_output->type = ROutput::Output;
! 	}
! 	current_output->output.append (buf);
  
! 	if ((out_buf_len += buf_length) > MAX_BUF_LENGTH) {
! 		RK_DO (qDebug ("Output buffer has %d characters. Forcing flush", out_buf_len), RBACKEND, DL_DEBUG);
! 		flushOutput ();
! 	}
! 	MUTEX_UNLOCK;
! }
  
! void RThread::flushOutput () {
! 	if (!current_output) return;		// avoid creating loads of traces
! 	RK_TRACE (RBACKEND);
! 
! 	current_command->output_list.append (current_output);
! 	if (current_output->type == ROutput::Output) {
! 		current_command->status |= RCommand::HasOutput;
! 	} else if (current_output->type == ROutput::Error) {
! 		current_command->status |= RCommand::HasError;
! 	}
  
  // pass a signal to the main thread for real-time update of output
***************
*** 202,210 ****
  		QCustomEvent *event = new QCustomEvent (RCOMMAND_OUTPUT_EVENT);
  		ROutputContainer *outc = new ROutputContainer;
! 		outc->output = out;
  		outc->command = current_command;
  		event->setData (outc);
  		qApp->postEvent (RKGlobals::rInterface (), event);
  	}
  }
  
--- 228,241 ----
  		QCustomEvent *event = new QCustomEvent (RCOMMAND_OUTPUT_EVENT);
  		ROutputContainer *outc = new ROutputContainer;
! 		outc->output = current_output;
  		outc->command = current_command;
  		event->setData (outc);
  		qApp->postEvent (RKGlobals::rInterface (), event);
  	}
+ 
+ 	RK_DO (qDebug ("output '%s'", current_output->output.latin1 ()), RBACKEND, DL_DEBUG);
+ // forget output
+ 	current_output = 0;
+ 	out_buf_len = 0;
  }
  
***************
*** 225,243 ****
  	if (!call_length) return;
  
  	// Unfortunately, errors still get printed to the output. We try this crude method for the time being:
  	current_command->output_list.last ()->type = ROutput::Error;
  	current_command->status |= RCommand::HasError;
  
- /*	// for now we ignore everything but the first string.
- 	ROutput *out = new ROutput;
- 	out->type = ROutput::Error;
- 	out->output = QString (call[0]);
- 
- 	thread->current_command->output_list.append (out);
- 	thread->current_command->status |= RCommand::HasError; */
- 	// TODO: pass a signal to the main thread for real-time update of output
- 
- 	//RThreadInternal::next_output_is_error = true;
  	RK_DO (qDebug ("error '%s'", call[0]), RBACKEND, DL_DEBUG);
  }
  
--- 256,267 ----
  	if (!call_length) return;
  
+ 	MUTEX_LOCK;
  	// Unfortunately, errors still get printed to the output. We try this crude method for the time being:
+ 	flushOutput ();
  	current_command->output_list.last ()->type = ROutput::Error;
  	current_command->status |= RCommand::HasError;
  
  	RK_DO (qDebug ("error '%s'", call[0]), RBACKEND, DL_DEBUG);
+ 	MUTEX_UNLOCK;
  }
  
***************
*** 250,253 ****
--- 274,278 ----
  	request->call_length = call_length;
  	MUTEX_LOCK;
+ 	flushOutput ();
  	RCommandStack *reply_stack = new RCommandStack ();
  	request->in_chain = reply_stack->startChain (reply_stack);
***************
*** 289,292 ****
--- 314,320 ----
  	RK_TRACE (RBACKEND);
  
+ 	MUTEX_LOCK;
+ 	flushOutput ();
+ 	MUTEX_UNLOCK;
  	args->done = false;
  
***************
*** 347,350 ****
--- 375,381 ----
  	// TODO: error-handling?
  
+ 	MUTEX_LOCK;
+ 	flushOutput ();
+ 	MUTEX_UNLOCK;
  	QCustomEvent *event = new QCustomEvent (RCOMMAND_OUT_EVENT);
  	event->setData (current_command);

Index: rinterface.cpp
===================================================================
RCS file: /cvsroot/rkward/rkward/rkward/rbackend/rinterface.cpp,v
retrieving revision 1.37
retrieving revision 1.38
diff -C2 -d -r1.37 -r1.38
*** rinterface.cpp	2 Nov 2005 21:11:38 -0000	1.37
--- rinterface.cpp	3 Nov 2005 15:24:56 -0000	1.38
***************
*** 45,48 ****
--- 45,49 ----
  
  #include <qdir.h>
+ #include <qtimer.h>
  
  #include <stdlib.h>
***************
*** 50,56 ****
  #include <signal.h>
  
  //static
! QMutex RInterface::mutex;
! //int RInterface::mutex_counter;
  
  RInterface::RInterface () {
--- 51,62 ----
  #include <signal.h>
  
+ // update output (for immediate output commands) at least this often:
+ #define FLUSH_INTERVAL 50
+ 
  //static
! QMutex RInterface::mutex (true);
! #ifdef DEBUG_MUTEX
! 	int RInterface::mutex_counter;
! #endif // DEBUG_MUTEX
  
  RInterface::RInterface () {
***************
*** 84,90 ****
  	
  	r_thread = new RThread ();
- 	r_thread->start ();
  
  	watch = new RKwatch ();
  }
  
--- 90,101 ----
  	
  	r_thread = new RThread ();
  
  	watch = new RKwatch ();
+ 
+ 	flush_timer = new QTimer (this);
+ 	connect (flush_timer, SIGNAL (timeout ()), this, SLOT (flushOutput ()));
+ 	flush_timer->start (FLUSH_INTERVAL);
+ 
+ 	r_thread->start ();
  }
  
***************
*** 112,116 ****
  		// if the thread did not exit, yet - bad luck.
  	}
! 	
  	delete watch;
  }
--- 123,128 ----
  		// if the thread did not exit, yet - bad luck.
  	}
! 
! 	delete flush_timer;
  	delete watch;
  }
***************
*** 175,178 ****
--- 187,198 ----
  }
  
+ void RInterface::flushOutput () {
+ // do not trace. called periodically
+ //	RK_TRACE (RBACKEND);
+ 	MUTEX_LOCK;
+ 	r_thread->flushOutput ();
+ 	MUTEX_UNLOCK;
+ }
+ 
  void RInterface::issueCommand (RCommand *command, RCommandChain *chain) { 
  	RK_TRACE (RBACKEND);





More information about the rkward-tracker mailing list