1
/*___INFO__MARK_BEGIN__*/
2
/*************************************************************************
4
* The Contents of this file are made available subject to the terms of
5
* the Sun Industry Standards Source License Version 1.2
7
* Sun Microsystems Inc., March, 2001
10
* Sun Industry Standards Source License Version 1.2
11
* =================================================
12
* The contents of this file are subject to the Sun Industry Standards
13
* Source License Version 1.2 (the "License"); You may not use this file
14
* except in compliance with the License. You may obtain a copy of the
15
* License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
17
* Software provided under this License is provided on an "AS IS" basis,
18
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
19
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
20
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
21
* See the License for the specific provisions governing your rights and
22
* obligations concerning the Software.
24
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
26
* Copyright: 2001 by Sun Microsystems, Inc.
28
* All Rights Reserved.
30
************************************************************************/
31
/*___INFO__MARK_END__*/
42
#include "sge_mtutil.h"
45
#define DEBUG RMON_LOCAL
49
* It increases scheduler dispatch time by 60-70%.
55
/* ALPHA (osf4 and tru64) have f(un)lockfile, but prototype is missing */
57
extern void flockfile(FILE *);
58
extern void funlockfile(FILE *);
62
RMON_NONE = 0, /* monitoring off */
63
RMON_LOCAL = 1, /* monitoring on */
64
RMON_BUF_SIZE = 5120 /* size of buffer used for monitoring messages */
67
monitoring_level RMON_DEBUG_ON = { {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L} };
68
monitoring_level RMON_DEBUG_ON_STORAGE = { {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L} };
70
static const char* empty = " ";
72
static u_long mtype = RMON_NONE;
73
#ifdef DEBUG_CLIENT_SUPPORT
74
static u_long mtype_storage = RMON_NONE;
78
static void mwrite(char *message, const char *thread_name);
79
static int set_debug_level_from_env(void);
80
static int set_debug_target_from_env(void);
81
static void rmon_mprintf_va(int debug_class, const char* fmt, va_list args);
83
#ifdef DEBUG_CLIENT_SUPPORT
84
static pthread_mutex_t rmon_print_callback_mutex = PTHREAD_MUTEX_INITIALIZER;
85
static pthread_mutex_t rmon_condition_mutex = PTHREAD_MUTEX_INITIALIZER;
86
static rmon_print_callback_func_t rmon_print_callback = NULL;
87
#define RMON_CALLBACK_FUNC_LOCK() pthread_mutex_lock(&rmon_print_callback_mutex)
88
#define RMON_CALLBACK_FUNC_UNLOCK() pthread_mutex_unlock(&rmon_print_callback_mutex)
89
#define RMON_CONDITION_LOCK() pthread_mutex_lock(&rmon_condition_mutex)
90
#define RMON_CONDITION_UNLOCK() pthread_mutex_unlock(&rmon_condition_mutex)
94
static pthread_key_t rmon_ctx_key;
95
static pthread_once_t rmon_ctx_key_once = PTHREAD_ONCE_INIT;
96
static void rmon_ctx_key_init(void);
97
static void rmon_ctx_key_destroy(void * ctx);
99
static pthread_key_t rmon_helper_key;
100
static pthread_once_t rmon_helper_key_once = PTHREAD_ONCE_INIT;
101
static void rmon_helper_key_init(void);
102
static void rmon_helper_key_destroy(void * ctx);
105
rmon_ctx_t* rmon_get_thread_ctx(void)
107
pthread_once(&rmon_ctx_key_once, rmon_ctx_key_init);
108
return (rmon_ctx_t*) pthread_getspecific(rmon_ctx_key);
111
void rmon_set_thread_ctx(rmon_ctx_t* ctx) {
112
pthread_once(&rmon_ctx_key_once, rmon_ctx_key_init);
113
pthread_setspecific(rmon_ctx_key, ctx);
116
/* Allocate the key */
117
static void rmon_ctx_key_init(void)
119
pthread_key_create(&rmon_ctx_key, rmon_ctx_key_destroy);
122
/* Free the thread-specific buffer */
123
static void rmon_ctx_key_destroy(void * ctx)
125
/* Nothing to destroy */
128
rmon_helper_t *rmon_get_helper(void)
130
rmon_helper_t *helper = NULL;
132
pthread_once(&rmon_helper_key_once, rmon_helper_key_init);
134
helper = pthread_getspecific(rmon_helper_key);
135
if (helper == NULL) {
136
helper = (rmon_helper_t *)malloc(sizeof(rmon_helper_t));
138
memset(helper, 0, sizeof(rmon_helper_t));
139
pthread_setspecific(rmon_helper_key, helper);
144
static void rmon_helper_key_init(void)
146
pthread_key_create(&rmon_helper_key, rmon_helper_key_destroy);
149
static void rmon_helper_key_destroy(void * ctx)
154
/****** rmon/Introduction ******************************************************
156
* RMON - Grid Engine Monitoring Interface
159
* The RMON library is a set of functions, which do allow monitoring of
160
* of application execution. The functions provided, however, should not
161
* be used directly. Rather the RMON functions are utilized by a set of
162
* monitoring macros, like 'DENTER' or 'DEXIT'.
164
* If monitoring is active, the RMON functions do get called very frequently.
165
* Hence, the overhead caused by monitoring needs to be minimal. For this
166
* reason, access to external global and static global variables is NOT
167
* synchronized through a mutex! Not using a lock of type 'pthread_mutex_t'
168
* also means that the RMON functions are async-signal safe.
170
* To use RMON library in a multi threaded environment, some restrictions
171
* must be followed strictly! It is of utmost importance, that the function
172
* 'rmon_mopen()' is ONLY invoked from exactly one thread. The thread which
173
* is calling 'rmon_mopen()' must be the ONLY thread at this point in time.
174
* 'DENTER_MAIN' is the only macro from which 'rmon_mopen()' is called. The
175
* macro 'DENTER_MAIN' is used at the beginning of a main function. At this
176
* point in time, the so called main-thread is the only thread.
178
* It is safe to call the remaining RMON functions, like 'rmon_menter()' or
179
* 'rmon_mexit()', from within multiple threads. 'rmon_mopen()' is the only
180
* RMON function which does change the critical global variables ('mtype',
181
* 'rmon_fp' and 'RMON_DEBUG_ON'). 'rmon_menter()' and 'rmon_mexit()' are used by
182
* the macro 'DENTER' and 'DEXIT', respectively.
184
*******************************************************************************/
186
/****** rmon_macros/rmon_condition() *******************************************
188
* rmon_condition() -- Check monitoring condition.
191
* int rmon_condition(int layer, int class)
194
* Check whether monitoring should be enabled for the given combination of
195
* 'layer' and 'class'.
198
* int layer - monitor layer
199
* int class - monitor class
206
* MT-NOTE: 'rmon_condition()' is MT safe with exceptions. See introduction!
208
*******************************************************************************/
209
int rmon_condition(int layer, int class)
212
#define MLGETL(s, i) ((s)->ml[i]) /* for the sake of speed */
216
* This is only a static u_long value used as flag for switching
217
* debug printing on/off. Therefore we don't need a mutex lock
220
#ifdef DEBUG_CLIENT_SUPPORT
221
if ( mtype == RMON_NONE ) {
225
/* if debug printing is on we use a lock for further layer checking */
226
RMON_CONDITION_LOCK();
228
ret_val = ((mtype != RMON_NONE) && (class & MLGETL(&RMON_DEBUG_ON, layer))) ? 1 : 0;
229
#ifdef DEBUG_CLIENT_SUPPORT
230
RMON_CONDITION_UNLOCK();
234
} /* rmon_condition() */
237
/****** rmon_macros/rmon_debug_client_callback() ****************************
239
* rmon_debug_client_callback() -- callback for debug clients
242
* static void rmon_debug_client_callback(int dc_connected, int debug_level)
245
* Is called when a debug client is connected/disconnected or on
246
* debug level changes. Use cl_com_application_debug() to send debug
247
* messages to the connected qping -dump client.
250
* int dc_connected - 1 debug client is connected
251
* 0 no debug client is connected
252
* int debug_level - debug level from 0 (off) to 5(DPRINTF)
254
* MT-NOTE: rmon_debug_client_callback() is MT safe
255
* (but is called from commlib thread, which means that no
256
* qmaster thread specifc setup is done), just use global
257
* thread locking methods which are initalized when called, or
258
* initalized at compile time)
260
*******************************************************************************/
261
void rmon_debug_client_callback(int dc_connected, int debug_level) {
262
#ifdef DEBUG_CLIENT_SUPPORT
263
RMON_CONDITION_LOCK();
265
/* we are saving the old value of the RMON_DEBUG_ON structure into RMON_DEBUG_ON_STORAGE */
267
/* TODO: support rmon debug levels with $SGE_DEBUG_LEVEL string ?
268
* if so, the debug_level parameter should be a string value
270
(&RMON_DEBUG_ON)->ml[TOP_LAYER] = 2;
271
if (debug_level > 1) {
272
(&RMON_DEBUG_ON)->ml[TOP_LAYER] = 3;
276
(&RMON_DEBUG_ON)->ml[TOP_LAYER] = (&RMON_DEBUG_ON_STORAGE)->ml[TOP_LAYER];
277
mtype = mtype_storage;
279
RMON_CONDITION_UNLOCK();
285
void rmon_set_print_callback(rmon_print_callback_func_t function_p) {
286
#ifdef DEBUG_CLIENT_SUPPORT
287
if (function_p != NULL) {
288
RMON_CALLBACK_FUNC_LOCK();
289
rmon_print_callback = *function_p;
290
RMON_CALLBACK_FUNC_UNLOCK();
299
/****** rmon_macros/rmon_is_enabled() ******************************************
301
* rmon_is_enabled() -- Check if monitoring is enabled.
304
* int rmon_is_enabled(void)
307
* Check if monitoring is enabled. Note that even if monitoring is enabled
308
* no actual monitoring output may be generated. Generation of monitoring
309
* output is controlled by 'rmon_condition()'.
315
* 1 - monitoring enabled
316
* 0 - monitoring disabled
319
* MT-NOTE: 'rmon_is_enabled()' is MT safe with exceptions. See introduction!
321
*******************************************************************************/
322
int rmon_is_enabled(void)
324
return ((mtype == RMON_LOCAL) ? 1 : 0);
325
} /* rmon_is_enabled() */
327
/****** rmon_macros/rmon_mopen() ***********************************************
329
* rmon_mopen() -- Open, i.e. initialize monitoring.
332
* void rmon_mopen(int *argc, char *argv[], char *programname)
335
* Initialize monitoring. Clear all monitoring levels. Set monitoring levels
336
* according to 'SGE_DEBUG_LEVEL' environment variable. Set monitoring
337
* target (i.e. output stream) according to 'SGE_DEBUG_TARGET' environment
338
* variable. Enable monitoring.
340
* NOTE: Even though 'argc' and 'argv' are not used, they do make sure that
341
* 'rmon_mopen()' is only used within a main function to a certain degree.
344
* int *argc - not used
345
* char *argv[] - not used
346
* char *programname - not used
352
* MT-NOTE: 'rmon_mopen()' is NOT MT safe. See introduction!
354
*******************************************************************************/
355
void rmon_mopen(int *argc, char *argv[], char *programname)
359
rmon_mlclr(&RMON_DEBUG_ON);
362
ret = set_debug_level_from_env();
363
ret = set_debug_target_from_env();
370
#ifdef DEBUG_CLIENT_SUPPORT
371
mtype_storage = mtype;
377
/****** rmon_macros/rmon_menter() **********************************************
379
* rmon_menter() -- Monitor function entry
382
* void rmon_menter(const char *func)
385
* Monitor function entry. Generate function entry message.
388
* const char *func - function name
394
* MT-NOTE: 'rmon_menter()' is MT safe with exceptions. See introduction!
396
*******************************************************************************/
398
void rmon_menter(const char *func, const char *thread_name)
400
char msgbuf[RMON_BUF_SIZE];
402
rmon_ctx_t *ctx = rmon_get_thread_ctx();
404
ctx->menter(ctx, func);
408
sprintf(msgbuf, "--> %s() {\n", func);
409
mwrite(msgbuf, thread_name);
414
/****** rmon_macros/rmon_mexit() ***********************************************
416
* rmon_mexit() -- Monitor function exit
419
* void rmon_mexit(const char *func, const char *file, int line)
422
* Monitor function exit. Generate function exit message.
425
* const char *func - function name
426
* const char *file - source file in which function is defined
427
* int line - number of invokation source line
433
* MT-NOTE: 'rmon_mexit()' is MT safe with exceptions. See introduction!
435
*******************************************************************************/
436
void rmon_mexit(const char *func, const char *file, int line, const char *thread_name)
438
char msgbuf[RMON_BUF_SIZE];
440
rmon_ctx_t *ctx = rmon_get_thread_ctx();
442
ctx->mexit(ctx, func, file, line);
446
sprintf(msgbuf, "<-- %s() %s %d }\n", func, file, line);
447
mwrite(msgbuf, thread_name);
451
/****** rmon_macros/rmon_mtrace() **********************************************
453
* rmon_mtrace() -- Monitor function progress
456
* void rmon_mtrace(const char *func, const char *file, int line)
459
* Monitor function progress. Generate function trace message.
462
* const char *func - function name
463
* const char *file - source file in which function is defined
464
* int line - number of invokation source line
470
* MT-NOTE: 'rmon_mtrace()' is MT safe with exceptions. See introduction!
472
*******************************************************************************/
473
void rmon_mtrace(const char *func, const char *file, int line, const char *thread_name)
475
char msgbuf[RMON_BUF_SIZE];
477
rmon_ctx_t *ctx = rmon_get_thread_ctx();
479
ctx->mtrace(ctx, func, file, line);
483
strcpy(msgbuf, empty);
484
sprintf(&msgbuf[4], "%s:%s:%d\n", func, file, line);
485
mwrite(msgbuf, thread_name);
486
} /* rmon_mtrace() */
488
/****** rmon_macros/rmon_mprintf() *********************************************
490
* rmon_mprintf() -- Print formatted monitoring message.
493
* void rmon_mprintf(const char *fmt, ...)
496
* Print formatted monitoring message.
499
* const char *fmt - format string
500
* ... - variable argument list
506
* MT-NOTE: 'rmon_mprintf()' is MT safe with exceptions. See introduction!
508
*******************************************************************************/
509
void rmon_mprintf(int debug_class, const char *fmt,...)
514
rmon_mprintf_va(debug_class, fmt, args);
518
} /* rmon_mprintf() */
521
void rmon_mprintf_lock(const char* fmt, ...) {
524
rmon_mprintf_va(LOCK, fmt, args);
528
void rmon_mprintf_info(const char* fmt, ...) {
531
rmon_mprintf_va(INFOPRINT, fmt, args);
535
void rmon_mprintf_timing(const char* fmt, ...) {
538
rmon_mprintf_va(TIMING, fmt, args);
542
void rmon_mprintf_special(const char* fmt, ...) {
545
rmon_mprintf_va(SPECIAL, fmt, args);
549
static void rmon_mprintf_va(int debug_class, const char* fmt, va_list args) {
550
char msgbuf[RMON_BUF_SIZE];
551
rmon_helper_t *helper = NULL;
553
rmon_ctx_t *ctx = rmon_get_thread_ctx();
555
ctx->mprintf(ctx, debug_class, fmt, args);
559
helper = rmon_get_helper();
560
strcpy(msgbuf, empty);
561
vsnprintf(&msgbuf[4], (RMON_BUF_SIZE) - 10 , fmt, args);
562
if ((helper != NULL) && (helper->thread_name != NULL) && (strlen(helper->thread_name) > 0)) {
563
mwrite(msgbuf, helper->thread_name);
565
mwrite(msgbuf, NULL);
569
/****** rmon_macros/mwrite() ***************************************************
571
* mwrite() -- Write monitoring message
574
* static void mwrite(char *message)
577
* Write monitoring message. The message is written to the output stream
578
* associated with 'rmon_fp'. The output stream is flushed immediately.
580
* A prefix is added to 'message'. It does consist of a trace sequence number,
581
* the PID and the thread ID of the calling thread.
584
* char *message - monitoring message
590
* MT-NOTE: 'mwrite()' is MT safe with exceptions. See introduction!
592
* MT-NOTE: It is guaranteed that the output of different threads is not
595
*******************************************************************************/
596
static void mwrite(char *message, const char *thread_name)
598
static u_long traceid = 0;
599
unsigned long tmp_pid = (unsigned long) getpid();
600
unsigned long tmp_thread = (unsigned long) pthread_self();
602
#if !defined(DARWIN6)
606
#ifdef DEBUG_CLIENT_SUPPORT
607
/* if there is a callback function, don't call standard function */
608
RMON_CALLBACK_FUNC_LOCK();
609
if (rmon_print_callback != NULL) {
610
rmon_print_callback(message, traceid, tmp_pid, tmp_thread);
612
RMON_CALLBACK_FUNC_UNLOCK();
615
if (thread_name != NULL) {
616
fprintf(rmon_fp, "%6ld %6d %12.12s ", traceid, (int)tmp_pid, thread_name);
618
fprintf(rmon_fp, "%6ld %6d %ld ", traceid, (int)tmp_pid, (long int)tmp_thread);
620
fprintf(rmon_fp, "%s", message);
624
#if !defined(DARWIN6)
625
funlockfile(rmon_fp);
631
/****** rmon_macros/set_debug_level_from_env() *********************************
633
* set_debug_level_from_env() -- Set debug level from environment variable.
636
* static int set_debug_level_from_env(void)
639
* Set debug level. Read environment variable "SGE_DEBUG_LEVEL" and use it
640
* to initialize debug levels.
647
* ENOENT - environment variable not set
648
* EINVAL - unexpected format
651
* MT-NOTE: 'set_debug_level_from_env()' is MT safe with exceptions.
652
* MT-NOTE: See introduction!
654
*******************************************************************************/
655
static int set_debug_level_from_env(void)
657
const char *env, *s = NULL;
660
if ((env = getenv("SGE_DEBUG_LEVEL")) == NULL) {
665
if ((i = sscanf(s, "%d%d%d%d%d%d%d%d", l, l+1, l+2, l+3, l+4, l+5, l+6, l+7)) != N_LAYER) {
666
printf("%s\n", MSG_RMON_ILLEGALDBUGLEVELFORMAT);
671
for (i = 0; i < N_LAYER; i++) {
672
rmon_mlputl(&RMON_DEBUG_ON, i, l[i]);
673
rmon_mlputl(&RMON_DEBUG_ON_STORAGE, i, l[i]);
678
} /* set_debug_level_from_env() */
680
/****** rmon_macros/set_debug_target_from_env() *********************************
682
* set_debug_target_from_env() -- Set debug target from environment variable.
685
* static int set_debug_target_from_env(void)
688
* Set debug target. Read environment variable "SGE_DEBUG_TARGET" and use it
689
* to initialize debug output target.
691
* 'SGE_DEBUG_TARGET' may either be 'stdout', 'stderr' or a fully qualified
692
* file name (that is file name and path). If a file name is given an
693
* already existing file with the same name will be overwritten.
700
* EACCES - file name is invalid or unable to open file
703
* MT-NOTE: 'set_debug_target_from_env()' is MT safe with exceptions.
704
* MT-NOTE: See introduction!
706
*******************************************************************************/
707
static int set_debug_target_from_env(void)
709
const char *env, *s = NULL;
711
if ((env = getenv("SGE_DEBUG_TARGET")) == NULL) {
716
if (strcmp(s, "stdout") == 0) {
718
} else if (strcmp(s, "stderr") == 0) {
720
} else if ((rmon_fp = fopen(s, "w")) == NULL) {
722
fprintf(rmon_fp, MSG_RMON_UNABLETOOPENXFORWRITING_S, s);
723
fprintf(rmon_fp, MSG_RMON_ERRNOXY_DS, errno, strerror(errno));
730
} /* set_debug_target_from_env() */