From: Maynard J. <may...@us...> - 2012-05-16 17:39:46
|
[PATCH] Flesh out operf JIT support so old jitdump files are removed This patch makes opjitconv delete old jitdump files when invoked by operf. Only jitdump files owned by the user who is running operf will be deleted. This patch is necessary because the only other way that old jitdump files are deleted is by way of opcontrol, and operf users should not have to use opcontrol at all. This patch has been committed to the perf-events branch, but review comments are welcome. Signed-off-by: Maynard Johnson <may...@us...> --- opjitconv/opjitconv.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++- opjitconv/opjitconv.h | 6 ++ pe_profiling/operf.cpp | 4 +- 3 files changed, 148 insertions(+), 3 deletions(-) diff --git a/opjitconv/opjitconv.c b/opjitconv/opjitconv.c index 9da0c82..3583f17 100644 --- a/opjitconv/opjitconv.c +++ b/opjitconv/opjitconv.c @@ -72,6 +72,9 @@ struct jitentry ** entries_address_ascending; int debug; /* indicates opjitconv invoked by non-root user via operf */ int non_root; +/* indicates we should delete jitdump files owned by the user */ +int delete_jitdumps; +LIST_HEAD(jitdump_deletion_candidates); /* * Front-end processing from this point to end of the source. @@ -311,8 +314,17 @@ chk_proc_id: goto out; } if (!(anon_dir = find_anon_dir_match(anon_sample_dirs, proc_id))) { - printf("Possible error: No matching anon samples for %s\n", - dmp_pathname); + /* With the capability of profiling with operf (as well as with + * the legacy oprofile daemon), users will not be using opcontrol + * to remove all jitdump files; instead, opjitconv will remove old + * jitdump files (see _cleanup_jitdumps() for details). But this cleanup + * strategy makes it quite likely that opjitconv will sometimes find + * jitdump files that are not owned by the current user or are in use + * by other operf users, thus, the current profile data would not have + * matching anon samples for such jitdump files. + */ + verbprintf(debug, "Informational message: No matching anon samples for %s\n", + dmp_pathname); rc = OP_JIT_CONV_NO_MATCHING_ANON_SAMPLES; goto free_res1; } @@ -481,6 +493,42 @@ static void filter_anon_samples_list(struct list_head * anon_dirs) } +static void _add_jitdumps_to_deletion_list(void * all_jitdumps, char const * jitdump_dir ) +{ + struct list_head * jd_fnames = (struct list_head *) all_jitdumps; + struct list_head * pos1, *pos2; + size_t dir_len = strlen(jitdump_dir); + + list_for_each_safe(pos1, pos2, jd_fnames) { + struct pathname * dmpfile = + list_entry(pos1, struct pathname, neighbor); + struct stat mystat; + char dmpfile_pathname[dir_len + 20]; + int fd; + memset(dmpfile_pathname, '\0', dir_len + 20); + strcpy(dmpfile_pathname, jitdump_dir); + strcat(dmpfile_pathname,dmpfile->name); + fd = open(dmpfile_pathname, O_RDONLY); + if (fd < 0) { + // Non-fatal error, so just display debug message and continue + verbprintf(debug, "opjitconv: cannot open jitdump file %s\n", + dmpfile_pathname); + continue; + } + if (fstat(fd, &mystat) < 0) { + // Non-fatal error, so just display debug message and continue + verbprintf(debug, "opjitconv: cannot fstat jitdump file"); + continue; + } + if (geteuid() == mystat.st_uid) { + struct jitdump_deletion_candidate * jdc = + xmalloc(sizeof(struct jitdump_deletion_candidate)); + jdc->name = xstrdup(dmpfile->name); + list_add(&jdc->neighbor, &jitdump_deletion_candidates); + } + } +} + static int op_process_jit_dumpfiles(char const * session_dir, unsigned long long start_time, unsigned long long end_time) { @@ -534,6 +582,9 @@ static int op_process_jit_dumpfiles(char const * session_dir, || list_empty(&jd_fnames)) goto rm_tmp; + if (delete_jitdumps) + _add_jitdumps_to_deletion_list(&jd_fnames, jitdump_dir); + /* Get user information (i.e. UID and GID) for special user 'oprofile'. */ if (non_root) { @@ -611,6 +662,82 @@ out: return rc; } +static void _cleanup_jitdumps(void) +{ + struct list_head * pos1, *pos2; + char const * jitdump_dir = "/var/lib/oprofile/jitdump/"; + size_t dir_len = strlen(jitdump_dir); + char dmpfile_pathname[dir_len + 20]; + char proc_fd_dir[PATH_MAX]; + + if (!delete_jitdumps) + return; + + /* The delete_jitdumps flag tells us to try to delete the jitdump files we found + * that belong to this user. Only operf should pass the --delete-jitdumps + * argument to opjitconv since legacy oprofile uses opcontrol to delete old + * jitdump files. + * + * The code below will only delete jitdump files that are not currently + * being used by another process. + */ + list_for_each_safe(pos1, pos2, &jitdump_deletion_candidates) { + DIR * dir; + struct dirent * dirent; + int pid; + size_t dmpfile_name_len; + int do_not_delete = 0; + struct jitdump_deletion_candidate * cand = list_entry(pos1, + struct jitdump_deletion_candidate, + neighbor); + memset(dmpfile_pathname, '\0', dir_len + 20); + memset(proc_fd_dir, '\0', PATH_MAX); + + if ((sscanf(cand->name, "%d", &pid)) != 1) { + verbprintf(debug, "Cannot get process id from jitdump file %s\n", + cand->name); + continue; + } + + strcpy(dmpfile_pathname, jitdump_dir); + strcat(dmpfile_pathname, cand->name); + dmpfile_name_len = strlen(dmpfile_pathname); + + sprintf(proc_fd_dir, "/proc/%d/fd/", pid); + if ((dir = opendir(proc_fd_dir))) { + size_t proc_fd_dir_len = strlen(proc_fd_dir); + while ((dirent = readdir(dir))) { + if (dirent->d_type == DT_LNK) { + char buf[1024]; + char fname[1024]; + memset(fname, '\0', 1024); + strcpy(fname, proc_fd_dir); + strncat(fname, dirent->d_name, 1023 - proc_fd_dir_len); + if (readlink(fname, buf, 1023) > 0) { + verbprintf(debug, "readlink found for %s\n", buf); + if (strncmp(buf, dmpfile_pathname, + dmpfile_name_len) == 0) { + do_not_delete = 1; + break; + } + } + } + } + } + if (!do_not_delete) + remove(dmpfile_pathname); + } + list_for_each_safe(pos1, pos2, &jitdump_deletion_candidates) { + struct jitdump_deletion_candidate * pname = list_entry(pos1, + struct jitdump_deletion_candidate, + neighbor); + free(pname->name); + list_del(&pname->neighbor); + free(pname); + } + +} + int main(int argc, char ** argv) { unsigned long long start_time, end_time; @@ -630,6 +757,13 @@ int main(int argc, char ** argv) argv++; } + delete_jitdumps = 0; + if (argc > 1 && strcmp(argv[1], "--delete-jitdumps") == 0) { + delete_jitdumps = 1; + argc--; + argv++; + } + if (argc != 4) { printf("Usage: opjitconv [-d] <session_dir> <starttime>" " <endtime>\n"); @@ -661,6 +795,9 @@ int main(int argc, char ** argv) verbprintf(debug, "start time/end time is %llu/%llu\n", start_time, end_time); rc = op_process_jit_dumpfiles(session_dir, start_time, end_time); + if (delete_jitdumps) + _cleanup_jitdumps(); + if (rc > OP_JIT_CONV_OK) { verbprintf(debug, "opjitconv: Ending with rc = %d. This code" " is usually OK, but can be useful for debugging" diff --git a/opjitconv/opjitconv.h b/opjitconv/opjitconv.h index 71c2c95..9562256 100644 --- a/opjitconv/opjitconv.h +++ b/opjitconv/opjitconv.h @@ -82,6 +82,12 @@ struct pathname struct list_head neighbor; }; +struct jitdump_deletion_candidate +{ + char * name; + struct list_head neighbor; +}; + /* jitsymbol.c */ void create_arrays(void); int resolve_overlaps(unsigned long long start_time); diff --git a/pe_profiling/operf.cpp b/pe_profiling/operf.cpp index bc5310f..bab5b2a 100644 --- a/pe_profiling/operf.cpp +++ b/pe_profiling/operf.cpp @@ -515,7 +515,7 @@ static void _do_jitdump_convert() struct timeval tv; char end_time_str[32]; char opjitconv_path[PATH_MAX + 1]; - char * exec_args[7]; + char * exec_args[8]; struct sigaction act; sigset_t ss; @@ -542,6 +542,7 @@ static void _do_jitdump_convert() const char * jitconv_pgm = "opjitconv"; const char * debug_option = "-d"; const char * non_root_user = "--non-root"; + const char * delete_jitdumps = "--delete-jitdumps"; gettimeofday(&tv, NULL); end_time = tv.tv_sec; sprintf(end_time_str, "%llu", end_time); @@ -552,6 +553,7 @@ static void _do_jitdump_convert() exec_args[arg_num++] = (char *)debug_option; if (my_uid != 0) exec_args[arg_num++] = (char *)non_root_user; + exec_args[arg_num++] = (char *)delete_jitdumps; exec_args[arg_num++] = (char *)operf_options::session_dir.c_str(); exec_args[arg_num++] = start_time_str; exec_args[arg_num++] = end_time_str; -- 1.6.2.rc2 |