Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'oprofile/org.eclipse.linuxtools.oprofile.core/natives/linux/opxml/samplefile.cc')
-rw-r--r--oprofile/org.eclipse.linuxtools.oprofile.core/natives/linux/opxml/samplefile.cc248
1 files changed, 248 insertions, 0 deletions
diff --git a/oprofile/org.eclipse.linuxtools.oprofile.core/natives/linux/opxml/samplefile.cc b/oprofile/org.eclipse.linuxtools.oprofile.core/natives/linux/opxml/samplefile.cc
new file mode 100644
index 0000000000..2bc55d8477
--- /dev/null
+++ b/oprofile/org.eclipse.linuxtools.oprofile.core/natives/linux/opxml/samplefile.cc
@@ -0,0 +1,248 @@
+/* samplefile - A class which represents a samplefile. This class either
+ represents a real disk file or a "fake" one (needed in cases where
+ Oprofile only collected samples in a dependency, like a library).
+ Written by Keith Seitz <keiths@redhat.com>
+ Copyright 2004 Red Hat, Inc.
+
+ This program is open source software licensed under the Eclipse
+ Public License ver. 1.
+
+ Alternatively, this program may be used under the terms of the GNU
+ General Public License as published by the Free Software Foundation;
+ either version 2 of the License, or (at your option) any later
+ version. */
+
+#include "samplefile.h"
+#include "sample.h"
+#include "stable.h"
+#include "xmlfmt.h"
+
+#include <algorithm>
+
+using namespace std;
+
+// From libutil++
+extern bool create_file_list (list<string>& file_list, const string& base_dir,
+ const string& filter = "*", bool recursive = true);
+
+samplefile::samplefile (string filename)
+{
+ _st = NULL;
+ _db = new oprofile_db (filename);
+ _filename = filename;
+ _get_info_from_filename ();
+}
+
+// This seems like a giant waste of time, but when it comes down to processing many
+// hundreds of samplefiles, we really need to be able to do this quickly.
+string
+samplefile::event_for_filename (string filename)
+{
+ string event;
+
+ string::size_type pos = filename.find_last_of ('/');
+ if (pos != string::npos)
+ {
+ string basename = filename.substr (pos + 1, string::npos);
+
+ // Tokenize the basename between the '.'. This seems like a contradiction
+ // to the speed mantra, but consider it a minimal sanity check.
+ vector<string> parts = _tokenize (basename, '.');
+ if (parts.size () == 6)
+ event = parts[0];
+ }
+
+ return event;
+}
+
+void
+samplefile::_get_info_from_filename (void)
+{
+ // First the easy stuff: event specifications
+ // Filenames look like: EVENT.COUNT.UMASK.TGID.TID.CPU
+ string basename;
+ string dir_name;
+ string::size_type pos = _filename.find_last_of ('/');
+ if (pos != string::npos)
+ {
+ dir_name = _filename.substr (0, pos);
+ basename = _filename.substr (pos + 1, string::npos);
+
+ // Tokenize the basename between the '.'
+ vector<string> parts = _tokenize (basename, '.');
+ if (parts.size () == 6)
+ {
+ // Right number of specifications!
+ int i = 0;
+ _event = parts[i++];
+ _count = parts[i++];
+ _unit_mask = parts[i++];
+ _tgid = parts[i++];
+ _tid = parts[i++];
+ _cpu = parts[i++];
+ }
+ else
+ return ;
+
+ /* Now the hard part: the lib and image names */
+
+ // Like the event spec, the easiest way to do this is to tokenize the pathname
+ parts = _tokenize (dir_name, '/');
+
+ // Strip off everything up to either "{root}" or "{kern}"
+ vector<string>::size_type i = 0;
+
+ /* Basically, we have
+ "/path/to/samples/<session>/{root} or {kern}"
+ + "/path/to/executable/{dep}" + "{root}" || "{kern}"
+ + "/path/to/library[/{cg}]
+ [+ "/path/to/callgraph"] */
+
+ // First "token" to look for is "{root}" or "{kern}"
+ for ( ; i < parts.size (); ++i)
+ {
+ if (parts[i] == "{root}" || parts[i] == "{kern}")
+ break;
+ }
+
+ // Skip past "{root}" or "{kern}"
+ ++i;
+
+ // Next "token" is "{dep}". Everything else is image name
+ for ( ; i < parts.size () && parts[i] != "{dep}"; ++i)
+ _image += "/" + parts[i];
+
+ // Skip past "{dep}"
+ ++i;
+
+ // "{dep}" must be followed by "{kern}" or "{root}"
+ if (parts[i] != "{kern}" && parts[i] != "{root}")
+ {
+ // Error. Filename truncated.
+ return;
+ }
+
+ // Skip past "{kern}" or "{root}"
+ ++i;
+
+ // Next "token" will be "{cg}" or string::npos
+ for ( ; i < parts.size () && parts[i] != "{cg}"; ++i)
+ _lib_image += "/" + parts[i];
+
+ // Skip past "{cg}" (or end)
+ ++i;
+
+ // Last bits will be callgraph
+ for ( ; i < parts.size (); ++i)
+ _callgraph += "/" + parts[i];
+ }
+}
+
+vector<string>
+samplefile::_tokenize (const string& str, char delim)
+{
+ vector<string> tokens;
+ string::size_type start, end;
+
+ start = end = 0;
+ while ((end = str.find (delim, start)) != string::npos)
+ {
+ if (start != end ) // ignore zero-length, i.e, str[0] == delim
+ tokens.push_back (str.substr (start, end - start));
+
+ // skip the delimiter character
+ start = end + 1;
+ }
+
+ // add any trailing stuff
+ if (start != str.length ())
+ tokens.push_back (str.substr (start, string::npos));
+
+ return tokens;
+}
+
+samplefile::~samplefile (void)
+{
+ if (_db != NULL)
+ {
+ delete _db;
+ _db = NULL;
+ }
+
+ if (_st != NULL)
+ {
+ delete _st;
+ _st = NULL;
+ }
+}
+
+// DO NOT FREE THE RESULT. ~oprofile_db will do it.
+const samplefile::samples_t
+samplefile::get_samples (void)
+{
+ samplefile::samples_t samples;
+
+ if (has_samplefile ())
+ {
+ if (_st == NULL)
+ {
+ _st = new symboltable (get_name ().c_str ());
+ _st->read_symbols ();
+ }
+
+ samples = _db->get_samples (_st);
+ }
+
+ return samples;
+}
+
+bool
+samplefile::get_debug_info (bfd_vma vma, const char*& func, const char*& file, unsigned int& line)
+{
+ return (_st == NULL ? false : _st->get_debug_info (vma, func, file, line));
+}
+
+void
+samplefile::get_sample_file_list (list<string>& file_list, const string& base_dir)
+{
+ file_list.clear ();
+
+ list<string> files;
+ if (create_file_list (files, base_dir))
+ {
+ list<string>::iterator i;
+ for (i = files.begin (); i != files.end (); ++i)
+ {
+ // Only allow unique filenames into the final list.
+ // (This can happen because we can have multiple counters
+ // for any given sample file.)
+ if (find (file_list.begin (), file_list.end (), *i)
+ == file_list.end ())
+ file_list.push_back (*i);
+ }
+ }
+}
+
+// Output header & list of samples
+/*
+ * <samplefile>/var/lib/oprofile/samples/current/blah/blah/blah</samplefile>
+ * SAMPLE (handled by class sample)
+ */
+ostream&
+operator<< (ostream& os, samplefile* sf)
+{
+ // output the sfile's full pathname (used for fetching debug info)
+ os << startt ("samplefile") << sf->get_sample_file_name () << endt;
+
+ // output list of samples
+ //TODO: grouped by symbol, then line number
+ samplefile::samples_t samples = sf->get_samples ();
+ samplefile::samples_t::iterator s;
+ for (s = samples.begin (); s != samples.end (); ++s)
+ {
+ const sample* smpl = samplefile::SAMPLE (*s);
+ os << smpl;
+ }
+
+ return os;
+}

Back to the top