[dev] [st] Removing timeouts in main loop

2012-09-16 Thread Roberto E. Vargas Caballero
This serie of patches try fix the problem of the timeout in main loop, which
causes st wakeup each 20 ms even thare is noting to do.

Please send comments and suggestion.

Best regards.
From 48aac423ea93820f8a406da3f4e53c8ce4bcb2a6 Mon Sep 17 00:00:00 2001
From: Roberto E. Vargas Caballero k...@shike2.com
Date: Fri, 14 Sep 2012 21:09:51 +0200
Subject:  Call XdbeQueryExtension before of calling any Xdbe
 function

XdbeQueryExtension() tells to the caller if the Xdbe extension is present in
the X server, so it should be called for sanity. But like is said in
XdbeQueryExtension(3):

	No other Xdbe functions may be called before this function.  If a
	client violates this rule, the effects of all subsequent Xdbe calls
	that it makes are undefined.

it is mandatory call this function.
---
 st.c |5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/st.c b/st.c
index 2e1ac67..b013bca 100644
--- a/st.c
+++ b/st.c
@@ -1970,7 +1970,7 @@ xinit(void) {
 	XSetWindowAttributes attrs;
 	Cursor cursor;
 	Window parent;
-	int sw, sh;
+	int sw, sh, major, minor;
 
 	if(!(xw.dpy = XOpenDisplay(NULL)))
 		die(Can't open display\n);
@@ -2021,9 +2021,10 @@ xinit(void) {
 			CWBackPixel | CWBorderPixel | CWBitGravity | CWEventMask
 			| CWColormap,
 			attrs);
+	if(!XdbeQueryExtension(xw.dpy, major, minor))
+		die(Xdbe extension is not present\n);
 	xw.buf = XdbeAllocateBackBufferName(xw.dpy, xw.win, XdbeCopied);
 
-
 	/* input methods */
 	xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL);
 	xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
-- 
1.7.10.4

From 56695b6abf41b1d3b7880666d959b7dadef741da Mon Sep 17 00:00:00 2001
From: Roberto E. Vargas Caballero k...@shike2.com
Date: Sat, 15 Sep 2012 12:03:37 +0200
Subject:  Call XSync in redraw

It is necessary call to XSync if you want a good tput flash, because in
other way you can not be sure that white screen will be shown.
---
 st.c |1 +
 1 file changed, 1 insertion(+)

diff --git a/st.c b/st.c
index b013bca..f4ad23d 100644
--- a/st.c
+++ b/st.c
@@ -2150,6 +2150,7 @@ redraw(void) {
 	struct timespec tv = {0, REDRAW_TIMEOUT * 1000};
 	tfulldirt();
 	draw();
+	XSync(xw.dpy, False); /* necessary for a good tput flash */
 	nanosleep(tv, NULL);
 }
 
-- 
1.7.10.4

From 124fe0dd1575401437093d1f6396ca7655ca5680 Mon Sep 17 00:00:00 2001
From: Roberto E. Vargas Caballero k...@shike2.com
Date: Sat, 15 Sep 2012 20:55:27 +0200
Subject:  Remove timeout in the main loop

The main loop waits until there is some data to read in file descriptors of
the X server or the pseudo tty. But it uses a timeout in select(), which
causes that st awake each 20 ms, even it doesn't have something to do. This
patch removes this problem removing the timeout, which is not needed.
---
 TODO |1 -
 st.c |   27 +++
 2 files changed, 3 insertions(+), 25 deletions(-)

diff --git a/TODO b/TODO
index 1996137..c77c105 100644
--- a/TODO
+++ b/TODO
@@ -15,7 +15,6 @@ code  interface
 
 * clean selection code
 * clean and complete terminfo entry
-* remove the timeouts in the main loop
 
 bugs
 
diff --git a/st.c b/st.c
index f4ad23d..d7ca875 100644
--- a/st.c
+++ b/st.c
@@ -53,8 +53,6 @@
 #define XK_NO_MOD UINT_MAX
 #define XK_ANY_MOD0
 
-#define SELECT_TIMEOUT (20*1000) /* 20 ms */
-#define DRAW_TIMEOUT  (20*1000) /* 20 ms */
 #define REDRAW_TIMEOUT (80*1000) /* 80 ms */
 
 #define SERRNO strerror(errno)
@@ -205,7 +203,6 @@ typedef struct {
 	int ch; /* char height */
 	int cw; /* char width  */
 	char state; /* focus, redraw, visible */
-	struct timeval lastdraw;
 } XWindow;
 
 typedef struct {
@@ -250,7 +247,6 @@ static void drawregion(int, int, int, int);
 static void execsh(void);
 static void sigchld(int);
 static void run(void);
-static bool last_draw_too_old(void);
 
 static void csidump(void);
 static void csihandle(void);
@@ -2158,7 +2154,6 @@ void
 draw() {
 	drawregion(0, 0, term.col, term.row);
 	xcopy();
-	gettimeofday(xw.lastdraw, NULL);
 }
 
 void
@@ -2345,41 +2340,25 @@ resize(XEvent *e) {
 	ttyresize(col, row);
 }
 
-bool
-last_draw_too_old(void) {
-	struct timeval now;
-	gettimeofday(now, NULL);
-	return TIMEDIFF(now, xw.lastdraw) = DRAW_TIMEOUT/1000;
-}
-
 void
 run(void) {
 	XEvent ev;
 	fd_set rfd;
 	int xfd = XConnectionNumber(xw.dpy);
-	struct timeval timeout = {0};
-	bool stuff_to_print = 0;
 
 	for(;;) {
 		FD_ZERO(rfd);
 		FD_SET(cmdfd, rfd);
 		FD_SET(xfd, rfd);
-		timeout.tv_sec  = 0;
-		timeout.tv_usec = SELECT_TIMEOUT;
-		if(select(MAX(xfd, cmdfd)+1, rfd, NULL, NULL, timeout)  0) {
+		if(select(MAX(xfd, cmdfd)+1, rfd, NULL, NULL, NULL)  0) {
 			if(errno == EINTR)
 continue;
 			die(select failed: %s\n, SERRNO);
 		}
-		if(FD_ISSET(cmdfd, rfd)) {
+		if(FD_ISSET(cmdfd, rfd))
 			ttyread();
-			stuff_to_print = 1;
-		}
 
-		if(stuff_to_print  last_draw_too_old()) {
-			stuff_to_print = 0;
-			draw();
-		}
+		draw();
 
 		while(XPending(xw.dpy)) {
 			XNextEvent(xw.dpy, ev);
-- 
1.7.10.4

From 

Re: [dev] [st] Removing timeouts in main loop

2012-09-16 Thread stanio
* Roberto E. Vargas Caballero k...@shike2.com [2012-09-16 09:48]:
 The main loop waits until there is some data to read in file descriptors of
 the X server or the pseudo tty. But it uses a timeout in select(), which
 causes that st awake each 20 ms, even it doesn't have something to do. This
 patch removes this problem removing the timeout, which is not needed.

I think this was supposed to make st faster, since it doesn't need to
draw things you'll never be able to read, i.e. anything faster than
20ms. 

--s_



Re: [dev] [st] Removing timeouts in main loop

2012-09-16 Thread Aurélien Aptel
On Sun, Sep 16, 2012 at 9:47 AM, Roberto E. Vargas Caballero
k...@shike2.com wrote:
 This serie of patches try fix the problem of the timeout in main loop, which
 causes st wakeup each 20 ms even thare is noting to do.

The timeout problem was introduced to speed up the rendering when a
lot of text is printed.
The logic is basically to not redraw on every read when the throughput is high:
- try to read data for SELECT_TIMEOUT ms max
- if something was read, handle it in the term
- if something was read and the last call to draw was more than
DRAW_TIMEOUT ms ago then redraw.

I don't have a unix machine at the moment but here is a simple testcase:

$ dd if=/dev/random bs=4K count=100 | hexdump

Increase the count and compare with other terms if necessary.



Re: [dev] [st] Removing timeouts in main loop

2012-09-16 Thread Aurélien Aptel
On Sun, Sep 16, 2012 at 11:51 AM, Aurélien Aptel
aurelien.ap...@gmail.com wrote:
 - try to read data for SELECT_TIMEOUT ms max
 - if something was read, handle it in the term
 - if something was read and the last call to draw was more than
 DRAW_TIMEOUT ms ago then redraw.

In retrospect, the Right Thing would be to have the SELECT_TIMEOUT
only if something is waiting to be redrawn i.e. after a call to draw,
always use select() with a NULL timeout.



Re: [dev] [st] Removing timeouts in main loop

2012-09-16 Thread Roberto E. Vargas Caballero
 The timeout problem was introduced to speed up the rendering when a
 lot of text is printed.
 The logic is basically to not redraw on every read when the throughput is 
 high:

I tried do the same thing putting the draw at the end of the loop, so if you
have a high throughput you will read more characters in ttyread and you will
do more operations that will not be rended.

Maybe a way to improve my patches is testing is some data can be read from
the file descriptors and in this case continue the loop. something like:

int i = 0;
for(;;) {
FD_ZERO(rfd);
FD_SET(cmdfd, rfd);
FD_SET(xfd, rfd);
if(select(MAX(xfd, cmdfd)+1, rfd, NULL, NULL, NULL)  0)
if(errno == EINTR)
 continue;
die(select failed: %s\n, SERRNO);
}
repeat:
if(FD_ISSET(cmdfd, rfd))
ttyread();

while(XPending(xw.dpy)) {
  XNextEvent(xw.dpy, ev);
  if(XFilterEvent(ev, xw.win))
  continue;
  if(handler[ev.type])
 (handler[ev.type])(ev);
}
if(i++  4) {
   struct timeval tv = {0};
   FD_ZERO(rfd);
   FD_SET(cmdfd, rfd);
   FD_SET(xfd, rfd);
   if(select(MAX(xfd, cmdfd)+1, rfd, NULL, NULL, tv)  0)
 goto repeat;
}
i = 0;
draw();
XFlush(xw.dpy);
}


 I don't have a unix machine at the moment but here is a simple testcase:

 $ dd if=/dev/random bs=4K count=100 | hexdump

 Increase the count and compare with other terms if necessary.

$ time dd if=/dev/zero bs=4K count=100 | hexdump -C -v

st before patches:

real  0m1.250s
user  0m0.616s
sys   0m0.308s

st after patches:

real 0m1.151s
user 0m0.536s
sys  0m0.296s


xterm:

real0m4.501s
user0m0.380s
sys 0m0.156s


uxterm:

real0m1.384s
user0m0.492s
sys 0m0.256s



Re: [dev] [st] Removing timeouts in main loop

2012-09-16 Thread Roberto E. Vargas Caballero
 Maybe a way to improve my patches is testing is some data can be read from
 the file descriptors and in this case continue the loop. something like:


   if(i++  4) {
  struct timeval tv = {0};
  FD_ZERO(rfd);
  FD_SET(cmdfd, rfd);
FD_SET(xfd, rfd);
  if(select(MAX(xfd, cmdfd)+1, rfd, NULL, NULL, tv)  0)
goto repeat;
 }
   i = 0;

Uhmmm, this is not a good idea, because it is pretty similar than
increase the input buffer by 4.



Re: [dev] [st] Removing timeouts in main loop

2012-09-16 Thread Christoph Lohmann
Hello.

On Sun, 16 Sep 2012 12:26:21 +0200 Aurélien Aptel aurelien.ap...@gmail.com 
wrote:
 On Sun, Sep 16, 2012 at 9:47 AM, Roberto E. Vargas Caballero
 k...@shike2.com wrote:
  This serie of patches try fix the problem of the timeout in main loop, which
  causes st wakeup each 20 ms even thare is noting to do.
 
 The timeout problem was introduced to speed up the rendering when a
 lot of text is printed.
 The logic is basically to not redraw on every read when the throughput is 
 high:
 - try to read data for SELECT_TIMEOUT ms max
 - if something was read, handle it in the term
 - if something was read and the last call to draw was more than
 DRAW_TIMEOUT ms ago then redraw.
 
 I don't have a unix machine at the moment but here is a simple testcase:
 
 $ dd if=/dev/random bs=4K count=100 | hexdump
 
 Increase the count and compare with other terms if necessary.

Look at tip. I added a solution mostly based on heuristics, but it works
and it’s simple.

If  there  is  something  to read from the tty, handle it, then wait for
five microseconds in select() and see if the  buffer  filled  again.  If
yes,  handle  this and do it again. After a certain amount of such loops
(1000) break and redraw the terminal. This arbitary break is  there  be‐
cause  without  it  the user would see a stuttering in the output and it
seems to go wrong. This loop number is related to my development machine
and  a  better  solution  to calculate or replace it with a more natural
value would be more fitting solution.

In  the  benchmark  you  proposed (count=500) I could reproduce the same
times as urxvt with the above changes.


Sincerely,

Christoph Lohmann




Re: [dev] [st] Removing timeouts in main loop

2012-09-16 Thread Aurélien Aptel
On Sun, Sep 16, 2012 at 12:26 PM, Christoph Lohmann 2...@r-36.net wrote:
 If  there  is  something  to read from the tty, handle it, then wait for
 five microseconds in select() and see if the  buffer  filled  again.  If
 yes,  handle  this and do it again. After a certain amount of such loops
 (1000) break and redraw the terminal. This arbitary break is  there  be‐
 cause  without  it  the user would see a stuttering in the output and it
 seems to go wrong. This loop number is related to my development machine
 and  a  better  solution  to calculate or replace it with a more natural
 value would be more fitting solution.

I'm not really sure it's simpler then. I will look into it tonight.

 In  the  benchmark  you  proposed (count=500) I could reproduce the same
 times as urxvt with the above changes.

I've made a mistake in the command, you should use /dev/urandom
instead of /dev/random because the latter can block on read, see $ man
4 random.



Re: [dev] [st] Removing timeouts in main loop

2012-09-16 Thread Christoph Lohmann
Hello.

On Sun, 16 Sep 2012 14:00:44 +0200 Aurélien Aptel aurelien.ap...@gmail.com 
wrote:
 On Sun, Sep 16, 2012 at 12:26 PM, Christoph Lohmann 2...@r-36.net wrote:
  If  there  is  something  to read from the tty, handle it, then wait for
  five microseconds in select() and see if the  buffer  filled  again.  If
  yes,  handle  this and do it again. After a certain amount of such loops
  (1000) break and redraw the terminal. This arbitary break is  there  be‐
  cause  without  it  the user would see a stuttering in the output and it
  seems to go wrong. This loop number is related to my development machine
  and  a  better  solution  to calculate or replace it with a more natural
  value would be more fitting solution.
 
 I'm not really sure it's simpler then. I will look into it tonight.
 
  In  the  benchmark  you  proposed (count=500) I could reproduce the same
  times as urxvt with the above changes.
 
 I've made a mistake in the command, you should use /dev/urandom
 instead of /dev/random because the latter can block on read, see $ man
 4 random.

Yes,  thanks. I forgot to mention that I changed it to /dev/urandom when
doing the comparison. Thinkpads don’t have the magic entropy device yet.
:(


Sincerely,

Christoph