operf_process_info.cpp

Go to the documentation of this file.
00001 /*
00002  * @file pe_profiling/operf_process_info.cpp
00003  * This file contains functions for storing process information,
00004  * handling exectuable mmappings, etc.
00005  *
00006  * @remark Copyright 2011 OProfile authors
00007  * @remark Read the file COPYING
00008  *
00009  * Created on: Dec 13, 2011
00010  * @author Maynard Johnson
00011  * (C) Copyright IBM Corp. 2011
00012  */
00013 
00014 #include <stdio.h>
00015 #include <iostream>
00016 #include <map>
00017 #include <string.h>
00018 #include "operf_process_info.h"
00019 #include "file_manip.h"
00020 #include "operf_utils.h"
00021 
00022 using namespace std;
00023 using namespace OP_perf_utils;
00024 
00025 operf_process_info::operf_process_info(pid_t tgid, const char * appname, bool app_arg_is_fullname, bool is_valid)
00026 : pid(tgid), _appname(appname ? appname : ""), valid(is_valid)
00027 {
00028     if (app_arg_is_fullname && appname) {
00029         appname_is_fullname = YES_FULLNAME;
00030         app_basename = op_basename(appname);
00031         num_app_chars_matched = (int)app_basename.length();
00032     } else if (appname) {
00033         appname_is_fullname = MAYBE_FULLNAME;
00034         num_app_chars_matched = -1;
00035         app_basename = appname;
00036     } else {
00037         appname_is_fullname = NOT_FULLNAME;
00038         num_app_chars_matched = -1;
00039         app_basename = "";
00040     }
00041     forked = false;
00042     parent_of_fork = NULL;
00043 }
00044 
00045 operf_process_info::~operf_process_info()
00046 {
00047     map<u64, struct operf_mmap *>::iterator it;
00048     map<u64, struct operf_mmap *>::iterator end;
00049 
00050     if (valid) {
00051         it = mmappings.begin();
00052         end = mmappings.end();
00053     } else {
00054         it = deferred_mmappings.begin();
00055         end = deferred_mmappings.end();
00056     }
00057     mmappings.clear();
00058     deferred_mmappings.clear();
00059 }
00060 
00061 void operf_process_info::process_new_mapping(struct operf_mmap * mapping)
00062 {
00063     // If we do not know the full pathname of our app yet,
00064     // let's try to determine if the passed filename is a good
00065     // candidate appname.
00066 
00067     if (!mapping->is_anon_mapping && (appname_is_fullname < YES_FULLNAME) && (num_app_chars_matched < (int)app_basename.length())) {
00068         string basename;
00069         int num_matched_chars = get_num_matching_chars(mapping->filename, basename);
00070         if (num_matched_chars > num_app_chars_matched) {
00071             appname_is_fullname = MAYBE_FULLNAME;
00072             _appname = mapping->filename;
00073             app_basename = basename;
00074             num_app_chars_matched = num_matched_chars;
00075             cverb << vmisc << "Best appname match is " << _appname << endl;
00076         }
00077     }
00078     mmappings[mapping->start_addr] = mapping;
00079     vector<operf_process_info *>::iterator it = forked_processes.begin();
00080     while (it != forked_processes.end()) {
00081         operf_process_info * p = *it;
00082         p->copy_new_parent_mapping(mapping);
00083         cverb << vmisc << "Copied new parent mapping for " << mapping->filename
00084               << " for forked process " << p->pid << endl;
00085         it++;
00086     }
00087 
00088 }
00089 
00090 /* This method should only be invoked when a "delayed" COMM event is processed.
00091  * By "delayed", I mean that we have already received MMAP events for the associated
00092  * process, for which we've had to create a partial operf_process_info object -- one
00093  * that has no _appname yet and is marked invalid.
00094  *
00095  * Given the above statement, the passed app_shortname "must" come from a comm.comm
00096  * field, which is 16 chars in length (thus the name of the arg).
00097  */
00098 void operf_process_info::process_deferred_mappings(string app_shortname)
00099 {
00100     _appname = app_shortname;
00101     app_basename = app_shortname;
00102     valid = true;
00103     map<u64, struct operf_mmap *>::iterator it = deferred_mmappings.begin();
00104     while (it != deferred_mmappings.end()) {
00105         process_new_mapping(it->second);
00106         cverb << vmisc << "Processed deferred mapping for " << it->second->filename << endl;
00107         it++;
00108     }
00109     deferred_mmappings.clear();
00110     process_deferred_forked_processes();
00111 }
00112 
00113 int operf_process_info::get_num_matching_chars(string mapped_filename, string & basename)
00114 {
00115     size_t app_length;
00116     size_t basename_length;
00117     const char * app_cstr, * basename_cstr;
00118     string app_basename;
00119     basename = op_basename(mapped_filename);
00120     if (appname_is_fullname == NOT_FULLNAME) {
00121         // This implies _appname is storing a short name from a COMM event
00122         app_length = _appname.length();
00123         app_cstr = _appname.c_str();
00124     } else {
00125         app_basename = op_basename(_appname);
00126         app_length = app_basename.length();
00127         app_cstr = app_basename.c_str();
00128     }
00129     basename_length = basename.length();
00130     if (app_length > basename_length)
00131         return -1;
00132 
00133     basename_cstr = basename.c_str();
00134     int num_matched_chars = 0;
00135     for (size_t i = 0; i < app_length; i++) {
00136         if (app_cstr[i] == basename_cstr[i])
00137             num_matched_chars++;
00138         else
00139             break;
00140     }
00141     return num_matched_chars ? num_matched_chars : -1;
00142 }
00143 
00144 const struct operf_mmap * operf_process_info::find_mapping_for_sample(u64 sample_addr)
00145 {
00146     map<u64, struct operf_mmap *>::iterator it = mmappings.begin();
00147     while (it != mmappings.end()) {
00148         if (sample_addr >= it->second->start_addr && sample_addr <= it->second->end_addr)
00149             return it->second;
00150         it++;
00151     }
00152     return NULL;
00153 }
00154 
00173 void operf_process_info::process_hypervisor_mapping(u64 ip)
00174 {
00175     bool create_new_hyperv_mmap = true;
00176     u64 curr_start, curr_end;
00177     map<u64, struct operf_mmap *>::iterator it;
00178     map<u64, struct operf_mmap *>::iterator end;
00179 
00180     curr_end = curr_start = ~0ULL;
00181     if (valid) {
00182         it = mmappings.begin();
00183         end = mmappings.end();
00184     } else {
00185         it = deferred_mmappings.begin();
00186         end = deferred_mmappings.end();
00187     }
00188     while (it != end) {
00189         if (it->second->is_hypervisor) {
00190             struct operf_mmap * _mmap = it->second;
00191             curr_start = _mmap->start_addr;
00192             curr_end = _mmap->end_addr;
00193             if (curr_start > ip) {
00194                 if (valid)
00195                     mmappings.erase(it);
00196                 else
00197                     deferred_mmappings.erase(it);
00198                 delete _mmap;
00199             } else {
00200                 create_new_hyperv_mmap = false;
00201                 if (curr_end <= ip)
00202                     _mmap->end_addr = ip;
00203             }
00204             break;
00205         }
00206         it++;
00207     }
00208 
00209     if (create_new_hyperv_mmap) {
00210         struct operf_mmap * hypervisor_mmap = new struct operf_mmap;
00211         memset(hypervisor_mmap, 0, sizeof(struct operf_mmap));
00212         hypervisor_mmap->start_addr = ip;
00213         hypervisor_mmap->end_addr = ((curr_end == ~0ULL) || (curr_end < ip)) ? ip : curr_end;
00214         strcpy(hypervisor_mmap->filename, "[hypervisor_bucket]");
00215         hypervisor_mmap->is_anon_mapping = true;
00216         hypervisor_mmap->pgoff = 0;
00217         hypervisor_mmap->is_hypervisor = true;
00218         if (cverb << vmisc) {
00219             cout << "Synthesize mmapping for " << hypervisor_mmap->filename << endl;
00220             cout << "\tstart_addr: " << hex << hypervisor_mmap->start_addr;
00221             cout << "; end addr: " << hypervisor_mmap->end_addr << endl;
00222         }
00223         if (valid)
00224             process_new_mapping(hypervisor_mmap);
00225         else
00226             add_deferred_mapping(hypervisor_mmap);
00227     }
00228 }
00229 
00230 void operf_process_info::copy_mappings_to_forked_process(operf_process_info * forked_pid)
00231 {
00232     map<u64, struct operf_mmap *>::iterator it = mmappings.begin();
00233     while (it != mmappings.end()) {
00234         struct operf_mmap * mapping = it->second;
00235         /* We can pass just the pointer of the operf_mmap object because the
00236          * original object is created in operf_utils:__handle_mmap_event and
00237          * is saved in the global all_images_map.
00238          */
00239             forked_pid->process_new_mapping(mapping);
00240             it++;
00241     }
00242 }
00243 
00244 void operf_process_info::connect_forked_process_to_parent(operf_process_info * parent)
00245 {
00246     forked = true;
00247     parent_of_fork = parent;
00248     if (parent->is_valid()) {
00249         valid = true;
00250         _appname = parent->get_app_name();
00251         if (parent->is_appname_valid() && !_appname.empty()) {
00252             appname_is_fullname = YES_FULLNAME;
00253             app_basename = op_basename(_appname);
00254             num_app_chars_matched = (int)app_basename.length();
00255         } else if (!_appname.empty()) {
00256             appname_is_fullname = MAYBE_FULLNAME;
00257             num_app_chars_matched = -1;
00258             app_basename = _appname;
00259         } else {
00260             appname_is_fullname = NOT_FULLNAME;
00261             num_app_chars_matched = -1;
00262             app_basename = "";
00263         }
00264         parent->copy_mappings_to_forked_process(this);
00265     }
00266 }
00267 
00268 void operf_process_info::process_deferred_forked_processes(void)
00269 {
00270     vector<operf_process_info *>::iterator it = forked_processes.begin();
00271     while (it != forked_processes.end()) {
00272         operf_process_info * p = *it;
00273         p->connect_forked_process_to_parent(this);
00274         cverb << vmisc << "Processed deferred forked process " << p->pid << endl;
00275         it++;
00276     }
00277 }
00278 
00279 void operf_process_info::remove_forked_process(pid_t forked_pid)
00280 {
00281     std::vector<operf_process_info *>::iterator it = forked_processes.begin();
00282     while (it != forked_processes.end()) {
00283         if ((*it)->pid == forked_pid) {
00284             forked_processes.erase(it);
00285             break;
00286         }
00287         it++;
00288     }
00289 }
00290 
00291 /* This function is called as a result of the following scenario:
00292  *   1. An operf_process_info was created for a FORK event
00293  *   2. The forked process was connected to (associated with) its parent,
00294  *      adding the parent's mmappings to the forked process's operf_process_info.
00295  *   3. Then the forked process does an exec, which results in a COMM
00296  *      event. The forked process is now considered completely separate
00297  *      from its parent, so we need to disassociate it from the parent.
00298  */
00299 void operf_process_info::disassociate_from_parent(char * app_shortname)
00300 {
00301     _appname = app_shortname;
00302     app_basename = app_shortname;
00303     appname_is_fullname = NOT_FULLNAME;
00304     valid = true;
00305     /* Now that we have a valid app shortname (from the COMM event data),
00306      * let's spin through our mmappings and process them -- see if we can
00307      * find one that has a good appname candidate.
00308      */
00309     num_app_chars_matched = 0;
00310     map<u64, struct operf_mmap *>::iterator it = mmappings.begin();
00311     while (it != mmappings.end()) {
00312         process_new_mapping(it->second);
00313         it++;
00314     }
00315     parent_of_fork->remove_forked_process(this->pid);
00316 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1