/**
* @file symbol_sort.cpp
* Sorting symbols
*
* @remark Copyright 2002, 2003 OProfile authors
* @remark Read the file COPYING
*
* @author Philippe Elie
* @author John Levon
*/
#include "symbol_sort.h"
#include "symbol_functors.h"
#include "name_storage.h"
#include "op_exception.h"
#include <algorithm>
#include <sstream>
using namespace std;
namespace {
bool long_filenames;
int image_compare(image_name_id l, image_name_id r)
{
if (long_filenames)
return image_names.name(l).compare(image_names.name(r));
return image_names.basename(l).compare(image_names.basename(r));
}
int debug_compare(debug_name_id l, debug_name_id r)
{
if (long_filenames)
return debug_names.name(l).compare(debug_names.name(r));
return debug_names.basename(l).compare(debug_names.basename(r));
}
int compare_by(sort_options::sort_order order,
symbol_entry const & lhs, symbol_entry const & rhs)
{
switch (order) {
case sort_options::sample:
if (lhs.sample.counts[0] < rhs.sample.counts[0])
return 1;
if (lhs.sample.counts[0] > rhs.sample.counts[0])
return -1;
return 0;
case sort_options::symbol:
return symbol_names.demangle(lhs.name).compare(
symbol_names.demangle(rhs.name));
case sort_options::image:
return image_compare(lhs.image_name, rhs.image_name);
case sort_options::app_name:
return image_compare(lhs.app_name, rhs.app_name);
case sort_options::vma:
if (lhs.sample.vma < rhs.sample.vma)
return -1;
if (lhs.sample.vma > rhs.sample.vma)
return 1;
return 0;
case sort_options::debug: {
file_location const & f1 = lhs.sample.file_loc;
file_location const & f2 = rhs.sample.file_loc;
int ret = debug_compare(f1.filename, f2.filename);
if (ret == 0)
ret = f1.linenr - f2.linenr;
return ret;
}
default: {
// static_cast<> to shut up g++ 2.91.66 which warn
// about ambiguity between <<(int) and <<(long int)
ostringstream os;
os << "compare_by(): unknown sort option: "
<< static_cast<int>(order) << endl;
throw op_fatal_error(os.str());
}
}
return 0;
}
struct symbol_compare {
symbol_compare(vector<sort_options::sort_order> const & order,
bool reverse)
: compare_order(order), reverse_sort(reverse) {}
bool operator()(symbol_entry const * lhs,
symbol_entry const * rhs) const {
return operator()(*lhs, *rhs);
}
bool operator()(symbol_entry const & lhs,
symbol_entry const & rhs) const;
protected:
vector<sort_options::sort_order> const & compare_order;
bool reverse_sort;
};
bool symbol_compare::operator()(symbol_entry const & lhs,
symbol_entry const & rhs) const
{
for (size_t i = 0; i < compare_order.size(); ++i) {
int ret = compare_by(compare_order[i], lhs, rhs);
if (reverse_sort)
ret = -ret;
if (ret != 0)
return ret < 0;
}
return false;
}
} // anonymous namespace
void sort_options::
sort(symbol_collection & syms, bool reverse_sort, bool lf) const
{
long_filenames = lf;
vector<sort_order> sort_option(options);
for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) {
if (find(sort_option.begin(), sort_option.end(), cur) ==
sort_option.end())
sort_option.push_back(cur);
}
stable_sort(syms.begin(), syms.end(),
symbol_compare(sort_option, reverse_sort));
}
void sort_options::
sort(diff_collection & syms, bool reverse_sort, bool lf) const
{
long_filenames = lf;
vector<sort_order> sort_option(options);
for (sort_order cur = first; cur != last; cur = sort_order(cur + 1)) {
if (find(sort_option.begin(), sort_option.end(), cur) ==
sort_option.end())
sort_option.push_back(cur);
}
stable_sort(syms.begin(), syms.end(),
symbol_compare(sort_option, reverse_sort));
}
void sort_options::add_sort_option(string const & name)
{
if (name == "vma") {
options.push_back(vma);
} else if (name == "sample") {
options.push_back(sample);
} else if (name == "symbol") {
options.push_back(symbol);
} else if (name == "debug") {
options.push_back(debug);
} else if (name == "image") {
options.push_back(image);
} else if (name == "app-name") {
options.push_back(app_name);
} else {
ostringstream os;
os << "unknown sort option: " << name << endl;
throw op_fatal_error(os.str());
}
}
void sort_options::add_sort_option(sort_options::sort_order order)
{
options.push_back(order);
}