00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include "hprof.h"
00040
00041 #include "java_crw_demo.h"
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 #define DEFAULT_TXT_SUFFIX ".txt"
00062 #define DEFAULT_OUTPUTFILE "java.hprof"
00063 #define DEFAULT_OUTPUTTEMP "java.hprof.temp"
00064
00065
00066 GlobalData *gdata;
00067
00068
00069 #define EXPERIMENT_NO_EARLY_HOOK 0x1
00070
00071
00072 #define DEFAULT_TRACE_DEPTH 4
00073
00074
00075 #define DEFAULT_SAMPLE_INTERVAL 10
00076
00077
00078 #define DEFAULT_CUTOFF_POINT 0.0001
00079
00080
00081 #define _TO_STR(a) #a
00082 #define TO_STR(a) _TO_STR(a)
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 #define BEGIN_CALLBACK() \
00104 { \
00105 jboolean bypass; \
00106 rawMonitorEnter(gdata->callbackLock); \
00107 if (gdata->vm_death_callback_active) { \
00108 \
00109 bypass = JNI_TRUE; \
00110 rawMonitorExit(gdata->callbackLock); \
00111 \
00112 rawMonitorEnter(gdata->callbackBlock); \
00113 rawMonitorExit(gdata->callbackBlock); \
00114 } else { \
00115 \
00116 gdata->active_callbacks++; \
00117 bypass = JNI_FALSE; \
00118 rawMonitorExit(gdata->callbackLock); \
00119 } \
00120 if ( !bypass ) { \
00121
00122
00123 #define END_CALLBACK() \
00124 rawMonitorEnter(gdata->callbackLock); \
00125 gdata->active_callbacks--; \
00126 \
00127 if (gdata->vm_death_callback_active) { \
00128 if (gdata->active_callbacks == 0) { \
00129 rawMonitorNotifyAll(gdata->callbackLock); \
00130 } \
00131 } \
00132 rawMonitorExit(gdata->callbackLock); \
00133 \
00134 rawMonitorEnter(gdata->callbackBlock); \
00135 rawMonitorExit(gdata->callbackBlock); \
00136 } \
00137 }
00138
00139
00140 static void set_callbacks(jboolean on);
00141
00142
00143
00144
00145
00146 static GlobalData *
00147 get_gdata(void)
00148 {
00149 static GlobalData data;
00150
00151
00152 (void)memset(&data, 0, sizeof(GlobalData));
00153
00154 data.fd = -1;
00155 data.heap_fd = -1;
00156 data.check_fd = -1;
00157 data.max_trace_depth = DEFAULT_TRACE_DEPTH;
00158 data.prof_trace_depth = DEFAULT_TRACE_DEPTH;
00159 data.sample_interval = DEFAULT_SAMPLE_INTERVAL;
00160 data.lineno_in_traces = JNI_TRUE;
00161 data.output_format = 'a';
00162 data.cutoff_point = DEFAULT_CUTOFF_POINT;
00163 data.dump_on_exit = JNI_TRUE;
00164 data.gc_start_time = -1L;
00165 #ifdef DEBUG
00166 data.debug = JNI_TRUE;
00167 data.coredump = JNI_TRUE;
00168 #endif
00169 data.micro_state_accounting = JNI_FALSE;
00170 data.force_output = JNI_TRUE;
00171 data.verbose = JNI_TRUE;
00172 data.primfields = JNI_TRUE;
00173 data.primarrays = JNI_TRUE;
00174
00175 data.table_serial_number_start = 1;
00176 data.class_serial_number_start = 100000;
00177 data.thread_serial_number_start = 200000;
00178 data.trace_serial_number_start = 300000;
00179 data.object_serial_number_start = 400000;
00180 data.frame_serial_number_start = 500000;
00181 data.gref_serial_number_start = 1;
00182
00183 data.table_serial_number_counter = data.table_serial_number_start;
00184 data.class_serial_number_counter = data.class_serial_number_start;
00185 data.thread_serial_number_counter = data.thread_serial_number_start;
00186 data.trace_serial_number_counter = data.trace_serial_number_start;
00187 data.object_serial_number_counter = data.object_serial_number_start;
00188 data.frame_serial_number_counter = data.frame_serial_number_start;
00189 data.gref_serial_number_counter = data.gref_serial_number_start;
00190
00191 data.unknown_thread_serial_num = data.thread_serial_number_counter++;
00192 return &data;
00193 }
00194
00195
00196
00197
00198 static void
00199 my_crw_fatal_error_handler(const char * msg, const char *file, int line)
00200 {
00201 char errmsg[256];
00202
00203 (void)md_snprintf(errmsg, sizeof(errmsg),
00204 "%s [%s:%d]", msg, file, line);
00205 errmsg[sizeof(errmsg)-1] = 0;
00206 HPROF_ERROR(JNI_TRUE, errmsg);
00207 }
00208
00209 static void
00210 list_all_tables(void)
00211 {
00212 string_list();
00213 class_list();
00214 frame_list();
00215 site_list();
00216 object_list();
00217 trace_list();
00218 monitor_list();
00219 tls_list();
00220 loader_list();
00221 }
00222
00223
00224
00225
00230
00231
00232
00233
00234
00235 static int
00236 connect_to_socket(char *hostname, unsigned short port)
00237 {
00238 int fd;
00239
00240 if (port == 0 || port > 65535) {
00241 HPROF_ERROR(JNI_FALSE, "invalid port number");
00242 return -1;
00243 }
00244 if (hostname == NULL) {
00245 HPROF_ERROR(JNI_FALSE, "hostname is NULL");
00246 return -1;
00247 }
00248
00249
00250 fd = md_connect(hostname, port);
00251 return fd;
00252 }
00253
00254
00255 static void
00256 make_unique_filename(char **filename)
00257 {
00258 int fd;
00259
00260
00261 fd = md_open(*filename);
00262 if ( fd >= 0 ) {
00263 int pid;
00264 char *new_name;
00265 char *old_name;
00266 char *prefix;
00267 char suffix[5];
00268 int new_len;
00269
00270
00271 md_close(fd);
00272
00273
00274 pid = md_getpid();
00275 old_name = *filename;
00276 new_len = (int)strlen(old_name)+64;
00277 new_name = HPROF_MALLOC(new_len);
00278 prefix = old_name;
00279 suffix[0] = 0;
00280
00281
00282 if (gdata->output_format != 'b') {
00283 char *dot;
00284 char *format_suffix;
00285
00286 format_suffix = DEFAULT_TXT_SUFFIX;
00287
00288 (void)strcpy(suffix, format_suffix);
00289
00290 dot = strrchr(old_name, '.');
00291 if ( dot != NULL ) {
00292 int i;
00293 int slen;
00294 int match;
00295
00296 slen = (int)strlen(format_suffix);
00297 match = 1;
00298 for ( i = 0; i < slen; i++ ) {
00299 if ( dot[i]==0 ||
00300 tolower(format_suffix[i]) != tolower(dot[i]) ) {
00301 match = 0;
00302 break;
00303 }
00304 }
00305 if ( match ) {
00306 (void)strcpy(suffix, dot);
00307 *dot = 0;
00308 }
00309 }
00310 }
00311
00312
00313 (void)md_snprintf(new_name, new_len,
00314 "%s.%d%s", prefix, pid, suffix);
00315 *filename = new_name;
00316 HPROF_FREE(old_name);
00317
00318
00319 (void)remove(gdata->output_filename);
00320 }
00321 }
00322
00323 static int
00324 get_tok(char **src, char *buf, int buflen, int sep)
00325 {
00326 int len;
00327 char *p;
00328
00329 buf[0] = 0;
00330 if ( **src == 0 ) {
00331 return 0;
00332 }
00333 p = strchr(*src, sep);
00334 if ( p==NULL ) {
00335 len = (int)strlen(*src);
00336 p = (*src) + len;
00337 } else {
00338
00339 len = (int)(p - (*src));
00340 }
00341 if ( (len+1) > buflen ) {
00342 return 0;
00343 }
00344 (void)memcpy(buf, *src, len);
00345 buf[len] = 0;
00346 if ( *p != 0 && *p == sep ) {
00347 (*src) = p+1;
00348 } else {
00349 (*src) = p;
00350 }
00351 return len;
00352 }
00353
00354 static jboolean
00355 setBinarySwitch(char **src, jboolean *ptr)
00356 {
00357 char buf[80];
00358
00359 if (!get_tok(src, buf, (int)sizeof(buf), ',')) {
00360 return JNI_FALSE;
00361 }
00362 if (strcmp(buf, "y") == 0) {
00363 *ptr = JNI_TRUE;
00364 } else if (strcmp(buf, "n") == 0) {
00365 *ptr = JNI_FALSE;
00366 } else {
00367 return JNI_FALSE;
00368 }
00369 return JNI_TRUE;
00370 }
00371
00372 static void
00373 print_usage(void)
00374 {
00375
00376 (void)fprintf(stdout,
00377 "\n"
00378 " HPROF: Heap and CPU Profiling Agent (JVMTI Demonstration Code)\n"
00379 "\n"
00380 AGENTNAME " usage: java " AGENTLIB "=[help]|[<option>=<value>, ...]\n"
00381 "\n"
00382 "Option Name and Value Description Default\n"
00383 "--------------------- ----------- -------\n"
00384 "heap=dump|sites|all heap profiling all\n"
00385 "cpu=samples|times|old CPU usage off\n"
00386 "monitor=y|n monitor contention n\n"
00387 "format=a|b text(txt) or binary output a\n"
00388 "file=<file> write data to file " DEFAULT_OUTPUTFILE "[{" DEFAULT_TXT_SUFFIX "}]\n"
00389 "net=<host>:<port> send data over a socket off\n"
00390 "depth=<size> stack trace depth " TO_STR(DEFAULT_TRACE_DEPTH) "\n"
00391 "interval=<ms> sample interval in ms " TO_STR(DEFAULT_SAMPLE_INTERVAL) "\n"
00392 "cutoff=<value> output cutoff point " TO_STR(DEFAULT_CUTOFF_POINT) "\n"
00393 "lineno=y|n line number in traces? y\n"
00394 "thread=y|n thread in traces? n\n"
00395 "doe=y|n dump on exit? y\n"
00396 "msa=y|n Solaris micro state accounting n\n"
00397 "force=y|n force output to <file> y\n"
00398 "verbose=y|n print messages about dumps y\n"
00399 "\n"
00400 "Obsolete Options\n"
00401 "----------------\n"
00402 "gc_okay=y|n\n"
00403
00404 #ifdef DEBUG
00405 "\n"
00406 "DEBUG Option Description Default\n"
00407 "------------ ----------- -------\n"
00408 "primfields=y|n include primitive field values y\n"
00409 "primarrays=y|n include primitive array values y\n"
00410 "debugflags=MASK Various debug flags 0\n"
00411 " 0x01 Report refs in and of unprepared classes\n"
00412 "logflags=MASK Logging to stderr 0\n"
00413 " " TO_STR(LOG_DUMP_MISC) " Misc logging\n"
00414 " " TO_STR(LOG_DUMP_LISTS) " Dump out the tables\n"
00415 " " TO_STR(LOG_CHECK_BINARY) " Verify & dump format=b\n"
00416 "coredump=y|n Core dump on fatal n\n"
00417 "errorexit=y|n Exit on any error n\n"
00418 "pause=y|n Pause on onload & echo PID n\n"
00419 "debug=y|n Turn on all debug checking n\n"
00420 "X=MASK Internal use only 0\n"
00421
00422 "\n"
00423 "Environment Variables\n"
00424 "---------------------\n"
00425 "_JAVA_HPROF_OPTIONS\n"
00426 " Options can be added externally via this environment variable.\n"
00427 " Anything contained in it will get a comma prepended to it (if needed),\n"
00428 " then it will be added to the end of the options supplied via the\n"
00429 " " XRUN " or " AGENTLIB " command line option.\n"
00430
00431 #endif
00432
00433 "\n"
00434 "Examples\n"
00435 "--------\n"
00436 " - Get sample cpu information every 20 millisec, with a stack depth of 3:\n"
00437 " java " AGENTLIB "=cpu=samples,interval=20,depth=3 classname\n"
00438 " - Get heap usage information based on the allocation sites:\n"
00439 " java " AGENTLIB "=heap=sites classname\n"
00440
00441 #ifdef DEBUG
00442 " - Using the external option addition with csh, log details on all runs:\n"
00443 " setenv _JAVA_HPROF_OPTIONS \"logflags=0xC\"\n"
00444 " java " AGENTLIB "=cpu=samples classname\n"
00445 " is the same as:\n"
00446 " java " AGENTLIB "=cpu=samples,logflags=0xC classname\n"
00447 #endif
00448
00449 "\n"
00450 "Notes\n"
00451 "-----\n"
00452 " - The option format=b cannot be used with monitor=y.\n"
00453 " - The option format=b cannot be used with cpu=old|times.\n"
00454 " - Use of the " XRUN " interface can still be used, e.g.\n"
00455 " java " XRUN ":[help]|[<option>=<value>, ...]\n"
00456 " will behave exactly the same as:\n"
00457 " java " AGENTLIB "=[help]|[<option>=<value>, ...]\n"
00458
00459 #ifdef DEBUG
00460 " - The debug options and environment variables are available with both java\n"
00461 " and java_g versions.\n"
00462 #endif
00463
00464 "\n"
00465 "Warnings\n"
00466 "--------\n"
00467 " - This is demonstration code for the JVMTI interface and use of BCI,\n"
00468 " it is not an official product or formal part of the JDK.\n"
00469 " - The " XRUN " interface will be removed in a future release.\n"
00470 " - The option format=b is considered experimental, this format may change\n"
00471 " in a future release.\n"
00472
00473 #ifdef DEBUG
00474 " - The obsolete options may be completely removed in a future release.\n"
00475 " - The debug options and environment variables are not considered public\n"
00476 " interfaces and can change or be removed with any type of update of\n"
00477 " " AGENTNAME ", including patches.\n"
00478 #endif
00479
00480 );
00481 }
00482
00483 static void
00484 option_error(char *description)
00485 {
00486 char errmsg[FILENAME_MAX+80];
00487
00488 (void)md_snprintf(errmsg, sizeof(errmsg),
00489 "%s option error: %s (%s)", AGENTNAME, description, gdata->options);
00490 errmsg[sizeof(errmsg)-1] = 0;
00491 HPROF_ERROR(JNI_FALSE, errmsg);
00492 error_exit_process(1);
00493 }
00494
00495 static void
00496 parse_options(char *command_line_options)
00497 {
00498 int file_or_net_option_seen = JNI_FALSE;
00499 char *all_options;
00500 char *extra_options;
00501 char *options;
00502 char *default_filename;
00503 int ulen;
00504
00505 if (command_line_options == 0)
00506 command_line_options = "";
00507
00508 if ((strcmp(command_line_options, "help")) == 0) {
00509 print_usage();
00510 error_exit_process(0);
00511 }
00512
00513 extra_options = getenv("_JAVA_HPROF_OPTIONS");
00514 if ( extra_options == NULL ) {
00515 extra_options = "";
00516 }
00517
00518 all_options = HPROF_MALLOC((int)strlen(command_line_options) +
00519 (int)strlen(extra_options) + 2);
00520 gdata->options = all_options;
00521 (void)strcpy(all_options, command_line_options);
00522 if ( extra_options[0] != 0 ) {
00523 if ( all_options[0] != 0 ) {
00524 (void)strcat(all_options, ",");
00525 }
00526 (void)strcat(all_options, extra_options);
00527 }
00528 options = all_options;
00529
00530 LOG2("parse_options()", all_options);
00531
00532 while (*options) {
00533 char option[16];
00534 char suboption[FILENAME_MAX+1];
00535 char *endptr;
00536
00537 if (!get_tok(&options, option, (int)sizeof(option), '=')) {
00538 option_error("general syntax error parsing options");
00539 }
00540 if (strcmp(option, "file") == 0) {
00541 if ( file_or_net_option_seen ) {
00542 option_error("file or net options should only appear once");
00543 }
00544 if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
00545 option_error("syntax error parsing file=filename");
00546 }
00547 gdata->utf8_output_filename = HPROF_MALLOC((int)strlen(suboption)+1);
00548 (void)strcpy(gdata->utf8_output_filename, suboption);
00549 file_or_net_option_seen = JNI_TRUE;
00550 } else if (strcmp(option, "net") == 0) {
00551 char port_number[16];
00552 if (file_or_net_option_seen ) {
00553 option_error("file or net options should only appear once");
00554 }
00555 if (!get_tok(&options, suboption, (int)sizeof(suboption), ':')) {
00556 option_error("net option missing ':'");
00557 }
00558 if (!get_tok(&options, port_number, (int)sizeof(port_number), ',')) {
00559 option_error("net option missing port");
00560 }
00561 gdata->net_hostname = HPROF_MALLOC((int)strlen(suboption)+1);
00562 (void)strcpy(gdata->net_hostname, suboption);
00563 gdata->net_port = (int)strtol(port_number, NULL, 10);
00564 file_or_net_option_seen = JNI_TRUE;
00565 } else if (strcmp(option, "format") == 0) {
00566 if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
00567 option_error("syntax error parsing format=a|b");
00568 }
00569 if (strcmp(suboption, "a") == 0) {
00570 gdata->output_format = 'a';
00571 } else if (strcmp(suboption, "b") == 0) {
00572 gdata->output_format = 'b';
00573 } else {
00574 option_error("format option value must be a|b");
00575 }
00576 } else if (strcmp(option, "depth") == 0) {
00577 if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
00578 option_error("syntax error parsing depth=DECIMAL");
00579 }
00580 gdata->max_trace_depth = (int)strtol(suboption, &endptr, 10);
00581 if ((endptr != NULL && *endptr != 0) || gdata->max_trace_depth < 0) {
00582 option_error("depth option value must be decimal and >= 0");
00583 }
00584 gdata->prof_trace_depth = gdata->max_trace_depth;
00585 } else if (strcmp(option, "interval") == 0) {
00586 if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
00587 option_error("syntax error parsing interval=DECIMAL");
00588 }
00589 gdata->sample_interval = (int)strtol(suboption, &endptr, 10);
00590 if ((endptr != NULL && *endptr != 0) || gdata->sample_interval <= 0) {
00591 option_error("interval option value must be decimal and > 0");
00592 }
00593 } else if (strcmp(option, "cutoff") == 0) {
00594 if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
00595 option_error("syntax error parsing cutoff=DOUBLE");
00596 }
00597 gdata->cutoff_point = strtod(suboption, &endptr);
00598 if ((endptr != NULL && *endptr != 0) || gdata->cutoff_point < 0) {
00599 option_error("cutoff option value must be floating point and >= 0");
00600 }
00601 } else if (strcmp(option, "cpu") == 0) {
00602 if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
00603 option_error("syntax error parsing cpu=y|samples|times|old");
00604 }
00605 if ((strcmp(suboption, "samples") == 0) ||
00606 (strcmp(suboption, "y") == 0)) {
00607 gdata->cpu_sampling = JNI_TRUE;
00608 } else if (strcmp(suboption, "times") == 0) {
00609 gdata->cpu_timing = JNI_TRUE;
00610 gdata->old_timing_format = JNI_FALSE;
00611 } else if (strcmp(suboption, "old") == 0) {
00612 gdata->cpu_timing = JNI_TRUE;
00613 gdata->old_timing_format = JNI_TRUE;
00614 } else {
00615 option_error("cpu option value must be y|samples|times|old");
00616 }
00617 } else if (strcmp(option, "heap") == 0) {
00618 if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
00619 option_error("syntax error parsing heap=dump|sites|all");
00620 }
00621 if (strcmp(suboption, "dump") == 0) {
00622 gdata->heap_dump = JNI_TRUE;
00623 } else if (strcmp(suboption, "sites") == 0) {
00624 gdata->alloc_sites = JNI_TRUE;
00625 } else if (strcmp(suboption, "all") == 0) {
00626 gdata->heap_dump = JNI_TRUE;
00627 gdata->alloc_sites = JNI_TRUE;
00628 } else {
00629 option_error("heap option value must be dump|sites|all");
00630 }
00631 } else if( strcmp(option,"lineno") == 0) {
00632 if ( !setBinarySwitch(&options, &(gdata->lineno_in_traces)) ) {
00633 option_error("lineno option value must be y|n");
00634 }
00635 } else if( strcmp(option,"thread") == 0) {
00636 if ( !setBinarySwitch(&options, &(gdata->thread_in_traces)) ) {
00637 option_error("thread option value must be y|n");
00638 }
00639 } else if( strcmp(option,"doe") == 0) {
00640 if ( !setBinarySwitch(&options, &(gdata->dump_on_exit)) ) {
00641 option_error("doe option value must be y|n");
00642 }
00643 } else if( strcmp(option,"msa") == 0) {
00644 if ( !setBinarySwitch(&options, &(gdata->micro_state_accounting)) ) {
00645 option_error("msa option value must be y|n");
00646 }
00647 } else if( strcmp(option,"force") == 0) {
00648 if ( !setBinarySwitch(&options, &(gdata->force_output)) ) {
00649 option_error("force option value must be y|n");
00650 }
00651 } else if( strcmp(option,"verbose") == 0) {
00652 if ( !setBinarySwitch(&options, &(gdata->verbose)) ) {
00653 option_error("verbose option value must be y|n");
00654 }
00655 } else if( strcmp(option,"primfields") == 0) {
00656 if ( !setBinarySwitch(&options, &(gdata->primfields)) ) {
00657 option_error("primfields option value must be y|n");
00658 }
00659 } else if( strcmp(option,"primarrays") == 0) {
00660 if ( !setBinarySwitch(&options, &(gdata->primarrays)) ) {
00661 option_error("primarrays option value must be y|n");
00662 }
00663 } else if( strcmp(option,"monitor") == 0) {
00664 if ( !setBinarySwitch(&options, &(gdata->monitor_tracing)) ) {
00665 option_error("monitor option value must be y|n");
00666 }
00667 } else if( strcmp(option,"gc_okay") == 0) {
00668 if ( !setBinarySwitch(&options, &(gdata->gc_okay)) ) {
00669 option_error("gc_okay option value must be y|n");
00670 }
00671 } else if (strcmp(option, "logflags") == 0) {
00672 if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
00673 option_error("logflags option value must be numeric");
00674 }
00675 gdata->logflags = (int)strtol(suboption, NULL, 0);
00676 } else if (strcmp(option, "debugflags") == 0) {
00677 if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
00678 option_error("debugflags option value must be numeric");
00679 }
00680 gdata->debugflags = (int)strtol(suboption, NULL, 0);
00681 } else if (strcmp(option, "coredump") == 0) {
00682 if ( !setBinarySwitch(&options, &(gdata->coredump)) ) {
00683 option_error("coredump option value must be y|n");
00684 }
00685 } else if (strcmp(option, "exitpause") == 0) {
00686 option_error("The exitpause option was removed, use -XX:OnError='cmd %%p'");
00687 } else if (strcmp(option, "errorexit") == 0) {
00688 if ( !setBinarySwitch(&options, &(gdata->errorexit)) ) {
00689 option_error("errorexit option value must be y|n");
00690 }
00691 } else if (strcmp(option, "pause") == 0) {
00692 if ( !setBinarySwitch(&options, &(gdata->pause)) ) {
00693 option_error("pause option value must be y|n");
00694 }
00695 } else if (strcmp(option, "debug") == 0) {
00696 if ( !setBinarySwitch(&options, &(gdata->debug)) ) {
00697 option_error("debug option value must be y|n");
00698 }
00699 } else if (strcmp(option, "precrash") == 0) {
00700 option_error("The precrash option was removed, use -XX:OnError='precrash -p %%p'");
00701 } else if (strcmp(option, "X") == 0) {
00702 if (!get_tok(&options, suboption, (int)sizeof(suboption), ',')) {
00703 option_error("X option value must be numeric");
00704 }
00705 gdata->experiment = (int)strtol(suboption, NULL, 0);
00706 } else {
00707 char errmsg[80];
00708 (void)strcpy(errmsg, "Unknown option: ");
00709 (void)strcat(errmsg, option);
00710 option_error(errmsg);
00711 }
00712 }
00713
00714 if (gdata->output_format == 'b') {
00715 if (gdata->cpu_timing) {
00716 option_error("cpu=times|old is not supported with format=b");
00717 }
00718 if (gdata->monitor_tracing) {
00719 option_error("monitor=y is not supported with format=b");
00720 }
00721 }
00722
00723 if (gdata->old_timing_format) {
00724 gdata->prof_trace_depth = 2;
00725 }
00726
00727 if (gdata->output_format == 'b') {
00728 default_filename = DEFAULT_OUTPUTFILE;
00729 } else {
00730 default_filename = DEFAULT_OUTPUTFILE DEFAULT_TXT_SUFFIX;
00731 }
00732
00733 if (!file_or_net_option_seen) {
00734 gdata->utf8_output_filename = HPROF_MALLOC((int)strlen(default_filename)+1);
00735 (void)strcpy(gdata->utf8_output_filename, default_filename);
00736 }
00737
00738 if ( gdata->utf8_output_filename != NULL ) {
00739
00740 ulen = (int)strlen(gdata->utf8_output_filename);
00741 gdata->output_filename = (char*)HPROF_MALLOC(ulen*3+3);
00742 #ifdef SKIP_NPT
00743 (void)strcpy(gdata->output_filename, gdata->utf8_output_filename);
00744 #else
00745 (void)(gdata->npt->utf8ToPlatform)
00746 (gdata->npt->utf, (jbyte*)gdata->utf8_output_filename, ulen,
00747 gdata->output_filename, ulen*3+3);
00748 #endif
00749 }
00750
00751
00752 if ( !gdata->cpu_timing &&
00753 !gdata->cpu_sampling &&
00754 !gdata->monitor_tracing &&
00755 !gdata->alloc_sites &&
00756 !gdata->heap_dump) {
00757 gdata->heap_dump = JNI_TRUE;
00758 gdata->alloc_sites = JNI_TRUE;
00759 }
00760
00761 if ( gdata->alloc_sites || gdata->heap_dump ) {
00762 gdata->obj_watch = JNI_TRUE;
00763 }
00764 if ( gdata->obj_watch || gdata->cpu_timing ) {
00765 gdata->bci = JNI_TRUE;
00766 }
00767
00768
00769 if (gdata->heap_dump) {
00770 char *base;
00771 int len;
00772
00773
00774 base = gdata->output_filename;
00775 if ( base==NULL ) {
00776 base = default_filename;
00777 }
00778 len = (int)strlen(base);
00779 gdata->heapfilename = HPROF_MALLOC(len + 5);
00780 (void)strcpy(gdata->heapfilename, base);
00781 (void)strcat(gdata->heapfilename, ".TMP");
00782 make_unique_filename(&(gdata->heapfilename));
00783 (void)remove(gdata->heapfilename);
00784 if (gdata->output_format == 'b') {
00785 if ( gdata->logflags & LOG_CHECK_BINARY ) {
00786 char * check_suffix;
00787
00788 check_suffix = ".check" DEFAULT_TXT_SUFFIX;
00789 gdata->checkfilename =
00790 HPROF_MALLOC((int)strlen(default_filename)+
00791 (int)strlen(check_suffix)+1);
00792 (void)strcpy(gdata->checkfilename, default_filename);
00793 (void)strcat(gdata->checkfilename, check_suffix);
00794 (void)remove(gdata->checkfilename);
00795 gdata->check_fd = md_creat(gdata->checkfilename);
00796 }
00797 if ( gdata->debug ) {
00798 gdata->logflags |= LOG_CHECK_BINARY;
00799 }
00800 gdata->heap_fd = md_creat_binary(gdata->heapfilename);
00801 } else {
00802 gdata->heap_fd = md_creat(gdata->heapfilename);
00803 }
00804 if ( gdata->heap_fd < 0 ) {
00805 char errmsg[FILENAME_MAX+80];
00806
00807 (void)md_snprintf(errmsg, sizeof(errmsg),
00808 "can't create temp heap file: %s", gdata->heapfilename);
00809 errmsg[sizeof(errmsg)-1] = 0;
00810 HPROF_ERROR(JNI_TRUE, errmsg);
00811 }
00812 }
00813
00814 if ( gdata->net_port > 0 ) {
00815 LOG2("Agent_OnLoad", "Connecting to socket");
00816 gdata->fd = connect_to_socket(gdata->net_hostname, (unsigned short)gdata->net_port);
00817 if (gdata->fd <= 0) {
00818 char errmsg[120];
00819
00820 (void)md_snprintf(errmsg, sizeof(errmsg),
00821 "can't connect to %s:%u", gdata->net_hostname, gdata->net_port);
00822 errmsg[sizeof(errmsg)-1] = 0;
00823 HPROF_ERROR(JNI_FALSE, errmsg);
00824 error_exit_process(1);
00825 }
00826 gdata->socket = JNI_TRUE;
00827 } else {
00828
00829 if ( !gdata->force_output ) {
00830 make_unique_filename(&(gdata->output_filename));
00831 }
00832
00833 (void)remove(gdata->output_filename);
00834
00835 if (gdata->output_format == 'b') {
00836 gdata->fd = md_creat_binary(gdata->output_filename);
00837 } else {
00838 gdata->fd = md_creat(gdata->output_filename);
00839 }
00840 if (gdata->fd < 0) {
00841 char errmsg[FILENAME_MAX+80];
00842
00843 (void)md_snprintf(errmsg, sizeof(errmsg),
00844 "can't create profile file: %s", gdata->output_filename);
00845 errmsg[sizeof(errmsg)-1] = 0;
00846 HPROF_ERROR(JNI_FALSE, errmsg);
00847 error_exit_process(1);
00848 }
00849 }
00850
00851 }
00852
00853
00854
00855
00856 static void
00857 reset_all_data(void)
00858 {
00859 if (gdata->cpu_sampling || gdata->cpu_timing || gdata->monitor_tracing) {
00860 rawMonitorEnter(gdata->data_access_lock);
00861 }
00862
00863 if (gdata->cpu_sampling || gdata->cpu_timing) {
00864 trace_clear_cost();
00865 }
00866 if (gdata->monitor_tracing) {
00867 monitor_clear();
00868 }
00869
00870 if (gdata->cpu_sampling || gdata->cpu_timing || gdata->monitor_tracing) {
00871 rawMonitorExit(gdata->data_access_lock);
00872 }
00873 }
00874
00875 static void reset_class_load_status(JNIEnv *env, jthread thread);
00876
00877 static void
00878 dump_all_data(JNIEnv *env)
00879 {
00880 verbose_message("Dumping");
00881 if (gdata->monitor_tracing) {
00882 verbose_message(" contended monitor usage ...");
00883 tls_dump_monitor_state(env);
00884 monitor_write_contended_time(env, gdata->cutoff_point);
00885 }
00886 if (gdata->heap_dump) {
00887 verbose_message(" Java heap ...");
00888
00889 reset_class_load_status(env, NULL);
00890 site_heapdump(env);
00891 }
00892 if (gdata->alloc_sites) {
00893 verbose_message(" allocation sites ...");
00894 site_write(env, 0, gdata->cutoff_point);
00895 }
00896 if (gdata->cpu_sampling) {
00897 verbose_message(" CPU usage by sampling running threads ...");
00898 trace_output_cost(env, gdata->cutoff_point);
00899 }
00900 if (gdata->cpu_timing) {
00901 if (!gdata->old_timing_format) {
00902 verbose_message(" CPU usage by timing methods ...");
00903 trace_output_cost(env, gdata->cutoff_point);
00904 } else {
00905 verbose_message(" CPU usage in old prof format ...");
00906 trace_output_cost_in_prof_format(env);
00907 }
00908 }
00909 reset_all_data();
00910 io_flush();
00911 verbose_message(" done.\n");
00912 }
00913
00914
00915
00916
00917 static void
00918 reset_class_load_status(JNIEnv *env, jthread thread)
00919 {
00920
00921 WITH_LOCAL_REFS(env, 1) {
00922 jint class_count;
00923 jclass *classes;
00924 jint i;
00925
00926
00927 getLoadedClasses(&classes, &class_count);
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938 if ( class_count != gdata->class_count ) {
00939
00940 rawMonitorEnter(gdata->data_access_lock); {
00941
00942
00943 class_all_status_remove(CLASS_IN_LOAD_LIST);
00944
00945
00946 for ( i = 0 ; i < class_count ; i++ ) {
00947 jobject loader;
00948
00949 loader = getClassLoader(classes[i]);
00950 event_class_load(env, thread, classes[i], loader);
00951 }
00952
00953
00954 class_do_unloads(env);
00955
00956 } rawMonitorExit(gdata->data_access_lock);
00957
00958 }
00959
00960
00961 jvmtiDeallocate(classes);
00962 gdata->class_count = class_count;
00963
00964 } END_WITH_LOCAL_REFS;
00965
00966 }
00967
00968
00969 static void
00970 object_free_cleanup(JNIEnv *env, jboolean force_class_table_reset)
00971 {
00972 Stack *stack;
00973
00974
00975 rawMonitorEnter(gdata->object_free_lock); {
00976 stack = gdata->object_free_stack;
00977 gdata->object_free_stack = NULL;
00978 } rawMonitorExit(gdata->object_free_lock);
00979
00980
00981
00982
00983 if ( stack != NULL ) {
00984 int count;
00985 int i;
00986
00987 count = stack_depth(stack);
00988
00989
00990 if ( count > 0 ) {
00991
00992 for ( i = 0 ; i < count ; i++ ) {
00993 ObjectIndex object_index;
00994 jlong tag;
00995
00996 tag = *(jlong*)stack_element(stack,i);
00997 object_index = tag_extract(tag);
00998
00999 (void)object_free(object_index);
01000 }
01001
01002
01003 reset_class_load_status(env, NULL);
01004 force_class_table_reset = JNI_FALSE;
01005
01006 }
01007
01008
01009 stack_term(stack);
01010 }
01011
01012
01013 if ( force_class_table_reset ) {
01014 reset_class_load_status(env, NULL);
01015 }
01016
01017 }
01018
01019
01020 static void JNICALL
01021 gc_finish_watcher(jvmtiEnv *jvmti, JNIEnv *env, void *p)
01022 {
01023 jboolean active;
01024
01025 active = JNI_TRUE;
01026
01027
01028 rawMonitorEnter(gdata->gc_finish_lock); {
01029 gdata->gc_finish_active = JNI_TRUE;
01030 } rawMonitorExit(gdata->gc_finish_lock);
01031
01032
01033 while ( active ) {
01034 jboolean do_cleanup;
01035
01036 do_cleanup = JNI_FALSE;
01037 rawMonitorEnter(gdata->gc_finish_lock); {
01038
01039 if ( gdata->gc_finish_stop_request ) {
01040
01041 active = JNI_FALSE;
01042 } else {
01043
01044 rawMonitorWait(gdata->gc_finish_lock, 0);
01045
01046 if ( gdata->gc_finish_stop_request ) {
01047
01048 active = JNI_FALSE;
01049 }
01050 }
01051 if ( active && gdata->gc_finish > 0 ) {
01052
01053 gdata->gc_finish = 0;
01054 do_cleanup = JNI_TRUE;
01055 }
01056 } rawMonitorExit(gdata->gc_finish_lock);
01057
01058
01059 if ( do_cleanup ) {
01060
01061
01062
01063
01064
01065
01066
01067 object_free_cleanup(env, JNI_FALSE);
01068
01069
01070 tls_garbage_collect(env);
01071 }
01072
01073 }
01074
01075
01076
01077
01078
01079 rawMonitorEnter(gdata->gc_finish_lock); {
01080 gdata->gc_finish_active = JNI_FALSE;
01081 rawMonitorNotifyAll(gdata->gc_finish_lock);
01082 } rawMonitorExit(gdata->gc_finish_lock);
01083 }
01084
01085
01086
01087
01088 static void
01089 setup_event_mode(jboolean onload_set_only, jvmtiEventMode state)
01090 {
01091 if ( onload_set_only ) {
01092 setEventNotificationMode(state,
01093 JVMTI_EVENT_VM_INIT, NULL);
01094 setEventNotificationMode(state,
01095 JVMTI_EVENT_VM_DEATH, NULL);
01096 if (gdata->bci) {
01097 setEventNotificationMode(state,
01098 JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
01099 }
01100 } else {
01101
01102 setEventNotificationMode(state,
01103 JVMTI_EVENT_THREAD_START, NULL);
01104 setEventNotificationMode(state,
01105 JVMTI_EVENT_THREAD_END, NULL);
01106 setEventNotificationMode(state,
01107 JVMTI_EVENT_CLASS_LOAD, NULL);
01108 setEventNotificationMode(state,
01109 JVMTI_EVENT_CLASS_PREPARE, NULL);
01110 setEventNotificationMode(state,
01111 JVMTI_EVENT_DATA_DUMP_REQUEST, NULL);
01112 if (gdata->cpu_timing) {
01113 setEventNotificationMode(state,
01114 JVMTI_EVENT_EXCEPTION_CATCH, NULL);
01115 }
01116 if (gdata->monitor_tracing) {
01117 setEventNotificationMode(state,
01118 JVMTI_EVENT_MONITOR_WAIT, NULL);
01119 setEventNotificationMode(state,
01120 JVMTI_EVENT_MONITOR_WAITED, NULL);
01121 setEventNotificationMode(state,
01122 JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
01123 setEventNotificationMode(state,
01124 JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
01125 }
01126 if (gdata->obj_watch) {
01127 setEventNotificationMode(state,
01128 JVMTI_EVENT_OBJECT_FREE, NULL);
01129 }
01130 setEventNotificationMode(state,
01131 JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL);
01132 setEventNotificationMode(state,
01133 JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL);
01134 }
01135 }
01136
01137
01138 static void JNICALL
01139 cbVMInit(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
01140 {
01141 rawMonitorEnter(gdata->data_access_lock); {
01142
01143 LoaderIndex loader_index;
01144 ClassIndex cnum;
01145 TlsIndex tls_index;
01146
01147 gdata->jvm_initializing = JNI_TRUE;
01148
01149
01150 gdata->header = "JAVA PROFILE 1.0.1";
01151 gdata->segmented = JNI_FALSE;
01152 if (gdata->output_format == 'b') {
01153
01154 gdata->maxMemory = getMaxMemory(env);
01155 gdata->maxHeapSegment = (jlong)2000000000;
01156
01157 if ( gdata->maxMemory >= gdata->maxHeapSegment ) {
01158 gdata->header = "JAVA PROFILE 1.0.2";
01159 gdata->segmented = JNI_TRUE;
01160 }
01161 }
01162
01163
01164
01165
01166
01167
01168 io_write_file_header();
01169
01170 LOG("cbVMInit begin");
01171
01172
01173 loader_index = loader_find_or_create(NULL,NULL);
01174
01175
01176 gdata->thread_cnum = class_find_or_create("Ljava/lang/Thread;",
01177 loader_index);
01178 class_add_status(gdata->thread_cnum, CLASS_SYSTEM);
01179
01180
01181 tls_index = tls_find_or_create(env, thread);
01182
01183
01184 tracker_setup_class();
01185
01186
01187 gdata->system_class_size = 0;
01188 cnum = class_find_or_create("Ljava/lang/Object;", loader_index);
01189
01190 gdata->system_trace_index = tls_get_trace(tls_index, env,
01191 gdata->max_trace_depth, JNI_FALSE);
01192 gdata->system_object_site_index = site_find_or_create(
01193 cnum, gdata->system_trace_index);
01194
01195
01196 gdata->hprof_trace_index = tls_get_trace(tls_index, env,
01197 gdata->max_trace_depth, JNI_FALSE);
01198 gdata->hprof_site_index = site_find_or_create(
01199 cnum, gdata->hprof_trace_index);
01200
01201 if ( gdata->logflags & LOG_DUMP_LISTS ) {
01202 list_all_tables();
01203 }
01204
01205
01206 reset_class_load_status(env, thread);
01207
01208
01209 if ( gdata->bci ) {
01210 tracker_setup_methods(env);
01211 }
01212
01213
01214
01215
01216 rawMonitorEnter(gdata->gc_finish_lock); {
01217 createAgentThread(env, "HPROF gc_finish watcher",
01218 &gc_finish_watcher);
01219 } rawMonitorExit(gdata->gc_finish_lock);
01220
01221
01222 if ( gdata->socket ) {
01223 listener_init(env);
01224 }
01225
01226
01227 if ( gdata->cpu_sampling ) {
01228
01229 cpu_sample_init(env);
01230 }
01231
01232
01233 setup_event_mode(JNI_FALSE, JVMTI_ENABLE);
01234
01235
01236
01237
01238 if ( gdata->bci ) {
01239 tracker_engage(env);
01240 }
01241
01242
01243 gdata->jvm_initialized = JNI_TRUE;
01244 gdata->jvm_initializing = JNI_FALSE;
01245
01246 LOG("cbVMInit end");
01247
01248 } rawMonitorExit(gdata->data_access_lock);
01249 }
01250
01251
01252 static void JNICALL
01253 cbVMDeath(jvmtiEnv *jvmti, JNIEnv *env)
01254 {
01255
01256
01257
01258 jboolean need_to_dump = JNI_FALSE;
01259
01260 LOG("cbVMDeath");
01261
01262
01263
01264
01265
01266 rawMonitorEnter(gdata->gc_finish_lock); {
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276 gdata->gc_finish_stop_request = JNI_TRUE;
01277 rawMonitorNotifyAll(gdata->gc_finish_lock);
01278
01279 while ( gdata->gc_finish_active ) {
01280 rawMonitorWait(gdata->gc_finish_lock,0);
01281 }
01282 } rawMonitorExit(gdata->gc_finish_lock);
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295 rawMonitorEnter(gdata->callbackBlock); {
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305 rawMonitorEnter(gdata->callbackLock); {
01306
01307 if ( gdata->bci ) {
01308 tracker_disengage(env);
01309 }
01310 gdata->vm_death_callback_active = JNI_TRUE;
01311 while (gdata->active_callbacks > 0) {
01312 rawMonitorWait(gdata->callbackLock, 0);
01313 }
01314 } rawMonitorExit(gdata->callbackLock);
01315
01316
01317
01318
01319
01320
01321 rawMonitorEnter(gdata->data_access_lock); {
01322 if ( gdata->jvm_initializing ) {
01323 HPROF_ERROR(JNI_TRUE, "VM Death during VM Init");
01324 return;
01325 }
01326 if ( !gdata->jvm_initialized ) {
01327 HPROF_ERROR(JNI_TRUE, "VM Death before VM Init");
01328 return;
01329 }
01330 if (gdata->jvm_shut_down) {
01331 HPROF_ERROR(JNI_TRUE, "VM Death more than once?");
01332 return;
01333 }
01334 } rawMonitorExit(gdata->data_access_lock);
01335
01336
01337 if ( gdata->cpu_sampling ) {
01338 cpu_sample_term(env);
01339 }
01340
01341
01342 rawMonitorEnter(gdata->dump_lock); {
01343
01344 gdata->jvm_shut_down = JNI_TRUE;
01345
01346 if (!gdata->dump_in_process) {
01347 need_to_dump = JNI_TRUE;
01348 gdata->dump_in_process = JNI_TRUE;
01349
01350
01351
01352
01353
01354
01355 }
01356
01357 } rawMonitorExit(gdata->dump_lock);
01358
01359
01360 if (gdata->dump_on_exit && need_to_dump) {
01361
01362 dump_all_data(env);
01363 }
01364
01365
01366
01367
01368
01369
01370
01371 set_callbacks(JNI_FALSE);
01372 setup_event_mode(JNI_FALSE, JVMTI_DISABLE);
01373 setup_event_mode(JNI_TRUE, JVMTI_DISABLE);
01374
01375
01376 io_write_file_footer();
01377
01378 } rawMonitorExit(gdata->callbackBlock);
01379
01380
01381 if (gdata->socket) {
01382 listener_term(env);
01383 } else {
01384 io_flush();
01385 }
01386
01387
01388 if ( gdata->fd >= 0 ) {
01389 (void)md_close(gdata->fd);
01390 gdata->fd = -1;
01391 if ( gdata->logflags & LOG_CHECK_BINARY ) {
01392 if (gdata->output_format == 'b' && gdata->output_filename != NULL) {
01393 check_binary_file(gdata->output_filename);
01394 }
01395 }
01396 }
01397 if ( gdata->heap_fd >= 0 ) {
01398 (void)md_close(gdata->heap_fd);
01399 gdata->heap_fd = -1;
01400 }
01401
01402 if ( gdata->check_fd >= 0 ) {
01403 (void)md_close(gdata->check_fd);
01404 gdata->check_fd = -1;
01405 }
01406
01407
01408 if (gdata->heap_dump) {
01409 (void)remove(gdata->heapfilename);
01410 }
01411
01412
01413 if ( gdata->logflags & LOG_DUMP_LISTS ) {
01414 list_all_tables();
01415 }
01416
01417
01418 class_delete_global_references(env);
01419 loader_delete_global_references(env);
01420 tls_delete_global_references(env);
01421
01422 }
01423
01424
01425 static void JNICALL
01426 cbThreadStart(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
01427 {
01428 LOG3("cbThreadStart", "thread is", (int)(long)(ptrdiff_t)thread);
01429
01430 BEGIN_CALLBACK() {
01431 event_thread_start(env, thread);
01432 } END_CALLBACK();
01433 }
01434
01435
01436 static void JNICALL
01437 cbThreadEnd(jvmtiEnv *jvmti, JNIEnv *env, jthread thread)
01438 {
01439 LOG3("cbThreadEnd", "thread is", (int)(long)(ptrdiff_t)thread);
01440
01441 BEGIN_CALLBACK() {
01442 event_thread_end(env, thread);
01443 } END_CALLBACK();
01444 }
01445
01446
01447 static void JNICALL
01448 cbClassFileLoadHook(jvmtiEnv *jvmti_env, JNIEnv* env,
01449 jclass class_being_redefined, jobject loader,
01450 const char* name, jobject protection_domain,
01451 jint class_data_len, const unsigned char* class_data,
01452 jint* new_class_data_len, unsigned char** new_class_data)
01453 {
01454
01455
01456
01457 LOG2("cbClassFileLoadHook:",(name==NULL?"Unknown":name));
01458
01459 if (!gdata->bci) {
01460 return;
01461 }
01462
01463 BEGIN_CALLBACK() {
01464 rawMonitorEnter(gdata->data_access_lock); {
01465 const char *classname;
01466
01467 if ( gdata->bci_counter == 0 ) {
01468
01469 class_prime_system_classes();
01470 }
01471
01472 gdata->bci_counter++;
01473
01474 *new_class_data_len = 0;
01475 *new_class_data = NULL;
01476
01477
01478 if ( name == NULL ) {
01479 classname = ((JavaCrwDemoClassname)
01480 (gdata->java_crw_demo_classname_function))
01481 (class_data, class_data_len, &my_crw_fatal_error_handler);
01482 if ( classname == NULL ) {
01483 HPROF_ERROR(JNI_TRUE, "No classname in classfile");
01484 }
01485 } else {
01486 classname = strdup(name);
01487 if ( classname == NULL ) {
01488 HPROF_ERROR(JNI_TRUE, "Ran out of malloc() space");
01489 }
01490 }
01491
01492
01493 if ( strcmp(classname, TRACKER_CLASS_NAME) != 0 ) {
01494 ClassIndex cnum;
01495 int system_class;
01496 unsigned char * new_image;
01497 long new_length;
01498 int len;
01499 char *signature;
01500 LoaderIndex loader_index;
01501
01502 LOG2("cbClassFileLoadHook injecting class" , classname);
01503
01504
01505 len = (int)strlen(classname);
01506 signature = HPROF_MALLOC(len+3);
01507 signature[0] = JVM_SIGNATURE_CLASS;
01508 (void)memcpy(signature+1, classname, len);
01509 signature[len+1] = JVM_SIGNATURE_ENDCLASS;
01510 signature[len+2] = 0;
01511 loader_index = loader_find_or_create(env,loader);
01512 if ( class_being_redefined != NULL ) {
01513 cnum = class_find_or_create(signature, loader_index);
01514 } else {
01515 cnum = class_create(signature, loader_index);
01516 }
01517 HPROF_FREE(signature);
01518 signature = NULL;
01519
01520
01521 class_add_status(cnum, CLASS_IN_LOAD_LIST);
01522
01523
01524 system_class = 0;
01525 if ( (!gdata->jvm_initialized)
01526 && (!gdata->jvm_initializing)
01527 && ( ( class_get_status(cnum) & CLASS_SYSTEM) != 0
01528 || gdata->bci_counter < 8 ) ) {
01529 system_class = 1;
01530 LOG2(classname, " is a system class");
01531 }
01532
01533 new_image = NULL;
01534 new_length = 0;
01535
01536
01537 ((JavaCrwDemo)(gdata->java_crw_demo_function))(
01538 cnum,
01539 classname,
01540 class_data,
01541 class_data_len,
01542 system_class,
01543 TRACKER_CLASS_NAME,
01544 TRACKER_CLASS_SIG,
01545 (gdata->cpu_timing)?TRACKER_CALL_NAME:NULL,
01546 (gdata->cpu_timing)?TRACKER_CALL_SIG:NULL,
01547 (gdata->cpu_timing)?TRACKER_RETURN_NAME:NULL,
01548 (gdata->cpu_timing)?TRACKER_RETURN_SIG:NULL,
01549 (gdata->obj_watch)?TRACKER_OBJECT_INIT_NAME:NULL,
01550 (gdata->obj_watch)?TRACKER_OBJECT_INIT_SIG:NULL,
01551 (gdata->obj_watch)?TRACKER_NEWARRAY_NAME:NULL,
01552 (gdata->obj_watch)?TRACKER_NEWARRAY_SIG:NULL,
01553 &new_image,
01554 &new_length,
01555 &my_crw_fatal_error_handler,
01556 &class_set_methods);
01557
01558 if ( new_length > 0 ) {
01559 unsigned char *jvmti_space;
01560
01561 LOG2("cbClassFileLoadHook DID inject this class", classname);
01562 jvmti_space = (unsigned char *)jvmtiAllocate((jint)new_length);
01563 (void)memcpy((void*)jvmti_space, (void*)new_image, (int)new_length);
01564 *new_class_data_len = (jint)new_length;
01565 *new_class_data = jvmti_space;
01566 } else {
01567 LOG2("cbClassFileLoadHook DID NOT inject this class", classname);
01568 *new_class_data_len = 0;
01569 *new_class_data = NULL;
01570 }
01571 if ( new_image != NULL ) {
01572 (void)free((void*)new_image);
01573 }
01574 }
01575 (void)free((void*)classname);
01576 } rawMonitorExit(gdata->data_access_lock);
01577 } END_CALLBACK();
01578 }
01579
01580
01581 static void JNICALL
01582 cbClassLoad(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass)
01583 {
01584
01585
01586
01587 LOG("cbClassLoad");
01588
01589 BEGIN_CALLBACK() {
01590 rawMonitorEnter(gdata->data_access_lock); {
01591
01592 WITH_LOCAL_REFS(env, 1) {
01593 jobject loader;
01594
01595 loader = getClassLoader(klass);
01596 event_class_load(env, thread, klass, loader);
01597 } END_WITH_LOCAL_REFS;
01598
01599 } rawMonitorExit(gdata->data_access_lock);
01600 } END_CALLBACK();
01601 }
01602
01603
01604 static void JNICALL
01605 cbClassPrepare(jvmtiEnv *jvmti, JNIEnv *env, jthread thread, jclass klass)
01606 {
01607
01608
01609
01610 LOG("cbClassPrepare");
01611
01612 BEGIN_CALLBACK() {
01613 rawMonitorEnter(gdata->data_access_lock); {
01614
01615 WITH_LOCAL_REFS(env, 1) {
01616 jobject loader;
01617
01618 loader = NULL;
01619 loader = getClassLoader(klass);
01620 event_class_prepare(env, thread, klass, loader);
01621 } END_WITH_LOCAL_REFS;
01622
01623 } rawMonitorExit(gdata->data_access_lock);
01624 } END_CALLBACK();
01625
01626 }
01627
01628
01629 static void JNICALL
01630 cbDataDumpRequest(jvmtiEnv *jvmti)
01631 {
01632 jboolean need_to_dump;
01633
01634 LOG("cbDataDumpRequest");
01635
01636 BEGIN_CALLBACK() {
01637 need_to_dump = JNI_FALSE;
01638 rawMonitorEnter(gdata->dump_lock); {
01639 if (!gdata->dump_in_process) {
01640 need_to_dump = JNI_TRUE;
01641 gdata->dump_in_process = JNI_TRUE;
01642 }
01643 } rawMonitorExit(gdata->dump_lock);
01644
01645 if (need_to_dump) {
01646 dump_all_data(getEnv());
01647
01648 rawMonitorEnter(gdata->dump_lock); {
01649 gdata->dump_in_process = JNI_FALSE;
01650 } rawMonitorExit(gdata->dump_lock);
01651
01652 if (gdata->cpu_sampling && !gdata->jvm_shut_down) {
01653 cpu_sample_on(NULL, 0);
01654 }
01655 }
01656 } END_CALLBACK();
01657
01658 }
01659
01660
01661 static void JNICALL
01662 cbExceptionCatch(jvmtiEnv *jvmti, JNIEnv* env,
01663 jthread thread, jmethodID method, jlocation location,
01664 jobject exception)
01665 {
01666 LOG("cbExceptionCatch");
01667
01668 BEGIN_CALLBACK() {
01669 event_exception_catch(env, thread, method, location, exception);
01670 } END_CALLBACK();
01671 }
01672
01673
01674 static void JNICALL
01675 cbMonitorWait(jvmtiEnv *jvmti, JNIEnv* env,
01676 jthread thread, jobject object, jlong timeout)
01677 {
01678 LOG("cbMonitorWait");
01679
01680 BEGIN_CALLBACK() {
01681 monitor_wait_event(env, thread, object, timeout);
01682 } END_CALLBACK();
01683 }
01684
01685
01686 static void JNICALL
01687 cbMonitorWaited(jvmtiEnv *jvmti, JNIEnv* env,
01688 jthread thread, jobject object, jboolean timed_out)
01689 {
01690 LOG("cbMonitorWaited");
01691
01692 BEGIN_CALLBACK() {
01693 monitor_waited_event(env, thread, object, timed_out);
01694 } END_CALLBACK();
01695 }
01696
01697
01698 static void JNICALL
01699 cbMonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv* env,
01700 jthread thread, jobject object)
01701 {
01702 LOG("cbMonitorContendedEnter");
01703
01704 BEGIN_CALLBACK() {
01705 monitor_contended_enter_event(env, thread, object);
01706 } END_CALLBACK();
01707 }
01708
01709
01710 static void JNICALL
01711 cbMonitorContendedEntered(jvmtiEnv *jvmti, JNIEnv* env,
01712 jthread thread, jobject object)
01713 {
01714 LOG("cbMonitorContendedEntered");
01715
01716 BEGIN_CALLBACK() {
01717 monitor_contended_entered_event(env, thread, object);
01718 } END_CALLBACK();
01719 }
01720
01721
01722 static void JNICALL
01723 cbGarbageCollectionStart(jvmtiEnv *jvmti)
01724 {
01725 LOG("cbGarbageCollectionStart");
01726
01727
01728
01729
01730
01731 gdata->gc_start_time = md_get_timemillis();
01732 }
01733
01734
01735 static void JNICALL
01736 cbGarbageCollectionFinish(jvmtiEnv *jvmti)
01737 {
01738 LOG("cbGarbageCollectionFinish");
01739
01740
01741
01742
01743
01744 if ( gdata->gc_start_time != -1L ) {
01745 gdata->time_in_gc += (md_get_timemillis() - gdata->gc_start_time);
01746 gdata->gc_start_time = -1L;
01747 }
01748
01749
01750 rawMonitorEnter(gdata->gc_finish_lock); {
01751
01752
01753
01754 if ( gdata->gc_finish_active ) {
01755 gdata->gc_finish++;
01756 rawMonitorNotifyAll(gdata->gc_finish_lock);
01757 }
01758 } rawMonitorExit(gdata->gc_finish_lock);
01759 }
01760
01761
01762 static void JNICALL
01763 cbObjectFree(jvmtiEnv *jvmti, jlong tag)
01764 {
01765 LOG3("cbObjectFree", "tag", (int)tag);
01766
01767
01768
01769
01770
01771 HPROF_ASSERT(tag!=(jlong)0);
01772 rawMonitorEnter(gdata->object_free_lock); {
01773 if ( !gdata->jvm_shut_down ) {
01774 Stack *stack;
01775
01776 stack = gdata->object_free_stack;
01777 if ( stack == NULL ) {
01778 gdata->object_free_stack = stack_init(512, 512, sizeof(jlong));
01779 stack = gdata->object_free_stack;
01780 }
01781 stack_push(stack, (void*)&tag);
01782 }
01783 } rawMonitorExit(gdata->object_free_lock);
01784 }
01785
01786 static void
01787 set_callbacks(jboolean on)
01788 {
01789 jvmtiEventCallbacks callbacks;
01790
01791 (void)memset(&callbacks,0,sizeof(callbacks));
01792 if ( ! on ) {
01793 setEventCallbacks(&callbacks);
01794 return;
01795 }
01796
01797
01798 callbacks.VMInit = &cbVMInit;
01799
01800 callbacks.VMDeath = &cbVMDeath;
01801
01802 callbacks.ThreadStart = &cbThreadStart;
01803
01804 callbacks.ThreadEnd = &cbThreadEnd;
01805
01806 callbacks.ClassFileLoadHook = &cbClassFileLoadHook;
01807
01808 callbacks.ClassLoad = &cbClassLoad;
01809
01810 callbacks.ClassPrepare = &cbClassPrepare;
01811
01812 callbacks.DataDumpRequest = &cbDataDumpRequest;
01813
01814 callbacks.ExceptionCatch = &cbExceptionCatch;
01815
01816 callbacks.MonitorWait = &cbMonitorWait;
01817
01818 callbacks.MonitorWaited = &cbMonitorWaited;
01819
01820 callbacks.MonitorContendedEnter = &cbMonitorContendedEnter;
01821
01822 callbacks.MonitorContendedEntered = &cbMonitorContendedEntered;
01823
01824 callbacks.GarbageCollectionStart = &cbGarbageCollectionStart;
01825
01826 callbacks.GarbageCollectionFinish = &cbGarbageCollectionFinish;
01827
01828 callbacks.ObjectFree = &cbObjectFree;
01829
01830 setEventCallbacks(&callbacks);
01831
01832 }
01833
01834 static void
01835 getCapabilities(void)
01836 {
01837 jvmtiCapabilities needed_capabilities;
01838 jvmtiCapabilities potential_capabilities;
01839
01840
01841 (void)memset(&needed_capabilities,0,sizeof(needed_capabilities));
01842 needed_capabilities.can_generate_garbage_collection_events = 1;
01843 needed_capabilities.can_tag_objects = 1;
01844 if (gdata->bci) {
01845 needed_capabilities.can_generate_all_class_hook_events = 1;
01846 }
01847 if (gdata->obj_watch) {
01848 needed_capabilities.can_generate_object_free_events = 1;
01849 }
01850 if (gdata->cpu_timing || gdata->cpu_sampling) {
01851 #if 0
01852 needed_capabilities.can_get_thread_cpu_time = 1;
01853 needed_capabilities.can_get_current_thread_cpu_time = 1;
01854 #endif
01855 needed_capabilities.can_generate_exception_events = 1;
01856 }
01857 if (gdata->monitor_tracing) {
01858 #if 0
01859 needed_capabilities.can_get_thread_cpu_time = 1;
01860 needed_capabilities.can_get_current_thread_cpu_time = 1;
01861 #endif
01862 needed_capabilities.can_get_owned_monitor_info = 1;
01863 needed_capabilities.can_get_current_contended_monitor = 1;
01864 needed_capabilities.can_get_monitor_info = 1;
01865 needed_capabilities.can_generate_monitor_events = 1;
01866 }
01867
01868
01869 getPotentialCapabilities(&potential_capabilities);
01870
01871
01872 needed_capabilities.can_get_source_file_name =
01873 potential_capabilities.can_get_source_file_name;
01874 needed_capabilities.can_get_line_numbers =
01875 potential_capabilities.can_get_line_numbers;
01876
01877
01878 addCapabilities(&needed_capabilities);
01879
01880 }
01881
01882
01883 static void *
01884 load_library(char *name)
01885 {
01886 char lname[FILENAME_MAX+1];
01887 char err_buf[256+FILENAME_MAX+1];
01888 char *boot_path;
01889 void *handle;
01890
01891 handle = NULL;
01892
01893
01894
01895
01896 getSystemProperty("sun.boot.library.path", &boot_path);
01897 md_build_library_name(lname, FILENAME_MAX, boot_path, name);
01898 handle = md_load_library(lname, err_buf, (int)sizeof(err_buf));
01899 if ( handle == NULL ) {
01900
01901 md_build_library_name(lname, FILENAME_MAX, "", name);
01902 handle = md_load_library(lname, err_buf, (int)sizeof(err_buf));
01903 if ( handle == NULL ) {
01904 HPROF_ERROR(JNI_TRUE, err_buf);
01905 }
01906 }
01907 return handle;
01908 }
01909
01910
01911 static void *
01912 lookup_library_symbol(void *library, char **symbols, int nsymbols)
01913 {
01914 void *addr;
01915 int i;
01916
01917 addr = NULL;
01918 for( i = 0 ; i < nsymbols; i++ ) {
01919 addr = md_find_library_entry(library, symbols[i]);
01920 if ( addr != NULL ) {
01921 break;
01922 }
01923 }
01924 if ( addr == NULL ) {
01925 char errmsg[256];
01926
01927 (void)md_snprintf(errmsg, sizeof(errmsg),
01928 "Cannot find library symbol '%s'", symbols[0]);
01929 HPROF_ERROR(JNI_TRUE, errmsg);
01930 }
01931 return addr;
01932 }
01933
01934
01935
01936
01937 JNIEXPORT jint JNICALL
01938 Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
01939 {
01940
01941 if ( gdata!=NULL && gdata->isLoaded==JNI_TRUE ) {
01942 HPROF_ERROR(JNI_TRUE, "Cannot load this JVM TI agent twice, check your java command line for duplicate hprof options.");
01943 return JNI_ERR;
01944 }
01945
01946 gdata = get_gdata();
01947
01948 gdata->isLoaded = JNI_TRUE;
01949
01950 error_setup();
01951
01952 LOG2("Agent_OnLoad", "gdata setup");
01953
01954 gdata->jvm = vm;
01955
01956 #ifndef SKIP_NPT
01957
01958 NPT_INITIALIZE(&(gdata->npt), NPT_VERSION, NULL);
01959 if ( gdata->npt == NULL ) {
01960 HPROF_ERROR(JNI_TRUE, "Cannot load npt library");
01961 }
01962 gdata->npt->utf = (gdata->npt->utfInitialize)(NULL);
01963 if ( gdata->npt->utf == NULL ) {
01964 HPROF_ERROR(JNI_TRUE, "Cannot initialize npt utf functions");
01965 }
01966 #endif
01967
01968
01969 getJvmti();
01970
01971
01972 #ifdef DEBUG
01973 gdata->debug_malloc_lock = createRawMonitor("HPROF debug_malloc lock");
01974 #endif
01975
01976 parse_options(options);
01977
01978 LOG2("Agent_OnLoad", "Has jvmtiEnv and options parsed");
01979
01980
01981 md_init();
01982
01983 string_init();
01984
01985 class_init();
01986 tls_init();
01987 trace_init();
01988 object_init();
01989
01990 site_init();
01991 frame_init();
01992 monitor_init();
01993 loader_init();
01994
01995 LOG2("Agent_OnLoad", "Tables initialized");
01996
01997 if ( gdata->pause ) {
01998 error_do_pause();
01999 }
02000
02001 getCapabilities();
02002
02003
02004 set_callbacks(JNI_TRUE);
02005
02006
02007 gdata->dump_lock = createRawMonitor("HPROF dump lock");
02008 gdata->data_access_lock = createRawMonitor("HPROF data access lock");
02009 gdata->callbackLock = createRawMonitor("HPROF callback lock");
02010 gdata->callbackBlock = createRawMonitor("HPROF callback block");
02011 gdata->object_free_lock = createRawMonitor("HPROF object free lock");
02012 gdata->gc_finish_lock = createRawMonitor("HPROF gc_finish lock");
02013
02014
02015 setup_event_mode(JNI_TRUE, JVMTI_ENABLE);
02016
02017 LOG2("Agent_OnLoad", "JVMTI capabilities, callbacks and initial notifications setup");
02018
02019
02020 gdata->jvm_initializing = JNI_FALSE;
02021 gdata->jvm_initialized = JNI_FALSE;
02022 gdata->vm_death_callback_active = JNI_FALSE;
02023 gdata->active_callbacks = 0;
02024
02025
02026 io_setup();
02027
02028
02029
02030
02031 gdata->micro_sec_ticks = md_get_microsecs();
02032
02033
02034 if ( gdata->bci ) {
02035
02036
02037 gdata->java_crw_demo_library = load_library("java_crw_demo");
02038
02039 {
02040 static char *symbols[] = JAVA_CRW_DEMO_SYMBOLS;
02041 gdata->java_crw_demo_function =
02042 lookup_library_symbol(gdata->java_crw_demo_library,
02043 symbols, (int)(sizeof(symbols)/sizeof(char*)));
02044 }
02045 {
02046 static char *symbols[] = JAVA_CRW_DEMO_CLASSNAME_SYMBOLS;
02047 gdata->java_crw_demo_classname_function =
02048 lookup_library_symbol(gdata->java_crw_demo_library,
02049 symbols, (int)(sizeof(symbols)/sizeof(char*)));
02050 }
02051 }
02052
02053 return JNI_OK;
02054 }
02055
02056 JNIEXPORT void JNICALL
02057 Agent_OnUnload(JavaVM *vm)
02058 {
02059 Stack *stack;
02060
02061 LOG("Agent_OnUnload");
02062
02063 gdata->isLoaded = JNI_FALSE;
02064
02065 stack = gdata->object_free_stack;
02066 gdata->object_free_stack = NULL;
02067 if ( stack != NULL ) {
02068 stack_term(stack);
02069 }
02070
02071 io_cleanup();
02072 loader_cleanup();
02073 tls_cleanup();
02074 monitor_cleanup();
02075 trace_cleanup();
02076 site_cleanup();
02077 object_cleanup();
02078 frame_cleanup();
02079 class_cleanup();
02080 string_cleanup();
02081
02082
02083 if ( gdata->net_hostname != NULL ) {
02084 HPROF_FREE(gdata->net_hostname);
02085 }
02086 if ( gdata->utf8_output_filename != NULL ) {
02087 HPROF_FREE(gdata->utf8_output_filename);
02088 }
02089 if ( gdata->output_filename != NULL ) {
02090 HPROF_FREE(gdata->output_filename);
02091 }
02092 if ( gdata->heapfilename != NULL ) {
02093 HPROF_FREE(gdata->heapfilename);
02094 }
02095 if ( gdata->checkfilename != NULL ) {
02096 HPROF_FREE(gdata->checkfilename);
02097 }
02098 if ( gdata->options != NULL ) {
02099 HPROF_FREE(gdata->options);
02100 }
02101
02102
02103 malloc_police();
02104
02105
02106
02107
02108
02109
02110
02111
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121 destroyRawMonitor(gdata->dump_lock);
02122 gdata->dump_lock = NULL;
02123 destroyRawMonitor(gdata->data_access_lock);
02124 gdata->data_access_lock = NULL;
02125 if ( gdata->cpu_sample_lock != NULL ) {
02126 destroyRawMonitor(gdata->cpu_sample_lock);
02127 gdata->cpu_sample_lock = NULL;
02128 }
02129 #ifdef DEBUG
02130 destroyRawMonitor(gdata->debug_malloc_lock);
02131 gdata->debug_malloc_lock = NULL;
02132 #endif
02133
02134
02135 if ( gdata->bci && gdata->java_crw_demo_library != NULL ) {
02136 md_unload_library(gdata->java_crw_demo_library);
02137 gdata->java_crw_demo_library = NULL;
02138 }
02139
02140
02141
02142
02143
02144
02145
02146
02147
02148
02149 }
02150