Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: courgette/adjustment_method_2.cc

Issue 118031: New adjustment method for Courgette.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « courgette/adjustment_method.cc ('k') | courgette/courgette.gyp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "courgette/adjustment_method.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <list>
10 #include <map>
11 #include <set>
12 #include <string>
13 #include <vector>
14
15 #include <iostream>
16
17 #include "base/basictypes.h"
18 #include "base/logging.h"
19 #include "base/string_util.h"
20
21 #include "courgette/assembly_program.h"
22 #include "courgette/courgette.h"
23 #include "courgette/encoded_program.h"
24 #include "courgette/image_info.h"
25
26 /*
27
28 Shingle weighting matching.
29
30 We have a sequence S1 of symbols from alphabet A1={A,B,C,...} called the 'model'
31 and a second sequence of S2 of symbols from alphabet A2={U,V,W,....} called the
32 'program'. Each symbol in A1 has a unique numerical name or index. We can
33 transcribe the sequence S1 to a sequence T1 of indexes of the symbols. We wish
34 to assign indexes to the symbols in A2 so that when we transcribe S2 into T2, T2
35 has long subsequences that occur in T1. This will ensure that the sequence
36 T1;T2 compresses to be only slightly larger than the compressed T1.
37
38 The algorithm for matching members of S2 with members of S1 is eager - it makes
39 matches without backtracking, until no more matches can be made. Each variable
40 (symbol) U,V,... in A2 has a set of candidates from A1, each candidate with a
41 weight summarizing the evidence for the match. We keep a VariableQueue of
42 U,V,... sorted by how much the evidence for the best choice outweighs the
43 evidence for the second choice, i.e. prioritized by how 'clear cut' the best
44 assignment is. We pick the variable with the most clear-cut candidate, make the
45 assignment, adjust the evidence and repeat.
46
47 What has not been described so far is how the evidence is gathered and
48 maintained. We are working under the assumption that S1 and S2 are largely
49 similar. (A different assumption might be that S1 and S2 are dissimilar except
50 for many long subsequences.)
51
52 A naive algorithm would consider all pairs (A,U) and for each pair assess the
53 benefit, or score, the assignment U:=A. The score might count the number of
54 occurrences of U in S2 which appear in similar contexts to A in S1.
55
56 To distinguish contexts we view S1 and S2 as a sequence of overlapping k-length
57 substrings or 'shingles'. Two shingles are compatible if the symbols in one
58 shingle could be matched with the symbols in the other symbol. For example, ABC
59 is *not* compatible with UVU because it would require conflicting matches A=U
60 and C=U. ABC is compatible with UVW, UWV, WUV, VUW etc. We can't tell which
61 until we make an assignment - the compatible shingles form an equivalence class.
62 After assigning U:=A then only UVW and UWV (equivalently AVW, AWV) are
63 compatible. As we make assignments the number of equivalence classes of
64 shingles increases and the number of members of each equivalence class
65 decreases. The compatibility test becomes more restrictive.
66
67 We gather evidence for the potential assignment U:=A by counting how many
68 shingles containing U are compatible with shingles containing A. Thus symbols
69 occurring a large number of times in compatible contexts will be assigned first.
70
71 Finding the 'most clear-cut' assignment by considering all pairs symbols and for
72 each pair comparing the contexts of each pair of occurrences of the symbols is
73 computationally infeasible. We get the job done in a reasonable time by
74 approaching it 'backwards' and making incremental changes as we make
75 assignments.
76
77 First the shingles are partitioned according to compatibility. In S1=ABCDD and
78 S2=UVWXX we have a total of 6 shingles, each occuring once. (ABC:1 BCD:1 CDD:1;
79 UVW:1 VWX: WXX:1) all fit the pattern <V0 V1 V2> or the pattern <V0 V1 V1>. The
80 first pattern indicates that each position matches a different symbol, the
81 second pattern indicates that the second symbol is repeated.
82
83 pattern S1 members S2 members
84 <V0 V1 V2>: {ABC:1, BCD:1}; {UVW:1, VWX:1}
85 <V0 V1 V1>: {CDD:1} {WXX:1}
86
87 The second pattern appears to have a unique assignment but we don't make the
88 assignment on such scant evidence. If S1 and S2 do not match exactly, there
89 will be numerous spurious low-score matches like this. Instead we must see what
90 assignments are indicated by considering all of the evidence.
91
92 First pattern has 2 x 2 = 4 shingle pairs. For each pair we count the number
93 of symbol assignments. For ABC:a * UVW:b accumulate min(a,b) to each of
94 {U:=A, V:=B, W:=C}.
95 After accumulating over all 2 x 2 pairs:
96 U: {A:1 B:1}
97 V: {A:1 B:2 C:1}
98 W: {B:1 C:2 D:1 }
99 X: {C:1 D:1}
100 The second pattern contributes:
101 W: {C:1}
102 X: {D:2}
103 Sum:
104 U: {A:1 B:1}
105 V: {A:1 B:2 C:1}
106 W: {B:1 C:3 D:1}
107 X: {C:1 D:3}
108
109 From this we decide to assign X:=D (because this assignment has both the largest
110 difference above the next candidate (X:=C) and this is also the largest
111 proportionately over the sum of alternatives).
112
113 Lets assume D has numerical 'name' 77. The assignment X:=D sets X to 77 too.
114 Next we repartition all the shingles containing X or D:
115
116 pattern S1 members S2 members
117 <V0 V1 V2>: {ABC:1}; {UVW:1}
118 <V0 V1 77>: {BCD:1}; {VWX:1}
119 <V0 77 77>: {CDD:1} {WXX:1}
120 As we repartition, we recalculate the contributions to the scores:
121 U: {A:1}
122 V: {B:2}
123 W: {C:3}
124 All the remaining assignments are now fixed.
125
126 There is one step in the incremental algorithm that is still infeasibly
127 expensive: the contributions due to the cross product of large equivalence
128 classes. We settle for making an approximation by computing the contribution of
129 the cross product of only the most common shingles. The hope is that the noise
130 from the long tail of uncounted shingles is well below the scores being used to
131 pick assignments. The second hope is that as assignment are made, the large
132 equivalence class will be partitioned into smaller equivalence classes, reducing
133 the noise over time.
134
135 In the code below the shingles are bigger (Shingle::kWidth = 5).
136 Class ShinglePattern holds the data for one pattern.
137
138 There is an optimization for this case:
139 <V0 V1 V1>: {CDD:1} {WXX:1}
140
141 Above we said that we don't make an assignment on this "scant evidence". There
142 is an exception: if there is only one variable unassigned (more like the <V0 77
143 77> pattern) AND there are no occurrences of C and W other than those counted in
144 this pattern, then there is no competing evidence and we go ahead with the
145 assignment immediately. This produces slightly better results because these
146 cases tend to be low-scoring and susceptible to small mistakes made in
147 low-scoring assignments in the approximation for large equivalence classes.
148
149 */
150
151 namespace courgette {
152 namespace adjustment_method_2 {
153
154 // We have three discretionary information logging levels for algorithm
155 // development. For now just configure with #defines.
156 // TODO(sra): make dependent of some configurable setting.
157 struct LogToCout {
158 LogToCout() {}
159 ~LogToCout() { std::cout << std::endl; }
160 std::ostream& stream() { return std::cout; }
161 };
162 #define LOG_TO_COUT (LogToCout().stream())
163 #define NO_LOG DLOG_IF(INFO, false)
164
165 #if 0 // Log to log file.
166 #define ALOG1 LOG(INFO)
167 #define ALOG2 LOG(INFO)
168 #define ALOG3 LOG(INFO)
169 #elif 0 // Log to stdout.
170 #define ALOG1 LOG_TO_COUT
171 #define ALOG2 LOG_TO_COUT
172 #define ALOG3 LOG_TO_COUT
173 #else // Log to nowhere.
174 #define ALOG1 NO_LOG
175 #define ALOG2 NO_LOG
176 #define ALOG3 NO_LOG
177 #endif
178
179 ////////////////////////////////////////////////////////////////////////////////
180
181 class AssignmentCandidates;
182 class LabelInfoMaker;
183 class Shingle;
184 class ShinglePattern;
185
186 // The purpose of adjustment is to assign indexes to Labels of a program 'p' to
187 // make the sequence of indexes similar to a 'model' program 'm'. Labels
188 // themselves don't have enough information to do this job, so we work with a
189 // LabelInfo surrogate for each label.
190 //
191 class LabelInfo {
192 public:
193 // Just a no-argument constructor and copy constructor. Actual LabelInfo
194 // objects are allocated in std::pair structs in a std::map.
195 LabelInfo()
196 : label_(NULL), is_model_(false), debug_index_(0), refs_(0),
197 assignment_(NULL), candidates_(NULL)
198 {}
199
200 ~LabelInfo();
201
202 AssignmentCandidates* candidates();
203
204 Label* label_; // The label that this info a surrogate for.
205
206 uint32 is_model_ : 1; // Is the label in the model?
207 uint32 debug_index_ : 31; // A small number for naming the label in debug
208 // output. The pair (is_model_, debug_index_) is
209 // unique.
210
211 uint32 refs_; // Number of times this Label is referenced.
212
213 LabelInfo* assignment_; // Label from other program corresponding to this.
214
215 std::vector<uint32> positions_; // Offsets into the trace of references.
216
217 private:
218 AssignmentCandidates* candidates_;
219
220 void operator=(const LabelInfo*); // Disallow assignment only.
221 // Public compiler generated copy constructor is needed to constuct
222 // std::pair<Label*, LabelInfo> so that fresh LabelInfos can be allocated
223 // inside a std::map.
224 };
225
226 typedef std::vector<LabelInfo*> Trace;
227
228 std::string ToString(const LabelInfo* info) {
229 std::string s;
230 StringAppendF(&s, "%c%d", "pm"[info->is_model_], info->debug_index_);
231 if (info->label_->index_ != Label::kNoIndex)
232 StringAppendF(&s, " (%d)", info->label_->index_);
233
234 StringAppendF(&s, " #%u", info->refs_);
235 return s;
236 }
237
238 // LabelInfoMaker maps labels to their surrogate LabelInfo objects.
239 class LabelInfoMaker {
240 public:
241 LabelInfoMaker() : debug_label_index_gen_(0) {}
242
243 LabelInfo* MakeLabelInfo(Label* label, bool is_model, uint32 position) {
244 LabelInfo& slot = label_infos_[label];
245 if (slot.label_ == NULL) {
246 slot.label_ = label;
247 slot.is_model_ = is_model;
248 slot.debug_index_ = ++debug_label_index_gen_;
249 }
250 slot.positions_.push_back(position);
251 ++slot.refs_;
252 return &slot;
253 }
254
255 void ResetDebugLabel() { debug_label_index_gen_ = 0; }
256
257 private:
258 int debug_label_index_gen_;
259
260 // Note LabelInfo is allocated 'flat' inside map::value_type, so the LabelInfo
261 // lifetimes are managed by the map.
262 std::map<Label*, LabelInfo> label_infos_;
263
264 DISALLOW_COPY_AND_ASSIGN(LabelInfoMaker);
265 };
266
267 struct OrderLabelInfo {
268 bool operator()(const LabelInfo* a, const LabelInfo* b) const {
269 if (a->label_->rva_ < b->label_->rva_) return true;
270 if (a->label_->rva_ > b->label_->rva_) return false;
271 if (a == b) return false;
272 return a->positions_ < b->positions_; // Lexicographic ordering of vector.
273 }
274 };
275
276 // AssignmentCandidates is a priority queue of candidate assignments to
277 // a single program LabelInfo, |program_info_|.
278 class AssignmentCandidates {
279 public:
280 explicit AssignmentCandidates(LabelInfo* program_info)
281 : program_info_(program_info) {}
282
283 LabelInfo* program_info() const { return program_info_; }
284
285 bool empty() const { return label_to_score_.empty(); }
286
287 LabelInfo* top_candidate() const { return queue_.begin()->second; }
288
289 void Update(LabelInfo* model_info, int delta_score) {
290 LOG_ASSERT(delta_score != 0);
291 int old_score = 0;
292 int new_score = 0;
293 LabelToScore::iterator p = label_to_score_.find(model_info);
294 if (p != label_to_score_.end()) {
295 old_score = p->second;
296 new_score = old_score + delta_score;
297 queue_.erase(ScoreAndLabel(old_score, p->first));
298 if (new_score == 0) {
299 label_to_score_.erase(p);
300 } else {
301 p->second = new_score;
302 queue_.insert(ScoreAndLabel(new_score, model_info));
303 }
304 } else {
305 new_score = delta_score;
306 label_to_score_.insert(std::make_pair(model_info, new_score));
307 queue_.insert(ScoreAndLabel(new_score, model_info));
308 }
309 LOG_ASSERT(queue_.size() == label_to_score_.size());
310 }
311
312 int TopScore() const {
313 int first_value = 0;
314 int second_value = 0;
315 Queue::const_iterator p = queue_.begin();
316 if (p != queue_.end()) {
317 first_value = p->first;
318 ++p;
319 if (p != queue_.end()) {
320 second_value = p->first;
321 }
322 }
323 return first_value - second_value;
324 }
325
326 bool HasPendingUpdates() { return !pending_updates_.empty(); }
327
328 void AddPendingUpdate(LabelInfo* model_info, int delta_score) {
329 LOG_ASSERT(delta_score != 0);
330 pending_updates_[model_info] += delta_score;
331 }
332
333 void ApplyPendingUpdates() {
334 // TODO(sra): try to walk |pending_updates_| and |label_to_score_| in
335 // lockstep. Try to batch updates to |queue_|.
336 size_t zeroes = 0;
337 for (LabelToScore::iterator p = pending_updates_.begin();
338 p != pending_updates_.end();
339 ++p) {
340 if (p->second != 0)
341 Update(p->first, p->second);
342 else
343 ++zeroes;
344 }
345 pending_updates_.clear();
346 }
347
348 void Print(int max) {
349 ALOG1 << "score " << TopScore() << " " << ToString(program_info_)
350 << " := ?";
351 if (!pending_updates_.empty())
352 ALOG1 << pending_updates_.size() << " pending";
353 int count = 0;
354 for (Queue::iterator q = queue_.begin(); q != queue_.end(); ++q) {
355 if (++count > max) break;
356 ALOG1 << " " << q->first << " " << ToString(q->second);
357 }
358 }
359
360 private:
361 typedef std::map<LabelInfo*, int, OrderLabelInfo> LabelToScore;
362 typedef std::pair<int, LabelInfo*> ScoreAndLabel;
363 struct OrderScoreAndLabelByScoreDecreasing {
364 OrderLabelInfo tie_breaker;
365 bool operator()(const ScoreAndLabel& a, const ScoreAndLabel& b) const {
366 if (a.first > b.first) return true;
367 if (a.first < b.first) return false;
368 return tie_breaker(a.second, b.second);
369 }
370 };
371 typedef std::set<ScoreAndLabel, OrderScoreAndLabelByScoreDecreasing> Queue;
372
373 LabelInfo* program_info_;
374 LabelToScore label_to_score_;
375 LabelToScore pending_updates_;
376 Queue queue_;
377 };
378
379 AssignmentCandidates* LabelInfo::candidates() {
380 if (candidates_ == NULL)
381 candidates_ = new AssignmentCandidates(this);
382 return candidates_;
383 }
384
385 LabelInfo::~LabelInfo() {
386 delete candidates_;
387 }
388
389 // A Shingle is a short fixed-length string of LabelInfos that actually occurs
390 // in a Trace. A Shingle may occur many times. We repesent the Shingle by the
391 // position of one of the occurrences in the Trace.
392 class Shingle {
393 public:
394 static const size_t kWidth = 5;
395
396 struct InterningLess {
397 bool operator()(const Shingle& a, const Shingle& b) const;
398 };
399
400 typedef std::set<Shingle, InterningLess> OwningSet;
401
402 static Shingle* Find(const Trace& trace, size_t position,
403 OwningSet* owning_set) {
404 std::pair<OwningSet::iterator, bool> pair =
405 owning_set->insert(Shingle(trace, position));
406 // pair.first is the newly inserted Shingle or the previouly inserted one
407 // that looks the same according to the comparator.
408 pair.first->add_position(position);
409 return &*pair.first;
410 }
411
412 LabelInfo* at(size_t i) const { return trace_[exemplar_position_ + i]; }
413 void add_position(size_t position) { positions_.push_back(position); }
414 size_t position_count() const { return positions_.size(); }
415
416 bool InModel() const { return at(0)->is_model_; }
417
418 ShinglePattern* pattern() const { return pattern_; }
419 void set_pattern(ShinglePattern* pattern) { pattern_ = pattern; }
420
421 struct PointerLess {
422 bool operator()(const Shingle* a, const Shingle* b) const {
423 // Arbitrary but repeatable (memory-address) independent ordering:
424 return a->exemplar_position_ < b->exemplar_position_;
425 // return InterningLess()(*a, *b);
426 }
427 };
428
429 private:
430 Shingle(const Trace& trace, size_t exemplar_position)
431 : trace_(trace),
432 exemplar_position_(exemplar_position),
433 pattern_(NULL) {
434 }
435
436 const Trace& trace_; // The shingle lives inside trace_.
437 size_t exemplar_position_; // At this position (and other positions).
438 std::vector<uint32> positions_; // Includes exemplar_position_.
439
440 ShinglePattern* pattern_; // Pattern changes as LabelInfos are assigned.
441
442 friend std::string ToString(const Shingle* instance);
443
444 // We can't disallow the copy constructor because we use std::set<Shingle> and
445 // VS2005's implementation of std::set<T>::set() requires T to have a copy
446 // constructor.
447 // DISALLOW_COPY_AND_ASSIGN(Shingle);
448 void operator=(const Shingle&); // Disallow assignment only.
449 };
450
451 std::string ToString(const Shingle* instance) {
452 std::string s;
453 const char* sep = "<";
454 for (size_t i = 0; i < Shingle::kWidth; ++i) {
455 // StringAppendF(&s, "%s%x ", sep, instance.at(i)->label_->rva_);
456 s += sep;
457 s += ToString(instance->at(i));
458 sep = ", ";
459 }
460 StringAppendF(&s, ">(%u)@{%d}", instance->exemplar_position_,
461 static_cast<int>(instance->position_count()));
462 return s;
463 }
464
465
466 bool Shingle::InterningLess::operator()(
467 const Shingle& a,
468 const Shingle& b) const {
469 for (size_t i = 0; i < kWidth; ++i) {
470 LabelInfo* info_a = a.at(i);
471 LabelInfo* info_b = b.at(i);
472 if (info_a->label_->rva_ < info_b->label_->rva_)
473 return true;
474 if (info_a->label_->rva_ > info_b->label_->rva_)
475 return false;
476 if (info_a->is_model_ < info_b->is_model_)
477 return true;
478 if (info_a->is_model_ > info_b->is_model_)
479 return false;
480 if (info_a != info_b) {
481 NOTREACHED();
482 }
483 }
484 return false;
485 }
486
487 class ShinglePattern {
488 public:
489 enum { kOffsetMask = 7, // Offset lives in low bits.
490 kFixed = 0, // kind & kVariable == 0 => fixed.
491 kVariable = 8 // kind & kVariable == 1 => variable.
492 };
493 // sequence[position + (kinds_[i] & kOffsetMask)] gives LabelInfo for position
494 // i of shingle. Below, second 'A' is duplicate of position 1, second '102'
495 // is duplicate of position 0.
496 //
497 // <102, A, 103, A , 102>
498 // --> <kFixed+0, kVariable+1, kFixed+2, kVariable+1, kFixed+0>
499 struct Index {
500 explicit Index(const Shingle* instance);
501 uint8 kinds_[Shingle::kWidth];
502 uint8 variables_;
503 uint8 unique_variables_;
504 uint8 first_variable_index_;
505 uint32 hash_;
506 int assigned_indexes_[Shingle::kWidth];
507 };
508
509 // ShinglePattern keeps histograms of member Shingle instances, ordered by
510 // decreasing number of occurrences. We don't have a pair (occurrence count,
511 // Shingle instance), so we use a FreqView adapter to make the instance
512 // pointer look like the pair.
513 class FreqView {
514 public:
515 explicit FreqView(const Shingle* instance) : instance_(instance) {}
516 size_t count() const { return instance_->position_count(); }
517 const Shingle* instance() const { return instance_; }
518 struct Greater {
519 bool operator()(const FreqView& a, const FreqView& b) const {
520 if (a.count() > b.count()) return true;
521 if (a.count() < b.count()) return false;
522 return resolve_ties(a.instance(), b.instance());
523 }
524 private:
525 Shingle::PointerLess resolve_ties;
526 };
527 private:
528 const Shingle* instance_;
529 };
530
531 typedef std::set<FreqView, FreqView::Greater> Histogram;
532
533 ShinglePattern() : index_(NULL), model_coverage_(0), program_coverage_(0) {}
534
535 const Index* index_; // Points to the key in the owning map value_type.
536 Histogram model_histogram_;
537 Histogram program_histogram_;
538 int model_coverage_;
539 int program_coverage_;
540 };
541
542 std::string ToString(const ShinglePattern::Index* index) {
543 std::string s;
544 if (index == NULL) {
545 s = "<null>";
546 } else {
547 StringAppendF(&s, "<%d: ", index->variables_);
548 const char* sep = "";
549 for (size_t i = 0; i < Shingle::kWidth; ++i) {
550 s += sep;
551 sep = ", ";
552 uint32 kind = index->kinds_[i];
553 int offset = kind & ShinglePattern::kOffsetMask;
554 if (kind & ShinglePattern::kVariable)
555 StringAppendF(&s, "V%d", offset);
556 else
557 StringAppendF(&s, "%d", index->assigned_indexes_[offset]);
558 }
559 StringAppendF(&s, " %x", index->hash_);
560 s += ">";
561 }
562 return s;
563 }
564
565 std::string HistogramToString(const ShinglePattern::Histogram& histogram,
566 size_t snippet_max) {
567 std::string s;
568 size_t histogram_size = histogram.size();
569 size_t snippet_size = 0;
570 for (ShinglePattern::Histogram::const_iterator p = histogram.begin();
571 p != histogram.end();
572 ++p) {
573 if (++snippet_size > snippet_max && snippet_size != histogram_size) {
574 s += " ...";
575 break;
576 }
577 StringAppendF(&s, " %d", p->count());
578 }
579 return s;
580 }
581
582 std::string HistogramToStringFull(const ShinglePattern::Histogram& histogram,
583 const char* indent,
584 size_t snippet_max) {
585 std::string s;
586
587 size_t histogram_size = histogram.size();
588 size_t snippet_size = 0;
589 for (ShinglePattern::Histogram::const_iterator p = histogram.begin();
590 p != histogram.end();
591 ++p) {
592 s += indent;
593 if (++snippet_size > snippet_max && snippet_size != histogram_size) {
594 s += "...\n";
595 break;
596 }
597 StringAppendF(&s, "(%d) ", p->count());
598 s += ToString(&(*p->instance()));
599 s += "\n";
600 }
601 return s;
602 }
603
604 std::string ToString(const ShinglePattern* pattern, size_t snippet_max = 3) {
605 std::string s;
606 if (pattern == NULL) {
607 s = "<null>";
608 } else {
609 s = "{";
610 s += ToString(pattern->index_);
611 StringAppendF(&s, "; %d(%d):",
612 static_cast<int>(pattern->model_histogram_.size()),
613 pattern->model_coverage_);
614
615 s += HistogramToString(pattern->model_histogram_, snippet_max);
616 StringAppendF(&s, "; %d(%d):",
617 static_cast<int>(pattern->program_histogram_.size()),
618 pattern->program_coverage_);
619 s += HistogramToString(pattern->program_histogram_, snippet_max);
620 s += "}";
621 }
622 return s;
623 }
624
625 std::string ShinglePatternToStringFull(const ShinglePattern* pattern,
626 size_t max) {
627 std::string s;
628 s += ToString(pattern->index_);
629 s += "\n";
630 size_t model_size = pattern->model_histogram_.size();
631 size_t program_size = pattern->program_histogram_.size();
632 StringAppendF(&s, " model shingles %u\n", model_size);
633 s += HistogramToStringFull(pattern->model_histogram_, " ", max);
634 StringAppendF(&s, " program shingles %u\n", program_size);
635 s += HistogramToStringFull(pattern->program_histogram_, " ", max);
636 return s;
637 }
638
639 struct ShinglePatternIndexLess {
640 bool operator()(const ShinglePattern::Index& a,
641 const ShinglePattern::Index& b) const {
642 if (a.hash_ < b.hash_) return true;
643 if (a.hash_ > b.hash_) return false;
644
645 for (size_t i = 0; i < Shingle::kWidth; ++i) {
646 if (a.kinds_[i] < b.kinds_[i]) return true;
647 if (a.kinds_[i] > b.kinds_[i]) return false;
648 if ((a.kinds_[i] & ShinglePattern::kVariable) == 0) {
649 if (a.assigned_indexes_[i] < b.assigned_indexes_[i])
650 return true;
651 if (a.assigned_indexes_[i] > b.assigned_indexes_[i])
652 return false;
653 }
654 }
655 return false;
656 }
657 };
658
659 static uint32 hash_combine(uint32 h, uint32 v) {
660 h += v;
661 return (h * (37 + 0x0000d100)) ^ (h >> 13);
662 }
663
664 ShinglePattern::Index::Index(const Shingle* instance) {
665 uint32 hash = 0;
666 variables_ = 0;
667 unique_variables_ = 0;
668 first_variable_index_ = 255;
669
670 for (size_t i = 0; i < Shingle::kWidth; ++i) {
671 LabelInfo* info = instance->at(i);
672 uint32 kind;
673 int code = -1;
674 size_t j = 0;
675 for ( ; j < i; ++j) {
676 if (info == instance->at(j)) { // Duplicate LabelInfo
677 kind = kinds_[j];
678 break;
679 }
680 }
681 if (j == i) { // Not found above.
682 if (info->assignment_) {
683 code = info->label_->index_;
684 assigned_indexes_[i] = code;
685 kind = kFixed + i;
686 } else {
687 kind = kVariable + i;
688 ++unique_variables_;
689 if (i < first_variable_index_)
690 first_variable_index_ = i;
691 }
692 }
693 if (kind & kVariable) ++variables_;
694 hash = hash_combine(hash, code);
695 hash = hash_combine(hash, kind);
696 kinds_[i] = kind;
697 assigned_indexes_[i] = code;
698 }
699 hash_ = hash;
700 }
701
702 struct ShinglePatternLess {
703 bool operator()(const ShinglePattern& a, const ShinglePattern& b) const {
704 return index_less(*a.index_, *b.index_);
705 }
706 ShinglePatternIndexLess index_less;
707 };
708
709 struct ShinglePatternPointerLess {
710 bool operator()(const ShinglePattern* a, const ShinglePattern* b) const {
711 return pattern_less(*a, *b);
712 }
713 ShinglePatternLess pattern_less;
714 };
715
716 template<int (*Scorer)(const ShinglePattern*)>
717 struct OrderShinglePatternByScoreDescending {
718 bool operator()(const ShinglePattern* a, const ShinglePattern* b) const {
719 int score_a = Scorer(a);
720 int score_b = Scorer(b);
721 if (score_a > score_b) return true;
722 if (score_a < score_b) return false;
723 return break_ties(a, b);
724 }
725 ShinglePatternPointerLess break_ties;
726 };
727
728 // Returns a score for a 'Single Use' rule. Returns -1 if the rule is not
729 // applicable.
730 int SingleUseScore(const ShinglePattern* pattern) {
731 if (pattern->index_->variables_ != 1)
732 return -1;
733
734 if (pattern->model_histogram_.size() != 1 ||
735 pattern->program_histogram_.size() != 1)
736 return -1;
737
738 // Does this pattern account for all uses of the variable?
739 const ShinglePattern::FreqView& program_freq =
740 *pattern->program_histogram_.begin();
741 const ShinglePattern::FreqView& model_freq =
742 *pattern->model_histogram_.begin();
743 int p1 = program_freq.count();
744 int m1 = model_freq.count();
745 if (p1 == m1) {
746 const Shingle* program_instance = program_freq.instance();
747 const Shingle* model_instance = model_freq.instance();
748 size_t variable_index = pattern->index_->first_variable_index_;
749 LabelInfo* program_info = program_instance->at(variable_index);
750 LabelInfo* model_info = model_instance->at(variable_index);
751 if (!program_info->assignment_) {
752 if (program_info->refs_ == p1 && model_info->refs_ == m1) {
753 return p1;
754 }
755 }
756 }
757 return -1;
758 }
759
760 // The VariableQueue is a priority queue of unassigned LabelInfos from
761 // the 'program' (the 'variables') and their AssignmentCandidates.
762 class VariableQueue {
763 public:
764 typedef std::pair<int, LabelInfo*> ScoreAndLabel;
765
766 VariableQueue() {}
767
768 bool empty() const { return queue_.empty(); }
769
770 const ScoreAndLabel& first() const { return *queue_.begin(); }
771
772 // For debugging only.
773 void Print() const {
774 for (Queue::const_iterator p = queue_.begin(); p != queue_.end(); ++p) {
775 AssignmentCandidates* candidates = p->second->candidates();
776 candidates->Print(std::numeric_limits<int>::max());
777 }
778 }
779
780 void AddPendingUpdate(LabelInfo* program_info, LabelInfo* model_info,
781 int delta_score) {
782 AssignmentCandidates* candidates = program_info->candidates();
783 if (!candidates->HasPendingUpdates()) {
784 pending_update_candidates_.push_back(candidates);
785 }
786 candidates->AddPendingUpdate(model_info, delta_score);
787 }
788
789 void ApplyPendingUpdates() {
790 for (size_t i = 0; i < pending_update_candidates_.size(); ++i) {
791 AssignmentCandidates* candidates = pending_update_candidates_[i];
792 int old_score = candidates->TopScore();
793 queue_.erase(ScoreAndLabel(old_score, candidates->program_info()));
794 candidates->ApplyPendingUpdates();
795 if (!candidates->empty()) {
796 int new_score = candidates->TopScore();
797 queue_.insert(ScoreAndLabel(new_score, candidates->program_info()));
798 }
799 }
800 pending_update_candidates_.clear();
801 }
802
803 private:
804 struct OrderScoreAndLabelByScoreDecreasing {
805 bool operator()(const ScoreAndLabel& a, const ScoreAndLabel& b) const {
806 if (a.first > b.first) return true;
807 if (a.first < b.first) return false;
808 return OrderLabelInfo()(a.second, b.second);
809 }
810 };
811 typedef std::set<ScoreAndLabel, OrderScoreAndLabelByScoreDecreasing> Queue;
812
813 Queue queue_;
814 std::vector<AssignmentCandidates*> pending_update_candidates_;
815
816 DISALLOW_COPY_AND_ASSIGN(VariableQueue);
817 };
818
819
820 class AssignmentProblem {
821 public:
822 AssignmentProblem(const Trace& trace, size_t model_end)
823 : trace_(trace),
824 model_end_(model_end) {
825 ALOG1 << "AssignmentProblem::AssignmentProblem " << model_end << ", "
826 << trace.size();
827 }
828
829 bool Solve() {
830 if (model_end_ < Shingle::kWidth ||
831 trace_.size() - model_end_ < Shingle::kWidth) {
832 // Nothing much we can do with such a short problem.
833 return true;
834 }
835 instances_.resize(trace_.size() - Shingle::kWidth + 1, NULL);
836 AddShingles(0, model_end_);
837 AddShingles(model_end_, trace_.size());
838 InitialClassify();
839 AddPatternsNeedingUpdatesToQueues();
840
841 patterns_needing_updates_.clear();
842 while (FindAndAssignBestLeader()) {
843 NO_LOG << "Updated " << patterns_needing_updates_.size() << " patterns";
844 patterns_needing_updates_.clear();
845 }
846 PrintActivePatterns();
847
848 return true;
849 }
850
851 private:
852 typedef std::set<Shingle*, Shingle::PointerLess> ShingleSet;
853
854 typedef std::set<const ShinglePattern*, ShinglePatternPointerLess>
855 ShinglePatternSet;
856
857 // Patterns are partitioned into the following sets:
858
859 // * Retired patterns (not stored). No shingles exist for this pattern (they
860 // all now match more specialized patterns).
861 // * Useless patterns (not stored). There are no 'program' shingles for this
862 // pattern (they all now match more specialized patterns).
863 // * Single-use patterns - single_use_pattern_queue_.
864 // * Other patterns - active_non_single_use_patterns_ / variable_queue_.
865
866 typedef std::set<const ShinglePattern*,
867 OrderShinglePatternByScoreDescending<&SingleUseScore> >
868 SingleUsePatternQueue;
869
870 void PrintPatternsHeader() const {
871 ALOG1 << shingle_instances_.size() << " instances "
872 << trace_.size() << " trace length "
873 << patterns_.size() << " shingle indexes "
874 << single_use_pattern_queue_.size() << " single use patterns "
875 << active_non_single_use_patterns_.size() << " active patterns";
876 }
877
878 void PrintActivePatterns() const {
879 for (ShinglePatternSet::const_iterator p =
880 active_non_single_use_patterns_.begin();
881 p != active_non_single_use_patterns_.end();
882 ++p) {
883 const ShinglePattern* pattern = *p;
884 ALOG1 << ToString(pattern, 10);
885 }
886 }
887
888 void PrintPatterns() const {
889 PrintAllPatterns();
890 PrintActivePatterns();
891 PrintAllShingles();
892 }
893
894 void PrintAllPatterns() const {
895 for (IndexToPattern::const_iterator p = patterns_.begin();
896 p != patterns_.end();
897 ++p) {
898 const ShinglePattern& pattern = p->second;
899 ALOG1 << ToString(&pattern, 10);
900 }
901 }
902
903 void PrintAllShingles() const {
904 for (Shingle::OwningSet::const_iterator p = shingle_instances_.begin();
905 p != shingle_instances_.end();
906 ++p) {
907 const Shingle& instance = *p;
908 ALOG1 << ToString(&instance) << " " << ToString(instance.pattern());
909 }
910 }
911
912
913 void AddShingles(size_t begin, size_t end) {
914 for (size_t i = begin; i + Shingle::kWidth - 1 < end; ++i) {
915 instances_[i] = Shingle::Find(trace_, i, &shingle_instances_);
916 }
917 }
918
919 void Declassify(Shingle* shingle) {
920 ShinglePattern* pattern = shingle->pattern();
921 if (shingle->InModel()) {
922 pattern->model_histogram_.erase(ShinglePattern::FreqView(shingle));
923 pattern->model_coverage_ -= shingle->position_count();
924 } else {
925 pattern->program_histogram_.erase(ShinglePattern::FreqView(shingle));
926 pattern->program_coverage_ -= shingle->position_count();
927 }
928 shingle->set_pattern(NULL);
929 }
930
931 void Reclassify(Shingle* shingle) {
932 ShinglePattern* pattern = shingle->pattern();
933 LOG_ASSERT(pattern == NULL);
934
935 ShinglePattern::Index index(shingle);
936 if (index.variables_ == 0)
937 return;
938
939 std::pair<IndexToPattern::iterator, bool> inserted =
940 patterns_.insert(std::make_pair(index, ShinglePattern()));
941
942 pattern = &inserted.first->second;
943 pattern->index_ = &inserted.first->first;
944 shingle->set_pattern(pattern);
945 patterns_needing_updates_.insert(pattern);
946
947 if (shingle->InModel()) {
948 pattern->model_histogram_.insert(ShinglePattern::FreqView(shingle));
949 pattern->model_coverage_ += shingle->position_count();
950 } else {
951 pattern->program_histogram_.insert(ShinglePattern::FreqView(shingle));
952 pattern->program_coverage_ += shingle->position_count();
953 }
954 }
955
956 void InitialClassify() {
957 for (Shingle::OwningSet::iterator p = shingle_instances_.begin();
958 p != shingle_instances_.end();
959 ++p) {
960 Reclassify(&*p);
961 }
962 }
963
964 // For the positions in |info|, find the shingles that overlap that position.
965 void AddAffectedPositions(LabelInfo* info, ShingleSet* affected_shingles) {
966 const size_t kWidth = Shingle::kWidth;
967 for (size_t i = 0; i < info->positions_.size(); ++i) {
968 size_t position = info->positions_[i];
969 // Find bounds to the subrange of |trace_| we are in.
970 size_t start = position < model_end_ ? 0 : model_end_;
971 size_t end = position < model_end_ ? model_end_ : trace_.size();
972
973 // Clip [position-kWidth+1, position+1)
974 size_t low = position > start + kWidth - 1
975 ? position - kWidth + 1
976 : start;
977 size_t high = position + kWidth < end ? position + 1 : end - kWidth + 1;
978
979 for (size_t shingle_position = low;
980 shingle_position < high;
981 ++shingle_position) {
982 Shingle* overlapping_shingle = instances_.at(shingle_position);
983 affected_shingles->insert(overlapping_shingle);
984 }
985 }
986 }
987
988 void RemovePatternsNeedingUpdatesFromQueues() {
989 for (ShinglePatternSet::iterator p = patterns_needing_updates_.begin();
990 p != patterns_needing_updates_.end();
991 ++p) {
992 RemovePatternFromQueues(*p);
993 }
994 }
995
996 void AddPatternsNeedingUpdatesToQueues() {
997 for (ShinglePatternSet::iterator p = patterns_needing_updates_.begin();
998 p != patterns_needing_updates_.end();
999 ++p) {
1000 AddPatternToQueues(*p);
1001 }
1002 variable_queue_.ApplyPendingUpdates();
1003 }
1004
1005 void RemovePatternFromQueues(const ShinglePattern* pattern) {
1006 int single_use_score = SingleUseScore(pattern);
1007 if (single_use_score > 0) {
1008 size_t n = single_use_pattern_queue_.erase(pattern);
1009 LOG_ASSERT(n == 1);
1010 } else if (pattern->program_histogram_.size() == 0 &&
1011 pattern->model_histogram_.size() == 0) {
1012 NOTREACHED(); // Should not come back to life.
1013 } else if (pattern->program_histogram_.size() == 0) {
1014 // Useless pattern.
1015 } else {
1016 active_non_single_use_patterns_.erase(pattern);
1017 AddPatternToLabelQueue(pattern, -1);
1018 }
1019 }
1020
1021 void AddPatternToQueues(const ShinglePattern* pattern) {
1022 int single_use_score = SingleUseScore(pattern);
1023 if (single_use_score > 0) {
1024 single_use_pattern_queue_.insert(pattern);
1025 } else if (pattern->program_histogram_.size() == 0 &&
1026 pattern->model_histogram_.size() == 0) {
1027 } else if (pattern->program_histogram_.size() == 0) {
1028 // Useless pattern.
1029 } else {
1030 active_non_single_use_patterns_.insert(pattern);
1031 AddPatternToLabelQueue(pattern, +1);
1032 }
1033 }
1034
1035 void AddPatternToLabelQueue(const ShinglePattern* pattern, int sign) {
1036 // For each possible assignment in this pattern, update the potential
1037 // contributions to the LabelInfo queues.
1038 size_t model_histogram_size = pattern->model_histogram_.size();
1039 size_t program_histogram_size = pattern->program_histogram_.size();
1040
1041 // We want to find for each symbol (LabelInfo) the maximum contribution that
1042 // could be achieved by making shingle-wise assignments between shingles in
1043 // the model and shingles in the program.
1044 //
1045 // If the shingles in the histograms are independent (no two shingles have a
1046 // symbol in common) then any permutation of the assignments is possible,
1047 // and the maximum contribution can be found by taking the maximum over all
1048 // the pairs.
1049 //
1050 // If the shingles are dependent two things happen. The maximum
1051 // contribution to any given symbol is a sum because the symbol has
1052 // contributions from all the shingles containing it. Second, some
1053 // assignments are blocked by previous incompatible assignments. We want to
1054 // avoid a combinatorial search, so we ignore the blocking.
1055
1056 const int kUnwieldy = 5;
1057
1058 typedef std::map<LabelInfo*, int> LabelToScore;
1059 typedef std::map<LabelInfo*, LabelToScore > ScoreSet;
1060 ScoreSet maxima;
1061
1062 size_t n_model_samples = 0;
1063 for (ShinglePattern::Histogram::const_iterator model_iter =
1064 pattern->model_histogram_.begin();
1065 model_iter != pattern->model_histogram_.end();
1066 ++model_iter) {
1067 if (++n_model_samples > kUnwieldy) break;
1068 const ShinglePattern::FreqView& model_freq = *model_iter;
1069 int m1 = model_freq.count();
1070 const Shingle* model_instance = model_freq.instance();
1071
1072 ScoreSet sums;
1073 size_t n_program_samples = 0;
1074 for (ShinglePattern::Histogram::const_iterator program_iter =
1075 pattern->program_histogram_.begin();
1076 program_iter != pattern->program_histogram_.end();
1077 ++program_iter) {
1078 if (++n_program_samples > kUnwieldy) break;
1079 const ShinglePattern::FreqView& program_freq = *program_iter;
1080 int p1 = program_freq.count();
1081 const Shingle* program_instance = program_freq.instance();
1082
1083 // int score = p1; // ? weigh all equally??
1084 int score = std::min(p1, m1);
1085
1086 for (size_t i = 0; i < Shingle::kWidth; ++i) {
1087 LabelInfo* program_info = program_instance->at(i);
1088 LabelInfo* model_info = model_instance->at(i);
1089 if ((model_info->assignment_ == NULL) !=
1090 (program_info->assignment_ == NULL)) {
1091 ALOG1 << "ERROR " << i
1092 << "\n\t" << ToString(pattern, 10)
1093 << "\n\t" << ToString(program_instance)
1094 << "\n\t" << ToString(model_instance);
1095 }
1096 if (!program_info->assignment_ && !model_info->assignment_) {
1097 sums[program_info][model_info] += score;
1098 }
1099 }
1100
1101 for (ScoreSet::iterator assignee_iterator = sums.begin();
1102 assignee_iterator != sums.end();
1103 ++assignee_iterator) {
1104 LabelInfo* program_info = assignee_iterator->first;
1105 for (LabelToScore::iterator p = assignee_iterator->second.begin();
1106 p != assignee_iterator->second.end();
1107 ++p) {
1108 LabelInfo* model_info = p->first;
1109 int score = p->second;
1110 int* slot = &maxima[program_info][model_info];
1111 *slot = std::max(*slot, score);
1112 }
1113 }
1114 }
1115 }
1116
1117 for (ScoreSet::iterator assignee_iterator = maxima.begin();
1118 assignee_iterator != maxima.end();
1119 ++assignee_iterator) {
1120 LabelInfo* program_info = assignee_iterator->first;
1121 for (LabelToScore::iterator p = assignee_iterator->second.begin();
1122 p != assignee_iterator->second.end();
1123 ++p) {
1124 LabelInfo* model_info = p->first;
1125 int score = sign * p->second;
1126 variable_queue_.AddPendingUpdate(program_info, model_info, score);
1127 }
1128 }
1129 }
1130
1131 void AssignOne(LabelInfo* model_info, LabelInfo* program_info) {
1132 LOG_ASSERT(!model_info->assignment_);
1133 LOG_ASSERT(!program_info->assignment_);
1134 LOG_ASSERT(model_info->is_model_);
1135 LOG_ASSERT(!program_info->is_model_);
1136
1137 ALOG2 << "Assign " << ToString(program_info)
1138 << " := " << ToString(model_info);
1139
1140 ShingleSet affected_shingles;
1141 AddAffectedPositions(model_info, &affected_shingles);
1142 AddAffectedPositions(program_info, &affected_shingles);
1143
1144 for (ShingleSet::iterator p = affected_shingles.begin();
1145 p != affected_shingles.end();
1146 ++p) {
1147 patterns_needing_updates_.insert((*p)->pattern());
1148 }
1149
1150 RemovePatternsNeedingUpdatesFromQueues();
1151
1152 for (ShingleSet::iterator p = affected_shingles.begin();
1153 p != affected_shingles.end();
1154 ++p) {
1155 Declassify(*p);
1156 }
1157
1158 program_info->label_->index_ = model_info->label_->index_;
1159 // Mark as assigned
1160 model_info->assignment_ = program_info;
1161 program_info->assignment_ = model_info;
1162
1163 for (ShingleSet::iterator p = affected_shingles.begin();
1164 p != affected_shingles.end();
1165 ++p) {
1166 Reclassify(*p);
1167 }
1168
1169 AddPatternsNeedingUpdatesToQueues();
1170 }
1171
1172 bool AssignFirstVariableOfHistogramHead(const ShinglePattern& pattern) {
1173 const ShinglePattern::FreqView& program_1 =
1174 *pattern.program_histogram_.begin();
1175 const ShinglePattern::FreqView& model_1 = *pattern.model_histogram_.begin();
1176 const Shingle* program_instance = program_1.instance();
1177 const Shingle* model_instance = model_1.instance();
1178 size_t variable_index = pattern.index_->first_variable_index_;
1179 LabelInfo* program_info = program_instance->at(variable_index);
1180 LabelInfo* model_info = model_instance->at(variable_index);
1181 AssignOne(model_info, program_info);
1182 return true;
1183 }
1184
1185 bool FindAndAssignBestLeader() {
1186 LOG_ASSERT(patterns_needing_updates_.empty());
1187
1188 if (!single_use_pattern_queue_.empty()) {
1189 const ShinglePattern& pattern = **single_use_pattern_queue_.begin();
1190 return AssignFirstVariableOfHistogramHead(pattern);
1191 }
1192
1193 if (variable_queue_.empty())
1194 return false;
1195
1196 const VariableQueue::ScoreAndLabel best = variable_queue_.first();
1197 int score = best.first;
1198 LabelInfo* assignee = best.second;
1199
1200 // TODO(sra): score (best.first) can be zero. A zero score means we are
1201 // blindly picking between two (or more) alternatives which look the same.
1202 // If we exit on the first zero-score we sometimes get 3-4% better total
1203 // compression. This indicates that 'infill' is doing a better job than
1204 // picking blindly. Perhaps we can use an extended region around the
1205 // undistinguished competing alternatives to break the tie.
1206 if (score == 0) {
1207 variable_queue_.Print();
1208 return false;
1209 }
1210
1211 AssignmentCandidates* candidates = assignee->candidates();
1212 if (candidates->empty())
1213 return false; // Should not happen.
1214
1215 AssignOne(candidates->top_candidate(), assignee);
1216 return true;
1217 }
1218
1219 private:
1220 // The trace vector contains the model sequence [0, model_end_) followed by
1221 // the program sequence [model_end_, trace.end())
1222 const Trace& trace_;
1223 size_t model_end_;
1224
1225 // |shingle_instances_| is the set of 'interned' shingles.
1226 Shingle::OwningSet shingle_instances_;
1227
1228 // |instances_| maps from position in |trace_| to Shingle at that position.
1229 std::vector<Shingle*> instances_;
1230
1231 SingleUsePatternQueue single_use_pattern_queue_;
1232 ShinglePatternSet active_non_single_use_patterns_;
1233 VariableQueue variable_queue_;
1234
1235 // Transient information: when we make an assignment, we need to recompute
1236 // priority queue information derived from these ShinglePatterns.
1237 ShinglePatternSet patterns_needing_updates_;
1238
1239 typedef std::map<ShinglePattern::Index,
1240 ShinglePattern, ShinglePatternIndexLess> IndexToPattern;
1241 IndexToPattern patterns_;
1242
1243 DISALLOW_COPY_AND_ASSIGN(AssignmentProblem);
1244 };
1245
1246 class Adjuster : public AdjustmentMethod {
1247 public:
1248 Adjuster() {}
1249 ~Adjuster() {}
1250
1251 bool Adjust(const AssemblyProgram& model, AssemblyProgram* program) {
1252 LOG(INFO) << "Adjuster::Adjust";
1253 prog_ = program;
1254 model_ = &model;
1255 return Finish();
1256 }
1257
1258 bool Finish() {
1259 prog_->UnassignIndexes();
1260 Trace abs32_trace_;
1261 Trace rel32_trace_;
1262 CollectTraces(model_, &abs32_trace_, &rel32_trace_, true);
1263 size_t abs32_model_end = abs32_trace_.size();
1264 size_t rel32_model_end = rel32_trace_.size();
1265 CollectTraces(prog_, &abs32_trace_, &rel32_trace_, false);
1266 Solve(abs32_trace_, abs32_model_end);
1267 Solve(rel32_trace_, rel32_model_end);
1268 prog_->AssignRemainingIndexes();
1269 return true;
1270 }
1271
1272 private:
1273 void CollectTraces(const AssemblyProgram* program, Trace* abs32, Trace* rel32,
1274 bool is_model) {
1275 label_info_maker_.ResetDebugLabel();
1276 const std::vector<Instruction*>& instructions = program->instructions();
1277 for (size_t i = 0; i < instructions.size(); ++i) {
1278 Instruction* instruction = instructions.at(i);
1279 if (Label* label = program->InstructionAbs32Label(instruction))
1280 ReferenceLabel(abs32, label, is_model);
1281 if (Label* label = program->InstructionRel32Label(instruction))
1282 ReferenceLabel(rel32, label, is_model);
1283 }
1284 // TODO(sra): we could simply append all the labels in index order to
1285 // incorporate some costing for entropy (bigger deltas) that will be
1286 // introduced into the label address table by non-monotonic ordering. This
1287 // would have some knock-on effects to parts of the algorithm that work on
1288 // single-occurrence labels.
1289 }
1290
1291 void Solve(const Trace& model, size_t model_end) {
1292 AssignmentProblem a(model, model_end);
1293 a.Solve();
1294 }
1295
1296 void ReferenceLabel(Trace* trace, Label* label, bool is_model) {
1297 trace->push_back(
1298 label_info_maker_.MakeLabelInfo(label, is_model, trace->size()));
1299 }
1300
1301 AssemblyProgram* prog_; // Program to be adjusted, owned by caller.
1302 const AssemblyProgram* model_; // Program to be mimicked, owned by caller.
1303
1304 LabelInfoMaker label_info_maker_;
1305
1306 private:
1307 DISALLOW_COPY_AND_ASSIGN(Adjuster);
1308 };
1309
1310 ////////////////////////////////////////////////////////////////////////////////
1311
1312 } // namespace adjustment_method_2
1313
1314 AdjustmentMethod* AdjustmentMethod::MakeShingleAdjustmentMethod() {
1315 return new adjustment_method_2::Adjuster();
1316 }
1317
1318 } // namespace courgette
OLDNEW
« no previous file with comments | « courgette/adjustment_method.cc ('k') | courgette/courgette.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698