parse_filename.cpp revision cc2ee177dbb3befca43e36cfc56778b006c3d050
1/** 2 * @file parse_filename.cpp 3 * Split a sample filename into its constituent parts 4 * 5 * @remark Copyright 2003 OProfile authors 6 * @remark Read the file COPYING 7 * 8 * @author Philippe Elie 9 */ 10 11#include <stdexcept> 12#include <vector> 13#include <string> 14#include <iostream> 15 16#include "parse_filename.h" 17#include "file_manip.h" 18#include "string_manip.h" 19 20using namespace std; 21 22namespace { 23 24// PP:3.19 event_name.count.unitmask.tgid.tid.cpu 25parsed_filename parse_event_spec(string const & event_spec) 26{ 27 typedef vector<string> parts_type; 28 typedef parts_type::size_type size_type; 29 30 size_type const nr_parts = 6; 31 32 parts_type parts = separate_token(event_spec, '.'); 33 34 if (parts.size() != nr_parts) { 35 throw invalid_argument("parse_event_spec(): bad event specification: " + event_spec); 36 } 37 38 for (size_type i = 0; i < nr_parts ; ++i) { 39 if (parts[i].empty()) { 40 throw invalid_argument("parse_event_spec(): bad event specification: " + event_spec); 41 } 42 } 43 44 parsed_filename result; 45 46 size_type i = 0; 47 result.event = parts[i++]; 48 result.count = parts[i++]; 49 result.unitmask = parts[i++]; 50 result.tgid = parts[i++]; 51 result.tid = parts[i++]; 52 result.cpu = parts[i++]; 53 54 return result; 55} 56 57 58/** 59 * @param component path component 60 * 61 * remove from path_component all directory left to {root}, {kern} or {anon} 62 */ 63void remove_base_dir(vector<string> & path) 64{ 65 vector<string>::iterator it; 66 for (it = path.begin(); it != path.end(); ++it) { 67 if (*it == "{root}" || *it == "{kern}" || *it == "{anon}") 68 break; 69 } 70 71 path.erase(path.begin(), it); 72} 73 74 75/// Handle an anon region. Pretty print the details. 76string const parse_anon(string const & str) 77{ 78 vector<string> parts = separate_token(str, '.'); 79 if (parts.size() != 3) 80 throw invalid_argument("parse_anon() invalid name: " + str); 81 82 string ret = "anon (tgid:"; 83 ret += parts[0] + " range:" + parts[1] + "-" + parts[2] + ")"; 84 return ret; 85} 86 87 88} // anonymous namespace 89 90 91/* 92 * valid filename are variations on: 93 * 94 * {kern}/name/event_spec 95 * {root}/path/to/bin/{dep}/{root}/path/to/bin/event_spec 96 * {root}/path/to/bin/{dep}/{anon}/pid.start.end/event_spec 97 * {root}/path/to/bin/{dep}/{kern}/name/event_spec 98 * {root}/path/to/bin/{dep}/{root}/path/to/bin/{cg}/{root}/path/to/bin/event_spec 99 100 * 101 * where /name/ denote a unique path component 102 */ 103parsed_filename parse_filename(string const & filename) 104{ 105 string::size_type pos = filename.find_last_of('/'); 106 if (pos == string::npos) { 107 throw invalid_argument("parse_filename() invalid filename: " + 108 filename); 109 } 110 string event_spec = filename.substr(pos + 1); 111 string filename_spec = filename.substr(0, pos); 112 113 parsed_filename result = parse_event_spec(event_spec); 114 115 result.filename = filename; 116 117 vector<string> path = separate_token(filename_spec, '/'); 118 119 remove_base_dir(path); 120 121 // pp_interface PP:3.19 to PP:3.23 path must start either with {root} 122 // or {kern} and we must found at least 2 component, remove_base_dir() 123 // return an empty path if {root} or {kern} are not found 124 if (path.size() < 2) { 125 throw invalid_argument("parse_filename() invalid filename: " + 126 filename); 127 } 128 129 size_t i; 130 for (i = 1 ; i < path.size() ; ++i) { 131 if (path[i] == "{dep}") 132 break; 133 134 result.image += "/" + path[i]; 135 } 136 137 if (i == path.size()) { 138 throw invalid_argument("parse_filename() invalid filename: " + 139 filename); 140 } 141 142 // skip "{dep}" 143 ++i; 144 145 // PP:3.19 {dep}/ must be followed by {kern}/, {root}/ or {anon}/ 146 if (path[i] != "{kern}" && path[i] != "{root}" && path[i] != "{anon}") { 147 throw invalid_argument("parse_filename() invalid filename: " + 148 filename); 149 } 150 151 bool anon = path[i] == "{anon}"; 152 153 // skip "{root}", "{kern}" or "{anon}" 154 ++i; 155 156 for (; i < path.size(); ++i) { 157 if (path[i] == "{cg}") 158 break; 159 160 if (anon) { 161 result.lib_image = parse_anon(path[i++]); 162 break; 163 } 164 result.lib_image += "/" + path[i]; 165 } 166 167 if (i == path.size()) 168 return result; 169 170 // skip "{cg}" 171 ++i; 172 if (i == path.size() || 173 (path[i] != "{kern}" && path[i] != "{root}" && path[i] != "{anon}")) { 174 throw invalid_argument("parse_filename() invalid filename: " 175 + filename); 176 } 177 178 // skip "{root}", "{kern}" or "{anon}" 179 anon = path[i] == "{anon}"; 180 ++i; 181 182 if (anon) { 183 result.cg_image = parse_anon(path[i++]); 184 } else { 185 for (; i < path.size(); ++i) 186 result.cg_image += "/" + path[i]; 187 } 188 189 return result; 190} 191 192bool parsed_filename::profile_spec_equal(parsed_filename const & parsed) 193{ 194 return event == parsed.event && 195 count == parsed.count && 196 unitmask == parsed.unitmask && 197 tgid == parsed.tgid && 198 tid == parsed.tid && 199 cpu == parsed.tid; 200} 201 202ostream & operator<<(ostream & out, parsed_filename const & data) 203{ 204 out << data.filename << endl; 205 out << data.image << " " << data.lib_image << " " 206 << data.event << " " << data.count << " " 207 << data.unitmask << " " << data.tgid << " " 208 << data.tid << " " << data.cpu << endl; 209 210 return out; 211} 212