~ubuntu-branches/ubuntu/precise/boinc/precise

« back to all changes in this revision

Viewing changes to client/app.cpp

Tags: 6.12.8+dfsg-1
* New upstream release.
* Simplified debian/rules

Show diffs side-by-side

added added

removed removed

Lines of Context:
28
28
#endif
29
29
 
30
30
#ifndef _WIN32
31
 
 
32
31
#include <unistd.h>
33
32
#if HAVE_SYS_WAIT_H
34
33
#include <sys/wait.h>
51
50
#include <cstdio>
52
51
#include <cmath>
53
52
#include <cstdlib>
54
 
 
55
 
#endif
56
 
 
57
 
#ifdef SIM
58
 
#include "sim.h"
59
 
#else
60
 
#include "client_state.h"
61
 
#include "client_types.h"
62
 
#endif
 
53
#endif
 
54
 
63
55
 
64
56
#include "error_numbers.h"
65
57
#include "filesys.h"
67
59
#include "parse.h"
68
60
#include "shmem.h"
69
61
#include "str_util.h"
 
62
#include "str_replace.h"
 
63
#include "util.h"
 
64
 
 
65
#include "client_state.h"
70
66
#include "client_msgs.h"
71
67
#include "procinfo.h"
72
68
#include "sandbox.h"
75
71
using std::max;
76
72
using std::min;
77
73
 
78
 
#define ABORT_TIMEOUT   60
79
 
    // if we send app <abort> request, wait this long before killing it.
80
 
    // This gives it time to download symbol files (which can be several MB)
81
 
    // and write stack trace to stderr
82
 
#define QUIT_TIMEOUT    10
83
 
    // Same, for <quit>.  Shorter because no stack trace is generated
 
74
bool exclusive_app_running;
 
75
bool exclusive_gpu_app_running;
 
76
int gpu_suspend_reason;
 
77
double non_boinc_cpu_usage;
84
78
 
85
79
ACTIVE_TASK::~ACTIVE_TASK() {
86
80
}
87
81
 
88
 
#ifndef SIM
89
 
 
90
82
ACTIVE_TASK::ACTIVE_TASK() {
91
83
    result = NULL;
92
84
    wup = NULL;
100
92
    graphics_mode_acked = MODE_UNSUPPORTED;
101
93
    graphics_mode_ack_timeout = 0;
102
94
    fraction_done = 0;
103
 
    episode_start_cpu_time = 0;
104
95
    run_interval_start_wall_time = gstate.now;
105
96
    checkpoint_cpu_time = 0;
106
97
    checkpoint_wall_time = 0;
107
98
    current_cpu_time = 0;
 
99
    once_ran_edf = false;
108
100
    elapsed_time = 0;
109
101
    checkpoint_elapsed_time = 0;
110
102
    have_trickle_down = false;
113
105
    needs_shmem = false;
114
106
    want_network = 0;
115
107
    premature_exit_count = 0;
116
 
        coprocs_reserved = false;
117
108
    quit_time = 0;
118
109
    memset(&procinfo, 0, sizeof(procinfo));
119
110
#ifdef _WIN32
120
 
    pid_handle = 0;
121
 
    shm_handle = 0;
 
111
    process_handle = NULL;
 
112
    shm_handle = NULL;
122
113
#endif
123
114
    premature_exit_count = 0;
124
115
}
125
116
 
126
 
static const char* task_state_name(int val) {
127
 
    switch (val) {
128
 
    case PROCESS_UNINITIALIZED: return "UNINITIALIZED";
129
 
    case PROCESS_EXECUTING: return "EXECUTING";
130
 
    case PROCESS_SUSPENDED: return "SUSPENDED";
131
 
    case PROCESS_ABORT_PENDING: return "ABORT_PENDING";
132
 
    case PROCESS_EXITED: return "EXITED";
133
 
    case PROCESS_WAS_SIGNALED: return "WAS_SIGNALED";
134
 
    case PROCESS_EXIT_UNKNOWN: return "EXIT_UNKNOWN";
135
 
    case PROCESS_ABORTED: return "ABORTED";
136
 
    case PROCESS_COULDNT_START: return "COULDNT_START";
137
 
    case PROCESS_QUIT_PENDING: return "QUIT_PENDING";
138
 
    }
139
 
    return "Unknown";
140
 
}
141
 
 
142
 
void ACTIVE_TASK::set_task_state(int val, const char* where) {
143
 
    _task_state = val;
144
 
    if (log_flags.task_debug) {
145
 
        msg_printf(result->project, MSG_INFO,
146
 
            "[task_debug] task_state=%s for %s from %s",
147
 
            task_state_name(val), result->name, where
148
 
        );
149
 
    }
 
117
// preempt this task;
 
118
// called from the CLIENT_STATE::enforce_schedule()
 
119
// and ACTIVE_TASK_SET::suspend_all()
 
120
//
 
121
int ACTIVE_TASK::preempt(int preempt_type) {
 
122
    int retval;
 
123
    bool remove=false;
 
124
 
 
125
    switch (preempt_type) {
 
126
    case REMOVE_NEVER:
 
127
        remove = false;
 
128
        break;
 
129
    case REMOVE_MAYBE_USER:
 
130
    case REMOVE_MAYBE_SCHED:
 
131
        // GPU jobs: always remove from mem, since it's tying up GPU RAM
 
132
        //
 
133
        if (result->uses_coprocs()) {
 
134
            remove = true;
 
135
            break;
 
136
        }
 
137
        // if it's never checkpointed, leave in mem
 
138
        //
 
139
        if (checkpoint_elapsed_time == 0) {
 
140
            remove = false;
 
141
            break;
 
142
        }
 
143
        // otherwise obey user prefs
 
144
        //
 
145
        remove = !gstate.global_prefs.leave_apps_in_memory;
 
146
        break;
 
147
    case REMOVE_ALWAYS:
 
148
        remove = true;
 
149
        break;
 
150
    }
 
151
 
 
152
    if (remove) {
 
153
        if (log_flags.cpu_sched) {
 
154
            msg_printf(result->project, MSG_INFO,
 
155
                "[cpu_sched] Preempting %s (removed from memory)",
 
156
                result->name
 
157
            );
 
158
        }
 
159
        set_task_state(PROCESS_QUIT_PENDING, "preempt");
 
160
        retval = request_exit();
 
161
    } else {
 
162
        if (log_flags.cpu_sched) {
 
163
            msg_printf(result->project, MSG_INFO,
 
164
                "[cpu_sched] Preempting %s (left in memory)",
 
165
                result->name
 
166
            );
 
167
        }
 
168
        retval = suspend();
 
169
    }
 
170
    return 0;
150
171
}
151
172
 
152
173
// called when a process has exited or we've killed it
153
174
//
154
175
void ACTIVE_TASK::cleanup_task() {
155
176
#ifdef _WIN32
156
 
    if (pid_handle) {
157
 
        CloseHandle(pid_handle);
158
 
        pid_handle = NULL;
 
177
    if (process_handle) {
 
178
        CloseHandle(process_handle);
 
179
        process_handle = NULL;
159
180
    }
160
181
    // detach from shared mem.
161
182
    // This will destroy shmem seg since we're the last attachment
176
197
        {
177
198
            retval = detach_shmem(app_client_shm.shm);
178
199
            if (retval) {
179
 
                msg_printf(NULL, MSG_INTERNAL_ERROR,
 
200
                msg_printf(wup->project, MSG_INTERNAL_ERROR,
180
201
                    "Couldn't detach shared memory: %s", boincerror(retval)
181
202
                );
182
203
            }
183
204
            retval = destroy_shmem(shmem_seg_name);
184
205
            if (retval) {
185
 
                msg_printf(NULL, MSG_INTERNAL_ERROR,
 
206
                msg_printf(wup->project, MSG_INTERNAL_ERROR,
186
207
                    "Couldn't destroy shared memory: %s", boincerror(retval)
187
208
                );
188
209
            }
191
212
        gstate.retry_shmem_time = 0;
192
213
    }
193
214
#endif
194
 
    
195
 
    free_coprocs();
196
215
 
197
 
    if (gstate.exit_after_finish) {
 
216
    if (config.exit_after_finish) {
198
217
        exit(0);
199
218
    }
200
219
}
201
220
 
 
221
#ifndef SIM
202
222
int ACTIVE_TASK::init(RESULT* rp) {
203
223
    result = rp;
204
224
    wup = rp->wup;
205
225
    app_version = rp->avp;
206
 
    max_cpu_time = rp->wup->rsc_fpops_bound/gstate.host_info.p_fpops;
 
226
    max_elapsed_time = rp->wup->rsc_fpops_bound/rp->avp->flops;
207
227
    max_disk_usage = rp->wup->rsc_disk_bound;
208
228
    max_mem_usage = rp->wup->rsc_memory_bound;
209
229
    get_slot_dir(slot, slot_dir, sizeof(slot_dir));
210
230
    relative_to_absolute(slot_dir, slot_path);
211
231
    return 0;
212
232
}
 
233
#endif
213
234
 
214
 
#if 0
215
235
// Deallocate memory to prevent unneeded reporting of memory leaks
216
236
//
217
237
void ACTIVE_TASK_SET::free_mem() {
225
245
        delete at;
226
246
    }
227
247
}
228
 
#endif
 
248
 
 
249
#ifndef SIM
229
250
 
230
251
bool app_running(vector<PROCINFO>& piv, const char* p) {
231
252
    for (unsigned int i=0; i<piv.size(); i++) {
232
253
        PROCINFO& pi = piv[i];
233
 
        if (!strcmp(pi.command, p)) {
 
254
        //msg_printf(0, MSG_INFO, "running: [%s]", pi.command);
 
255
        if (!strcasecmp(pi.command, p)) {
234
256
            return true;
235
257
        }
236
258
    }
237
259
    return false;
238
260
}
239
261
 
 
262
#if 0  // debugging
 
263
void procinfo_show(PROCINFO& pi, vector<PROCINFO>& piv) {
 
264
        unsigned int i;
 
265
        memset(&pi, 0, sizeof(pi));
 
266
        for (i=0; i<piv.size(); i++) {
 
267
                PROCINFO& p = piv[i];
 
268
 
 
269
        pi.kernel_time += p.kernel_time;
 
270
        pi.user_time += p.user_time;
 
271
        msg_printf(NULL, MSG_INFO, "%d %s: boinc %d low %d (%f %f) total (%f %f)",
 
272
            p.id, p.command, p.is_boinc_app, p.is_low_priority, p.kernel_time, p.user_time, pi.kernel_time, pi.user_time
 
273
        );
 
274
    }
 
275
}
 
276
#endif
 
277
 
240
278
void ACTIVE_TASK_SET::get_memory_usage() {
241
279
    static double last_mem_time=0;
242
280
    unsigned int i;
243
281
        int retval;
 
282
    static bool first = true;
 
283
    static double last_cpu_time;
244
284
 
245
285
    double diff = gstate.now - last_mem_time;
246
286
    if (diff < 10) return;
250
290
    retval = procinfo_setup(piv);
251
291
        if (retval) {
252
292
                if (log_flags.mem_usage_debug) {
253
 
                        msg_printf(0, MSG_INTERNAL_ERROR,
254
 
                                "[mem_usage_debug] procinfo_setup() returned %d", retval
 
293
                        msg_printf(NULL, MSG_INTERNAL_ERROR,
 
294
                                "[mem_usage] procinfo_setup() returned %d", retval
255
295
                        );
256
296
                }
257
297
                return;
258
298
        }
259
299
    for (i=0; i<active_tasks.size(); i++) {
260
300
        ACTIVE_TASK* atp = active_tasks[i];
261
 
        if (atp->scheduler_state == CPU_SCHED_SCHEDULED) {
262
 
            PROCINFO& pi = atp->procinfo;
263
 
            unsigned long last_page_fault_count = pi.page_fault_count;
264
 
            memset(&pi, 0, sizeof(pi));
265
 
            pi.id = atp->pid;
266
 
            procinfo_app(pi, piv);
267
 
            pi.working_set_size_smoothed = .5*pi.working_set_size_smoothed + pi.working_set_size;
268
 
 
269
 
            int pf = pi.page_fault_count - last_page_fault_count;
270
 
            pi.page_fault_rate = pf/diff;
271
 
            if (log_flags.mem_usage_debug) {
272
 
                msg_printf(atp->result->project, MSG_INFO,
273
 
                    "[mem_usage_debug] %s: RAM %.2fMB, page %.2fMB, %.2f page faults/sec, user CPU %.3f, kernel CPU %.3f",
274
 
                    atp->result->name,
275
 
                    pi.working_set_size/MEGA, pi.swap_size/MEGA,
276
 
                    pi.page_fault_rate,
277
 
                    pi.user_time, pi.kernel_time
278
 
                );
279
 
            }
 
301
        if (atp->task_state() == PROCESS_UNINITIALIZED) continue;
 
302
        if (atp->pid ==0) continue;
 
303
 
 
304
        // scan all active tasks with a process, even if not scheduled, because
 
305
        // 1) we might have recently suspended a tasks,
 
306
        //    and we still need to count its time
 
307
        // 2) preempted tasks might not actually suspend themselves
 
308
        //    (and we'd count that as non-BOINC CPU usage
 
309
        //    and suspend everything).
 
310
 
 
311
        PROCINFO& pi = atp->procinfo;
 
312
        unsigned long last_page_fault_count = pi.page_fault_count;
 
313
        memset(&pi, 0, sizeof(pi));
 
314
        pi.id = atp->pid;
 
315
        procinfo_app(pi, piv, atp->app_version->graphics_exec_file);
 
316
        pi.working_set_size_smoothed = .5*pi.working_set_size_smoothed + pi.working_set_size;
 
317
 
 
318
        int pf = pi.page_fault_count - last_page_fault_count;
 
319
        pi.page_fault_rate = pf/diff;
 
320
        if (log_flags.mem_usage_debug) {
 
321
            msg_printf(atp->result->project, MSG_INFO,
 
322
                "[mem_usage] %s: RAM %.2fMB, page %.2fMB, %.2f page faults/sec, user CPU %.3f, kernel CPU %.3f",
 
323
                atp->result->name,
 
324
                pi.working_set_size/MEGA, pi.swap_size/MEGA,
 
325
                pi.page_fault_rate,
 
326
                pi.user_time, pi.kernel_time
 
327
            );
280
328
        }
281
329
    }
282
330
 
283
331
    exclusive_app_running = false;
 
332
    bool old_egar = exclusive_gpu_app_running;
 
333
    exclusive_gpu_app_running = false;
284
334
    for (i=0; i<config.exclusive_apps.size(); i++) {
285
335
        if (app_running(piv, config.exclusive_apps[i].c_str())) {
286
336
            exclusive_app_running = true;
287
337
            break;
288
338
        }
289
339
    }
 
340
    for (i=0; i<config.exclusive_gpu_apps.size(); i++) {
 
341
        if (app_running(piv, config.exclusive_gpu_apps[i].c_str())) {
 
342
            exclusive_gpu_app_running = true;
 
343
            break;
 
344
        }
 
345
    }
 
346
    if (old_egar != exclusive_gpu_app_running) {
 
347
        gstate.request_schedule_cpus("Exclusive GPU app status changed");
 
348
    }
290
349
 
291
 
#if 0
292
 
    // the following is not useful because most OSs don't
293
 
    // move idle processes out of RAM, so physical memory is always full
 
350
    // get info on non-BOINC processes.
 
351
    // mem usage info is not useful because most OSs don't
 
352
    // move idle processes out of RAM, so physical memory is always full.
 
353
    // Also (at least on Win) page faults are used for various things,
 
354
    // not all of them generate disk I/O,
 
355
    // so they're not useful for detecting paging/thrashing.
294
356
    //
 
357
    PROCINFO pi;
 
358
    //procinfo_show(pi, piv);
295
359
    procinfo_other(pi, piv);
296
 
    msg_printf(NULL, MSG_INFO, "All others: RAM %.2fMB, page %.2fMB, user %.3f, kernel %.3f",
297
 
        pi.working_set_size/MEGA, pi.swap_size/MEGA,
298
 
        pi.user_time, pi.kernel_time
299
 
    );
 
360
    if (log_flags.mem_usage_debug) {
 
361
        msg_printf(NULL, MSG_INFO,
 
362
            "[mem_usage] All others: RAM %.2fMB, page %.2fMB, user %.3f, kernel %.3f",
 
363
            pi.working_set_size/MEGA, pi.swap_size/MEGA,
 
364
            pi.user_time, pi.kernel_time
 
365
        );
 
366
    }
 
367
    double new_cpu_time = pi.user_time + pi.kernel_time;
 
368
    if (first) {
 
369
        first = false;
 
370
    } else {
 
371
        non_boinc_cpu_usage = (new_cpu_time - last_cpu_time)/(diff*gstate.host_info.p_ncpus);
 
372
        // processes might have exited in the last 10 sec,
 
373
        // causing this to be negative.
 
374
        if (non_boinc_cpu_usage < 0) non_boinc_cpu_usage = 0;
 
375
        if (log_flags.mem_usage_debug) {
 
376
            msg_printf(NULL, MSG_INFO,
 
377
                "[mem_usage] non-BOINC CPU usage: %.2f%%", non_boinc_cpu_usage*100
 
378
            );
 
379
        }
 
380
    }
 
381
    last_cpu_time = new_cpu_time;
 
382
}
 
383
 
300
384
#endif
301
 
}
302
 
 
303
 
// Do periodic checks on running apps:
304
 
// - get latest CPU time and % done info
305
 
// - check if any has exited, and clean up
306
 
// - see if any has exceeded its CPU or disk space limits, and abort it
307
 
//
308
 
bool ACTIVE_TASK_SET::poll() {
309
 
    bool action;
310
 
    unsigned int i;
311
 
    static double last_time = 0;
312
 
    if (gstate.now - last_time < 1.0) return false;
313
 
    last_time = gstate.now;
314
 
 
315
 
    action = check_app_exited();
316
 
    send_heartbeats();
317
 
    send_trickle_downs();
318
 
    graphics_poll();
319
 
    process_control_poll();
320
 
    get_memory_usage();
321
 
    action |= check_rsc_limits_exceeded();
322
 
    action |= get_msgs();
323
 
    for (i=0; i<active_tasks.size(); i++) {
324
 
        ACTIVE_TASK* atp = active_tasks[i];
325
 
        if (atp->task_state() == PROCESS_ABORT_PENDING) {
326
 
            if (gstate.now > atp->abort_time + ABORT_TIMEOUT) {
327
 
                atp->kill_task(false);
328
 
            }
329
 
        }
330
 
        if (atp->task_state() == PROCESS_QUIT_PENDING) {
331
 
            if (gstate.now > atp->quit_time + QUIT_TIMEOUT) {
332
 
                atp->kill_task(true);
333
 
            }
334
 
        }
335
 
    }
336
 
 
337
 
    if (action) {
338
 
        gstate.set_client_state_dirty("ACTIVE_TASK_SET::poll");
339
 
    }
340
 
 
341
 
    return action;
342
 
}
343
385
 
344
386
// There's a new trickle file.
345
387
// Move it from slot dir to project dir
408
450
// Get a free slot,
409
451
// and make a slot dir if needed
410
452
//
411
 
int ACTIVE_TASK_SET::get_free_slot() {
 
453
void ACTIVE_TASK::get_free_slot(RESULT* rp) {
 
454
#ifndef SIM
412
455
    int j, retval;
413
456
    char path[1024];
414
457
 
415
458
    for (j=0; ; j++) {
416
 
        if (is_slot_in_use(j)) continue;
 
459
        if (gstate.active_tasks.is_slot_in_use(j)) continue;
417
460
 
418
461
        // make sure we can make an empty directory for this slot
419
462
        //
420
463
        get_slot_dir(j, path, sizeof(path));
421
464
        if (boinc_file_exists(path)) {
422
465
            if (is_dir(path)) {
423
 
                retval = client_clean_out_dir(path);
424
 
                if (!retval) return j;
 
466
                retval = client_clean_out_dir(path, "get_free_slot()");
 
467
                if (!retval) break;
425
468
            }
426
469
        } else {
427
470
            retval = make_slot_dir(j);
428
 
            if (!retval) return j;
 
471
            if (!retval) break;
429
472
        }
430
473
    }
431
 
    return ERR_NOT_FOUND;   // probably never get here
 
474
    slot = j;
 
475
    if (log_flags.slot_debug) {
 
476
        msg_printf(rp->project, MSG_INFO, "[slot] assigning slot %d to %s", j, rp->name);
 
477
    }
 
478
#endif
432
479
}
433
480
 
434
481
bool ACTIVE_TASK_SET::slot_taken(int slot) {
454
501
        "    <checkpoint_elapsed_time>%f</checkpoint_elapsed_time>\n"
455
502
        "    <fraction_done>%f</fraction_done>\n"
456
503
        "    <current_cpu_time>%f</current_cpu_time>\n"
 
504
        "    <once_ran_edf>%d</once_ran_edf>\n"
457
505
        "    <swap_size>%f</swap_size>\n"
458
506
        "    <working_set_size>%f</working_set_size>\n"
459
507
        "    <working_set_size_smoothed>%f</working_set_size_smoothed>\n"
467
515
        checkpoint_elapsed_time,
468
516
        fraction_done,
469
517
        current_cpu_time,
 
518
        once_ran_edf?1:0,
470
519
        procinfo.swap_size,
471
520
        procinfo.working_set_size,
472
521
        procinfo.working_set_size_smoothed,
476
525
    return 0;
477
526
}
478
527
 
 
528
#ifndef SIM
 
529
 
479
530
int ACTIVE_TASK::write_gui(MIOFILE& fout) {
480
531
    fout.printf(
481
532
        "<active_task>\n"
482
533
        "    <active_task_state>%d</active_task_state>\n"
483
534
        "    <app_version_num>%d</app_version_num>\n"
484
535
        "    <slot>%d</slot>\n"
 
536
        "    <pid>%d</pid>\n"
485
537
        "    <scheduler_state>%d</scheduler_state>\n"
486
538
        "    <checkpoint_cpu_time>%f</checkpoint_cpu_time>\n"
487
539
        "    <fraction_done>%f</fraction_done>\n"
496
548
        task_state(),
497
549
        app_version->version_num,
498
550
        slot,
 
551
        pid,
499
552
        scheduler_state,
500
553
        checkpoint_cpu_time,
501
554
        fraction_done,
527
580
    return 0;
528
581
}
529
582
 
 
583
#endif
 
584
 
530
585
int ACTIVE_TASK::parse(MIOFILE& fin) {
531
586
    char buf[256], result_name[256], project_master_url[256];
532
587
    int n, dummy;
533
588
    unsigned int i;
534
 
    PROJECT* project;
 
589
    PROJECT* project=0;
 
590
    double x;
535
591
 
536
592
    strcpy(result_name, "");
537
593
    strcpy(project_master_url, "");
542
598
            if (!project) {
543
599
                msg_printf(
544
600
                    NULL, MSG_INTERNAL_ERROR,
545
 
                    "State file error: project %s not found\n",
 
601
                    "State file error: project %s not found for task\n",
546
602
                    project_master_url
547
603
                );
548
604
                return ERR_NULL;
551
607
            if (!result) {
552
608
                msg_printf(
553
609
                    project, MSG_INTERNAL_ERROR,
554
 
                    "State file error: result %s not found\n",
 
610
                    "State file error: result %s not found for task\n",
555
611
                    result_name
556
612
                );
557
613
                return ERR_NULL;
563
619
                || result->ready_to_report
564
620
                || result->state() != RESULT_FILES_DOWNLOADED
565
621
            ) {
566
 
                msg_printf(project, MSG_INTERNAL_ERROR,
567
 
                    "State file error: result %s is in wrong state\n",
568
 
                    result_name
569
 
                );
570
622
                return ERR_BAD_RESULT_STATE;
571
623
            }
572
624
 
608
660
        else if (parse_str(buf, "<project_master_url>", project_master_url, sizeof(project_master_url))) continue;
609
661
        else if (parse_int(buf, "<slot>", slot)) continue;
610
662
        else if (parse_int(buf, "<active_task_state>", dummy)) continue;
611
 
        else if (parse_double(buf, "<checkpoint_cpu_time>", checkpoint_cpu_time)) {
612
 
            current_cpu_time = checkpoint_cpu_time;
613
 
            continue;
614
 
        }
 
663
        else if (parse_double(buf, "<checkpoint_cpu_time>", checkpoint_cpu_time)) continue;
 
664
        else if (parse_bool(buf, "once_ran_edf", once_ran_edf)) continue;
615
665
        else if (parse_double(buf, "<fraction_done>", fraction_done)) continue;
616
 
        else if (parse_double(buf, "<checkpoint_elapsed_time>", checkpoint_elapsed_time)) {
617
 
            elapsed_time = checkpoint_elapsed_time;
618
 
            continue;
619
 
        }
 
666
        else if (parse_double(buf, "<checkpoint_elapsed_time>", checkpoint_elapsed_time)) continue;
620
667
        else if (parse_int(buf, "<app_version_num>", n)) continue;
621
668
        else if (parse_double(buf, "<swap_size>", procinfo.swap_size)) continue;
622
669
        else if (parse_double(buf, "<working_set_size>", procinfo.working_set_size)) continue;
623
670
        else if (parse_double(buf, "<working_set_size_smoothed>", procinfo.working_set_size_smoothed)) continue;
624
671
        else if (parse_double(buf, "<page_fault_rate>", procinfo.page_fault_rate)) continue;
 
672
        else if (parse_double(buf, "<current_cpu_time>", x)) continue;
625
673
        else {
626
674
            if (log_flags.unparsed_xml) {
627
 
                msg_printf(0, MSG_INFO,
 
675
                msg_printf(project, MSG_INFO,
628
676
                    "[unparsed_xml] ACTIVE_TASK::parse(): unrecognized %s\n", buf
629
677
                );
630
678
            }
633
681
    return ERR_XML_PARSE;
634
682
}
635
683
 
636
 
void ACTIVE_TASK::reserve_coprocs() {
637
 
    gstate.coprocs.reserve_coprocs(
638
 
                app_version->coprocs, this, log_flags.coproc_debug, "coproc_debug"
639
 
        );
640
 
    coprocs_reserved = true;
641
 
}
642
 
 
643
 
void ACTIVE_TASK::free_coprocs() {
644
 
    if (!coprocs_reserved) return;
645
 
    gstate.coprocs.free_coprocs(
646
 
                app_version->coprocs, this, log_flags.coproc_debug, "coproc_debug"
647
 
        );
648
 
    coprocs_reserved = false;
649
 
}
650
 
 
651
 
// Write XML information about this active task set
652
 
//
653
684
int ACTIVE_TASK_SET::write(MIOFILE& fout) {
654
685
    unsigned int i;
655
686
    int retval;
663
694
    return 0;
664
695
}
665
696
 
666
 
// Parse XML information about an active task set
667
 
//
668
697
int ACTIVE_TASK_SET::parse(MIOFILE& fin) {
669
698
    ACTIVE_TASK* atp;
670
699
    char buf[256];
688
717
            else delete atp;
689
718
        } else {
690
719
            if (log_flags.unparsed_xml) {
691
 
                msg_printf(0, MSG_INFO,
 
720
                msg_printf(NULL, MSG_INFO,
692
721
                    "[unparsed_xml] ACTIVE_TASK_SET::parse(): unrecognized %s\n", buf
693
722
                );
694
723
            }
697
726
    return ERR_XML_PARSE;
698
727
}
699
728
 
 
729
#ifndef SIM
 
730
 
700
731
void MSG_QUEUE::init(char* n) {
701
732
        strcpy(name, n);
702
733
        last_block = 0;
744
775
// if the last message in the buffer is "msg", remove it and return 1
745
776
//
746
777
int MSG_QUEUE::msg_queue_purge(const char* msg) {
747
 
        int count = msgs.size();
 
778
        int count = (int)msgs.size();
748
779
        if (!count) return 0;
749
780
        vector<string>::iterator iter = msgs.begin();
750
781
        for (int i=0; i<count-1; i++) {
774
805
        return false;
775
806
}
776
807
 
 
808
#endif
 
809
 
777
810
void ACTIVE_TASK_SET::report_overdue() {
778
811
    unsigned int i;
779
812
    ACTIVE_TASK* atp;
782
815
        atp = active_tasks[i];
783
816
        double diff = (gstate.now - atp->result->report_deadline)/86400;
784
817
        if (diff > 0) {
785
 
            msg_printf(atp->result->project, MSG_USER_ERROR,
786
 
                "Task %s is %.2f days overdue.", atp->result->name, diff
787
 
            );
788
 
            msg_printf(atp->result->project, MSG_USER_ERROR,
789
 
                "You may not get credit for it.  Consider aborting it."
 
818
            msg_printf(atp->result->project, MSG_INFO,
 
819
                "Task %s is %.2f days overdue; you may not get credit for it.  Consider aborting it.", atp->result->name, diff
790
820
            );
791
821
        }
792
822
    }
816
846
                    fip->status = FILE_PRESENT;
817
847
                }
818
848
            } else {
819
 
                msg_printf(0, MSG_INTERNAL_ERROR, "Can't find uploadable file %s", p);
 
849
                msg_printf(wup->project, MSG_INTERNAL_ERROR,
 
850
                    "Can't find uploadable file %s", p
 
851
                );
820
852
            }
821
853
            sprintf(path, "%s/%s", slot_dir, buf);
822
854
            delete_project_owned_file(path, true);  // delete the link file
841
873
}
842
874
 
843
875
void ACTIVE_TASK_SET::network_available() {
 
876
#ifndef SIM
844
877
    for (unsigned int i=0; i<active_tasks.size(); i++) {
845
878
        ACTIVE_TASK* atp = active_tasks[i];
846
879
        if (atp->want_network) {
847
880
            atp->send_network_available();
848
881
        }
849
882
    }
 
883
#endif
850
884
}
851
885
 
852
886
void ACTIVE_TASK::upload_notify_app(const FILE_INFO* fip, const FILE_REF* frp) {
873
907
    }
874
908
}
875
909
 
 
910
#ifndef SIM
876
911
void ACTIVE_TASK_SET::init() {
877
912
    for (unsigned int i=0; i<active_tasks.size(); i++) {
878
913
        ACTIVE_TASK* atp = active_tasks[i];
879
914
        atp->init(atp->result);
880
915
        atp->scheduler_state = CPU_SCHED_PREEMPTED;
 
916
        atp->read_task_state_file();
 
917
        atp->current_cpu_time = atp->checkpoint_cpu_time;
 
918
        atp->elapsed_time = atp->checkpoint_elapsed_time;
881
919
    }
882
920
}
883
921
 
884
922
#endif
885
923
 
886
 
const char *BOINC_RCSID_778b61195e = "$Id: app.cpp 16622 2008-12-04 18:13:52Z romw $";
 
924
static const char* task_state_name(int val) {
 
925
    switch (val) {
 
926
    case PROCESS_UNINITIALIZED: return "UNINITIALIZED";
 
927
    case PROCESS_EXECUTING: return "EXECUTING";
 
928
    case PROCESS_SUSPENDED: return "SUSPENDED";
 
929
    case PROCESS_ABORT_PENDING: return "ABORT_PENDING";
 
930
    case PROCESS_EXITED: return "EXITED";
 
931
    case PROCESS_WAS_SIGNALED: return "WAS_SIGNALED";
 
932
    case PROCESS_EXIT_UNKNOWN: return "EXIT_UNKNOWN";
 
933
    case PROCESS_ABORTED: return "ABORTED";
 
934
    case PROCESS_COULDNT_START: return "COULDNT_START";
 
935
    case PROCESS_QUIT_PENDING: return "QUIT_PENDING";
 
936
    }
 
937
    return "Unknown";
 
938
}
 
939
 
 
940
void ACTIVE_TASK::set_task_state(int val, const char* where) {
 
941
    _task_state = val;
 
942
    if (log_flags.task_debug) {
 
943
        msg_printf(result->project, MSG_INFO,
 
944
            "[task] task_state=%s for %s from %s",
 
945
            task_state_name(val), result->name, where
 
946
        );
 
947
    }
 
948
}
 
949