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