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