This source file includes following definitions.
- candidates_
- ToString
- MakeLabelInfo
- ResetDebugLabel
- program_info
- empty
- top_candidate
- Update
- TopScore
- HasPendingUpdates
- AddPendingUpdate
- ApplyPendingUpdates
- Print
- candidates
- Find
- at
- add_position
- position_count
- InModel
- pattern
- set_pattern
- pattern_
- ToString
- count
- instance
- program_coverage_
- ToString
- HistogramToString
- HistogramToStringFull
- ToString
- ShinglePatternToStringFull
- hash_combine
- SingleUseScore
- empty
- first
- Print
- AddPendingUpdate
- ApplyPendingUpdates
- model_end_
- Solve
- PrintPatternsHeader
- PrintActivePatterns
- PrintPatterns
- PrintAllPatterns
- PrintAllShingles
- AddShingles
- Declassify
- Reclassify
- InitialClassify
- AddAffectedPositions
- RemovePatternsNeedingUpdatesFromQueues
- AddPatternsNeedingUpdatesToQueues
- RemovePatternFromQueues
- AddPatternToQueues
- AddPatternToLabelQueue
- AssignOne
- AssignFirstVariableOfHistogramHead
- FindAndAssignBestLeader
- model_
- Adjust
- Finish
- CollectTraces
- Solve
- ReferenceLabel
- MakeShingleAdjustmentMethod
#include "courgette/adjustment_method.h"
#include <algorithm>
#include <limits>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "base/time/time.h"
#include "courgette/assembly_program.h"
#include "courgette/courgette.h"
#include "courgette/encoded_program.h"
namespace courgette {
namespace adjustment_method_2 {
class AssignmentCandidates;
class LabelInfoMaker;
class Shingle;
class ShinglePattern;
class LabelInfo {
public:
LabelInfo()
: label_(NULL), is_model_(false), debug_index_(0), refs_(0),
assignment_(NULL), candidates_(NULL)
{}
~LabelInfo();
AssignmentCandidates* candidates();
Label* label_;
uint32 is_model_ : 1;
uint32 debug_index_ : 31;
int refs_;
LabelInfo* assignment_;
std::vector<uint32> positions_;
private:
AssignmentCandidates* candidates_;
void operator=(const LabelInfo*);
};
typedef std::vector<LabelInfo*> Trace;
std::string ToString(const LabelInfo* info) {
std::string s;
base::StringAppendF(&s, "%c%d", "pm"[info->is_model_], info->debug_index_);
if (info->label_->index_ != Label::kNoIndex)
base::StringAppendF(&s, " (%d)", info->label_->index_);
base::StringAppendF(&s, " #%u", info->refs_);
return s;
}
class LabelInfoMaker {
public:
LabelInfoMaker() : debug_label_index_gen_(0) {}
LabelInfo* MakeLabelInfo(Label* label, bool is_model, uint32 position) {
LabelInfo& slot = label_infos_[label];
if (slot.label_ == NULL) {
slot.label_ = label;
slot.is_model_ = is_model;
slot.debug_index_ = ++debug_label_index_gen_;
}
slot.positions_.push_back(position);
++slot.refs_;
return &slot;
}
void ResetDebugLabel() { debug_label_index_gen_ = 0; }
private:
int debug_label_index_gen_;
std::map<Label*, LabelInfo> label_infos_;
DISALLOW_COPY_AND_ASSIGN(LabelInfoMaker);
};
struct OrderLabelInfo {
bool operator()(const LabelInfo* a, const LabelInfo* b) const {
if (a->label_->rva_ < b->label_->rva_) return true;
if (a->label_->rva_ > b->label_->rva_) return false;
if (a == b) return false;
return a->positions_ < b->positions_;
}
};
class AssignmentCandidates {
public:
explicit AssignmentCandidates(LabelInfo* program_info)
: program_info_(program_info) {}
LabelInfo* program_info() const { return program_info_; }
bool empty() const { return label_to_score_.empty(); }
LabelInfo* top_candidate() const { return queue_.begin()->second; }
void Update(LabelInfo* model_info, int delta_score) {
LOG_ASSERT(delta_score != 0);
int old_score = 0;
int new_score = 0;
LabelToScore::iterator p = label_to_score_.find(model_info);
if (p != label_to_score_.end()) {
old_score = p->second;
new_score = old_score + delta_score;
queue_.erase(ScoreAndLabel(old_score, p->first));
if (new_score == 0) {
label_to_score_.erase(p);
} else {
p->second = new_score;
queue_.insert(ScoreAndLabel(new_score, model_info));
}
} else {
new_score = delta_score;
label_to_score_.insert(std::make_pair(model_info, new_score));
queue_.insert(ScoreAndLabel(new_score, model_info));
}
LOG_ASSERT(queue_.size() == label_to_score_.size());
}
int TopScore() const {
int first_value = 0;
int second_value = 0;
Queue::const_iterator p = queue_.begin();
if (p != queue_.end()) {
first_value = p->first;
++p;
if (p != queue_.end()) {
second_value = p->first;
}
}
return first_value - second_value;
}
bool HasPendingUpdates() { return !pending_updates_.empty(); }
void AddPendingUpdate(LabelInfo* model_info, int delta_score) {
LOG_ASSERT(delta_score != 0);
pending_updates_[model_info] += delta_score;
}
void ApplyPendingUpdates() {
size_t zeroes = 0;
for (LabelToScore::iterator p = pending_updates_.begin();
p != pending_updates_.end();
++p) {
if (p->second != 0)
Update(p->first, p->second);
else
++zeroes;
}
pending_updates_.clear();
}
void Print(int max) {
VLOG(2) << "score " << TopScore() << " " << ToString(program_info_)
<< " := ?";
if (!pending_updates_.empty())
VLOG(2) << pending_updates_.size() << " pending";
int count = 0;
for (Queue::iterator q = queue_.begin(); q != queue_.end(); ++q) {
if (++count > max) break;
VLOG(2) << " " << q->first << " " << ToString(q->second);
}
}
private:
typedef std::map<LabelInfo*, int, OrderLabelInfo> LabelToScore;
typedef std::pair<int, LabelInfo*> ScoreAndLabel;
struct OrderScoreAndLabelByScoreDecreasing {
OrderLabelInfo tie_breaker;
bool operator()(const ScoreAndLabel& a, const ScoreAndLabel& b) const {
if (a.first > b.first) return true;
if (a.first < b.first) return false;
return tie_breaker(a.second, b.second);
}
};
typedef std::set<ScoreAndLabel, OrderScoreAndLabelByScoreDecreasing> Queue;
LabelInfo* program_info_;
LabelToScore label_to_score_;
LabelToScore pending_updates_;
Queue queue_;
};
AssignmentCandidates* LabelInfo::candidates() {
if (candidates_ == NULL)
candidates_ = new AssignmentCandidates(this);
return candidates_;
}
LabelInfo::~LabelInfo() {
delete candidates_;
}
class Shingle {
public:
static const size_t kWidth = 5;
struct InterningLess {
bool operator()(const Shingle& a, const Shingle& b) const;
};
typedef std::set<Shingle, InterningLess> OwningSet;
static Shingle* Find(const Trace& trace, size_t position,
OwningSet* owning_set) {
std::pair<OwningSet::iterator, bool> pair =
owning_set->insert(Shingle(trace, position));
Shingle* shingle = const_cast<Shingle*>(&*pair.first);
shingle->add_position(position);
return shingle;
}
LabelInfo* at(size_t i) const { return trace_[exemplar_position_ + i]; }
void add_position(size_t position) {
positions_.push_back(static_cast<uint32>(position));
}
int position_count() const { return static_cast<int>(positions_.size()); }
bool InModel() const { return at(0)->is_model_; }
ShinglePattern* pattern() const { return pattern_; }
void set_pattern(ShinglePattern* pattern) { pattern_ = pattern; }
struct PointerLess {
bool operator()(const Shingle* a, const Shingle* b) const {
return a->exemplar_position_ < b->exemplar_position_;
}
};
private:
Shingle(const Trace& trace, size_t exemplar_position)
: trace_(trace),
exemplar_position_(exemplar_position),
pattern_(NULL) {
}
const Trace& trace_;
size_t exemplar_position_;
std::vector<uint32> positions_;
ShinglePattern* pattern_;
friend std::string ToString(const Shingle* instance);
void operator=(const Shingle&);
};
std::string ToString(const Shingle* instance) {
std::string s;
const char* sep = "<";
for (size_t i = 0; i < Shingle::kWidth; ++i) {
s += sep;
s += ToString(instance->at(i));
sep = ", ";
}
base::StringAppendF(&s, ">(%" PRIuS ")@{%d}",
instance->exemplar_position_,
instance->position_count());
return s;
}
bool Shingle::InterningLess::operator()(
const Shingle& a,
const Shingle& b) const {
for (size_t i = 0; i < kWidth; ++i) {
LabelInfo* info_a = a.at(i);
LabelInfo* info_b = b.at(i);
if (info_a->label_->rva_ < info_b->label_->rva_)
return true;
if (info_a->label_->rva_ > info_b->label_->rva_)
return false;
if (info_a->is_model_ < info_b->is_model_)
return true;
if (info_a->is_model_ > info_b->is_model_)
return false;
if (info_a != info_b) {
NOTREACHED();
}
}
return false;
}
class ShinglePattern {
public:
enum { kOffsetMask = 7,
kFixed = 0,
kVariable = 8
};
struct Index {
explicit Index(const Shingle* instance);
uint8 kinds_[Shingle::kWidth];
uint8 variables_;
uint8 unique_variables_;
uint8 first_variable_index_;
uint32 hash_;
int assigned_indexes_[Shingle::kWidth];
};
class FreqView {
public:
explicit FreqView(const Shingle* instance) : instance_(instance) {}
int count() const { return instance_->position_count(); }
const Shingle* instance() const { return instance_; }
struct Greater {
bool operator()(const FreqView& a, const FreqView& b) const {
if (a.count() > b.count()) return true;
if (a.count() < b.count()) return false;
return resolve_ties(a.instance(), b.instance());
}
private:
Shingle::PointerLess resolve_ties;
};
private:
const Shingle* instance_;
};
typedef std::set<FreqView, FreqView::Greater> Histogram;
ShinglePattern() : index_(NULL), model_coverage_(0), program_coverage_(0) {}
const Index* index_;
Histogram model_histogram_;
Histogram program_histogram_;
int model_coverage_;
int program_coverage_;
};
std::string ToString(const ShinglePattern::Index* index) {
std::string s;
if (index == NULL) {
s = "<null>";
} else {
base::StringAppendF(&s, "<%d: ", index->variables_);
const char* sep = "";
for (size_t i = 0; i < Shingle::kWidth; ++i) {
s += sep;
sep = ", ";
uint32 kind = index->kinds_[i];
int offset = kind & ShinglePattern::kOffsetMask;
if (kind & ShinglePattern::kVariable)
base::StringAppendF(&s, "V%d", offset);
else
base::StringAppendF(&s, "%d", index->assigned_indexes_[offset]);
}
base::StringAppendF(&s, " %x", index->hash_);
s += ">";
}
return s;
}
std::string HistogramToString(const ShinglePattern::Histogram& histogram,
size_t snippet_max) {
std::string s;
size_t histogram_size = histogram.size();
size_t snippet_size = 0;
for (ShinglePattern::Histogram::const_iterator p = histogram.begin();
p != histogram.end();
++p) {
if (++snippet_size > snippet_max && snippet_size != histogram_size) {
s += " ...";
break;
}
base::StringAppendF(&s, " %d", p->count());
}
return s;
}
std::string HistogramToStringFull(const ShinglePattern::Histogram& histogram,
const char* indent,
size_t snippet_max) {
std::string s;
size_t histogram_size = histogram.size();
size_t snippet_size = 0;
for (ShinglePattern::Histogram::const_iterator p = histogram.begin();
p != histogram.end();
++p) {
s += indent;
if (++snippet_size > snippet_max && snippet_size != histogram_size) {
s += "...\n";
break;
}
base::StringAppendF(&s, "(%d) ", p->count());
s += ToString(&(*p->instance()));
s += "\n";
}
return s;
}
std::string ToString(const ShinglePattern* pattern, size_t snippet_max = 3) {
std::string s;
if (pattern == NULL) {
s = "<null>";
} else {
s = "{";
s += ToString(pattern->index_);
base::StringAppendF(&s, "; %d(%d):",
static_cast<int>(pattern->model_histogram_.size()),
pattern->model_coverage_);
s += HistogramToString(pattern->model_histogram_, snippet_max);
base::StringAppendF(&s, "; %d(%d):",
static_cast<int>(pattern->program_histogram_.size()),
pattern->program_coverage_);
s += HistogramToString(pattern->program_histogram_, snippet_max);
s += "}";
}
return s;
}
std::string ShinglePatternToStringFull(const ShinglePattern* pattern,
size_t max) {
std::string s;
s += ToString(pattern->index_);
s += "\n";
size_t model_size = pattern->model_histogram_.size();
size_t program_size = pattern->program_histogram_.size();
base::StringAppendF(&s, " model shingles %" PRIuS "\n", model_size);
s += HistogramToStringFull(pattern->model_histogram_, " ", max);
base::StringAppendF(&s, " program shingles %" PRIuS "\n", program_size);
s += HistogramToStringFull(pattern->program_histogram_, " ", max);
return s;
}
struct ShinglePatternIndexLess {
bool operator()(const ShinglePattern::Index& a,
const ShinglePattern::Index& b) const {
if (a.hash_ < b.hash_) return true;
if (a.hash_ > b.hash_) return false;
for (size_t i = 0; i < Shingle::kWidth; ++i) {
if (a.kinds_[i] < b.kinds_[i]) return true;
if (a.kinds_[i] > b.kinds_[i]) return false;
if ((a.kinds_[i] & ShinglePattern::kVariable) == 0) {
if (a.assigned_indexes_[i] < b.assigned_indexes_[i])
return true;
if (a.assigned_indexes_[i] > b.assigned_indexes_[i])
return false;
}
}
return false;
}
};
static uint32 hash_combine(uint32 h, uint32 v) {
h += v;
return (h * (37 + 0x0000d100)) ^ (h >> 13);
}
ShinglePattern::Index::Index(const Shingle* instance) {
uint32 hash = 0;
variables_ = 0;
unique_variables_ = 0;
first_variable_index_ = 255;
for (uint32 i = 0; i < Shingle::kWidth; ++i) {
LabelInfo* info = instance->at(i);
uint32 kind = 0;
int code = -1;
size_t j = 0;
for ( ; j < i; ++j) {
if (info == instance->at(j)) {
kind = kinds_[j];
break;
}
}
if (j == i) {
if (info->assignment_) {
code = info->label_->index_;
assigned_indexes_[i] = code;
kind = kFixed + i;
} else {
kind = kVariable + i;
++unique_variables_;
if (i < first_variable_index_)
first_variable_index_ = i;
}
}
if (kind & kVariable) ++variables_;
hash = hash_combine(hash, code);
hash = hash_combine(hash, kind);
kinds_[i] = kind;
assigned_indexes_[i] = code;
}
hash_ = hash;
}
struct ShinglePatternLess {
bool operator()(const ShinglePattern& a, const ShinglePattern& b) const {
return index_less(*a.index_, *b.index_);
}
ShinglePatternIndexLess index_less;
};
struct ShinglePatternPointerLess {
bool operator()(const ShinglePattern* a, const ShinglePattern* b) const {
return pattern_less(*a, *b);
}
ShinglePatternLess pattern_less;
};
template<int (*Scorer)(const ShinglePattern*)>
struct OrderShinglePatternByScoreDescending {
bool operator()(const ShinglePattern* a, const ShinglePattern* b) const {
int score_a = Scorer(a);
int score_b = Scorer(b);
if (score_a > score_b) return true;
if (score_a < score_b) return false;
return break_ties(a, b);
}
ShinglePatternPointerLess break_ties;
};
int SingleUseScore(const ShinglePattern* pattern) {
if (pattern->index_->variables_ != 1)
return -1;
if (pattern->model_histogram_.size() != 1 ||
pattern->program_histogram_.size() != 1)
return -1;
const ShinglePattern::FreqView& program_freq =
*pattern->program_histogram_.begin();
const ShinglePattern::FreqView& model_freq =
*pattern->model_histogram_.begin();
int p1 = program_freq.count();
int m1 = model_freq.count();
if (p1 == m1) {
const Shingle* program_instance = program_freq.instance();
const Shingle* model_instance = model_freq.instance();
size_t variable_index = pattern->index_->first_variable_index_;
LabelInfo* program_info = program_instance->at(variable_index);
LabelInfo* model_info = model_instance->at(variable_index);
if (!program_info->assignment_) {
if (program_info->refs_ == p1 && model_info->refs_ == m1) {
return p1;
}
}
}
return -1;
}
class VariableQueue {
public:
typedef std::pair<int, LabelInfo*> ScoreAndLabel;
VariableQueue() {}
bool empty() const { return queue_.empty(); }
const ScoreAndLabel& first() const { return *queue_.begin(); }
void Print() const {
for (Queue::const_iterator p = queue_.begin(); p != queue_.end(); ++p) {
AssignmentCandidates* candidates = p->second->candidates();
candidates->Print(std::numeric_limits<int>::max());
}
}
void AddPendingUpdate(LabelInfo* program_info, LabelInfo* model_info,
int delta_score) {
AssignmentCandidates* candidates = program_info->candidates();
if (!candidates->HasPendingUpdates()) {
pending_update_candidates_.push_back(candidates);
}
candidates->AddPendingUpdate(model_info, delta_score);
}
void ApplyPendingUpdates() {
for (size_t i = 0; i < pending_update_candidates_.size(); ++i) {
AssignmentCandidates* candidates = pending_update_candidates_[i];
int old_score = candidates->TopScore();
queue_.erase(ScoreAndLabel(old_score, candidates->program_info()));
candidates->ApplyPendingUpdates();
if (!candidates->empty()) {
int new_score = candidates->TopScore();
queue_.insert(ScoreAndLabel(new_score, candidates->program_info()));
}
}
pending_update_candidates_.clear();
}
private:
struct OrderScoreAndLabelByScoreDecreasing {
bool operator()(const ScoreAndLabel& a, const ScoreAndLabel& b) const {
if (a.first > b.first) return true;
if (a.first < b.first) return false;
return OrderLabelInfo()(a.second, b.second);
}
};
typedef std::set<ScoreAndLabel, OrderScoreAndLabelByScoreDecreasing> Queue;
Queue queue_;
std::vector<AssignmentCandidates*> pending_update_candidates_;
DISALLOW_COPY_AND_ASSIGN(VariableQueue);
};
class AssignmentProblem {
public:
AssignmentProblem(const Trace& trace, size_t model_end)
: trace_(trace),
model_end_(model_end) {
VLOG(2) << "AssignmentProblem::AssignmentProblem " << model_end << ", "
<< trace.size();
}
bool Solve() {
if (model_end_ < Shingle::kWidth ||
trace_.size() - model_end_ < Shingle::kWidth) {
return true;
}
instances_.resize(trace_.size() - Shingle::kWidth + 1, NULL);
AddShingles(0, model_end_);
AddShingles(model_end_, trace_.size());
InitialClassify();
AddPatternsNeedingUpdatesToQueues();
patterns_needing_updates_.clear();
while (FindAndAssignBestLeader())
patterns_needing_updates_.clear();
PrintActivePatterns();
return true;
}
private:
typedef std::set<Shingle*, Shingle::PointerLess> ShingleSet;
typedef std::set<const ShinglePattern*, ShinglePatternPointerLess>
ShinglePatternSet;
typedef std::set<const ShinglePattern*,
OrderShinglePatternByScoreDescending<&SingleUseScore> >
SingleUsePatternQueue;
void PrintPatternsHeader() const {
VLOG(2) << shingle_instances_.size() << " instances "
<< trace_.size() << " trace length "
<< patterns_.size() << " shingle indexes "
<< single_use_pattern_queue_.size() << " single use patterns "
<< active_non_single_use_patterns_.size() << " active patterns";
}
void PrintActivePatterns() const {
for (ShinglePatternSet::const_iterator p =
active_non_single_use_patterns_.begin();
p != active_non_single_use_patterns_.end();
++p) {
const ShinglePattern* pattern = *p;
VLOG(2) << ToString(pattern, 10);
}
}
void PrintPatterns() const {
PrintAllPatterns();
PrintActivePatterns();
PrintAllShingles();
}
void PrintAllPatterns() const {
for (IndexToPattern::const_iterator p = patterns_.begin();
p != patterns_.end();
++p) {
const ShinglePattern& pattern = p->second;
VLOG(2) << ToString(&pattern, 10);
}
}
void PrintAllShingles() const {
for (Shingle::OwningSet::const_iterator p = shingle_instances_.begin();
p != shingle_instances_.end();
++p) {
const Shingle& instance = *p;
VLOG(2) << ToString(&instance) << " " << ToString(instance.pattern());
}
}
void AddShingles(size_t begin, size_t end) {
for (size_t i = begin; i + Shingle::kWidth - 1 < end; ++i) {
instances_[i] = Shingle::Find(trace_, i, &shingle_instances_);
}
}
void Declassify(Shingle* shingle) {
ShinglePattern* pattern = shingle->pattern();
if (shingle->InModel()) {
pattern->model_histogram_.erase(ShinglePattern::FreqView(shingle));
pattern->model_coverage_ -= shingle->position_count();
} else {
pattern->program_histogram_.erase(ShinglePattern::FreqView(shingle));
pattern->program_coverage_ -= shingle->position_count();
}
shingle->set_pattern(NULL);
}
void Reclassify(Shingle* shingle) {
ShinglePattern* pattern = shingle->pattern();
LOG_ASSERT(pattern == NULL);
ShinglePattern::Index index(shingle);
if (index.variables_ == 0)
return;
std::pair<IndexToPattern::iterator, bool> inserted =
patterns_.insert(std::make_pair(index, ShinglePattern()));
pattern = &inserted.first->second;
pattern->index_ = &inserted.first->first;
shingle->set_pattern(pattern);
patterns_needing_updates_.insert(pattern);
if (shingle->InModel()) {
pattern->model_histogram_.insert(ShinglePattern::FreqView(shingle));
pattern->model_coverage_ += shingle->position_count();
} else {
pattern->program_histogram_.insert(ShinglePattern::FreqView(shingle));
pattern->program_coverage_ += shingle->position_count();
}
}
void InitialClassify() {
for (Shingle::OwningSet::iterator p = shingle_instances_.begin();
p != shingle_instances_.end();
++p) {
Reclassify(const_cast<Shingle*>(&*p));
}
}
void AddAffectedPositions(LabelInfo* info, ShingleSet* affected_shingles) {
const size_t kWidth = Shingle::kWidth;
for (size_t i = 0; i < info->positions_.size(); ++i) {
size_t position = info->positions_[i];
size_t start = position < model_end_ ? 0 : model_end_;
size_t end = position < model_end_ ? model_end_ : trace_.size();
size_t low = position > start + kWidth - 1
? position - kWidth + 1
: start;
size_t high = position + kWidth < end ? position + 1 : end - kWidth + 1;
for (size_t shingle_position = low;
shingle_position < high;
++shingle_position) {
Shingle* overlapping_shingle = instances_.at(shingle_position);
affected_shingles->insert(overlapping_shingle);
}
}
}
void RemovePatternsNeedingUpdatesFromQueues() {
for (ShinglePatternSet::iterator p = patterns_needing_updates_.begin();
p != patterns_needing_updates_.end();
++p) {
RemovePatternFromQueues(*p);
}
}
void AddPatternsNeedingUpdatesToQueues() {
for (ShinglePatternSet::iterator p = patterns_needing_updates_.begin();
p != patterns_needing_updates_.end();
++p) {
AddPatternToQueues(*p);
}
variable_queue_.ApplyPendingUpdates();
}
void RemovePatternFromQueues(const ShinglePattern* pattern) {
int single_use_score = SingleUseScore(pattern);
if (single_use_score > 0) {
size_t n = single_use_pattern_queue_.erase(pattern);
LOG_ASSERT(n == 1);
} else if (pattern->program_histogram_.empty() &&
pattern->model_histogram_.empty()) {
NOTREACHED();
} else if (pattern->program_histogram_.empty()) {
} else {
active_non_single_use_patterns_.erase(pattern);
AddPatternToLabelQueue(pattern, -1);
}
}
void AddPatternToQueues(const ShinglePattern* pattern) {
int single_use_score = SingleUseScore(pattern);
if (single_use_score > 0) {
single_use_pattern_queue_.insert(pattern);
} else if (pattern->program_histogram_.empty() &&
pattern->model_histogram_.empty()) {
} else if (pattern->program_histogram_.empty()) {
} else {
active_non_single_use_patterns_.insert(pattern);
AddPatternToLabelQueue(pattern, +1);
}
}
void AddPatternToLabelQueue(const ShinglePattern* pattern, int sign) {
const size_t kUnwieldy = 5;
typedef std::map<LabelInfo*, int> LabelToScore;
typedef std::map<LabelInfo*, LabelToScore > ScoreSet;
ScoreSet maxima;
size_t n_model_samples = 0;
for (ShinglePattern::Histogram::const_iterator model_iter =
pattern->model_histogram_.begin();
model_iter != pattern->model_histogram_.end();
++model_iter) {
if (++n_model_samples > kUnwieldy) break;
const ShinglePattern::FreqView& model_freq = *model_iter;
int m1 = model_freq.count();
const Shingle* model_instance = model_freq.instance();
ScoreSet sums;
size_t n_program_samples = 0;
for (ShinglePattern::Histogram::const_iterator program_iter =
pattern->program_histogram_.begin();
program_iter != pattern->program_histogram_.end();
++program_iter) {
if (++n_program_samples > kUnwieldy) break;
const ShinglePattern::FreqView& program_freq = *program_iter;
int p1 = program_freq.count();
const Shingle* program_instance = program_freq.instance();
int score = std::min(p1, m1);
for (size_t i = 0; i < Shingle::kWidth; ++i) {
LabelInfo* program_info = program_instance->at(i);
LabelInfo* model_info = model_instance->at(i);
if ((model_info->assignment_ == NULL) !=
(program_info->assignment_ == NULL)) {
VLOG(2) << "ERROR " << i
<< "\n\t" << ToString(pattern, 10)
<< "\n\t" << ToString(program_instance)
<< "\n\t" << ToString(model_instance);
}
if (!program_info->assignment_ && !model_info->assignment_) {
sums[program_info][model_info] += score;
}
}
for (ScoreSet::iterator assignee_iterator = sums.begin();
assignee_iterator != sums.end();
++assignee_iterator) {
LabelInfo* program_info = assignee_iterator->first;
for (LabelToScore::iterator p = assignee_iterator->second.begin();
p != assignee_iterator->second.end();
++p) {
LabelInfo* model_info = p->first;
int score = p->second;
int* slot = &maxima[program_info][model_info];
*slot = std::max(*slot, score);
}
}
}
}
for (ScoreSet::iterator assignee_iterator = maxima.begin();
assignee_iterator != maxima.end();
++assignee_iterator) {
LabelInfo* program_info = assignee_iterator->first;
for (LabelToScore::iterator p = assignee_iterator->second.begin();
p != assignee_iterator->second.end();
++p) {
LabelInfo* model_info = p->first;
int score = sign * p->second;
variable_queue_.AddPendingUpdate(program_info, model_info, score);
}
}
}
void AssignOne(LabelInfo* model_info, LabelInfo* program_info) {
LOG_ASSERT(!model_info->assignment_);
LOG_ASSERT(!program_info->assignment_);
LOG_ASSERT(model_info->is_model_);
LOG_ASSERT(!program_info->is_model_);
VLOG(3) << "Assign " << ToString(program_info)
<< " := " << ToString(model_info);
ShingleSet affected_shingles;
AddAffectedPositions(model_info, &affected_shingles);
AddAffectedPositions(program_info, &affected_shingles);
for (ShingleSet::iterator p = affected_shingles.begin();
p != affected_shingles.end();
++p) {
patterns_needing_updates_.insert((*p)->pattern());
}
RemovePatternsNeedingUpdatesFromQueues();
for (ShingleSet::iterator p = affected_shingles.begin();
p != affected_shingles.end();
++p) {
Declassify(*p);
}
program_info->label_->index_ = model_info->label_->index_;
model_info->assignment_ = program_info;
program_info->assignment_ = model_info;
for (ShingleSet::iterator p = affected_shingles.begin();
p != affected_shingles.end();
++p) {
Reclassify(*p);
}
AddPatternsNeedingUpdatesToQueues();
}
bool AssignFirstVariableOfHistogramHead(const ShinglePattern& pattern) {
const ShinglePattern::FreqView& program_1 =
*pattern.program_histogram_.begin();
const ShinglePattern::FreqView& model_1 = *pattern.model_histogram_.begin();
const Shingle* program_instance = program_1.instance();
const Shingle* model_instance = model_1.instance();
size_t variable_index = pattern.index_->first_variable_index_;
LabelInfo* program_info = program_instance->at(variable_index);
LabelInfo* model_info = model_instance->at(variable_index);
AssignOne(model_info, program_info);
return true;
}
bool FindAndAssignBestLeader() {
LOG_ASSERT(patterns_needing_updates_.empty());
if (!single_use_pattern_queue_.empty()) {
const ShinglePattern& pattern = **single_use_pattern_queue_.begin();
return AssignFirstVariableOfHistogramHead(pattern);
}
if (variable_queue_.empty())
return false;
const VariableQueue::ScoreAndLabel best = variable_queue_.first();
int score = best.first;
LabelInfo* assignee = best.second;
if (score == 0) {
variable_queue_.Print();
return false;
}
AssignmentCandidates* candidates = assignee->candidates();
if (candidates->empty())
return false;
AssignOne(candidates->top_candidate(), assignee);
return true;
}
private:
const Trace& trace_;
size_t model_end_;
Shingle::OwningSet shingle_instances_;
std::vector<Shingle*> instances_;
SingleUsePatternQueue single_use_pattern_queue_;
ShinglePatternSet active_non_single_use_patterns_;
VariableQueue variable_queue_;
ShinglePatternSet patterns_needing_updates_;
typedef std::map<ShinglePattern::Index,
ShinglePattern, ShinglePatternIndexLess> IndexToPattern;
IndexToPattern patterns_;
DISALLOW_COPY_AND_ASSIGN(AssignmentProblem);
};
class Adjuster : public AdjustmentMethod {
public:
Adjuster() : prog_(NULL), model_(NULL) {}
~Adjuster() {}
bool Adjust(const AssemblyProgram& model, AssemblyProgram* program) {
VLOG(1) << "Adjuster::Adjust";
prog_ = program;
model_ = &model;
return Finish();
}
bool Finish() {
prog_->UnassignIndexes();
Trace abs32_trace_;
Trace rel32_trace_;
CollectTraces(model_, &abs32_trace_, &rel32_trace_, true);
size_t abs32_model_end = abs32_trace_.size();
size_t rel32_model_end = rel32_trace_.size();
CollectTraces(prog_, &abs32_trace_, &rel32_trace_, false);
Solve(abs32_trace_, abs32_model_end);
Solve(rel32_trace_, rel32_model_end);
prog_->AssignRemainingIndexes();
return true;
}
private:
void CollectTraces(const AssemblyProgram* program, Trace* abs32, Trace* rel32,
bool is_model) {
label_info_maker_.ResetDebugLabel();
const InstructionVector& instructions = program->instructions();
for (size_t i = 0; i < instructions.size(); ++i) {
Instruction* instruction = instructions[i];
if (Label* label = program->InstructionAbs32Label(instruction))
ReferenceLabel(abs32, label, is_model);
if (Label* label = program->InstructionRel32Label(instruction))
ReferenceLabel(rel32, label, is_model);
}
}
void Solve(const Trace& model, size_t model_end) {
base::Time start_time = base::Time::Now();
AssignmentProblem a(model, model_end);
a.Solve();
VLOG(1) << " Adjuster::Solve "
<< (base::Time::Now() - start_time).InSecondsF();
}
void ReferenceLabel(Trace* trace, Label* label, bool is_model) {
trace->push_back(
label_info_maker_.MakeLabelInfo(label, is_model,
static_cast<uint32>(trace->size())));
}
AssemblyProgram* prog_;
const AssemblyProgram* model_;
LabelInfoMaker label_info_maker_;
private:
DISALLOW_COPY_AND_ASSIGN(Adjuster);
};
}
AdjustmentMethod* AdjustmentMethod::MakeShingleAdjustmentMethod() {
return new adjustment_method_2::Adjuster();
}
}