00001
00018 #include "config.h"
00019
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <getopt.h>
00023 #include <dirent.h>
00024 #include <exception>
00025 #include <pwd.h>
00026 #include <errno.h>
00027 #include <sys/time.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030 #include <sys/stat.h>
00031 #include <sys/types.h>
00032 #include <fcntl.h>
00033 #include <sys/wait.h>
00034 #include <ftw.h>
00035 #include <getopt.h>
00036 #include <iostream>
00037 #include "operf_utils.h"
00038 #include "op_libiberty.h"
00039 #include "string_manip.h"
00040 #include "cverb.h"
00041 #include "operf_counter.h"
00042 #include "op_cpu_type.h"
00043 #include "op_cpufreq.h"
00044 #include "op_events.h"
00045 #include "op_string.h"
00046 #include "operf_kernel.h"
00047 #include "child_reader.h"
00048 #include "op_get_time.h"
00049
00050 using namespace std;
00051
00052 typedef enum END_CODE {
00053 ALL_OK = 0,
00054 APP_ABNORMAL_END = 1,
00055 PERF_RECORD_ERROR = 2,
00056 PERF_READ_ERROR = 4,
00057 PERF_BOTH_ERROR = 8
00058 } end_code_t;
00059
00060
00061 char * app_name = NULL;
00062 pid_t app_PID = -1;
00063 uint64_t kernel_start, kernel_end;
00064 operf_read operfRead;
00065 op_cpu cpu_type;
00066 double cpu_speed;
00067 char op_samples_current_dir[PATH_MAX];
00068 uint op_nr_counters;
00069 verbose vmisc("misc");
00070 uid_t my_uid;
00071 bool no_vmlinux;
00072 int kptr_restrict;
00073 char * start_time_human_readable;
00074
00075 #define DEFAULT_OPERF_OUTFILE "operf.data"
00076 #define CALLGRAPH_MIN_COUNT_SCALE 15
00077
00078 static char full_pathname[PATH_MAX];
00079 static char * app_name_SAVE = NULL;
00080 static char * app_args = NULL;
00081 static pid_t jitconv_pid = -1;
00082 static bool app_started;
00083 static pid_t operf_record_pid;
00084 static pid_t operf_read_pid;
00085 static string samples_dir;
00086 static bool startApp;
00087 static string outputfile;
00088 static char start_time_str[32];
00089 static vector<operf_event_t> events;
00090 static bool jit_conversion_running;
00091 static void convert_sample_data(void);
00092 static int sample_data_pipe[2];
00093 static bool ctl_c = false;
00094
00095
00096 namespace operf_options {
00097 bool system_wide;
00098 bool append;
00099 int pid;
00100 bool callgraph;
00101 int mmap_pages_mult;
00102 string session_dir;
00103 string vmlinux;
00104 bool separate_cpu;
00105 bool separate_thread;
00106 bool post_conversion;
00107 vector<string> evts;
00108 }
00109
00110 static const char * valid_verbose_vals[] = { "debug", "record", "convert", "misc", "sfile", "arcs", "all"};
00111 #define NUM_VERBOSE_OPTIONS (sizeof(valid_verbose_vals)/sizeof(char *))
00112
00113 struct option long_options [] =
00114 {
00115 {"verbose", required_argument, NULL, 'V'},
00116 {"session-dir", required_argument, NULL, 'd'},
00117 {"vmlinux", required_argument, NULL, 'k'},
00118 {"callgraph", no_argument, NULL, 'g'},
00119 {"system-wide", no_argument, NULL, 's'},
00120 {"append", no_argument, NULL, 'a'},
00121 {"pid", required_argument, NULL, 'p'},
00122 {"events", required_argument, NULL, 'e'},
00123 {"separate-cpu", no_argument, NULL, 'c'},
00124 {"separate-thread", no_argument, NULL, 't'},
00125 {"lazy-conversion", no_argument, NULL, 'l'},
00126 {"help", no_argument, NULL, 'h'},
00127 {"version", no_argument, NULL, 'v'},
00128 {"usage", no_argument, NULL, 'u'},
00129 {NULL, 9, NULL, 0}
00130 };
00131
00132 const char * short_options = "V:d:k:gsap:e:ctlhuv";
00133
00134 vector<string> verbose_string;
00135
00136 static void __print_usage_and_exit(const char * extra_msg)
00137 {
00138 if (extra_msg)
00139 cerr << extra_msg << endl;
00140 cerr << "usage: operf [ options ] [ --system-wide | --pid <pid> | [ command [ args ] ] ]" << endl;
00141 cerr << "See operf man page for details." << endl;
00142 exit(EXIT_FAILURE);
00143 }
00144
00145
00146 static void op_sig_stop(int val __attribute__((unused)))
00147 {
00148
00149
00150 size_t dummy __attribute__ ((__unused__));
00151 ctl_c = true;
00152 if (cverb << vdebug)
00153 dummy = write(1, "in op_sig_stop\n", 15);
00154 if (startApp)
00155 kill(app_PID, SIGKILL);
00156 }
00157
00158 static void _handle_sigint(int val __attribute__((unused)))
00159 {
00160 size_t dummy __attribute__ ((__unused__));
00161 ctl_c = true;
00162 if (cverb << vdebug)
00163 dummy = write(1, "in _handle_sigint\n", 19);
00164 return;
00165 }
00166
00167
00168 void _set_signals_for_record(void)
00169 {
00170 struct sigaction act;
00171 sigset_t ss;
00172
00173 sigfillset(&ss);
00174 sigprocmask(SIG_UNBLOCK, &ss, NULL);
00175
00176 act.sa_handler = _handle_sigint;
00177 act.sa_flags = 0;
00178 sigemptyset(&act.sa_mask);
00179 sigaddset(&act.sa_mask, SIGINT);
00180 if (sigaction(SIGINT, &act, NULL)) {
00181 perror("operf: install of SIGINT handler failed: ");
00182 exit(EXIT_FAILURE);
00183 }
00184 }
00185
00186 void set_signals(void)
00187 {
00188 struct sigaction act;
00189 sigset_t ss;
00190
00191 sigfillset(&ss);
00192 sigprocmask(SIG_UNBLOCK, &ss, NULL);
00193
00194 act.sa_handler = op_sig_stop;
00195 act.sa_flags = 0;
00196 sigemptyset(&act.sa_mask);
00197 sigaddset(&act.sa_mask, SIGINT);
00198
00199 if (sigaction(SIGINT, &act, NULL)) {
00200 perror("operf: install of SIGINT handler failed: ");
00201 exit(EXIT_FAILURE);
00202 }
00203 }
00204
00205 static int app_ready_pipe[2], start_app_pipe[2], operf_record_ready_pipe[2];
00206
00207 void run_app(void)
00208 {
00209 char * app_fname = rindex(app_name, '/') + 1;
00210 if (!app_fname) {
00211 string msg = "Error trying to parse app name ";
00212 msg += app_name;
00213 __print_usage_and_exit(msg.c_str());
00214 }
00215
00216 vector<string> exec_args_str;
00217 if (app_args) {
00218 size_t end_pos;
00219 string app_args_str = app_args;
00220
00221
00222
00223 do {
00224 end_pos = app_args_str.find_first_of(' ', 0);
00225 if (end_pos != string::npos) {
00226 exec_args_str.push_back(app_args_str.substr(0, end_pos));
00227 app_args_str = app_args_str.substr(end_pos + 1);
00228 } else {
00229 exec_args_str.push_back(app_args_str);
00230 }
00231 } while (end_pos != string::npos);
00232 }
00233
00234 vector<const char *> exec_args;
00235 exec_args.push_back(app_fname);
00236 vector<string>::iterator it;
00237 cverb << vdebug << "Exec args are: " << app_fname << " ";
00238
00239
00240 for (it = exec_args_str.begin(); it != exec_args_str.end(); it++) {
00241 exec_args.push_back((*it).c_str());
00242 cverb << vdebug << (*it).c_str() << " ";
00243 }
00244 exec_args.push_back((char *) NULL);
00245 cverb << vdebug << endl;
00246
00247 execvp("", ((char * const *)&exec_args[0]));
00248
00249 int startup = 1;
00250 if (write(app_ready_pipe[1], &startup, sizeof(startup)) < 0) {
00251 perror("Internal error on app_ready_pipe");
00252 _exit(EXIT_FAILURE);
00253 }
00254
00255
00256 int startme = 0;
00257 if (read(start_app_pipe[0], &startme, sizeof(startme)) == -1) {
00258 perror("Internal error in run_app on start_app_pipe");
00259 _exit(EXIT_FAILURE);
00260 }
00261 if (startme != 1)
00262 _exit(EXIT_SUCCESS);
00263
00264 cverb << vdebug << "parent says start app " << app_name << endl;
00265 app_started = true;
00266 execvp(app_name, ((char * const *)&exec_args[0]));
00267 cerr << "Failed to exec " << exec_args[0] << ": " << strerror(errno) << endl;
00268
00269 _exit(EXIT_FAILURE);
00270
00271 }
00272
00273 int start_profiling(void)
00274 {
00275
00276
00277 struct timeval tv;
00278 unsigned long long start_time = 0ULL;
00279 gettimeofday(&tv, NULL);
00280 start_time = 0ULL;
00281 start_time = tv.tv_sec;
00282 sprintf(start_time_str, "%llu", start_time);
00283 start_time_human_readable = op_get_time();
00284 startApp = ((app_PID != operf_options::pid) && (operf_options::system_wide == false));
00285
00286 if (startApp) {
00287 if (pipe(app_ready_pipe) < 0 || pipe(start_app_pipe) < 0) {
00288 perror("Internal error: operf-record could not create pipe");
00289 _exit(EXIT_FAILURE);
00290 }
00291 app_PID = fork();
00292 if (app_PID < 0) {
00293 perror("Internal error: fork failed");
00294 _exit(EXIT_FAILURE);
00295 } else if (app_PID == 0) {
00296 if (!operf_options::post_conversion) {
00297 close(sample_data_pipe[0]);
00298 close(sample_data_pipe[1]);
00299 }
00300 run_app();
00301 }
00302 }
00303
00304
00305 if (pipe(operf_record_ready_pipe) < 0) {
00306 perror("Internal error: could not create pipe");
00307 return -1;
00308 }
00309 operf_record_pid = fork();
00310 if (operf_record_pid < 0) {
00311 return -1;
00312 } else if (operf_record_pid == 0) {
00313 int ready = 0;
00314 int exit_code = EXIT_SUCCESS;
00315 _set_signals_for_record();
00316 close(operf_record_ready_pipe[0]);
00317 if (!operf_options::post_conversion)
00318 close(sample_data_pipe[0]);
00319
00320
00321
00322
00323
00324
00325 try {
00326 OP_perf_utils::vmlinux_info_t vi;
00327 int outfd;
00328 int flags = O_WRONLY | O_CREAT | O_TRUNC;
00329 vi.image_name = operf_options::vmlinux;
00330 vi.start = kernel_start;
00331 vi.end = kernel_end;
00332 if (operf_options::post_conversion) {
00333 outfd = open(outputfile.c_str(), flags, S_IRUSR|S_IWUSR);
00334 if (outfd < 0) {
00335 string errmsg = "Internal error: Could not create temporary output file. errno is ";
00336 errmsg += strerror(errno);
00337 throw runtime_error(errmsg);
00338 }
00339 } else {
00340 outfd = sample_data_pipe[1];
00341 }
00342 operf_record operfRecord(outfd, operf_options::system_wide, app_PID,
00343 (operf_options::pid == app_PID), events, vi,
00344 operf_options::callgraph,
00345 operf_options::separate_cpu, operf_options::post_conversion);
00346 if (operfRecord.get_valid() == false) {
00347
00348
00349
00350
00351
00352
00353
00354 cerr << "operf record init failed" << endl;
00355 cerr << "usage: operf [ options ] [ --system-wide | --pid <pid> | [ command [ args ] ] ]" << endl;
00356
00357
00358 goto fail_out;
00359 }
00360
00361 ready = 1;
00362 if (write(operf_record_ready_pipe[1], &ready, sizeof(ready)) < 0) {
00363 perror("Internal error on operf_record_ready_pipe");
00364 exit_code = EXIT_FAILURE;
00365 goto fail_out;
00366 }
00367
00368
00369 operfRecord.recordPerfData();
00370 cverb << vmisc << "Total bytes recorded from perf events: " << dec
00371 << operfRecord.get_total_bytes_recorded() << endl;
00372 } catch (runtime_error re) {
00373
00374
00375
00376
00377 if (!ctl_c || (cverb << vmisc)) {
00378 cerr << "Caught runtime_error: " << re.what() << endl;
00379 exit_code = EXIT_FAILURE;
00380 }
00381 goto fail_out;
00382 }
00383
00384 _exit(exit_code);
00385
00386 fail_out:
00387 if (!ready){
00388
00389
00390
00391
00392 if (write(operf_record_ready_pipe[1], &ready, sizeof(ready)) < 0) {
00393 perror("Internal error on operf_record_ready_pipe");
00394 }
00395 }
00396 _exit(exit_code);
00397 } else {
00398 int recorder_ready = 0;
00399 int startup;
00400 close(operf_record_ready_pipe[1]);
00401 if (startApp) {
00402 if (read(app_ready_pipe[0], &startup, sizeof(startup)) == -1) {
00403 perror("Internal error on app_ready_pipe");
00404 return -1;
00405 } else if (startup != 1) {
00406 cerr << "app is not ready to start; exiting" << endl;
00407 return -1;
00408 }
00409 }
00410
00411 if (read(operf_record_ready_pipe[0], &recorder_ready, sizeof(recorder_ready)) == -1) {
00412 perror("Internal error on operf_record_ready_pipe");
00413 return -1;
00414 } else if (recorder_ready != 1) {
00415 cverb << vdebug << "operf record process failure; exiting" << endl;
00416 if (startApp) {
00417 cverb << vdebug << "telling child to abort starting of app" << endl;
00418 startup = 0;
00419 if (write(start_app_pipe[1], &startup, sizeof(startup)) < 0) {
00420 perror("Internal error on start_app_pipe");
00421 }
00422 }
00423 return -1;
00424 }
00425
00426 if (startApp) {
00427
00428 cverb << vdebug << "telling child to start app" << endl;
00429 if (write(start_app_pipe[1], &startup, sizeof(startup)) < 0) {
00430 perror("Internal error on start_app_pipe");
00431 return -1;
00432 }
00433 }
00434
00435 }
00436 if (!operf_options::system_wide)
00437 app_started = true;
00438
00439
00440 return 0;
00441 }
00442
00443 static end_code_t _kill_operf_read_pid(end_code_t rc)
00444 {
00445
00446 int waitpid_status;
00447 struct timeval tv;
00448 long long start_time_sec;
00449 long long usec_timer;
00450 bool keep_trying = true;
00451 waitpid_status = 0;
00452 gettimeofday(&tv, NULL);
00453 start_time_sec = tv.tv_sec;
00454 usec_timer = tv.tv_usec;
00455
00456
00457
00458
00459 while (keep_trying) {
00460 int option = WNOHANG;
00461 int wait_rc;
00462 gettimeofday(&tv, NULL);
00463 if (tv.tv_sec > start_time_sec + 5) {
00464 keep_trying = false;
00465 option = 0;
00466 cerr << "now trying to kill convert pid..." << endl;
00467
00468 if (kill(operf_read_pid, SIGUSR1) < 0) {
00469 perror("Attempt to stop operf-read process failed");
00470 rc = rc ? PERF_BOTH_ERROR : PERF_READ_ERROR;
00471 break;
00472 }
00473 } else {
00474
00475
00476
00477
00478 if ((tv.tv_usec % 1000000) > (usec_timer + 100000)
00479 || (tv.tv_usec < usec_timer))
00480 usec_timer = tv.tv_usec;
00481 else
00482 continue;
00483 }
00484 if ((wait_rc = waitpid(operf_read_pid, &waitpid_status, option)) < 0) {
00485 keep_trying = false;
00486 if (errno != ECHILD) {
00487 perror("waitpid for operf-read process failed");
00488 rc = rc ? PERF_BOTH_ERROR : PERF_READ_ERROR;
00489 }
00490 } else if (wait_rc) {
00491 if (WIFEXITED(waitpid_status)) {
00492 keep_trying = false;
00493 if (!WEXITSTATUS(waitpid_status)) {
00494 cverb << vdebug << "operf-read process returned OK" << endl;
00495 } else if (WIFEXITED(waitpid_status)) {
00496
00497
00498
00499
00500 if (!ctl_c || cverb << vdebug) {
00501 cerr << "operf-read process ended abnormally. Status = "
00502 << WEXITSTATUS(waitpid_status) << endl;
00503 rc = rc ? PERF_BOTH_ERROR : PERF_READ_ERROR;
00504 }
00505 }
00506 } else if (WIFSIGNALED(waitpid_status)) {
00507 keep_trying = false;
00508
00509
00510
00511
00512 if (!ctl_c || cverb << vdebug) {
00513 cerr << "operf-read process killed by signal "
00514 << WTERMSIG(waitpid_status) << endl;
00515 rc = PERF_RECORD_ERROR;
00516 }
00517 }
00518 }
00519 }
00520 return rc;
00521 }
00522
00523 static end_code_t _kill_operf_record_pid(void)
00524 {
00525 int waitpid_status = 0;
00526 end_code_t rc = ALL_OK;
00527
00528
00529 if (kill(operf_record_pid, SIGUSR1) < 0) {
00530 perror("Attempt to stop operf-record process failed");
00531 rc = PERF_RECORD_ERROR;
00532 } else {
00533 if (waitpid(operf_record_pid, &waitpid_status, 0) < 0) {
00534 perror("waitpid for operf-record process failed");
00535 rc = PERF_RECORD_ERROR;
00536 } else {
00537 if (WIFEXITED(waitpid_status) && (!WEXITSTATUS(waitpid_status))) {
00538 cverb << vdebug << "operf-record process returned OK" << endl;
00539 } else if (WIFEXITED(waitpid_status)) {
00540
00541
00542
00543
00544 if (!ctl_c || cverb << vdebug) {
00545 cerr << "operf-record process ended abnormally: "
00546 << WEXITSTATUS(waitpid_status) << endl;
00547 rc = PERF_RECORD_ERROR;
00548 }
00549 } else if (WIFSIGNALED(waitpid_status)) {
00550 if (!ctl_c || cverb << vdebug) {
00551 cerr << "operf-record process killed by signal "
00552 << WTERMSIG(waitpid_status) << endl;
00553 rc = PERF_RECORD_ERROR;
00554 }
00555 }
00556 }
00557 }
00558 return rc;
00559 }
00560
00561 static end_code_t _run(void)
00562 {
00563 int waitpid_status = 0;
00564 end_code_t rc = ALL_OK;
00565 bool kill_record = true;
00566
00567
00568 sigset_t ss;
00569 sigfillset(&ss);
00570 sigprocmask(SIG_BLOCK, &ss, NULL);
00571
00572
00573
00574
00575 if (!operf_options::post_conversion && pipe(sample_data_pipe) < 0) {
00576 perror("Internal error: operf-record could not create pipe");
00577 _exit(EXIT_FAILURE);
00578 }
00579
00580 if (start_profiling() < 0) {
00581 return PERF_RECORD_ERROR;
00582 }
00583
00584 if (startApp)
00585 cverb << vdebug << "app " << app_PID << " is running" << endl;
00586
00587
00588
00589
00590
00591
00592
00593
00594 if (!operf_options::post_conversion) {
00595 if (!(!app_started && !operf_options::system_wide)) {
00596 cverb << vdebug << "Forking read pid" << endl;
00597 operf_read_pid = fork();
00598 if (operf_read_pid < 0) {
00599 perror("Internal error: fork failed");
00600 _exit(EXIT_FAILURE);
00601 } else if (operf_read_pid == 0) {
00602 close(sample_data_pipe[1]);
00603 convert_sample_data();
00604 }
00605
00606 close(sample_data_pipe[0]);
00607 close(sample_data_pipe[1]);
00608 }
00609 }
00610
00611 set_signals();
00612 cerr << "operf: Profiler started" << endl;
00613 if (startApp) {
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626 struct timeval tv;
00627 long long usec_timer;
00628 bool keep_trying = true;
00629 const char * app_process = "profiled app";
00630 const char * record_process = "operf-record process";
00631 waitpid_status = 0;
00632 gettimeofday(&tv, NULL);
00633 usec_timer = tv.tv_usec;
00634 cverb << vdebug << "going into waitpid on profiled app " << app_PID << endl;
00635
00636
00637 while (keep_trying) {
00638 pid_t the_pid = app_PID;
00639 int wait_rc;
00640 const char * the_process = app_process;
00641 gettimeofday(&tv, NULL);
00642
00643
00644
00645
00646 if ((tv.tv_usec % 1000000) > (usec_timer + 100000)
00647 || (tv.tv_usec < usec_timer))
00648 usec_timer = tv.tv_usec;
00649 else
00650 continue;
00651
00652 bool trying_user_app = true;
00653 again:
00654 if ((wait_rc = waitpid(the_pid, &waitpid_status, WNOHANG)) < 0) {
00655 keep_trying = false;
00656 if (errno == EINTR) {
00657
00658 cverb << vdebug << "Caught ctrl-C. Killed " << the_process << "." << endl;
00659 } else {
00660 cerr << "waitpid for " << the_process << " failed: " << strerror(errno) << endl;
00661 rc = trying_user_app ? APP_ABNORMAL_END : PERF_RECORD_ERROR;
00662 }
00663 } else if (wait_rc) {
00664 keep_trying = false;
00665 if (WIFEXITED(waitpid_status) && (!WEXITSTATUS(waitpid_status))) {
00666 cverb << vdebug << the_process << " ended normally." << endl;
00667 } else if (WIFEXITED(waitpid_status)) {
00668 cerr << the_process << " exited with the following status: "
00669 << WEXITSTATUS(waitpid_status) << endl;
00670 rc = trying_user_app ? APP_ABNORMAL_END : PERF_RECORD_ERROR;
00671 } else if (WIFSIGNALED(waitpid_status)) {
00672 if (WTERMSIG(waitpid_status) != SIGKILL) {
00673 cerr << the_process << " killed by signal "
00674 << WTERMSIG(waitpid_status) << endl;
00675 rc = trying_user_app ? APP_ABNORMAL_END : PERF_RECORD_ERROR;
00676 }
00677 } else {
00678 keep_trying = true;
00679 }
00680 }
00681 if (trying_user_app && (rc == ALL_OK)) {
00682 trying_user_app = false;
00683 the_pid = operf_record_pid;
00684 the_process = record_process;
00685 goto again;
00686 } else if (rc != ALL_OK) {
00687
00688 if (!trying_user_app)
00689 kill_record = false;
00690 }
00691 }
00692 } else {
00693
00694 cout << "operf: Press Ctl-c or 'kill -SIGINT " << getpid() << "' to stop profiling" << endl;
00695 cverb << vdebug << "going into waitpid on operf record process " << operf_record_pid << endl;
00696 if (waitpid(operf_record_pid, &waitpid_status, 0) < 0) {
00697 if (errno == EINTR) {
00698 cverb << vdebug << "Caught ctrl-C. Killing operf-record process . . ." << endl;
00699 } else {
00700 cerr << "waitpid errno is " << errno << endl;
00701 perror("waitpid for operf-record process failed");
00702 kill_record = false;
00703 rc = PERF_RECORD_ERROR;
00704 }
00705 } else {
00706 if (WIFEXITED(waitpid_status) && (!WEXITSTATUS(waitpid_status))) {
00707 cverb << vdebug << "waitpid for operf-record process returned OK" << endl;
00708 } else if (WIFEXITED(waitpid_status)) {
00709 kill_record = false;
00710 cerr << "operf-record process ended abnormally: "
00711 << WEXITSTATUS(waitpid_status) << endl;
00712 rc = PERF_RECORD_ERROR;
00713 } else if (WIFSIGNALED(waitpid_status)) {
00714 kill_record = false;
00715 cerr << "operf-record process killed by signal "
00716 << WTERMSIG(waitpid_status) << endl;
00717 rc = PERF_RECORD_ERROR;
00718 }
00719 }
00720 }
00721 if (kill_record) {
00722 if (operf_options::post_conversion)
00723 rc = _kill_operf_record_pid();
00724 else
00725 rc = _kill_operf_read_pid(_kill_operf_record_pid());
00726 } else {
00727 if (!operf_options::post_conversion)
00728 rc = _kill_operf_read_pid(rc);
00729 }
00730
00731 return rc;
00732 }
00733
00734 static void cleanup(void)
00735 {
00736 free(app_name_SAVE);
00737 free(app_args);
00738 events.clear();
00739 verbose_string.clear();
00740 if (operf_options::post_conversion) {
00741 string cmd = "rm -f " + outputfile;
00742 if (system(cmd.c_str()) != 0)
00743 cerr << "Unable to remove " << outputfile << endl;
00744 }
00745 }
00746
00747 static void _jitconv_complete(int val __attribute__((unused)))
00748 {
00749 int child_status;
00750 pid_t the_pid = wait(&child_status);
00751 if (the_pid != jitconv_pid) {
00752 return;
00753 }
00754 jit_conversion_running = false;
00755 if (WIFEXITED(child_status) && (!WEXITSTATUS(child_status))) {
00756 cverb << vdebug << "JIT dump processing complete." << endl;
00757 } else {
00758 if (WIFSIGNALED(child_status))
00759 cerr << "child received signal " << WTERMSIG(child_status) << endl;
00760 else
00761 cerr << "JIT dump processing exited abnormally: "
00762 << WEXITSTATUS(child_status) << endl;
00763 }
00764 }
00765
00766 static void _set_signals_for_convert(void)
00767 {
00768 struct sigaction act;
00769 sigset_t ss;
00770
00771 sigfillset(&ss);
00772 sigprocmask(SIG_UNBLOCK, &ss, NULL);
00773
00774 act.sa_handler = _jitconv_complete;
00775 act.sa_flags = 0;
00776 sigemptyset(&act.sa_mask);
00777 sigaddset(&act.sa_mask, SIGCHLD);
00778 if (sigaction(SIGCHLD, &act, NULL)) {
00779 perror("operf: install of SIGCHLD handler failed: ");
00780 exit(EXIT_FAILURE);
00781 }
00782
00783 act.sa_handler = _handle_sigint;
00784 sigemptyset(&act.sa_mask);
00785 sigaddset(&act.sa_mask, SIGINT);
00786 if (sigaction(SIGINT, &act, NULL)) {
00787 perror("operf: install of SIGINT handler failed: ");
00788 exit(EXIT_FAILURE);
00789 }
00790 }
00791
00792 static void _do_jitdump_convert()
00793 {
00794 int arg_num;
00795 unsigned long long end_time = 0ULL;
00796 struct timeval tv;
00797 char end_time_str[32];
00798 char opjitconv_path[PATH_MAX + 1];
00799 char * exec_args[8];
00800
00801 jitconv_pid = fork();
00802 switch (jitconv_pid) {
00803 case -1:
00804 perror("Error forking JIT dump process!");
00805 break;
00806 case 0: {
00807 const char * jitconv_pgm = "opjitconv";
00808 const char * debug_option = "-d";
00809 const char * non_root_user = "--non-root";
00810 const char * delete_jitdumps = "--delete-jitdumps";
00811 gettimeofday(&tv, NULL);
00812 end_time = tv.tv_sec;
00813 sprintf(end_time_str, "%llu", end_time);
00814 sprintf(opjitconv_path, "%s/%s", OP_BINDIR, jitconv_pgm);
00815 arg_num = 0;
00816 exec_args[arg_num++] = (char *)jitconv_pgm;
00817 if (cverb << vdebug)
00818 exec_args[arg_num++] = (char *)debug_option;
00819 if (my_uid != 0)
00820 exec_args[arg_num++] = (char *)non_root_user;
00821 exec_args[arg_num++] = (char *)delete_jitdumps;
00822 exec_args[arg_num++] = (char *)operf_options::session_dir.c_str();
00823 exec_args[arg_num++] = start_time_str;
00824 exec_args[arg_num++] = end_time_str;
00825 exec_args[arg_num] = (char *) NULL;
00826 execvp(opjitconv_path, exec_args);
00827 fprintf(stderr, "Failed to exec %s: %s\n",
00828 exec_args[0], strerror(errno));
00829
00830 _exit(EXIT_FAILURE);
00831 break;
00832 }
00833 default:
00834 jit_conversion_running = true;
00835 break;
00836 }
00837
00838 }
00839
00840 static int __delete_old_previous_sample_data(const char *fpath,
00841 const struct stat *sb __attribute__((unused)),
00842 int tflag __attribute__((unused)),
00843 struct FTW *ftwbuf __attribute__((unused)))
00844 {
00845 if (remove(fpath)) {
00846 perror("sample data removal error");
00847 return FTW_STOP;
00848 } else {
00849 return FTW_CONTINUE;
00850 }
00851 }
00852
00853
00854
00855
00856
00857 static void convert_sample_data(void)
00858 {
00859 int inputfd;
00860 string inputfname;
00861 int rc = EXIT_SUCCESS;
00862 int keep_waiting = 0;
00863 string current_sampledir = samples_dir + "/current/";
00864 string previous_sampledir = samples_dir + "/previous";
00865 current_sampledir.copy(op_samples_current_dir, current_sampledir.length(), 0);
00866
00867 if (!app_started && !operf_options::system_wide)
00868 return;
00869
00870 if (!operf_options::append) {
00871 int flags = FTW_DEPTH | FTW_ACTIONRETVAL;
00872 errno = 0;
00873 if (nftw(previous_sampledir.c_str(), __delete_old_previous_sample_data, 32, flags) !=0 &&
00874 errno != ENOENT) {
00875 cerr << "Unable to remove old sample data at " << previous_sampledir << "." << endl;
00876 if (errno)
00877 cerr << strerror(errno) << endl;
00878 rc = EXIT_FAILURE;
00879 goto out;
00880 }
00881 if (rename(current_sampledir.c_str(), previous_sampledir.c_str()) < 0) {
00882 if (errno && (errno != ENOENT)) {
00883 cerr << "Unable to move old profile data to " << previous_sampledir << endl;
00884 cerr << strerror(errno) << endl;
00885 rc = EXIT_FAILURE;
00886 goto out;
00887 }
00888 }
00889 }
00890 rc = mkdir(current_sampledir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
00891 if (rc && (errno != EEXIST)) {
00892 cerr << "Error trying to create " << current_sampledir << " dir." << endl;
00893 perror("mkdir failed with");
00894 rc = EXIT_FAILURE;
00895 goto out;
00896 }
00897
00898 if (operf_options::post_conversion) {
00899 inputfd = -1;
00900 inputfname = outputfile;
00901 } else {
00902 inputfd = sample_data_pipe[0];
00903 inputfname = "";
00904 }
00905 operfRead.init(inputfd, inputfname, current_sampledir, cpu_type, events, operf_options::system_wide);
00906 if ((rc = operfRead.readPerfHeader()) < 0) {
00907 if (rc != OP_PERF_HANDLED_ERROR)
00908 cerr << "Error: Cannot create read header info for sample data " << endl;
00909 rc = EXIT_FAILURE;
00910 goto out;
00911 }
00912 cverb << vdebug << "Successfully read header info for sample data " << endl;
00913 if (operfRead.is_valid()) {
00914 try {
00915 int num = operfRead.convertPerfData();
00916 cverb << vdebug << "operf_read: Total bytes received from operf_record process: " << dec << num << endl;
00917 } catch (runtime_error e) {
00918 cerr << "Caught runtime error from operf_read::convertPerfData" << endl;
00919 cerr << e.what() << endl;
00920 rc = EXIT_FAILURE;
00921 goto out;
00922 }
00923 }
00924 _set_signals_for_convert();
00925 cverb << vdebug << "Calling _do_jitdump_convert" << endl;
00926 _do_jitdump_convert();
00927 while (jit_conversion_running && (keep_waiting < 2)) {
00928 sleep(1);
00929 keep_waiting++;
00930 }
00931 if (jit_conversion_running) {
00932 kill(jitconv_pid, SIGKILL);
00933 }
00934 out:
00935 if (!operf_options::post_conversion)
00936 _exit(rc);
00937 }
00938
00939
00940 static int find_app_file_in_dir(const struct dirent * d)
00941 {
00942 if (!strcmp(d->d_name, app_name))
00943 return 1;
00944 else
00945 return 0;
00946 }
00947
00948 static int get_PATH_based_pathname(char * path_holder, size_t n)
00949 {
00950 int retval = -1;
00951
00952 char * real_path = getenv("PATH");
00953 char * path = (char *) xstrdup(real_path);
00954 char * segment = strtok(path, ":");
00955 while (segment) {
00956 struct dirent ** namelist;
00957 int rc = scandir(segment, &namelist, find_app_file_in_dir, NULL);
00958 if (rc < 0) {
00959 cerr << app_name << " cannot be found in your PATH." << endl;
00960 break;
00961 } else if (rc == 1) {
00962 size_t applen = strlen(app_name);
00963 size_t dirlen = strlen(segment);
00964
00965 if (applen + dirlen + 2 > n) {
00966 cerr << "Path segment " << segment
00967 << " prepended to the passed app name is too long"
00968 << endl;
00969 retval = -1;
00970 break;
00971 }
00972 strncpy(path_holder, segment, dirlen);
00973 strcat(path_holder, "/");
00974 strncat(path_holder, app_name, applen);
00975 retval = 0;
00976 free(namelist[0]);
00977 free(namelist);
00978 break;
00979 }
00980 segment = strtok(NULL, ":");
00981 }
00982 free(path);
00983 return retval;
00984 }
00985 int validate_app_name(void)
00986 {
00987 int rc = 0;
00988 struct stat filestat;
00989 size_t len = strlen(app_name);
00990
00991 if (len > (size_t) (OP_APPNAME_LEN - 1)) {
00992 cerr << "app name longer than max allowed (" << OP_APPNAME_LEN
00993 << " chars)\n";
00994 cerr << app_name << endl;
00995 rc = -1;
00996 goto out;
00997 }
00998
00999 if (index(app_name, '/') == app_name) {
01000
01001 strncpy(full_pathname, app_name, len);
01002 } else if ((app_name[0] == '.') && (app_name[1] == '/')) {
01003
01004 if (getcwd(full_pathname, PATH_MAX) == NULL) {
01005 rc = -1;
01006 cerr << "getcwd [1] failed when trying to find app name " << app_name << ". Aborting."
01007 << endl;
01008 goto out;
01009 }
01010 strcat(full_pathname, "/");
01011 strcat(full_pathname, (app_name + 2));
01012 } else if (index(app_name, '/')) {
01013
01014 if (getcwd(full_pathname, PATH_MAX) == NULL) {
01015 rc = -1;
01016 cerr << "getcwd [2] failed when trying to find app name " << app_name << ". Aborting."
01017 << endl;
01018 goto out;
01019 }
01020 strcat(full_pathname, "/");
01021 strcat(full_pathname, app_name);
01022 } else {
01023
01024 rc = get_PATH_based_pathname(full_pathname, PATH_MAX);
01025 }
01026
01027 if (rc) {
01028 cerr << "Problem finding app name " << app_name << ". Aborting."
01029 << endl;
01030 goto out;
01031 }
01032 app_name_SAVE = app_name;
01033 app_name = full_pathname;
01034 if (stat(app_name, &filestat)) {
01035 char msg[OP_APPNAME_LEN + 50];
01036 snprintf(msg, OP_APPNAME_LEN + 50, "Non-existent app name \"%s\"",
01037 app_name);
01038 perror(msg);
01039 rc = -1;
01040 }
01041
01042 out: return rc;
01043 }
01044
01045 static void _get_event_code(operf_event_t * event)
01046 {
01047 FILE * fp;
01048 char oprof_event_code[9];
01049 string command;
01050 u64 base_code, config;
01051 base_code = config = 0ULL;
01052
01053 command = OP_BINDIR;
01054 command += "ophelp ";
01055 command += event->name;
01056
01057 fp = popen(command.c_str(), "r");
01058 if (fp == NULL) {
01059 cerr << "Unable to execute ophelp to get info for event "
01060 << event->name << endl;
01061 exit(EXIT_FAILURE);
01062 }
01063 if (fgets(oprof_event_code, sizeof(oprof_event_code), fp) == NULL) {
01064 pclose(fp);
01065 cerr << "Unable to find info for event "
01066 << event->name << endl;
01067 exit(EXIT_FAILURE);
01068 }
01069
01070 pclose(fp);
01071
01072 base_code = strtoull(oprof_event_code, (char **) NULL, 10);
01073
01074
01075 #if defined(__i386__) || defined(__x86_64__)
01076
01077 const char * vendor_AMD = "AuthenticAMD";
01078 if (op_is_cpu_vendor((char *)vendor_AMD)) {
01079 config = base_code & 0xF00ULL;
01080 config = config << 32;
01081 }
01082
01083
01084 config |= base_code & 0xFFULL;
01085
01086
01087 if (event->um_name[0]) {
01088 char mask[12];
01089 char buf[20];
01090 if ((snprintf(buf, 20, "%lu", event->count)) == -1) {
01091 cerr << "Error parsing event count of " << event->count << endl;
01092 exit(EXIT_FAILURE);
01093 }
01094 command = OP_BINDIR;
01095 command += "ophelp ";
01096 command += "--extra-mask ";
01097 command += event->name;
01098 command += ":";
01099 command += buf;
01100 command += ":";
01101 command += event->um_name;
01102 fp = popen(command.c_str(), "r");
01103 if (fp == NULL) {
01104 cerr << "Unable to execute ophelp to get info for event "
01105 << event->name << endl;
01106 exit(EXIT_FAILURE);
01107 }
01108 if (fgets(mask, sizeof(mask), fp) == NULL) {
01109 pclose(fp);
01110 cerr << "Unable to find unit mask info for " << event->um_name << " for event "
01111 << event->name << endl;
01112 exit(EXIT_FAILURE);
01113 }
01114 pclose(fp);
01115 config |= strtoull(mask, (char **) NULL, 10);
01116 } else {
01117 config |= ((event->evt_um & 0xFFULL) << 8);
01118 }
01119 #else
01120 config = base_code;
01121 #endif
01122
01123 event->op_evt_code = base_code;
01124 event->evt_code = config;
01125 }
01126
01127 static void _process_events_list(void)
01128 {
01129 string cmd = OP_BINDIR;
01130 cmd += "/ophelp --check-events ";
01131 for (unsigned int i = 0; i < operf_options::evts.size(); i++) {
01132 FILE * fp;
01133 string full_cmd = cmd;
01134 string event_spec = operf_options::evts[i];
01135 if (operf_options::callgraph) {
01136 full_cmd += " --callgraph=1 ";
01137 }
01138 full_cmd += event_spec;
01139 fp = popen(full_cmd.c_str(), "r");
01140 if (fp == NULL) {
01141 cerr << "Unable to execute ophelp to get info for event "
01142 << event_spec << endl;
01143 exit(EXIT_FAILURE);
01144 }
01145 if (fgetc(fp) == EOF) {
01146 pclose(fp);
01147 cerr << "Error retrieving info for event "
01148 << event_spec << endl;
01149 if (operf_options::callgraph)
01150 cerr << "Note: When doing callgraph profiling, the sample count must be"
01151 << endl << "15 times the minimum count value for the event." << endl;
01152 exit(EXIT_FAILURE);
01153 }
01154 fclose(fp);
01155 char * event_str = op_xstrndup(event_spec.c_str(), event_spec.length());
01156 operf_event_t event;
01157 strncpy(event.name, strtok(event_str, ":"), OP_MAX_EVT_NAME_LEN);
01158 event.count = atoi(strtok(NULL, ":"));
01159
01160
01161
01162
01163
01164 char * info;
01165 #define _OP_UM 1
01166 #define _OP_KERNEL 2
01167 #define _OP_USER 3
01168 int place = _OP_UM;
01169 char * endptr = NULL;
01170 event.evt_um = 0ULL;
01171 event.no_kernel = 0;
01172 event.no_user = 0;
01173 memset(event.um_name, '\0', OP_MAX_UM_NAME_LEN);
01174 while ((info = strtok(NULL, ":"))) {
01175 switch (place) {
01176 case _OP_UM:
01177 event.evt_um = strtoul(info, &endptr, 0);
01178
01179
01180 if (*endptr) {
01181 event.evt_um = 0;
01182 strncpy(event.um_name, info, OP_MAX_UM_NAME_LEN);
01183 }
01184 break;
01185 case _OP_KERNEL:
01186 if (atoi(info) == 0)
01187 event.no_kernel = 1;
01188 break;
01189 case _OP_USER:
01190 if (atoi(info) == 0)
01191 event.no_user = 1;
01192 break;
01193 }
01194 place++;
01195 }
01196 free(event_str);
01197 _get_event_code(&event);
01198 events.push_back(event);
01199 }
01200 #if (defined(__powerpc__) || defined(__powerpc64__))
01201 {
01202
01203
01204
01205
01206
01207 using namespace OP_perf_utils;
01208 if (!op_convert_event_vals(&events)) {
01209 cerr << "Unable to convert all oprofile event values to perf_event values" << endl;
01210 exit(EXIT_FAILURE);
01211 }
01212 }
01213 #endif
01214 }
01215
01216 static void get_default_event(void)
01217 {
01218 operf_event_t dft_evt;
01219 struct op_default_event_descr descr;
01220 vector<operf_event_t> tmp_events;
01221
01222
01223 op_default_event(cpu_type, &descr);
01224 if (descr.name[0] == '\0') {
01225 cerr << "Unable to find default event" << endl;
01226 exit(EXIT_FAILURE);
01227 }
01228
01229 memset(&dft_evt, 0, sizeof(dft_evt));
01230 if (operf_options::callgraph) {
01231 struct op_event * _event;
01232 op_events(cpu_type);
01233 if ((_event = find_event_by_name(descr.name, 0, 0))) {
01234 dft_evt.count = _event->min_count * CALLGRAPH_MIN_COUNT_SCALE;
01235 } else {
01236 cerr << "Error getting event info for " << descr.name << endl;
01237 exit(EXIT_FAILURE);
01238 }
01239 } else {
01240 dft_evt.count = descr.count;
01241 }
01242 dft_evt.evt_um = descr.um;
01243 strncpy(dft_evt.name, descr.name, OP_MAX_EVT_NAME_LEN - 1);
01244 _get_event_code(&dft_evt);
01245 events.push_back(dft_evt);
01246
01247 #if (defined(__powerpc__) || defined(__powerpc64__))
01248 {
01249
01250
01251
01252
01253
01254 using namespace OP_perf_utils;
01255 if (!op_convert_event_vals(&events)) {
01256 cerr << "Unable to convert all oprofile event values to perf_event values" << endl;
01257 exit(EXIT_FAILURE);
01258 }
01259 }
01260 #endif
01261 }
01262
01263 static void _process_session_dir(void)
01264 {
01265 if (operf_options::session_dir.empty()) {
01266 char * cwd = NULL;
01267 int rc;
01268 cwd = (char *) xmalloc(PATH_MAX);
01269
01270 cwd = getcwd(cwd, PATH_MAX);
01271 operf_options::session_dir = cwd;
01272 operf_options::session_dir +="/oprofile_data";
01273 samples_dir = operf_options::session_dir + "/samples";
01274 free(cwd);
01275 rc = mkdir(operf_options::session_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
01276 if (rc && (errno != EEXIST)) {
01277 cerr << "Error trying to create " << operf_options::session_dir << " dir." << endl;
01278 perror("mkdir failed with");
01279 exit(EXIT_FAILURE);
01280 }
01281 rc = mkdir(samples_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
01282 if (rc && (errno != EEXIST)) {
01283 cerr << "Error trying to create " << samples_dir << " dir." << endl;
01284 perror("mkdir failed with");
01285 exit(EXIT_FAILURE);
01286 }
01287 } else {
01288 struct stat filestat;
01289 int rc;
01290 if (stat(operf_options::session_dir.c_str(), &filestat)) {
01291 perror("stat operation on passed session-dir failed");
01292 exit(EXIT_FAILURE);
01293 }
01294 if (!S_ISDIR(filestat.st_mode)) {
01295 cerr << "Passed session-dir " << operf_options::session_dir
01296 << " is not a directory" << endl;
01297 exit(EXIT_FAILURE);
01298 }
01299 samples_dir = operf_options::session_dir + "/samples";
01300 rc = mkdir(samples_dir.c_str(), S_IRWXU);
01301 if (rc && (errno != EEXIST)) {
01302 cerr << "Error trying to create " << samples_dir << " dir." << endl;
01303 perror("mkdir failed with");
01304 exit(EXIT_FAILURE);
01305 }
01306 }
01307 cverb << vdebug << "Using samples dir " << samples_dir << endl;
01308 }
01309
01310 bool _get_vmlinux_address_info(vector<string> args, string cmp_val, string &str)
01311 {
01312 bool found = false;
01313 child_reader reader("objdump", args);
01314 if (reader.error()) {
01315 cerr << "An error occurred while trying to get vmlinux address info:\n\n";
01316 cerr << reader.error_str() << endl;
01317 exit(EXIT_FAILURE);
01318 }
01319
01320 while (reader.getline(str)) {
01321 if (str.find(cmp_val.c_str()) != string::npos) {
01322 found = true;
01323 break;
01324 }
01325 }
01326
01327
01328
01329 ostringstream std_err;
01330 ostringstream std_out;
01331 reader.get_data(std_out, std_err);
01332 if (std_err.str().length()) {
01333 cerr << "An error occurred while getting vmlinux address info:\n\n";
01334 cerr << std_err.str() << endl;
01335
01336
01337 if (!found)
01338 exit(EXIT_FAILURE);
01339 }
01340
01341
01342 reader.terminate_process();
01343
01344
01345
01346 if (reader.error()) {
01347 cerr << "An error occur during the execution of objdump to get vmlinux address info:\n\n";
01348 cerr << reader.error_str() << endl;
01349 if (!found)
01350 exit(EXIT_FAILURE);
01351 }
01352 return found;
01353 }
01354
01355 string _process_vmlinux(string vmlinux_file)
01356 {
01357 vector<string> args;
01358 char start[17], end[17];
01359 string str, start_end;
01360 bool found;
01361 int ret;
01362
01363 no_vmlinux = false;
01364 args.push_back("-h");
01365 args.push_back(vmlinux_file);
01366 if ((found = _get_vmlinux_address_info(args, " .text", str))) {
01367 cverb << vmisc << str << endl;
01368 ret = sscanf(str.c_str(), " %*s %*s %*s %s", start);
01369 }
01370 if (!found || ret != 1){
01371 cerr << "Unable to obtain vmlinux start address." << endl;
01372 cerr << "The specified vmlinux file (" << vmlinux_file << ") "
01373 << "does not seem to be valid." << endl;
01374 cerr << "Make sure you are using a non-compressed image file "
01375 << "(e.g. vmlinux not vmlinuz)" << endl;
01376 exit(EXIT_FAILURE);
01377 }
01378
01379 args.clear();
01380 args.push_back("-t");
01381 args.push_back(vmlinux_file);
01382 if ((found = _get_vmlinux_address_info(args, " _etext", str))) {
01383 cverb << vmisc << str << endl;
01384 ret = sscanf(str.c_str(), "%s", end);
01385 }
01386 if (!found || ret != 1){
01387 cerr << "Unable to obtain vmlinux end address." << endl;
01388 cerr << "The specified vmlinux file (" << vmlinux_file << ") "
01389 << "does not seem to be valid." << endl;
01390 cerr << "Make sure you are using a non-compressed image file "
01391 << "(e.g. vmlinux not vmlinuz)" << endl;
01392 exit(EXIT_FAILURE);
01393 }
01394
01395 errno = 0;
01396 kernel_start = strtoull(start, NULL, 16);
01397 if (errno) {
01398 cerr << "Unable to convert vmlinux start address " << start
01399 << " to a valid hex value. errno is " << strerror(errno) << endl;
01400 exit(EXIT_FAILURE);
01401 }
01402 errno = 0;
01403 kernel_end = strtoull(end, NULL, 16);
01404 if (errno) {
01405 cerr << "Unable to convert vmlinux end address " << start
01406 << " to a valid hex value. errno is " << strerror(errno) << endl;
01407 exit(EXIT_FAILURE);
01408 }
01409
01410 start_end = start;
01411 start_end.append(",");
01412 start_end.append(end);
01413 return start_end;
01414 }
01415
01416 static void _print_valid_verbose_options(void)
01417 {
01418 cerr << "Valid verbosity options are: ";
01419 for (unsigned i = 0; i < (NUM_VERBOSE_OPTIONS - 1); i++)
01420 cerr << valid_verbose_vals[i] << ",";
01421 cerr << valid_verbose_vals[NUM_VERBOSE_OPTIONS - 1] << endl;
01422 }
01423
01424 static bool _validate_verbose_args(char * verbosity)
01425 {
01426 bool valid_verbosity = true;
01427
01428 char * verbose_cand = strtok(verbosity, ",");
01429 do {
01430 unsigned i;
01431 for (i = 0; i < (NUM_VERBOSE_OPTIONS); i++) {
01432 if (!strcmp(verbose_cand, valid_verbose_vals[i])) {
01433 verbose_string.push_back(verbose_cand);
01434 break;
01435 }
01436 }
01437 if (i == NUM_VERBOSE_OPTIONS) {
01438 valid_verbosity = false;
01439 cerr << "Verbosity argument " << verbose_cand << " is not valid." << endl;
01440 _print_valid_verbose_options();
01441 }
01442 } while ((verbose_cand = strtok(NULL, ",")) && valid_verbosity);
01443 return valid_verbosity;
01444 }
01445
01446 static int _process_operf_and_app_args(int argc, char * const argv[])
01447 {
01448 bool keep_trying = true;
01449 int idx_of_non_options = 0;
01450 setenv("POSIXLY_CORRECT", "1", 0);
01451 while (keep_trying) {
01452 int option_idx = 0;
01453 int c = getopt_long(argc, argv, short_options, long_options, &option_idx);
01454 switch (c) {
01455 char * endptr;
01456 char * event;
01457
01458 case -1:
01459 if (optind != argc) {
01460 idx_of_non_options = optind;
01461 }
01462 keep_trying = false;
01463 break;
01464 case '?':
01465 cerr << "non-option detected at optind " << optind << endl;
01466 keep_trying = false;
01467 idx_of_non_options = -1;
01468 break;
01469 case 'V':
01470 if (!_validate_verbose_args(optarg))
01471 __print_usage_and_exit("NULL");
01472 break;
01473 case 'd':
01474 operf_options::session_dir = optarg;
01475 break;
01476 case 'k':
01477 operf_options::vmlinux = optarg;
01478 break;
01479 case 'g':
01480 operf_options::callgraph = true;
01481 break;
01482 case 's':
01483 operf_options::system_wide = true;
01484 break;
01485 case 'a':
01486 operf_options::append = true;
01487 break;
01488 case 'p':
01489 operf_options::pid = strtol(optarg, &endptr, 10);
01490 if ((endptr >= optarg) && (endptr <= (optarg + strlen(optarg) - 1)))
01491 __print_usage_and_exit("operf: Invalid numeric value for --pid option.");
01492 break;
01493 case 'e':
01494 event = strtok(optarg, ",");
01495 do {
01496 operf_options::evts.push_back(event);
01497 } while ((event = strtok(NULL, ",")));
01498 break;
01499 case 'c':
01500 operf_options::separate_cpu = true;
01501 break;
01502 case 't':
01503 operf_options::separate_thread = true;
01504 break;
01505 case 'l':
01506 operf_options::post_conversion = true;
01507 break;
01508 case 'h':
01509 __print_usage_and_exit(NULL);
01510 break;
01511 case 'u':
01512 __print_usage_and_exit(NULL);
01513 break;
01514 case 'v':
01515 cout << argv[0] << ": " << PACKAGE << " " << VERSION << " compiled on " << __DATE__
01516 << " " << __TIME__ << endl;
01517 exit(EXIT_SUCCESS);
01518 break;
01519 default:
01520 __print_usage_and_exit("unexpected end of arg parsing");
01521 }
01522 }
01523 return idx_of_non_options;
01524 }
01525
01526 static void process_args(int argc, char * const argv[])
01527 {
01528 int non_options_idx = _process_operf_and_app_args(argc, argv);
01529
01530 if (non_options_idx < 0) {
01531 __print_usage_and_exit(NULL);
01532 } else if ((non_options_idx) > 0) {
01533 if (operf_options::pid || operf_options::system_wide)
01534 __print_usage_and_exit(NULL);
01535
01536 app_name = (char *) xmalloc(strlen(argv[non_options_idx]) + 1);
01537 strcpy(app_name, argv[non_options_idx]);
01538 if (non_options_idx < (argc -1)) {
01539 size_t length_all_app_args = 0;
01540 non_options_idx++;
01541 for(int i = non_options_idx; i < argc; i++)
01542 length_all_app_args += strlen(argv[i]) + 1;
01543 if (length_all_app_args) {
01544 app_args = (char *) xmalloc(length_all_app_args);
01545 strcpy(app_args, argv[non_options_idx]);
01546 non_options_idx++;
01547 while (non_options_idx < argc) {
01548 strcat(app_args, " ");
01549 strcat(app_args, argv[non_options_idx]);
01550 non_options_idx++;
01551 }
01552 }
01553 }
01554 if (validate_app_name() < 0) {
01555 __print_usage_and_exit(NULL);
01556 }
01557 } else {
01558 if (operf_options::pid) {
01559 if (operf_options::system_wide)
01560 __print_usage_and_exit(NULL);
01561 app_PID = operf_options::pid;
01562 } else if (operf_options::system_wide) {
01563 app_PID = -1;
01564 } else {
01565 __print_usage_and_exit(NULL);
01566 }
01567 }
01568
01569
01570
01571
01572
01573
01574 if (!verbose::setup(verbose_string)) {
01575 cerr << "unknown --verbose= options\n";
01576 exit(EXIT_FAILURE);
01577 }
01578
01579 _process_session_dir();
01580 if (operf_options::post_conversion)
01581 outputfile = samples_dir + "/" + DEFAULT_OPERF_OUTFILE;
01582
01583 if (operf_options::evts.empty()) {
01584
01585 get_default_event();
01586 } else {
01587 _process_events_list();
01588 }
01589 op_nr_counters = events.size();
01590
01591 if (operf_options::vmlinux.empty()) {
01592 no_vmlinux = true;
01593 operf_create_vmlinux(NULL, NULL);
01594 } else {
01595 string startEnd = _process_vmlinux(operf_options::vmlinux);
01596 operf_create_vmlinux(operf_options::vmlinux.c_str(), startEnd.c_str());
01597 }
01598
01599 return;
01600 }
01601
01602 static int _check_perf_events_cap(void)
01603 {
01604
01605
01606
01607
01608
01609 struct perf_event_attr attr;
01610 pid_t pid ;
01611 memset(&attr, 0, sizeof(attr));
01612 attr.size = sizeof(attr);
01613 attr.sample_type = PERF_SAMPLE_IP;
01614
01615 pid = getpid();
01616 syscall(__NR_perf_event_open, &attr, pid, 0, -1, 0);
01617 return errno;
01618
01619 }
01620
01621 static void _precheck_permissions_to_samplesdir(string sampledir, bool for_current)
01622 {
01623
01624
01625
01626
01627
01628
01629
01630 string sampledir_testfile = sampledir + "/.xxxTeStFiLe";
01631 ofstream afile;
01632 errno = 0;
01633 afile.open(sampledir_testfile.c_str());
01634 if (!afile.is_open() && (errno != ENOENT)) {
01635 if (operf_options::append && for_current)
01636 cerr << "Unable to write to sample data directory at "
01637 << sampledir << "." << endl;
01638 else
01639 cerr << "Unable to remove old sample data at "
01640 << sampledir << "." << endl;
01641 if (errno)
01642 cerr << strerror(errno) << endl;
01643 cerr << "Try a manual removal of " << sampledir << endl;
01644 cleanup();
01645 exit(1);
01646 }
01647 afile.close();
01648
01649 }
01650
01651 static int _get_sys_value(const char * filename)
01652 {
01653 char str[10];
01654 int _val = -999;
01655 FILE * fp = fopen(filename, "r");
01656 if (fp == NULL)
01657 return _val;
01658 if (fgets(str, 9, fp))
01659 sscanf(str, "%d", &_val);
01660 fclose(fp);
01661 return _val;
01662 }
01663
01664
01665 int main(int argc, char * const argv[])
01666 {
01667 int rc;
01668 throttled = false;
01669 if ((rc = _check_perf_events_cap())) {
01670 if (rc == EBUSY) {
01671 cerr << "Performance monitor unit is busy. Do 'opcontrol --deinit' and try again." << endl;
01672 exit(1);
01673 }
01674 if (rc == ENOSYS) {
01675 cerr << "Your kernel does not implement a required syscall"
01676 << " for the operf program." << endl;
01677 } else if (rc == ENOENT) {
01678 cerr << "Your kernel's Performance Events Subsystem does not support"
01679 << " your processor type." << endl;
01680 } else {
01681 cerr << "Unexpected error running operf: " << strerror(rc) << endl;
01682 }
01683 cerr << "Please use the opcontrol command instead of operf." << endl;
01684 exit(1);
01685 }
01686
01687 cpu_type = op_get_cpu_type();
01688 cpu_speed = op_cpu_frequency();
01689 process_args(argc, argv);
01690
01691 int perf_event_paranoid = _get_sys_value("/proc/sys/kernel/perf_event_paranoid");
01692 my_uid = geteuid();
01693 if (operf_options::system_wide && ((my_uid != 0) && (perf_event_paranoid > 0))) {
01694 cerr << "To do system-wide profiling, either you must be root or" << endl;
01695 cerr << "/proc/sys/kernel/perf_event_paranoid must be set to 0 or -1." << endl;
01696 cleanup();
01697 exit(1);
01698 }
01699
01700 if (cpu_type == CPU_NO_GOOD) {
01701 cerr << "Unable to ascertain cpu type. Exiting." << endl;
01702 cleanup();
01703 exit(1);
01704 }
01705
01706 if (my_uid != 0) {
01707 bool for_current = true;
01708 string current_sampledir = samples_dir + "/current";
01709 _precheck_permissions_to_samplesdir(current_sampledir, for_current);
01710 if (!operf_options::append) {
01711 string previous_sampledir = samples_dir + "/previous";
01712 for_current = false;
01713 _precheck_permissions_to_samplesdir(previous_sampledir, for_current);
01714 }
01715 }
01716 kptr_restrict = _get_sys_value("/proc/sys/kernel/kptr_restrict");
01717 end_code_t run_result;
01718 if ((run_result = _run())) {
01719 if (startApp && app_started && (run_result != APP_ABNORMAL_END)) {
01720 int rc;
01721 cverb << vdebug << "Killing profiled app . . ." << endl;
01722 rc = kill(app_PID, SIGKILL);
01723 if (rc) {
01724 if (errno == ESRCH)
01725 cverb << vdebug
01726 << "Unable to kill profiled app because it has already ended"
01727 << endl;
01728 else
01729 perror("Attempt to kill profiled app failed.");
01730 }
01731 }
01732 if ((run_result == PERF_RECORD_ERROR) || (run_result == PERF_BOTH_ERROR)) {
01733 cerr << "Error running profiler" << endl;
01734 } else if (run_result == PERF_READ_ERROR) {
01735 cerr << "Error converting operf sample data to oprofile sample format" << endl;
01736 } else {
01737 cerr << "WARNING: Profile results may be incomplete due to to abend of profiled app." << endl;
01738 }
01739 } else {
01740 cerr << endl << "Profiling done." << endl;
01741 }
01742 if (operf_options::post_conversion) {
01743 if (!(!app_started && !operf_options::system_wide))
01744 convert_sample_data();
01745 }
01746 cleanup();
01747 return run_result;;
01748 }