~ubuntu-branches/ubuntu/lucid/boinc/lucid-backports

« back to all changes in this revision

Viewing changes to client/cs_prefs.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Rene Mayorga
  • Date: 2009-05-23 13:29:17 UTC
  • mfrom: (1.3.1 upstream) (9.1.1 experimental)
  • Revision ID: james.westby@ubuntu.com-20090523132917-3rvmkmkxbw17181o
Tags: 6.4.5+dfsg-2
* Uploaded to unstable
* Include a patch picked from Upstream SVN
   to avoid FTBFSs whith gcc 4.4 (Closes: #526666)
* remove CUDA dir that contais binary-only non DFSG software
* change section from boinc-dbg to debug
* set orig +dfsg since we remove non-dfsg software 
  when we pull the tag from upstream
  + Add Comments about this on README.Source
* Move schedtool to Recommends, (Closes: #532133)
* Add ru debconf templates translation, thanks
  to Yuri Kozlov <yuray@komyakino.ru> (Closes: #531205)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// This file is part of BOINC.
 
2
// http://boinc.berkeley.edu
 
3
// Copyright (C) 2008 University of California
 
4
//
 
5
// BOINC is free software; you can redistribute it and/or modify it
 
6
// under the terms of the GNU Lesser General Public License
 
7
// as published by the Free Software Foundation,
 
8
// either version 3 of the License, or (at your option) any later version.
 
9
//
 
10
// BOINC is distributed in the hope that it will be useful,
 
11
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
13
// See the GNU Lesser General Public License for more details.
 
14
//
 
15
// You should have received a copy of the GNU Lesser General Public License
 
16
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
 
17
 
 
18
// Logic related to general (also known as global) preferences:
 
19
// when to compute, how much disk to use, etc.
 
20
//
 
21
 
 
22
#ifdef _WIN32
 
23
#include "boinc_win.h"
 
24
#endif
 
25
 
 
26
#ifndef _WIN32
 
27
#include "config.h"
 
28
#if HAVE_SYS_STAT_H
 
29
#include <sys/stat.h>
 
30
#endif
 
31
#if HAVE_SYS_TYPES_H
 
32
#include <sys/types.h>
 
33
#endif
 
34
#endif
 
35
 
 
36
#include "str_util.h"
 
37
#include "util.h"
 
38
#include "filesys.h"
 
39
#include "parse.h"
 
40
#include "file_names.h"
 
41
#include "cpu_benchmark.h"
 
42
#include "client_msgs.h"
 
43
#include "client_state.h"
 
44
 
 
45
using std::min;
 
46
using std::string;
 
47
 
 
48
#define MAX_PROJ_PREFS_LEN  65536
 
49
    // max length of project-specific prefs
 
50
 
 
51
// Return the maximum allowed disk usage as determined by user preferences.
 
52
// There are three different settings in the prefs;
 
53
// return the least of the three.
 
54
//
 
55
double CLIENT_STATE::allowed_disk_usage(double boinc_total) {
 
56
    double limit_pct, limit_min_free, limit_abs;
 
57
 
 
58
    limit_pct = host_info.d_total*global_prefs.disk_max_used_pct/100.0;
 
59
    limit_min_free = boinc_total + host_info.d_free - global_prefs.disk_min_free_gb*GIGA;
 
60
    limit_abs = global_prefs.disk_max_used_gb*(GIGA);
 
61
 
 
62
    double size = min(min(limit_abs, limit_pct), limit_min_free);
 
63
    if (size < 0) size = 0;
 
64
    return size;
 
65
}
 
66
 
 
67
int CLIENT_STATE::project_disk_usage(PROJECT* p, double& size) {
 
68
    char buf[256];
 
69
    unsigned int i;
 
70
    double s;
 
71
 
 
72
    get_project_dir(p, buf, sizeof(buf));
 
73
    dir_size(buf, size);
 
74
 
 
75
    for (i=0; i<active_tasks.active_tasks.size(); i++) {
 
76
        ACTIVE_TASK* atp = active_tasks.active_tasks[i];
 
77
        if (atp->wup->project != p) continue;
 
78
        get_slot_dir(atp->slot, buf, sizeof(buf));
 
79
        dir_size(buf, s);
 
80
        size += s;
 
81
    }
 
82
 
 
83
    return 0;
 
84
}
 
85
 
 
86
int CLIENT_STATE::total_disk_usage(double& size) {
 
87
    return dir_size(".", size);
 
88
}
 
89
 
 
90
// See if we should suspend processing
 
91
//
 
92
int CLIENT_STATE::check_suspend_processing() {
 
93
    if (are_cpu_benchmarks_running()) {
 
94
        return SUSPEND_REASON_BENCHMARKS;
 
95
    }
 
96
 
 
97
    if (config.start_delay && now < client_start_time + config.start_delay) {
 
98
        return SUSPEND_REASON_INITIAL_DELAY;
 
99
    }
 
100
 
 
101
    switch(run_mode.get_current()) {
 
102
    case RUN_MODE_ALWAYS: break;
 
103
    case RUN_MODE_NEVER:
 
104
        return SUSPEND_REASON_USER_REQ;
 
105
    default:
 
106
        if (!global_prefs.run_on_batteries
 
107
            && host_info.host_is_running_on_batteries()
 
108
        ) {
 
109
            return SUSPEND_REASON_BATTERIES;
 
110
        }
 
111
 
 
112
        if (!global_prefs.run_if_user_active && user_active) {
 
113
            return SUSPEND_REASON_USER_ACTIVE;
 
114
        }
 
115
        if (global_prefs.cpu_times.suspended()) {
 
116
            return SUSPEND_REASON_TIME_OF_DAY;
 
117
        }
 
118
    }
 
119
 
 
120
    if (global_prefs.suspend_if_no_recent_input) {
 
121
        bool idle = host_info.users_idle(
 
122
            check_all_logins, global_prefs.suspend_if_no_recent_input
 
123
        );
 
124
        if (idle) {
 
125
            return SUSPEND_REASON_NO_RECENT_INPUT;
 
126
        }
 
127
    }
 
128
 
 
129
    if (global_prefs.cpu_usage_limit != 100) {
 
130
        static double last_time=0, debt=0;
 
131
        double diff = now - last_time;
 
132
        last_time = now;
 
133
        if (diff >= POLL_INTERVAL/2. && diff < POLL_INTERVAL*10.) {
 
134
            debt += diff*global_prefs.cpu_usage_limit/100;
 
135
            if (debt < 0) {
 
136
                return SUSPEND_REASON_CPU_USAGE_LIMIT;
 
137
            } else {
 
138
                debt -= diff;
 
139
            }
 
140
        }
 
141
    }
 
142
 
 
143
    if (active_tasks.exclusive_app_running) {
 
144
        return SUSPEND_REASON_EXCLUSIVE_APP_RUNNING;
 
145
    }
 
146
    return 0;
 
147
}
 
148
 
 
149
static string reason_string(int reason) {
 
150
    string s_reason;
 
151
    if (reason & SUSPEND_REASON_BATTERIES) {
 
152
        s_reason += " - on batteries";
 
153
    }
 
154
    if (reason & SUSPEND_REASON_USER_ACTIVE) {
 
155
        s_reason += " - user is active";
 
156
    }
 
157
    if (reason & SUSPEND_REASON_USER_REQ) {
 
158
        s_reason += " - user request";
 
159
    }
 
160
    if (reason & SUSPEND_REASON_TIME_OF_DAY) {
 
161
        s_reason += " - time of day";
 
162
    }
 
163
    if (reason & SUSPEND_REASON_BENCHMARKS) {
 
164
        s_reason += " - running CPU benchmarks";
 
165
    }
 
166
    if (reason & SUSPEND_REASON_DISK_SIZE) {
 
167
        s_reason += " - out of disk space - change global prefs";
 
168
    }
 
169
    if (reason & SUSPEND_REASON_NO_RECENT_INPUT) {
 
170
        s_reason += " - no recent user activity";
 
171
    }
 
172
    if (reason & SUSPEND_REASON_INITIAL_DELAY) {
 
173
        s_reason += " - initial delay";
 
174
    }
 
175
    if (reason & SUSPEND_REASON_EXCLUSIVE_APP_RUNNING) {
 
176
        s_reason += " - an exclusive app is running";
 
177
    }
 
178
    return s_reason;
 
179
}
 
180
 
 
181
void print_suspend_tasks_message(int reason) {
 
182
    string s_reason = "Suspending computation" + reason_string(reason);
 
183
    msg_printf(NULL, MSG_INFO, s_reason.c_str());
 
184
}
 
185
 
 
186
int CLIENT_STATE::suspend_tasks(int reason) {
 
187
    if (reason == SUSPEND_REASON_CPU_USAGE_LIMIT) {
 
188
        if (log_flags.cpu_sched) {
 
189
            msg_printf(NULL, MSG_INFO, "[cpu_sched] Suspending - CPU throttle");
 
190
        }
 
191
        active_tasks.suspend_all(true);
 
192
    } else {
 
193
        print_suspend_tasks_message(reason);
 
194
        active_tasks.suspend_all(false);
 
195
    }
 
196
    return 0;
 
197
}
 
198
 
 
199
int CLIENT_STATE::resume_tasks(int reason) {
 
200
    if (reason == SUSPEND_REASON_CPU_USAGE_LIMIT) {
 
201
        if (log_flags.cpu_sched) {
 
202
            msg_printf(NULL, MSG_INFO, "[cpu_sched] Resuming - CPU throttle");
 
203
        }
 
204
        active_tasks.unsuspend_all();
 
205
    } else {
 
206
        msg_printf(NULL, MSG_INFO, "Resuming computation");
 
207
        active_tasks.unsuspend_all();
 
208
        request_schedule_cpus("Resuming computation");
 
209
    }
 
210
    return 0;
 
211
}
 
212
 
 
213
int CLIENT_STATE::check_suspend_network() {
 
214
    switch(network_mode.get_current()) {
 
215
    case RUN_MODE_ALWAYS: return 0;
 
216
    case RUN_MODE_NEVER:
 
217
        return SUSPEND_REASON_USER_REQ;
 
218
    }
 
219
    if (!global_prefs.run_if_user_active && user_active) {
 
220
        return SUSPEND_REASON_USER_ACTIVE;
 
221
    }
 
222
    if (global_prefs.net_times.suspended()) {
 
223
        return SUSPEND_REASON_TIME_OF_DAY;
 
224
    }
 
225
    return 0;
 
226
}
 
227
 
 
228
int CLIENT_STATE::suspend_network(int reason) {
 
229
    string s_reason;
 
230
    s_reason = "Suspending network activity" + reason_string(reason);
 
231
    msg_printf(NULL, MSG_INFO, s_reason.c_str());
 
232
    pers_file_xfers->suspend();
 
233
    return 0;
 
234
}
 
235
 
 
236
int CLIENT_STATE::resume_network() {
 
237
    msg_printf(NULL, MSG_INFO, "Resuming network activity");
 
238
    return 0;
 
239
}
 
240
 
 
241
// call this only after parsing global prefs
 
242
//
 
243
PROJECT* CLIENT_STATE::global_prefs_source_project() {
 
244
    return lookup_project(global_prefs.source_project);
 
245
}
 
246
 
 
247
void CLIENT_STATE::show_global_prefs_source(bool found_venue) {
 
248
    PROJECT* pp = global_prefs_source_project();
 
249
    if (pp) {
 
250
        msg_printf(NULL, MSG_INFO,
 
251
            "General prefs: from %s (last modified %s)",
 
252
            pp->get_project_name(), time_to_string(global_prefs.mod_time)
 
253
        );
 
254
    } else {
 
255
        msg_printf(NULL, MSG_INFO,
 
256
            "General prefs: from %s (last modified %s)",
 
257
            global_prefs.source_project,
 
258
            time_to_string(global_prefs.mod_time)
 
259
        );
 
260
    }
 
261
    if (strlen(main_host_venue)) {
 
262
                msg_printf(NULL, MSG_INFO, "Computer location: %s", main_host_venue);
 
263
        if (found_venue) {
 
264
            msg_printf(NULL, MSG_INFO,
 
265
                "General prefs: using separate prefs for %s", main_host_venue
 
266
            );
 
267
        } else {
 
268
            msg_printf(NULL, MSG_INFO,
 
269
                "General prefs: no separate prefs for %s; using your defaults",
 
270
                main_host_venue
 
271
            );
 
272
        }
 
273
    } else {
 
274
                msg_printf(NULL, MSG_INFO, "Host location: none");
 
275
        msg_printf(NULL, MSG_INFO, "General prefs: using your defaults");
 
276
    }
 
277
}
 
278
 
 
279
// parse user's project preferences,
 
280
// generating FILE_REF and FILE_INFO objects for each <app_file> element.
 
281
//
 
282
int PROJECT::parse_preferences_for_user_files() {
 
283
    char buf[1024];
 
284
    string timestamp, open_name, url, filename;
 
285
    FILE_INFO* fip;
 
286
    FILE_REF fr;
 
287
 
 
288
    user_files.clear();
 
289
    size_t n=0, start, end;
 
290
    while (1) {
 
291
        start = project_specific_prefs.find("<app_file>", n);
 
292
        if (start == string::npos) break;
 
293
        end = project_specific_prefs.find("</app_file>", n);
 
294
        if (end == string::npos) break;
 
295
        start += strlen("<app_file>");
 
296
        string x = project_specific_prefs.substr(start, end);
 
297
        n = end + strlen("</app_file>");
 
298
 
 
299
        strlcpy(buf, x.c_str(), sizeof(buf));
 
300
        if (!parse_str(buf, "<timestamp>", timestamp)) break;
 
301
        if (!parse_str(buf, "<open_name>", open_name)) break;
 
302
        if (!parse_str(buf, "<url>", url)) break;
 
303
 
 
304
        filename = open_name + "_" + timestamp;
 
305
        fip = gstate.lookup_file_info(this, filename.c_str());
 
306
        if (!fip) {
 
307
            fip = new FILE_INFO;
 
308
            fip->project = this;
 
309
            fip->urls.push_back(url);
 
310
            strcpy(fip->name, filename.c_str());
 
311
            fip->is_user_file = true;
 
312
            gstate.file_infos.push_back(fip);
 
313
        }
 
314
 
 
315
        fr.file_info = fip;
 
316
        strcpy(fr.open_name, open_name.c_str());
 
317
        user_files.push_back(fr);
 
318
    }
 
319
    return 0;
 
320
}
 
321
 
 
322
// Read global preferences into the global_prefs structure.
 
323
// 1) read the override file to get venue in case it's there
 
324
// 2) read global_prefs.xml
 
325
// 3) read the override file again
 
326
//
 
327
// This is called:
 
328
// - on startup
 
329
// - on completion of a scheduler or AMS RPC, if they sent prefs
 
330
// - in response to read_global_prefs_override GUI RPC
 
331
//
 
332
void CLIENT_STATE::read_global_prefs() {
 
333
    bool found_venue;
 
334
    int retval;
 
335
        FILE* f;
 
336
    string foo;
 
337
 
 
338
    retval = read_file_string(GLOBAL_PREFS_OVERRIDE_FILE, foo);
 
339
    if (!retval) {
 
340
                parse_str(foo.c_str(), "<host_venue>", main_host_venue, sizeof(main_host_venue));
 
341
        }
 
342
 
 
343
    retval = global_prefs.parse_file(
 
344
        GLOBAL_PREFS_FILE_NAME, main_host_venue, found_venue
 
345
    );
 
346
    if (retval) {
 
347
        if (retval == ERR_FOPEN) {
 
348
            msg_printf(NULL, MSG_INFO,
 
349
                "No general preferences found - using BOINC defaults"
 
350
            );
 
351
        } else {
 
352
            msg_printf(NULL, MSG_INFO,
 
353
                "Couldn't parse preferences file - using BOINC defaults"
 
354
            );
 
355
            boinc_delete_file(GLOBAL_PREFS_FILE_NAME);
 
356
            global_prefs.init();
 
357
        }
 
358
    } else {
 
359
                // check that the source project's venue matches main_host_venue.
 
360
                // If not, read file again.
 
361
                // This is a fix for cases where main_host_venue is out of synch
 
362
                //
 
363
                PROJECT* p = global_prefs_source_project();
 
364
                if (p && strcmp(main_host_venue, p->host_venue)) {
 
365
                        strcpy(main_host_venue, p->host_venue);
 
366
                        global_prefs.parse_file(GLOBAL_PREFS_FILE_NAME, main_host_venue, found_venue);
 
367
                }
 
368
        show_global_prefs_source(found_venue);
 
369
    }
 
370
 
 
371
    // read the override file
 
372
    //
 
373
    f = fopen(GLOBAL_PREFS_OVERRIDE_FILE, "r");
 
374
    if (f) {
 
375
        MIOFILE mf;
 
376
        GLOBAL_PREFS_MASK mask;
 
377
        mf.init_file(f);
 
378
        XML_PARSER xp(&mf);
 
379
        global_prefs.parse_override(xp, "", found_venue, mask);
 
380
        msg_printf(NULL, MSG_INFO, "Reading preferences override file");
 
381
        fclose(f);
 
382
    }
 
383
 
 
384
    msg_printf(NULL, MSG_INFO,
 
385
                "Preferences limit memory usage when active to %.2fMB",
 
386
        (host_info.m_nbytes*global_prefs.ram_max_used_busy_frac)/MEGA
 
387
    );
 
388
    msg_printf(NULL, MSG_INFO,
 
389
                "Preferences limit memory usage when idle to %.2fMB",
 
390
                (host_info.m_nbytes*global_prefs.ram_max_used_idle_frac)/MEGA
 
391
    );
 
392
    double x;
 
393
    total_disk_usage(x);
 
394
    msg_printf(NULL, MSG_INFO,
 
395
                "Preferences limit disk usage to %.2fGB",
 
396
        allowed_disk_usage(x)/GIGA
 
397
    );
 
398
    // max_cpus, bandwidth limits may have changed
 
399
    //
 
400
    set_ncpus();
 
401
    if (ncpus != host_info.p_ncpus) {
 
402
        msg_printf(NULL, MSG_INFO,
 
403
            "Preferences limit # CPUs to %d", ncpus
 
404
        );
 
405
    }
 
406
        file_xfers->set_bandwidth_limits(true);
 
407
        file_xfers->set_bandwidth_limits(false);
 
408
        request_schedule_cpus("Prefs update");
 
409
        request_work_fetch("Prefs update");
 
410
}
 
411
 
 
412
int CLIENT_STATE::save_global_prefs(
 
413
    char* global_prefs_xml, char* master_url, char* scheduler_url
 
414
) {
 
415
    FILE* f = boinc_fopen(GLOBAL_PREFS_FILE_NAME, "w");
 
416
    if (!f) return ERR_FOPEN;
 
417
    fprintf(f,
 
418
        "<global_preferences>\n"
 
419
    );
 
420
 
 
421
    // tag with the project and scheduler URL,
 
422
    // but only if not already tagged
 
423
    //
 
424
    if (!strstr(global_prefs_xml, "<source_project>")) {
 
425
        fprintf(f,
 
426
            "    <source_project>%s</source_project>\n"
 
427
            "    <source_scheduler>%s</source_scheduler>\n",
 
428
            master_url,
 
429
            scheduler_url
 
430
        );
 
431
    }
 
432
    fprintf(f,
 
433
        "%s"
 
434
        "</global_preferences>\n",
 
435
        global_prefs_xml
 
436
    );
 
437
    fclose(f);
 
438
    return 0;
 
439
}
 
440
 
 
441
// amount of RAM usable now
 
442
//
 
443
double CLIENT_STATE::available_ram() {
 
444
    if (user_active) {
 
445
        return host_info.m_nbytes * global_prefs.ram_max_used_busy_frac;
 
446
    } else {
 
447
                return host_info.m_nbytes * global_prefs.ram_max_used_idle_frac;
 
448
    }
 
449
}
 
450
 
 
451
// max amount that will ever be usable
 
452
//
 
453
double CLIENT_STATE::max_available_ram() {
 
454
        return host_info.m_nbytes*std::max(
 
455
                global_prefs.ram_max_used_busy_frac, global_prefs.ram_max_used_idle_frac
 
456
        );
 
457
}
 
458
 
 
459
const char *BOINC_RCSID_92ad99cddf = "$Id: cs_prefs.cpp 16388 2008-11-02 20:09:59Z davea $";