Ticket #463 (reopened Defect)

Opened 2 years ago

Last modified 3 months ago

user activity detection inoperative on Linux

Reported by: fthomas Assigned to: davea
Priority: Major Milestone: Undetermined
Component: Client - Daemon Version:
Keywords: patch Cc: davea

Description

Hi,

Since r13948 HOST_INFO::users_idle() in client/hostinfo_unix.C always returns true on Debian Linux and therefore the client doesn't suspend computation while the user is active (neither mouse nor keyboard activity is recognized). I compiled 5.10.27 with the previous HOST_INFO::users_idle() but all the #ifdefs removed and the resulting client suspends computation when the keyboard is used but doesn't suspend when the mouse is used. I thought this is because there is no /dev/mouse on my system, only /dev/input/mice and /dev/input/mouse0, but using both device files in HOST_INFO::users_idle() doesn't get computation suspending working when the mouse is used.

Grüße,
Frank

My global_prefs_override.xml contains the following relevant settings:

<global_preferences>
  ...
  <run_if_user_active>0</run_if_user_active>
  <idle_time_to_run>1.000000</idle_time_to_run>
  ...
</global_preferences>

Attachments

boinc-idlefix.patch (4.1 kB) - added by oteodoro on 01/04/08 22:05:18.
alternative mouse idle detection for linux clients
interrupts_idle.patch (1.7 kB) - added by fthomas on 04/14/08 05:20:29.
Patch to integrate interrupts_idle() into client/hostinfo_unix.C.

Change History

11/08/07 03:01:07 changed by fthomas

BTW: The part about not detecting mouse activity was also reported in #71 and #359. Ticket #71 was closed because of r13948, but as I said above this change does not fix the issue with broken mouse activity detection. Maybe #71 should be reopened?

12/02/07 06:53:39 changed by fthomas

Alex Malinovich confirmed independently from me that r13948 broke keyboard detection on Debian GNU/Linux, see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=448982#26.

12/02/07 07:37:25 changed by fthomas

I've just tested the official 5.10.28 Development version (Ubuntu Release - standard GUI) build from boinc.berkeley.edu and as expected it also does not detect keyboard and mouse activity on Debian GNU/Linux.

12/02/07 18:27:34 changed by davea

  • status changed from new to closed.
  • resolution set to fixed.

(In [14346]) - client: hopefully fix keyboard input detection on Linux

(may fix #463)

12/03/07 03:14:54 changed by fthomas

  • status changed from closed to reopened.
  • resolution deleted.

I've applied r14346 to 5.10.30 and built it, but keyboard input detection is still broken.

12/25/07 20:14:34 changed by davea

I don't have a desktop Debian system to test on; Frank, would you be able to debug this? (it should be something fairly simple)

(follow-up: ↓ 13 ) 12/30/07 05:08:43 changed by fthomas

Ok, here is what I found out. Negating check_all_logins results in the client suspending computation when there is activity on a terminal:

--- a/client/hostinfo_unix.C
+++ b/client/hostinfo_unix.C
@@ -965,7 +965,7 @@ bool HOST_INFO::users_idle(bool check_all_logins, double idl
     time_t idle_time = time(0) - (long) (60 * idle_time_to_run);

 #ifdef HAVE_UTMP_H
-    if (check_all_logins) {
+    if (!check_all_logins) {
         if (!all_logins_idle(idle_time)) return false;
     }
 #endif

Where activity on a terminal means either opening a terminal or typing something into a terminal. The client does not suspend when there is general keyboard activity, typing a URL into FireFox's location bar for example. With this change boinc behaves as before r13948. Was the check_all_logins parameter in function calls of users_idle() changed after r13948?

The device_idle(idle_time, "/dev/mouse") and device_idle(idle_time, "/dev/kbd") calls always return true on Debian GNU/Linux because there are no such device files (as I said in my initial report). They would be useless even if the device is changed to /dev/input/mouse0 (which exists on Debian) because its atime (time of last access) is always the time as the system booted up. My /dev is handled by udev, I don't know if the device's atime is updated, when udev is not used.

BTW: All tests were performed with the current code in trunk/boinc/.

12/30/07 14:45:24 changed by davea

  • status changed from reopened to closed.
  • resolution set to fixed.

(In [14449]) - Partly fix keyboard detection on Linux.

With this change, we detect opening a terminal or typing into a terminal; we don't detect typing into other applications. (from Frank Thomas). Partly fixes #463

01/04/08 22:05:18 changed by oteodoro

  • attachment boinc-idlefix.patch added.

alternative mouse idle detection for linux clients

01/04/08 22:05:51 changed by oteodoro

On my computer, Boinc segfaults on me when i pass --check_all_logins to boinc_client. The mouse fails to work also when I unpatched parts of the r13948 code. I created a patch for Linux to detect input mouse events from /dev/input/mouse0 which requires the CONFIG_INPUT_EVDEV kernel option. As of now, with this patch, both my keyboard and mouse events kill the project process and also the segfault gets avoided. It was patched against 5.8.28.

Tests that produced segfaults: 6.1.5 (trunk) fail, 5.10.29 fail, 5.10.28 fail, 5.10.27 fail, 5.10.26 good, 5.10.25 good, 5.10.21 good

01/04/08 22:06:44 changed by oteodoro

i mean 5.10.28

01/04/08 22:11:29 changed by oteodoro

the attachment didn't put the headers :( ill insert here

--- client/client_state.C.orig	2008-01-04 21:03:14.000000000 -0800
+++ client/client_state.C	2008-01-04 20:53:06.000000000 -0800
@@ -34,6 +34,10 @@
 #endif
 #endif
 
+#ifdef linux
+#include <sys/fcntl.h>
+#endif
+
 #include "parse.h"
 #include "str_util.h"
 #include "util.h"
@@ -125,6 +129,19 @@
     launched_by_manager = false;
     initialized = false;
     last_wakeup_time = dtime();
+#ifdef linux
+    mouse_moved = true;
+    mouse_event_t = time(NULL);
+    mouse_fd = open("/dev/input/mouse0", O_RDONLY);
+#endif    
+}
+
+CLIENT_STATE::~CLIENT_STATE()
+{
+#ifdef linux
+    if(mouse_fd != -1)
+        close(mouse_fd);
+#endif
 }
 
 void CLIENT_STATE::show_host_info() {
@@ -414,6 +431,10 @@
 		http_ops->get_fdset(curl_fds);
         all_fds = curl_fds;
         gui_rpcs.get_fdset(gui_rpc_fds, all_fds);
+#ifdef linux
+        FD_SET(mouse_fd, &all_fds.read_fds);
+        if (mouse_fd > all_fds.max_fd) all_fds.max_fd = mouse_fd;
+#endif        
         double_to_timeval(x, tv);
         n = select(
             all_fds.max_fd+1,
@@ -429,6 +451,17 @@
 
         http_ops->got_select(all_fds, x);
         gui_rpcs.got_select(all_fds);
+#ifdef linux
+        if (mouse_fd != -1) {
+            if (FD_ISSET(mouse_fd, &all_fds.read_fds)) {
+                char ps2_packet[3]; //assume ps/2 mouse protocol 3 byte packet
+                if(read(mouse_fd, ps2_packet, 3) == 3) {
+                    mouse_moved = true;
+                    mouse_event_t = time(NULL);
+                }
+            }
+        }
+#endif
 
         if (n==0) break;
 
@@ -496,6 +529,10 @@
 #ifdef __APPLE__
          , &idletime
 #endif
+#ifdef linux
+         , &mouse_moved
+         , mouse_event_t
+#endif
     );
 
     if (user_active != old_user_active) {
--- client/client_state.h.orig	2008-01-04 21:03:14.000000000 -0800
+++ client/client_state.h	2008-01-04 19:58:12.000000000 -0800
@@ -213,6 +213,7 @@
 // --------------- client_state.C:
 public:
     CLIENT_STATE();
+    ~CLIENT_STATE();    
     void show_host_info();
     int init();
     bool poll_slow_events();
@@ -243,6 +244,11 @@
     bool garbage_collect_always();
     bool update_results();
     int nresults_for_project(PROJECT*);
+#ifdef linux
+    int mouse_fd;
+    bool mouse_moved;
+    time_t mouse_event_t;
+#endif
 
 // --------------- cpu_sched.C:
 private:
--- client/hostinfo_unix.C.orig	2008-01-04 21:03:14.000000000 -0800
+++ client/hostinfo_unix.C	2008-01-04 19:58:12.000000000 -0800
@@ -946,6 +946,24 @@
     return (idleTime > (60 * idle_time_to_run));
 }
 
+#elif linux
+
+bool HOST_INFO::users_idle(bool check_all_logins, double idle_time_to_run, bool* mouse_moved, time_t mouse_event_t) {
+    time_t cur_time = time(NULL);
+    time_t idle_time = cur_time - (long) (60 * idle_time_to_run);
+    if (mouse_event_t != 0) {
+        if (mouse_moved && mouse_event_t < idle_time)
+            *mouse_moved = false;
+    }
+
+    bool idle_result = true;
+#ifdef HAVE_UTMP_H
+    idle_result = idle_result && all_logins_idle(idle_time);
+#endif
+    idle_result = idle_result && (mouse_moved ? !*mouse_moved : true);
+    return idle_result;
+}
+
 #else  // ! __APPLE__
 
 bool HOST_INFO::users_idle(bool check_all_logins, double idle_time_to_run) {
--- lib/hostinfo.h.orig	2008-01-04 21:03:21.000000000 -0800
+++ lib/hostinfo.h	2008-01-04 19:58:12.000000000 -0800
@@ -72,6 +72,8 @@
     bool host_is_running_on_batteries();
 #ifdef __APPLE__
     bool users_idle(bool check_all_logins, double idle_time_to_run, double *actual_idle_time=NULL);
+#elif linux
+    bool users_idle(bool check_all_logins, double idle_time_to_run, bool* mouse_moved = NULL, time_t mouse_event_t = 0);
 #else
     bool users_idle(bool check_all_logins, double idle_time_to_run);
 #endif
--- checkin_notes.orig	2008-01-04 21:03:32.000000000 -0800
+++ checkin_notes	2008-01-04 19:58:12.000000000 -0800
@@ -7985,3 +7985,13 @@
     mac_installer/
         release_boinc.sh
         release_GridRepublic.sh
+
+Orson Teodoro 04 Jan 2008
+    - Linux: Input event mouse idle detection and segfault fix
+    client/
+        client_state.C
+        client_state.h
+        hostinfo_unix.C
+        main.C
+    lib/
+        hostinfo.h

01/08/08 14:40:05 changed by davea

Ideally I'd like a simpler/smaller fix (e.g., not involving changes to client_state.C).

I think the same thing could be done entirely within one function, using a static fd variable, and using non-blocking I/O instead of select()

(in reply to: ↑ 7 ) 01/14/08 12:19:48 changed by fthomas

Replying to fthomas (myself):

Ok, here is what I found out. Negating check_all_logins results in the client suspending computation when there is activity on a terminal:

...

With this change boinc behaves as before r13948. Was the check_all_logins parameter in function calls of users_idle() changed after r13948?

I just found out that the client has the --check_all_logins option which sets the boolean CLIENT_STATE::check_all_logins to true if the client is started with it. Now if one starts the client with --check_all_logins activity detection will fail because of r14449. Instead of applying r14449 the BOINC client should be rather started with the --check_all_logins option, right? But what I don't understand is why activity detection worked before r13948 and without the --check_all_logins option, because the assignment of CLIENT_STATE::check_all_logins did not changed. Probably the use of --check_all_logins prior to r13948 also broke activity detection.

04/09/08 07:49:26 changed by fthomas

I've just toyed with Linux event interface to check for user input (from any input device) and this code snippet is the result:

#include <cstdio>
#include <ctime>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include <linux/input.h>

#define EVENT_DEVICES 32
static int fd[EVENT_DEVICES];
static time_t last_event = time(NULL);

void open_event_devs() {
    char event_dev[32];

    for (int i = 0; i < EVENT_DEVICES; i++) {
        sprintf(event_dev, "/dev/input/event%i", i);
        fd[i] = open(event_dev, O_RDONLY|O_NONBLOCK);
    }
}

bool event_devs_idle(time_t t) {
    struct input_event ev;
    bool retval = true;

    if (last_event > t) return false;

    for (int i = 0; i < EVENT_DEVICES; i++) {
        if (fd[i] == -1)
            continue;
        if (read(fd[i], &ev, sizeof(struct input_event)) < 0)
            continue;
        if (ev.time.tv_sec > t) {
            last_event = ev.time.tv_sec;
            retval = false;
        }
    }
    return retval;
}

int main(int argc, char** argv) {
    open_event_devs();

    while (1) {
        time_t idle_time = time(NULL) - 3;
        if (event_devs_idle(idle_time))
            printf("OOO System is idle...\n");
        else
            printf("XXX User is active...\n");
        usleep(500000);
    }
    return 0;
}

This seems to work but the problem with /dev/input/event%i is that they are normally only readable by root (as well as other files in /dev/input/). So probably my code example or oteodoro's patch are NOT applicable to solve this problem.

BTW: Some documentation about the Linux event interface is available here:

http://www.frogmouth.net/hid-doco/x401.html http://www.frogmouth.net/hid-doco/c537.html

04/11/08 13:48:51 changed by Ageless

  • status changed from closed to reopened.
  • resolution deleted.

04/11/08 13:51:18 changed by Ageless

  • version set to 5.10.45.
  • milestone changed from 5.10 to 6.2.

Reopening to allow others to add comments, if necessary. This thread on the BOINC Dev forums shows it isn't working in 5.10.45

I'll update the milestone as well. But is there any solution in sight before the release of BOINC 6.2?

(follow-up: ↓ 28 ) 04/11/08 16:39:05 changed by Dagorath

It isn't just Debian, it's broke on Fedora 8/7/5 too.

<rant> I can appreciate the fact that volunteers working on this problem have families and jobs as their top priority. All of us appreciate the tremendous effort you volunteers put forth and wish we had the skills/knowledge to help out. I hope this problem can be given a little more attention than it has been given because it seems a lot of people are turning to Linux as Vista proves to be just another M$ scam.

BOINC does a pretty decent job of living off spare CPU cycles but not always, probably due to badly designed/written science apps, etc. Therefore we have a backup... BOINC can be configured to suspend apps on keyboard/mouse activity. That backup absolutely must work on all platforms or BOINC will acquire the reputation for being a resource hog. Users will not overlook that sin and software reviewers and bloggers will spread the word if the problem continues.

My Fedora 8 and 5 hosts are at the disposal of anybody who needs to test fixes for this problem. Contact me direct at dagorath at shaw dot ca if it helps. </rant>

04/14/08 04:07:43 changed by fthomas

Heureka! I think I've found a possible solution for this problem by reading the /proc/interrupts file and counting the interrupts of the keyboard, mouse or a PS/2 device (but not of an USB HID). If the mouse is moved or a keystroke happens the interrupts counter is increased and activity can then be detected. And since /proc/interrupts is normally world-readable, file permissions are also not a problem. Here is the code:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <unistd.h>

FILE* f;
long irq_count[256];

bool interrupts_idle(time_t t) {
    static time_t last_irq = time(NULL);
    char line[256];
    int i = 0;
    long ccount = 0;

    rewind(f);
    while (fgets(line, sizeof(line), f)) {
        // Check for mouse, keyboard and PS/2 devices.
        if (strcasestr(line, "mouse") != NULL ||
            strcasestr(line, "keyboard") != NULL ||
            strcasestr(line, "i8042") != NULL) {
            // If any IRQ count changed, update last_irq.
            if (sscanf(line, "%d: %ld", &i, &ccount) == 2 &&
                irq_count[i] != ccount) {
                last_irq = time(NULL);
                irq_count[i] = ccount;
            }
        }
    }
    return last_irq < t ? true : false;
}

int main(int argc, char** argv) {
    f = fopen("/proc/interrupts", "r");
    if (! f)
        exit(1);

    while (1) {
        time_t idle_time = time(NULL) - 3;
        if (interrupts_idle(idle_time))
            printf("OOO System is idle...\n");
        else
            printf("XXX User is active...\n");
        usleep(500000);
    }
    exit(0);
}

BTW: Can somebody (with the required permissions) please change the title of this ticket to "user activity detection partially inoperative on Linux", thanks.

04/14/08 05:20:29 changed by fthomas

  • attachment interrupts_idle.patch added.

Patch to integrate interrupts_idle() into client/hostinfo_unix.C.

04/14/08 05:28:09 changed by fthomas

Ok, I've just added the file interrupts_idle.patch which adds interrupts_idle() to client/hostinfo_unix.C. It seems to work fine for me. David, can you please test it and maybe improve the code.

(follow-up: ↓ 23 ) 04/14/08 15:23:02 changed by davea

  • summary changed from user activity detection got broken with r13948 on Debian Linux to user activity detection partially inoperative on.

I checked in the interrupts_idle() code.

Should we get rid of the other checks (e.g., all_tty_idle(), device_idle())?

04/14/08 15:33:18 changed by Nicolas

[15049]: improved user idle checking on Linux

Nobody said it's completely fixed, though :)

04/14/08 15:33:33 changed by Nicolas

  • summary changed from user activity detection partially inoperative on to user activity detection partially inoperative on Linux.

Fix title.

(in reply to: ↑ 20 ) 04/15/08 02:59:43 changed by fthomas

Replying to davea:

I checked in the interrupts_idle() code.

Thanks. I noticed that other functions that read from files under /proc are guarded by "#if LINUX_LIKE_SYSTEM". Should the interrupts_idle() call be guarded by this too? I also want to note that interrupts_idle() will always return false when it is first called. That means that boinc_client after it has been started always assumes that the user is not idle.

Should we get rid of the other checks (e.g., all_tty_idle(), device_idle())?

At least all_logins_idle() and all_tty_idle() should stay because interrupts_idle() will not detect activity from a remote login.

The question is if there are other systems where device_idle() works but interrupts_idle() not. Do other Unix-like systems even have /proc/interrupts? (According to http://en.wikipedia.org/wiki/Procfs /proc/interrupts seems to be a Linux extension)

10/02/08 07:13:35 changed by Dagorath

  • version deleted.
  • summary changed from user activity detection partially inoperative on Linux to user activity detection inoperative on Linux.

Are we sliding backwards on this issue? In BOINC 6.2.15 on Linux Fedora 5 and 6.2.14 on Fedora 9, BOINC fails to detect typing in a terminal. I was under the impression that much was working.

10/02/08 14:49:34 changed by davea

My test results on FC9 with 6.3.12:

PS/2 keyboard: detected PS/2 mouse: detected USB keyboard: detected USB mouse: not detected

Any ideas on how to detect USB mouse?

10/23/08 02:00:21 changed by Pepo

  • cc changed from fthomas to fthomas, Pepo.
  • keywords set to patch.

As it actually belongs here too (although it does not solve the issue BOINC-side, but is hopefully the right shot):

According to Rom Walton:

This may explain why we run across the keyboard and mouse activity detection in Linux every once and while:
http://www.cs.wisc.edu/condor/kernel.patch.html

Distributions that rely on the Linux 2.4.x and all Linux 2.6.x kernels through version 2.6.10, do not modify the atime of the input device file. [...] The problem manifests itself in that Condor cannot properly detect console USB keyboard or USB mouse activity.


The submitted 2.6.10 patch is adding just following to 6 different input devices' driver files:

if (retval > 0)
	file->f_dentry->d_inode->i_atime = CURRENT_TIME;

02/25/09 15:19:50 changed by romw

  • milestone changed from 6.6 to Undetermined.

(in reply to: ↑ 17 ; follow-up: ↓ 29 ) 05/09/09 17:36:52 changed by ex-user

Replying to Dagorath:

BOINC does a pretty decent job of living off spare CPU cycles but not always, probably due to badly designed/written science apps, etc. Therefore we have a backup... BOINC can be configured to suspend apps on keyboard/mouse activity. That backup absolutely must work on all platforms or BOINC will acquire the reputation for being a resource hog. Users will not overlook that sin and software reviewers and bloggers will spread the word if the problem continues.

Running Ubuntu 9.04 with BOINC 6.2.18 and this old bug still exist. I'm glad to share my idle CPU, but this bug is quite annoying, so I've uninstalled BOINC until it is fixed.

(in reply to: ↑ 28 ) 06/05/09 14:47:03 changed by LiSrt

Replying to ex-user:

Replying to Dagorath:

BOINC does a pretty decent job of living off spare CPU cycles but not always, probably due to badly designed/written science apps, etc. Therefore we have a backup... BOINC can be configured to suspend apps on keyboard/mouse activity. That backup absolutely must work on all platforms or BOINC will acquire the reputation for being a resource hog. Users will not overlook that sin and software reviewers and bloggers will spread the word if the problem continues.

Running Ubuntu 9.04 with BOINC 6.2.18 and this old bug still exist. I'm glad to share my idle CPU, but this bug is quite annoying, so I've uninstalled BOINC until it is fixed.

I am getting this on Mandriva 2009.1 with all updates and BOINC 6.6.31

It's only noticeable because with the CUDA functionality added, I only want the graphics card to be used by BOINC while I'm away from the computer, however the "in-use" detection appears broken.

As soon as I start BOINC, it will wait for however long I've specified in the "...idle for x minutes" preference before it starts hogging 100% of the GPU no matter if the mouse moves or stuff is typed in a word processor or browser. This is not acceptable - it causes freezing for several seconds at a time.

What is *odd* is that if I type in any terminal window, BOINC detects it and stops using the GPU...

(follow-up: ↓ 31 ) 06/05/09 15:02:32 changed by davea

The mechanisms for detecting activity differ between USB devices and PS2 devices, and they differ between distros and versions as well. We only have 1 Linux system for testing (FC10), and we rely on outside developers to provide code for the other cases. Can you point me to code for Ubuntu?

(in reply to: ↑ 30 ) 07/14/09 16:23:43 changed by fcestrada

  • cc changed from fthomas, Pepo to davea.

Replying to davea:

The mechanisms for detecting activity differ between USB devices and PS2 devices, and they differ between distros and versions as well. We only have 1 Linux system for testing (FC10), and we rely on outside developers to provide code for the other cases. Can you point me to code for Ubuntu?

This bug persists in Debian. I forwarded you in our system the bug http://bugs.debian.org/534273 and the Debian BOINC Maintainers want to help you to solve it. If you need any test or help, please contact us in pkg-boinc-devel@lists.alioth.debian.org or 534273@bugs.debian.org


If this page is incomplete or incorrect, please edit it or add it to the wiki to-do list. To do this, you must be logged in; click Login or Register above.