1 /*****************************************************************************\
2 * slurm_acct_gather_profile.c - implementation-independent job profile
3 * accounting plugin definitions
4 *****************************************************************************
5 * Copyright (C) 2013 Bull S. A. S.
6 * Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois.
7 *
8 * Written by Rod Schultz <rod.schultz@bull.com>
9 *
10 * This file is part of Slurm, a resource management program.
11 * For details, see <https://slurm.schedmd.com>.
12 * Please also read the included file: DISCLAIMER.
13 *
14 * Slurm is free software; you can redistribute it and/or modify it under
15 * the terms of the GNU General Public License as published by the Free
16 * Software Foundation; either version 2 of the License, or (at your option)
17 * any later version.
18 *
19 * In addition, as a special exception, the copyright holders give permission
20 * to link the code of portions of this program with the OpenSSL library under
21 * certain conditions as described in each individual source file, and
22 * distribute linked combinations including the two. You must obey the GNU
23 * General Public License in all respects for all of the code used other than
24 * OpenSSL. If you modify file(s) with this exception, you may extend this
25 * exception to your version of the file(s), but you are not obligated to do
26 * so. If you do not wish to do so, delete this exception statement from your
27 * version. If you delete this exception statement from all source files in
28 * the program, then also delete it here.
29 *
30 * Slurm is distributed in the hope that it will be useful, but WITHOUT ANY
31 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
32 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
33 * details.
34 *
35 * You should have received a copy of the GNU General Public License along
36 * with Slurm; if not, write to the Free Software Foundation, Inc.,
37 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 \*****************************************************************************/
39
40 #ifdef HAVE_CONFIG_H
41 # include "config.h"
42 #endif
43
44 #include <pthread.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #if HAVE_SYS_PRCTL_H
49 # include <sys/prctl.h>
50 #endif
51
52 #include "src/common/macros.h"
53 #include "src/common/plugin.h"
54 #include "src/common/plugrack.h"
55 #include "src/common/read_config.h"
56 #include "src/common/slurm_acct_gather_filesystem.h"
57 #include "src/common/slurm_acct_gather_interconnect.h"
58 #include "src/common/slurm_acct_gather_profile.h"
59 #include "src/common/slurm_acct_gather_energy.h"
60 #include "src/common/slurm_jobacct_gather.h"
61 #include "src/common/slurm_protocol_api.h"
62 #include "src/common/timers.h"
63 #include "src/common/xmalloc.h"
64 #include "src/common/xstring.h"
65
66 /* These 2 should remain the same. */
67 #define SLEEP_TIME 1
68 #define USLEEP_TIME 1000000
69
70 typedef struct slurm_acct_gather_profile_ops {
71 void (*child_forked) (void);
72 void (*conf_options) (s_p_options_t **full_options,
73 int *full_options_cnt);
74 void (*conf_set) (s_p_hashtbl_t *tbl);
75 void* (*get) (enum acct_gather_profile_info info_type,
76 void *data);
77 int (*node_step_start) (stepd_step_rec_t*);
78 int (*node_step_end) (void);
79 int (*task_start) (uint32_t);
80 int (*task_end) (pid_t);
81 int64_t (*create_group)(const char*);
82 int (*create_dataset) (const char*, int64_t,
83 acct_gather_profile_dataset_t *);
84 int (*add_sample_data) (uint32_t, void*, time_t);
85 void (*conf_values) (List *data);
86 bool (*is_active) (uint32_t);
87
88 } slurm_acct_gather_profile_ops_t;
89
90 /*
91 * These strings must be kept in the same order as the fields
92 * declared for slurm_acct_gather_profile_ops_t.
93 */
94 static const char *syms[] = {
95 "acct_gather_profile_p_child_forked",
96 "acct_gather_profile_p_conf_options",
97 "acct_gather_profile_p_conf_set",
98 "acct_gather_profile_p_get",
99 "acct_gather_profile_p_node_step_start",
100 "acct_gather_profile_p_node_step_end",
101 "acct_gather_profile_p_task_start",
102 "acct_gather_profile_p_task_end",
103 "acct_gather_profile_p_create_group",
104 "acct_gather_profile_p_create_dataset",
105 "acct_gather_profile_p_add_sample_data",
106 "acct_gather_profile_p_conf_values",
107 "acct_gather_profile_p_is_active",
108 };
109
110 acct_gather_profile_timer_t acct_gather_profile_timer[PROFILE_CNT];
111
112 static bool acct_gather_profile_running = false;
113 static pthread_mutex_t profile_running_mutex = PTHREAD_MUTEX_INITIALIZER;
114
115 static slurm_acct_gather_profile_ops_t ops;
116 static plugin_context_t *g_context = NULL;
117 static pthread_mutex_t g_context_lock = PTHREAD_MUTEX_INITIALIZER;
118 static pthread_mutex_t profile_mutex = PTHREAD_MUTEX_INITIALIZER;
119 static pthread_t timer_thread_id = 0;
120 static pthread_mutex_t timer_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
121 static pthread_cond_t timer_thread_cond = PTHREAD_COND_INITIALIZER;
122 static bool init_run = false;
123
_set_freq(int type,char * freq,char * freq_def)124 static void _set_freq(int type, char *freq, char *freq_def)
125 {
126 if ((acct_gather_profile_timer[type].freq =
127 acct_gather_parse_freq(type, freq)) == -1)
128 if ((acct_gather_profile_timer[type].freq =
129 acct_gather_parse_freq(type, freq_def)) == -1)
130 acct_gather_profile_timer[type].freq = 0;
131 }
132
133 /*
134 * This thread wakes up other profiling threads in the jobacct plugins,
135 * and operates on a 1-second granularity.
136 */
137
_timer_thread(void * args)138 static void *_timer_thread(void *args)
139 {
140 int i, now, diff;
141 struct timeval tvnow;
142 struct timespec abs;
143
144 #if HAVE_SYS_PRCTL_H
145 if (prctl(PR_SET_NAME, "acctg_prof", NULL, NULL, NULL) < 0) {
146 error("%s: cannot set my name to %s %m",
147 __func__, "acctg_prof");
148 }
149 #endif
150
151 /* setup timer */
152 gettimeofday(&tvnow, NULL);
153 abs.tv_sec = tvnow.tv_sec;
154 abs.tv_nsec = tvnow.tv_usec * 1000;
155
156 while (init_run && acct_gather_profile_test()) {
157 slurm_mutex_lock(&g_context_lock);
158 now = time(NULL);
159
160 for (i=0; i<PROFILE_CNT; i++) {
161 if (acct_gather_suspend_test()) {
162 /* Handle suspended time as if it
163 * didn't happen */
164 if (!acct_gather_profile_timer[i].freq)
165 continue;
166 if (acct_gather_profile_timer[i].last_notify)
167 acct_gather_profile_timer[i].
168 last_notify += SLEEP_TIME;
169 else
170 acct_gather_profile_timer[i].
171 last_notify = now;
172 continue;
173 }
174
175 diff = now - acct_gather_profile_timer[i].last_notify;
176 /* info ("%d is %d and %d", i, */
177 /* acct_gather_profile_timer[i].freq, */
178 /* diff); */
179 if (!acct_gather_profile_timer[i].freq
180 || (diff < acct_gather_profile_timer[i].freq))
181 continue;
182 if (!acct_gather_profile_test())
183 break; /* Shutting down */
184 debug2("profile signaling type %s",
185 acct_gather_profile_type_t_name(i));
186
187 /* signal poller to start */
188 slurm_mutex_lock(&acct_gather_profile_timer[i].
189 notify_mutex);
190 slurm_cond_signal(
191 &acct_gather_profile_timer[i].notify);
192 slurm_mutex_unlock(&acct_gather_profile_timer[i].
193 notify_mutex);
194 acct_gather_profile_timer[i].last_notify = now;
195 }
196 slurm_mutex_unlock(&g_context_lock);
197
198 /*
199 * Sleep until the next second interval, or until signaled
200 * to shutdown by acct_gather_profile_fini().
201 */
202
203 abs.tv_sec += 1;
204 slurm_mutex_lock(&timer_thread_mutex);
205 slurm_cond_timedwait(&timer_thread_cond, &timer_thread_mutex,
206 &abs);
207 slurm_mutex_unlock(&timer_thread_mutex);
208 }
209
210 return NULL;
211 }
212
acct_gather_profile_init(void)213 extern int acct_gather_profile_init(void)
214 {
215 int retval = SLURM_SUCCESS;
216 char *plugin_type = "acct_gather_profile";
217 char *type = NULL;
218
219 if (init_run && g_context)
220 return retval;
221
222 slurm_mutex_lock(&g_context_lock);
223
224 if (g_context)
225 goto done;
226
227 type = slurm_get_acct_gather_profile_type();
228
229 g_context = plugin_context_create(
230 plugin_type, type, (void **)&ops, syms, sizeof(syms));
231
232 if (!g_context) {
233 error("cannot create %s context for %s", plugin_type, type);
234 retval = SLURM_ERROR;
235 goto done;
236 }
237 init_run = true;
238
239 done:
240 slurm_mutex_unlock(&g_context_lock);
241 if (retval == SLURM_SUCCESS)
242 retval = acct_gather_conf_init();
243 if (retval != SLURM_SUCCESS)
244 fatal("can not open the %s plugin", type);
245 xfree(type);
246
247 return retval;
248 }
249
acct_gather_profile_fini(void)250 extern int acct_gather_profile_fini(void)
251 {
252 int rc = SLURM_SUCCESS, i;
253
254 if (!g_context)
255 return SLURM_SUCCESS;
256
257 slurm_mutex_lock(&g_context_lock);
258
259 if (!g_context)
260 goto done;
261
262 init_run = false;
263
264 for (i=0; i < PROFILE_CNT; i++) {
265 switch (i) {
266 case PROFILE_ENERGY:
267 acct_gather_energy_fini();
268 break;
269 case PROFILE_TASK:
270 jobacct_gather_fini();
271 break;
272 case PROFILE_FILESYSTEM:
273 acct_gather_filesystem_fini();
274 break;
275 case PROFILE_NETWORK:
276 acct_gather_interconnect_fini();
277 break;
278 default:
279 fatal("Unhandled profile option %d please update "
280 "slurm_acct_gather_profile.c "
281 "(acct_gather_profile_fini)", i);
282 }
283 }
284
285 if (timer_thread_id) {
286 slurm_mutex_lock(&timer_thread_mutex);
287 slurm_cond_signal(&timer_thread_cond);
288 slurm_mutex_unlock(&timer_thread_mutex);
289 pthread_join(timer_thread_id, NULL);
290 }
291
292 rc = plugin_context_destroy(g_context);
293 g_context = NULL;
294 done:
295 slurm_mutex_unlock(&g_context_lock);
296
297 return rc;
298 }
299
acct_gather_profile_to_string(uint32_t profile)300 extern char *acct_gather_profile_to_string(uint32_t profile)
301 {
302 static char profile_str[128];
303
304 profile_str[0] = '\0';
305 if (profile == ACCT_GATHER_PROFILE_NOT_SET)
306 strcat(profile_str, "NotSet");
307 else if (profile == ACCT_GATHER_PROFILE_NONE)
308 strcat(profile_str, "None");
309 else {
310 if (profile & ACCT_GATHER_PROFILE_ENERGY)
311 strcat(profile_str, "Energy");
312 if (profile & ACCT_GATHER_PROFILE_LUSTRE) {
313 if (profile_str[0])
314 strcat(profile_str, ",");
315 strcat(profile_str, "Lustre");
316 }
317 if (profile & ACCT_GATHER_PROFILE_NETWORK) {
318 if (profile_str[0])
319 strcat(profile_str, ",");
320 strcat(profile_str, "Network");
321 }
322 if (profile & ACCT_GATHER_PROFILE_TASK) {
323 if (profile_str[0])
324 strcat(profile_str, ",");
325 strcat(profile_str, "Task");
326 }
327 }
328 return profile_str;
329 }
330
acct_gather_profile_from_string(const char * profile_str)331 extern uint32_t acct_gather_profile_from_string(const char *profile_str)
332 {
333 uint32_t profile = ACCT_GATHER_PROFILE_NOT_SET;
334
335 if (!profile_str) {
336 } else if (xstrcasestr(profile_str, "none"))
337 profile = ACCT_GATHER_PROFILE_NONE;
338 else if (xstrcasestr(profile_str, "all"))
339 profile = ACCT_GATHER_PROFILE_ALL;
340 else {
341 if (xstrcasestr(profile_str, "energy"))
342 profile |= ACCT_GATHER_PROFILE_ENERGY;
343 if (xstrcasestr(profile_str, "task"))
344 profile |= ACCT_GATHER_PROFILE_TASK;
345
346 if (xstrcasestr(profile_str, "lustre"))
347 profile |= ACCT_GATHER_PROFILE_LUSTRE;
348
349 if (xstrcasestr(profile_str, "network"))
350 profile |= ACCT_GATHER_PROFILE_NETWORK;
351 }
352
353 return profile;
354 }
355
acct_gather_profile_type_to_string(uint32_t series)356 extern char *acct_gather_profile_type_to_string(uint32_t series)
357 {
358 if (series == ACCT_GATHER_PROFILE_ENERGY)
359 return "Energy";
360 else if (series == ACCT_GATHER_PROFILE_TASK)
361 return "Task";
362 else if (series == ACCT_GATHER_PROFILE_LUSTRE)
363 return "Lustre";
364 else if (series == ACCT_GATHER_PROFILE_NETWORK)
365 return "Network";
366
367 return "Unknown";
368 }
369
acct_gather_profile_type_from_string(char * series_str)370 extern uint32_t acct_gather_profile_type_from_string(char *series_str)
371 {
372 if (!xstrcasecmp(series_str, "energy"))
373 return ACCT_GATHER_PROFILE_ENERGY;
374 else if (!xstrcasecmp(series_str, "task"))
375 return ACCT_GATHER_PROFILE_TASK;
376 else if (!xstrcasecmp(series_str, "lustre"))
377 return ACCT_GATHER_PROFILE_LUSTRE;
378 else if (!xstrcasecmp(series_str, "network"))
379 return ACCT_GATHER_PROFILE_NETWORK;
380
381 return ACCT_GATHER_PROFILE_NOT_SET;
382 }
383
acct_gather_profile_type_t_name(acct_gather_profile_type_t type)384 extern char *acct_gather_profile_type_t_name(acct_gather_profile_type_t type)
385 {
386 switch (type) {
387 case PROFILE_ENERGY:
388 return "Energy";
389 break;
390 case PROFILE_TASK:
391 return "Task";
392 break;
393 case PROFILE_FILESYSTEM:
394 return "Lustre";
395 break;
396 case PROFILE_NETWORK:
397 return "Network";
398 break;
399 case PROFILE_CNT:
400 return "CNT?";
401 break;
402 default:
403 fatal("Unhandled profile option %d please update "
404 "slurm_acct_gather_profile.c "
405 "(acct_gather_profile_type_t_name)", type);
406 }
407
408 return "Unknown";
409 }
410
acct_gather_profile_dataset_str(acct_gather_profile_dataset_t * dataset,void * data,char * str,int str_len)411 extern char *acct_gather_profile_dataset_str(
412 acct_gather_profile_dataset_t *dataset, void *data,
413 char *str, int str_len)
414 {
415 int cur_loc = 0;
416
417 while (dataset && (dataset->type != PROFILE_FIELD_NOT_SET)) {
418 switch (dataset->type) {
419 case PROFILE_FIELD_UINT64:
420 cur_loc += snprintf(str+cur_loc, str_len-cur_loc,
421 "%s%s=%"PRIu64,
422 cur_loc ? " " : "",
423 dataset->name, *(uint64_t *)data);
424 data += sizeof(uint64_t);
425 break;
426 case PROFILE_FIELD_DOUBLE:
427 cur_loc += snprintf(str+cur_loc, str_len-cur_loc,
428 "%s%s=%lf",
429 cur_loc ? " " : "",
430 dataset->name, *(double *)data);
431 data += sizeof(double);
432 break;
433 case PROFILE_FIELD_NOT_SET:
434 break;
435 }
436
437 if (cur_loc >= str_len)
438 break;
439 dataset++;
440 }
441
442 return str;
443 }
444
acct_gather_profile_startpoll(char * freq,char * freq_def)445 extern int acct_gather_profile_startpoll(char *freq, char *freq_def)
446 {
447 int i;
448 uint32_t profile = ACCT_GATHER_PROFILE_NOT_SET;
449
450 if (acct_gather_profile_init() < 0)
451 return SLURM_ERROR;
452
453 slurm_mutex_lock(&profile_running_mutex);
454 if (acct_gather_profile_running) {
455 slurm_mutex_unlock(&profile_running_mutex);
456 error("acct_gather_profile_startpoll: poll already started!");
457 return SLURM_SUCCESS;
458 }
459 acct_gather_profile_running = true;
460 slurm_mutex_unlock(&profile_running_mutex);
461
462 (*(ops.get))(ACCT_GATHER_PROFILE_RUNNING, &profile);
463 xassert(profile != ACCT_GATHER_PROFILE_NOT_SET);
464
465 for (i=0; i < PROFILE_CNT; i++) {
466 memset(&acct_gather_profile_timer[i], 0,
467 sizeof(acct_gather_profile_timer_t));
468 slurm_cond_init(&acct_gather_profile_timer[i].notify, NULL);
469 slurm_mutex_init(&acct_gather_profile_timer[i].notify_mutex);
470
471 switch (i) {
472 case PROFILE_ENERGY:
473 if (!(profile & ACCT_GATHER_PROFILE_ENERGY))
474 break;
475 _set_freq(i, freq, freq_def);
476
477 acct_gather_energy_startpoll(
478 acct_gather_profile_timer[i].freq);
479 break;
480 case PROFILE_TASK:
481 /* Always set up the task (always first) to be
482 done since it is used to control memory
483 consumption and such. It will check
484 profile inside it's plugin.
485 */
486 _set_freq(i, freq, freq_def);
487
488 jobacct_gather_startpoll(
489 acct_gather_profile_timer[i].freq);
490
491 break;
492 case PROFILE_FILESYSTEM:
493 if (!(profile & ACCT_GATHER_PROFILE_LUSTRE))
494 break;
495 _set_freq(i, freq, freq_def);
496
497 acct_gather_filesystem_startpoll(
498 acct_gather_profile_timer[i].freq);
499 break;
500 case PROFILE_NETWORK:
501 if (!(profile & ACCT_GATHER_PROFILE_NETWORK))
502 break;
503 _set_freq(i, freq, freq_def);
504
505 acct_gather_interconnect_startpoll(
506 acct_gather_profile_timer[i].freq);
507 break;
508 default:
509 fatal("Unhandled profile option %d please update "
510 "slurm_acct_gather_profile.c "
511 "(acct_gather_profile_startpoll)", i);
512 }
513 }
514
515 /* create polling thread */
516 slurm_thread_create(&timer_thread_id, _timer_thread, NULL);
517
518 debug3("acct_gather_profile_startpoll dynamic logging enabled");
519
520 return SLURM_SUCCESS;
521 }
522
acct_gather_profile_endpoll(void)523 extern void acct_gather_profile_endpoll(void)
524 {
525 int i;
526
527 slurm_mutex_lock(&profile_running_mutex);
528 if (!acct_gather_profile_running) {
529 slurm_mutex_unlock(&profile_running_mutex);
530 debug2("acct_gather_profile_startpoll: poll already ended!");
531 return;
532 }
533 acct_gather_profile_running = false;
534 slurm_mutex_unlock(&profile_running_mutex);
535
536 for (i=0; i < PROFILE_CNT; i++) {
537 /* end remote threads */
538 slurm_mutex_lock(&acct_gather_profile_timer[i].notify_mutex);
539 slurm_cond_signal(&acct_gather_profile_timer[i].notify);
540 slurm_mutex_unlock(&acct_gather_profile_timer[i].notify_mutex);
541 acct_gather_profile_timer[i].freq = 0;
542 switch (i) {
543 case PROFILE_ENERGY:
544 break;
545 case PROFILE_TASK:
546 jobacct_gather_endpoll();
547 break;
548 case PROFILE_FILESYSTEM:
549 break;
550 case PROFILE_NETWORK:
551 break;
552 default:
553 fatal("Unhandled profile option %d please update "
554 "slurm_acct_gather_profile.c "
555 "(acct_gather_profile_endpoll)", i);
556 }
557 }
558 }
559
acct_gather_profile_g_child_forked(void)560 extern int acct_gather_profile_g_child_forked(void)
561 {
562 if (acct_gather_profile_init() < 0)
563 return SLURM_ERROR;
564
565 (*(ops.child_forked))();
566 return SLURM_SUCCESS;
567 }
568
acct_gather_profile_g_conf_options(s_p_options_t ** full_options,int * full_options_cnt)569 extern int acct_gather_profile_g_conf_options(s_p_options_t **full_options,
570 int *full_options_cnt)
571 {
572 if (acct_gather_profile_init() < 0)
573 return SLURM_ERROR;
574
575 (*(ops.conf_options))(full_options, full_options_cnt);
576 return SLURM_SUCCESS;
577 }
578
acct_gather_profile_g_conf_set(s_p_hashtbl_t * tbl)579 extern int acct_gather_profile_g_conf_set(s_p_hashtbl_t *tbl)
580 {
581 if (acct_gather_profile_init() < 0)
582 return SLURM_ERROR;
583
584 (*(ops.conf_set))(tbl);
585 return SLURM_SUCCESS;
586 }
587
acct_gather_profile_g_get(enum acct_gather_profile_info info_type,void * data)588 extern int acct_gather_profile_g_get(enum acct_gather_profile_info info_type,
589 void *data)
590 {
591 if (acct_gather_profile_init() < 0)
592 return SLURM_ERROR;
593
594 (*(ops.get))(info_type, data);
595 return SLURM_SUCCESS;
596 }
597
acct_gather_profile_g_node_step_start(stepd_step_rec_t * job)598 extern int acct_gather_profile_g_node_step_start(stepd_step_rec_t* job)
599 {
600 if (acct_gather_profile_init() < 0)
601 return SLURM_ERROR;
602
603 return (*(ops.node_step_start))(job);
604 }
605
acct_gather_profile_g_node_step_end(void)606 extern int acct_gather_profile_g_node_step_end(void)
607 {
608 int retval = SLURM_ERROR;
609
610
611 retval = (*(ops.node_step_end))();
612 return retval;
613 }
614
acct_gather_profile_g_task_start(uint32_t taskid)615 extern int acct_gather_profile_g_task_start(uint32_t taskid)
616 {
617 int retval = SLURM_ERROR;
618
619 if (acct_gather_profile_init() < 0)
620 return retval;
621
622 slurm_mutex_lock(&profile_mutex);
623 retval = (*(ops.task_start))(taskid);
624 slurm_mutex_unlock(&profile_mutex);
625 return retval;
626 }
627
acct_gather_profile_g_task_end(pid_t taskpid)628 extern int acct_gather_profile_g_task_end(pid_t taskpid)
629 {
630 int retval = SLURM_ERROR;
631
632 if (acct_gather_profile_init() < 0)
633 return retval;
634
635 slurm_mutex_lock(&profile_mutex);
636 retval = (*(ops.task_end))(taskpid);
637 slurm_mutex_unlock(&profile_mutex);
638 return retval;
639 }
640
acct_gather_profile_g_create_group(const char * name)641 extern int64_t acct_gather_profile_g_create_group(const char *name)
642 {
643 int64_t retval = SLURM_ERROR;
644
645 if (acct_gather_profile_init() < 0)
646 return retval;
647
648 slurm_mutex_lock(&profile_mutex);
649 retval = (*(ops.create_group))(name);
650 slurm_mutex_unlock(&profile_mutex);
651 return retval;
652 }
653
acct_gather_profile_g_create_dataset(const char * name,int64_t parent,acct_gather_profile_dataset_t * dataset)654 extern int acct_gather_profile_g_create_dataset(
655 const char *name, int64_t parent,
656 acct_gather_profile_dataset_t *dataset)
657 {
658 int retval = SLURM_ERROR;
659
660 if (acct_gather_profile_init() < 0)
661 return retval;
662
663 slurm_mutex_lock(&profile_mutex);
664 retval = (*(ops.create_dataset))(name, parent, dataset);
665 slurm_mutex_unlock(&profile_mutex);
666 return retval;
667 }
668
acct_gather_profile_g_add_sample_data(int dataset_id,void * data,time_t sample_time)669 extern int acct_gather_profile_g_add_sample_data(int dataset_id, void* data,
670 time_t sample_time)
671 {
672 int retval = SLURM_ERROR;
673
674 if (acct_gather_profile_init() < 0)
675 return retval;
676
677 slurm_mutex_lock(&profile_mutex);
678 retval = (*(ops.add_sample_data))(dataset_id, data, sample_time);
679 slurm_mutex_unlock(&profile_mutex);
680 return retval;
681 }
682
acct_gather_profile_g_conf_values(void * data)683 extern void acct_gather_profile_g_conf_values(void *data)
684 {
685 if (acct_gather_profile_init() < 0)
686 return;
687
688 (*(ops.conf_values))(data);
689 }
690
acct_gather_profile_g_is_active(uint32_t type)691 extern bool acct_gather_profile_g_is_active(uint32_t type)
692 {
693 if (acct_gather_profile_init() < 0)
694 return false;
695
696 return (*(ops.is_active))(type);
697 }
698
acct_gather_profile_test(void)699 extern bool acct_gather_profile_test(void)
700 {
701 bool rc;
702 slurm_mutex_lock(&profile_running_mutex);
703 rc = acct_gather_profile_running;
704 slurm_mutex_unlock(&profile_running_mutex);
705 return rc;
706 }
707