~ubuntu-branches/ubuntu/saucy/slurm-llnl/saucy

« back to all changes in this revision

Viewing changes to src/plugins/jobacct_gather/linux/jobacct_gather_linux.c

  • Committer: Bazaar Package Importer
  • Author(s): Gennaro Oliva
  • Date: 2008-05-30 13:11:30 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20080530131130-l6ko6aie7xhrlmxe
Tags: 1.3.3-1
* New upstream release
* Removed patches to src/slurmctd/controller.c src/slurmdbd/slurmdbd.c
  doc/man/man1/sacctmgr.1 included to upstream
* Edited watch file to seek for 1.3 releases
* doc/man/man1/salloc.1 doc/man/man1/sbatch.1 doc/man/man5/slurm.conf.5
  patched to improve formatting and avoid manual warnings 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************\
 
2
 *  jobacct_gather_linux.c - slurm job accounting gather plugin for linux.
 
3
 *****************************************************************************
 
4
 *  Copyright (C) 2005 Hewlett-Packard Development Company, L.P.
 
5
 *  Written by Andy Riebs, <andy.riebs@hp.com>, who borrowed heavily
 
6
 *  from other parts of SLURM, and Danny Auble, <da@llnl.gov>
 
7
 *  LLNL-CODE-402394.
 
8
 *  
 
9
 *  This file is part of SLURM, a resource management program.
 
10
 *  For details, see <http://www.llnl.gov/linux/slurm/>.
 
11
 *  
 
12
 *  SLURM is free software; you can redistribute it and/or modify it under
 
13
 *  the terms of the GNU General Public License as published by the Free
 
14
 *  Software Foundation; either version 2 of the License, or (at your option)
 
15
 *  any later version.
 
16
 *
 
17
 *  In addition, as a special exception, the copyright holders give permission 
 
18
 *  to link the code of portions of this program with the OpenSSL library under
 
19
 *  certain conditions as described in each individual source file, and 
 
20
 *  distribute linked combinations including the two. You must obey the GNU 
 
21
 *  General Public License in all respects for all of the code used other than 
 
22
 *  OpenSSL. If you modify file(s) with this exception, you may extend this 
 
23
 *  exception to your version of the file(s), but you are not obligated to do 
 
24
 *  so. If you do not wish to do so, delete this exception statement from your
 
25
 *  version.  If you delete this exception statement from all source files in 
 
26
 *  the program, then also delete it here.
 
27
 *  
 
28
 *  SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
 
29
 *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
30
 *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 
31
 *  details.
 
32
 *  
 
33
 *  You should have received a copy of the GNU General Public License along
 
34
 *  with SLURM; if not, write to the Free Software Foundation, Inc.,
 
35
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA.
 
36
 *
 
37
 *  This file is patterned after jobcomp_linux.c, written by Morris Jette and
 
38
 *  Copyright (C) 2002 The Regents of the University of California.
 
39
\*****************************************************************************/
 
40
 
 
41
#include <fcntl.h>
 
42
#include <signal.h>
 
43
#include "src/common/jobacct_common.h"
 
44
#include "src/common/slurm_protocol_api.h"
 
45
#include "src/common/slurm_protocol_defs.h"
 
46
#include "src/slurmd/common/proctrack.h"
 
47
 
 
48
#define _DEBUG 0
 
49
 
 
50
/*
 
51
 * These variables are required by the generic plugin interface.  If they
 
52
 * are not found in the plugin, the plugin loader will ignore it.
 
53
 *
 
54
 * plugin_name - a string giving a human-readable description of the
 
55
 * plugin.  There is no maximum length, but the symbol must refer to
 
56
 * a valid string.
 
57
 *
 
58
 * plugin_type - a string suggesting the type of the plugin or its
 
59
 * applicability to a particular form of data or method of data handling.
 
60
 * If the low-level plugin API is used, the contents of this string are
 
61
 * unimportant and may be anything.  SLURM uses the higher-level plugin
 
62
 * interface which requires this string to be of the form
 
63
 *
 
64
 *      <application>/<method>
 
65
 *
 
66
 * where <application> is a description of the intended application of
 
67
 * the plugin (e.g., "jobacct" for SLURM job completion logging) and <method>
 
68
 * is a description of how this plugin satisfies that application.  SLURM will
 
69
 * only load job completion logging plugins if the plugin_type string has a 
 
70
 * prefix of "jobacct/".
 
71
 *
 
72
 * plugin_version - an unsigned 32-bit integer giving the version number
 
73
 * of the plugin.  If major and minor revisions are desired, the major
 
74
 * version number may be multiplied by a suitable magnitude constant such
 
75
 * as 100 or 1000.  Various SLURM versions will likely require a certain
 
76
 * minimum versions for their plugins as the job accounting API 
 
77
 * matures.
 
78
 */
 
79
const char plugin_name[] = "Job accounting gather LINUX plugin";
 
80
const char plugin_type[] = "jobacct_gather/linux";
 
81
const uint32_t plugin_version = 100;
 
82
 
 
83
/* Other useful declarations */
 
84
 
 
85
typedef struct prec {   /* process record */
 
86
        pid_t   pid;
 
87
        pid_t   ppid;
 
88
        int     usec;   /* user cpu time */
 
89
        int     ssec;   /* system cpu time */
 
90
        int     pages;  /* pages */
 
91
        int     rss;    /* rss */
 
92
        int     vsize;  /* virtual size */
 
93
} prec_t;
 
94
 
 
95
static int freq = 0;
 
96
static DIR  *slash_proc = NULL;
 
97
static pthread_mutex_t reading_mutex = PTHREAD_MUTEX_INITIALIZER;
 
98
 
 
99
/* Finally, pre-define all local routines. */
 
100
 
 
101
static void _acct_kill_job(void);
 
102
static void _get_offspring_data(List prec_list, prec_t *ancestor, pid_t pid);
 
103
static void _get_process_data();
 
104
static int _get_process_data_line(int in, prec_t *prec);
 
105
static void *_watch_tasks(void *arg);
 
106
static void _destroy_prec(void *object);
 
107
 
 
108
/* 
 
109
 * _get_offspring_data() -- collect memory usage data for the offspring
 
110
 *
 
111
 * For each process that lists <pid> as its parent, add its memory
 
112
 * usage data to the ancestor's <prec> record. Recurse to gather data
 
113
 * for *all* subsequent generations.
 
114
 *
 
115
 * IN:  prec_list       list of prec's
 
116
 *      ancestor        The entry in precTable[] to which the data
 
117
 *                      should be added. Even as we recurse, this will
 
118
 *                      always be the prec for the base of the family
 
119
 *                      tree.
 
120
 *      pid             The process for which we are currently looking 
 
121
 *                      for offspring.
 
122
 *
 
123
 * OUT: none.
 
124
 *
 
125
 * RETVAL:      none.
 
126
 *
 
127
 * THREADSAFE! Only one thread ever gets here.
 
128
 */
 
129
static void
 
130
_get_offspring_data(List prec_list, prec_t *ancestor, pid_t pid) {
 
131
        
 
132
        ListIterator itr;
 
133
        prec_t *prec = NULL;
 
134
 
 
135
        itr = list_iterator_create(prec_list);
 
136
        while((prec = list_next(itr))) {
 
137
                if (prec->ppid == pid) {
 
138
#if _DEBUG
 
139
                        info("pid:%u ppid:%u rss:%d KB", 
 
140
                             prec->pid, prec->ppid, prec->rss);
 
141
#endif
 
142
                        _get_offspring_data(prec_list, ancestor, prec->pid);
 
143
                        ancestor->usec += prec->usec;
 
144
                        ancestor->ssec += prec->ssec;
 
145
                        ancestor->pages += prec->pages;
 
146
                        ancestor->rss += prec->rss;
 
147
                        ancestor->vsize += prec->vsize;
 
148
                }
 
149
        }
 
150
        list_iterator_destroy(itr);
 
151
        return;
 
152
}
 
153
 
 
154
/*
 
155
 * _get_process_data() - Build a table of all current processes
 
156
 *
 
157
 * IN:  pid.
 
158
 *
 
159
 * OUT: none
 
160
 *
 
161
 * THREADSAFE! Only one thread ever gets here.
 
162
 *
 
163
 * Assumption:
 
164
 *    Any file with a name of the form "/proc/[0-9]+/stat"
 
165
 *    is a Linux-style stat entry. We disregard the data if they look
 
166
 *    wrong.
 
167
 */
 
168
static void _get_process_data() {
 
169
        static  int     slash_proc_open = 0;
 
170
 
 
171
        struct  dirent *slash_proc_entry;
 
172
        char            *iptr = NULL, *optr = NULL;
 
173
        FILE            *stat_fp = NULL;
 
174
        char            proc_stat_file[256];    /* Allow ~20x extra length */
 
175
        List prec_list = NULL;
 
176
        pid_t *pids = NULL;
 
177
        int npids = 0;
 
178
        uint32_t total_job_mem = 0;
 
179
        int             i, fd;
 
180
        ListIterator itr;
 
181
        ListIterator itr2;
 
182
        prec_t *prec = NULL;
 
183
        struct jobacctinfo *jobacct = NULL;
 
184
        static int processing = 0;
 
185
 
 
186
        if(!pgid_plugin && cont_id == (uint32_t)NO_VAL) {
 
187
                debug("cont_id hasn't been set yet not running poll");
 
188
                return; 
 
189
        }
 
190
 
 
191
        if(processing) {
 
192
                debug("already running, returning");
 
193
                return;
 
194
        }
 
195
        processing = 1;
 
196
        prec_list = list_create(_destroy_prec);
 
197
 
 
198
        if(!pgid_plugin) {
 
199
                /* get only the processes in the proctrack container */
 
200
                slurm_container_get_pids(cont_id, &pids, &npids);
 
201
                if(!npids) {
 
202
                        debug4("no pids in this container %d", cont_id);
 
203
                        goto finished;
 
204
                }
 
205
                for (i = 0; i < npids; i++) {
 
206
                        snprintf(proc_stat_file, 256,
 
207
                                 "/proc/%d/stat", pids[i]);
 
208
                        if ((stat_fp = fopen(proc_stat_file, "r"))==NULL)
 
209
                                continue;  /* Assume the process went away */
 
210
                        /*
 
211
                         * Close the file on exec() of user tasks.
 
212
                         *
 
213
                         * NOTE: If we fork() slurmstepd after the
 
214
                         * fopen() above and before the fcntl() below,
 
215
                         * then the user task may have this extra file
 
216
                         * open, which can cause problems for
 
217
                         * checkpoint/restart, but this should be a very rare 
 
218
                         * problem in practice.
 
219
                         */ 
 
220
                        fd = fileno(stat_fp);
 
221
                        fcntl(fd, F_SETFD, FD_CLOEXEC);
 
222
                        
 
223
                        prec = xmalloc(sizeof(prec_t));
 
224
                        if (_get_process_data_line(fd, prec))
 
225
                                list_append(prec_list, prec);
 
226
                        else 
 
227
                                xfree(prec);
 
228
                        fclose(stat_fp);
 
229
                }
 
230
        } else {
 
231
                slurm_mutex_lock(&reading_mutex);
 
232
        
 
233
                if (slash_proc_open) {
 
234
                        rewinddir(slash_proc);
 
235
                } else {
 
236
                        slash_proc=opendir("/proc");
 
237
                        if (slash_proc == NULL) {
 
238
                                perror("opening /proc");
 
239
                                slurm_mutex_unlock(&reading_mutex);
 
240
                                goto finished;
 
241
                        }
 
242
                        slash_proc_open=1;
 
243
                }
 
244
                strcpy(proc_stat_file, "/proc/");
 
245
                
 
246
                while ((slash_proc_entry = readdir(slash_proc))) {
 
247
                        
 
248
                        /* Save a few cyles by simulating
 
249
                           strcat(statFileName, slash_proc_entry->d_name);
 
250
                           strcat(statFileName, "/stat");
 
251
                           while checking for a numeric filename (which really
 
252
                           should be a pid).
 
253
                        */
 
254
                        optr = proc_stat_file + sizeof("/proc");
 
255
                        iptr = slash_proc_entry->d_name;
 
256
                        i = 0;
 
257
                        do {
 
258
                                if((*iptr < '0') 
 
259
                                   || ((*optr++ = *iptr++) > '9')) {
 
260
                                        i = -1;
 
261
                                        break;
 
262
                                }
 
263
                        } while (*iptr);
 
264
                        
 
265
                        if(i == -1)
 
266
                                continue;
 
267
                        iptr = (char*)"/stat";
 
268
                        
 
269
                        do {
 
270
                                *optr++ = *iptr++;
 
271
                        } while (*iptr);
 
272
                        *optr = 0;
 
273
                        
 
274
                        if ((stat_fp = fopen(proc_stat_file,"r"))==NULL)
 
275
                                continue;  /* Assume the process went away */
 
276
                        /*
 
277
                         * Close the file on exec() of user tasks.
 
278
                         *
 
279
                         * NOTE: If we fork() slurmstepd after the
 
280
                         * fopen() above and before the fcntl() below,
 
281
                         * then the user task may have this extra file
 
282
                         * open, which can cause problems for
 
283
                         * checkpoint/restart, but this should be a very rare 
 
284
                         * problem in practice.
 
285
                         */ 
 
286
                        fd = fileno(stat_fp);
 
287
                        fcntl(fd, F_SETFD, FD_CLOEXEC);
 
288
 
 
289
                        prec = xmalloc(sizeof(prec_t));
 
290
                        if (_get_process_data_line(fd, prec))
 
291
                                list_append(prec_list, prec);
 
292
                        else 
 
293
                                xfree(prec);
 
294
                        fclose(stat_fp);
 
295
                }
 
296
                slurm_mutex_unlock(&reading_mutex);
 
297
        
 
298
        }
 
299
                
 
300
        if (!list_count(prec_list)) {
 
301
                goto finished;  /* We have no business being here! */
 
302
        }
 
303
        
 
304
        slurm_mutex_lock(&jobacct_lock);
 
305
        if(!task_list || !list_count(task_list)) {
 
306
                slurm_mutex_unlock(&jobacct_lock);
 
307
                goto finished;
 
308
        }
 
309
 
 
310
        itr = list_iterator_create(task_list);
 
311
        while((jobacct = list_next(itr))) {
 
312
                itr2 = list_iterator_create(prec_list);
 
313
                while((prec = list_next(itr2))) {
 
314
                        if (prec->pid == jobacct->pid) {
 
315
#if _DEBUG
 
316
                                info("pid:%u ppid:%u rss:%d KB", 
 
317
                                     prec->pid, prec->ppid, prec->rss);
 
318
#endif
 
319
                                /* find all my descendents */
 
320
                                _get_offspring_data(prec_list, 
 
321
                                                    prec, prec->pid);
 
322
                                /* tally their usage */
 
323
                                jobacct->max_rss = jobacct->tot_rss = 
 
324
                                        MAX(jobacct->max_rss, prec->rss);
 
325
                                total_job_mem += prec->rss;
 
326
                                jobacct->max_vsize = jobacct->tot_vsize = 
 
327
                                        MAX(jobacct->max_vsize, prec->vsize);
 
328
                                jobacct->max_pages = jobacct->tot_pages =
 
329
                                        MAX(jobacct->max_pages, prec->pages);
 
330
                                jobacct->min_cpu = jobacct->tot_cpu = 
 
331
                                        MAX(jobacct->min_cpu, 
 
332
                                            (prec->usec + prec->ssec));
 
333
                                debug2("%d mem size %u %u time %u",
 
334
                                      jobacct->pid, jobacct->max_rss, 
 
335
                                      jobacct->max_vsize, jobacct->tot_cpu);
 
336
                                break;
 
337
                        }
 
338
                }
 
339
                list_iterator_destroy(itr2);
 
340
        }
 
341
        list_iterator_destroy(itr);
 
342
        slurm_mutex_unlock(&jobacct_lock);
 
343
 
 
344
        if (job_mem_limit) {
 
345
                debug("Job %u memory used:%u limit:%u KB", 
 
346
                      acct_job_id, total_job_mem, job_mem_limit);
 
347
        }
 
348
        if (acct_job_id && job_mem_limit && 
 
349
            (total_job_mem > job_mem_limit)) {
 
350
                error("Job %u exceeded %u KB memory limit, being killed",
 
351
                       acct_job_id, job_mem_limit);
 
352
                _acct_kill_job();
 
353
        }
 
354
 
 
355
finished:
 
356
        list_destroy(prec_list);
 
357
        processing = 0; 
 
358
        return;
 
359
}
 
360
 
 
361
/* _acct_kill_job() issue RPC to kill a slurm job */
 
362
static void _acct_kill_job(void)
 
363
{
 
364
        slurm_msg_t msg;
 
365
        job_step_kill_msg_t req;
 
366
 
 
367
        slurm_msg_t_init(&msg);
 
368
        /* 
 
369
         * Request message:
 
370
         */
 
371
        req.job_id      = acct_job_id;
 
372
        req.job_step_id = NO_VAL;
 
373
        req.signal      = SIGKILL;
 
374
        req.batch_flag  = 0;
 
375
        msg.msg_type    = REQUEST_CANCEL_JOB_STEP;
 
376
        msg.data        = &req;
 
377
 
 
378
        slurm_send_only_controller_msg(&msg);
 
379
}
 
380
 
 
381
/* _get_process_data_line() - get line of data from /proc/<pid>/stat
 
382
 *
 
383
 * IN:  in - input file descriptor
 
384
 * OUT: prec - the destination for the data
 
385
 *
 
386
 * RETVAL:      ==0 - no valid data
 
387
 *              !=0 - data are valid
 
388
 *
 
389
 * Based upon stat2proc() from the ps command. It can handle arbitrary executable 
 
390
 * file basenames for `cmd', i.e. those with embedded whitespace or embedded ')'s.  
 
391
 * Such names confuse %s (see scanf(3)), so the string is split and %39c is used 
 
392
 * instead. (except for embedded ')' "(%[^)]c)" would work.
 
393
 */
 
394
static int _get_process_data_line(int in, prec_t *prec) {
 
395
        char sbuf[256], *tmp;
 
396
        int num_read, nvals;
 
397
        char cmd[40], state[1];
 
398
        int ppid, pgrp, session, tty_nr, tpgid;
 
399
        long unsigned flags, minflt, cminflt, majflt, cmajflt;
 
400
        long unsigned utime, stime, starttime, vsize;
 
401
        long int cutime, cstime, priority, nice, timeout, itrealvalue, rss;
 
402
 
 
403
        num_read = read(in, sbuf, (sizeof(sbuf) - 1));
 
404
        if (num_read <= 0)
 
405
                return 0;
 
406
        sbuf[num_read] = '\0';
 
407
 
 
408
        tmp = strrchr(sbuf, ')');       /* split into "PID (cmd" and "<rest>" */
 
409
        *tmp = '\0';                    /* replace trailing ')' with NUL */
 
410
        /* parse these two strings separately, skipping the leading "(". */
 
411
        nvals = sscanf(sbuf, "%d (%39c", &prec->pid, cmd);
 
412
        if (nvals < 2)
 
413
                return 0;
 
414
 
 
415
        nvals = sscanf(tmp + 2,         /* skip space after ')' too */
 
416
                "%c %d %d %d %d %d "
 
417
                "%lu %lu %lu %lu %lu "
 
418
                "%lu %lu %ld %ld %ld %ld "
 
419
                "%ld %ld %lu %lu %ld",
 
420
                state, &ppid, &pgrp, &session, &tty_nr, &tpgid,
 
421
                &flags, &minflt, &cminflt, &majflt, &cmajflt,
 
422
                &utime, &stime, &cutime, &cstime, &priority, &nice,
 
423
                &timeout, &itrealvalue, &starttime, &vsize, &rss);
 
424
        /* There are some additional fields, which we do not scan or use */
 
425
        if ((nvals < 22) || (rss < 0))
 
426
                return 0;
 
427
 
 
428
        /* Copy the values that slurm records into our data structure */
 
429
        prec->ppid  = ppid;
 
430
        prec->pages = majflt;
 
431
        prec->usec  = utime;
 
432
        prec->ssec  = stime;
 
433
        prec->vsize = vsize / 1024;               /* convert from bytes to KB */
 
434
        prec->rss   = rss * getpagesize() / 1024; /* convert from pages to KB */
 
435
        return 1;
 
436
}
 
437
 
 
438
static void _task_sleep(int rem)
 
439
{
 
440
        while (rem)
 
441
                rem = sleep(rem);       /* subject to interupt */
 
442
}
 
443
 
 
444
/* _watch_tasks() -- monitor slurm jobs and track their memory usage
 
445
 *
 
446
 * IN, OUT:     Irrelevant; this is invoked by pthread_create()
 
447
 */
 
448
 
 
449
static void *_watch_tasks(void *arg)
 
450
{
 
451
        /* Give chance for processes to spawn before starting 
 
452
         * the polling. This should largely eliminate the 
 
453
         * the chance of having /proc open when the tasks are 
 
454
         * spawned, which would prevent a valid checkpoint/restart
 
455
         * with some systems */
 
456
        _task_sleep(1);
 
457
 
 
458
        while(!jobacct_shutdown) {  /* Do this until shutdown is requested */
 
459
                if(!jobacct_suspended) {
 
460
                        _get_process_data();    /* Update the data */ 
 
461
                }
 
462
                _task_sleep(freq);
 
463
        } 
 
464
        return NULL;
 
465
}
 
466
 
 
467
 
 
468
static void _destroy_prec(void *object)
 
469
{
 
470
        prec_t *prec = (prec_t *)object;
 
471
        xfree(prec);
 
472
        return;
 
473
}
 
474
 
 
475
/*
 
476
 * init() is called when the plugin is loaded, before any other functions
 
477
 * are called.  Put global initialization here.
 
478
 */
 
479
extern int init ( void )
 
480
{
 
481
        char *temp = slurm_get_proctrack_type();
 
482
        if(!strcasecmp(temp, "proctrack/pgid")) {
 
483
                info("WARNING: We will use a much slower algorithm with "
 
484
                     "proctrack/pgid, use Proctracktype=proctrack/linuxproc "
 
485
                     "or Proctracktype=proctrack/rms with %s",
 
486
                     plugin_name);
 
487
                pgid_plugin = true;
 
488
        }
 
489
        xfree(temp);
 
490
        temp = slurm_get_accounting_storage_type();
 
491
        if(!strcasecmp(temp, ACCOUNTING_STORAGE_TYPE_NONE)) {
 
492
                error("WARNING: Even though we are collecting accounting "
 
493
                      "information you have asked for it not to be stored "
 
494
                      "(%s) if this is not what you have in mind you will "
 
495
                      "need to change it.", ACCOUNTING_STORAGE_TYPE_NONE);
 
496
        }
 
497
        xfree(temp);
 
498
        verbose("%s loaded", plugin_name);
 
499
        return SLURM_SUCCESS;
 
500
}
 
501
 
 
502
extern int fini ( void )
 
503
{
 
504
        return SLURM_SUCCESS;
 
505
}
 
506
 
 
507
extern struct jobacctinfo *jobacct_gather_p_create(jobacct_id_t *jobacct_id)
 
508
{
 
509
        return jobacct_common_alloc_jobacct(jobacct_id);
 
510
}
 
511
 
 
512
extern void jobacct_gather_p_destroy(struct jobacctinfo *jobacct)
 
513
{
 
514
        jobacct_common_free_jobacct(jobacct);
 
515
}
 
516
 
 
517
extern int jobacct_gather_p_setinfo(struct jobacctinfo *jobacct, 
 
518
                                    enum jobacct_data_type type, void *data)
 
519
{
 
520
        return jobacct_common_setinfo(jobacct, type, data);
 
521
        
 
522
}
 
523
 
 
524
extern int jobacct_gather_p_getinfo(struct jobacctinfo *jobacct, 
 
525
                                    enum jobacct_data_type type, void *data)
 
526
{
 
527
        return jobacct_common_getinfo(jobacct, type, data);
 
528
}
 
529
 
 
530
extern void jobacct_gather_p_pack(struct jobacctinfo *jobacct, Buf buffer)
 
531
{
 
532
        jobacct_common_pack(jobacct, buffer);
 
533
}
 
534
 
 
535
extern int jobacct_gather_p_unpack(struct jobacctinfo **jobacct, Buf buffer)
 
536
{
 
537
        return jobacct_common_unpack(jobacct, buffer);
 
538
}
 
539
 
 
540
extern void jobacct_gather_p_aggregate(struct jobacctinfo *dest,
 
541
                                       struct jobacctinfo *from)
 
542
{
 
543
        jobacct_common_aggregate(dest, from);
 
544
}
 
545
 
 
546
/*
 
547
 * jobacct_startpoll() is called when the plugin is loaded by
 
548
 * slurmd, before any other functions are called.  Put global
 
549
 * initialization here.
 
550
 */
 
551
 
 
552
extern int jobacct_gather_p_startpoll(uint16_t frequency)
 
553
{
 
554
        int rc = SLURM_SUCCESS;
 
555
        
 
556
        pthread_attr_t attr;
 
557
        pthread_t _watch_tasks_thread_id;
 
558
         
 
559
        debug("%s loaded", plugin_name);
 
560
 
 
561
        debug("jobacct-gather: frequency = %d", frequency);
 
562
                
 
563
        jobacct_shutdown = false;
 
564
        
 
565
        if (frequency == 0) {   /* don't want dynamic monitoring? */
 
566
                debug2("jobacct-gather LINUX dynamic logging disabled");
 
567
                return rc;
 
568
        }
 
569
 
 
570
        freq = frequency;
 
571
        task_list = list_create(jobacct_common_free_jobacct);
 
572
        
 
573
        /* create polling thread */
 
574
        slurm_attr_init(&attr);
 
575
        if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
 
576
                error("pthread_attr_setdetachstate error %m");
 
577
        
 
578
        if  (pthread_create(&_watch_tasks_thread_id, &attr,
 
579
                            &_watch_tasks, NULL)) {
 
580
                debug("jobacct-gather failed to create _watch_tasks "
 
581
                      "thread: %m");
 
582
                frequency = 0;
 
583
        }
 
584
        else 
 
585
                debug3("jobacct-gather LINUX dynamic logging enabled");
 
586
        slurm_attr_destroy(&attr);
 
587
        
 
588
        return rc;
 
589
}
 
590
 
 
591
extern int jobacct_gather_p_endpoll()
 
592
{
 
593
        slurm_mutex_lock(&jobacct_lock);
 
594
        if(task_list)
 
595
                list_destroy(task_list);
 
596
        task_list = NULL;
 
597
        slurm_mutex_unlock(&jobacct_lock);
 
598
        
 
599
        if (slash_proc) {
 
600
                slurm_mutex_lock(&reading_mutex);
 
601
                (void) closedir(slash_proc);
 
602
                slurm_mutex_unlock(&reading_mutex);
 
603
        }
 
604
 
 
605
        jobacct_shutdown = true;
 
606
        
 
607
        return SLURM_SUCCESS;
 
608
}
 
609
 
 
610
extern void jobacct_gather_p_change_poll(uint16_t frequency)
 
611
{
 
612
        freq = frequency;
 
613
        if (freq == 0)
 
614
                jobacct_shutdown = true;
 
615
        return;
 
616
}
 
617
 
 
618
extern void jobacct_gather_p_suspend_poll()
 
619
{
 
620
        jobacct_common_suspend_poll();
 
621
}
 
622
 
 
623
extern void jobacct_gather_p_resume_poll()
 
624
{
 
625
        jobacct_common_resume_poll();
 
626
}
 
627
 
 
628
extern int jobacct_gather_p_set_proctrack_container_id(uint32_t id)
 
629
{
 
630
        return jobacct_common_set_proctrack_container_id(id);
 
631
}
 
632
 
 
633
extern int jobacct_gather_p_add_task(pid_t pid, jobacct_id_t *jobacct_id)
 
634
{
 
635
        return jobacct_common_add_task(pid, jobacct_id);
 
636
}
 
637
 
 
638
 
 
639
extern struct jobacctinfo *jobacct_gather_p_stat_task(pid_t pid)
 
640
{
 
641
        _get_process_data();
 
642
        return jobacct_common_stat_task(pid);
 
643
}
 
644
 
 
645
extern struct jobacctinfo *jobacct_gather_p_remove_task(pid_t pid)
 
646
{
 
647
        return jobacct_common_remove_task(pid);
 
648
}
 
649
 
 
650
extern void jobacct_gather_p_2_sacct(sacct_t *sacct, 
 
651
                                     struct jobacctinfo *jobacct)
 
652
{
 
653
        jobacct_common_2_sacct(sacct, jobacct);
 
654
}
 
655
 
 
656