| // Copyright 2012 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| // An implementation of a Reorderer. The LinearOrderGenerator simply orders code |
| // blocks in the order that they were executed as seen in the call-trace. |
| // If data ordering is enabled, all data blocks referred to by a code block |
| // are assumed to have been touched when the code block was executed, and they |
| // are output in that order. |
| // |
| // If multiple runs of the instrumented binary are seen in the trace files, each |
| // run will be processed independently, and for each unique block, the count of |
| // how many runs in which its execution was seen is maintained. Blocks are first |
| // sorted by the number of individual runs in which they were seen (decreasing), |
| // and then sorted by the order in which they were seen. For the special case |
| // of blocks that were only seen in a single run of the binary, these are |
| // separated by run and then sorted by time seen. |
| // |
| // Consider a trace file that contains 3 runs of an executable. The generated |
| // ordering will be as follows: |
| // |
| // code seen in all 3 runs, code seen in any 2 runs, code seen only in 1st run, |
| // code seen only in 2nd run, code seen only in 3rd run |
| // |
| // In the case where there is a single run of the instrumented binary, the |
| // ordering will be a simple ordering of blocks by order of execution, as per |
| // our original proof-of-concept ordering. |
| |
| #ifndef SYZYGY_REORDER_LINEAR_ORDER_GENERATOR_H_ |
| #define SYZYGY_REORDER_LINEAR_ORDER_GENERATOR_H_ |
| |
| #include <map> |
| #include <set> |
| #include <vector> |
| |
| #include "syzygy/reorder/reorderer.h" |
| |
| namespace reorder { |
| |
| // A simple linear order generator. See comment at top of this header file for |
| // more details. |
| class LinearOrderGenerator : public Reorderer::OrderGenerator { |
| public: |
| struct BlockCall; |
| |
| LinearOrderGenerator(); |
| virtual ~LinearOrderGenerator(); |
| |
| // OrderGenerator implementation. |
| virtual bool OnProcessStarted(uint32_t process_id, |
| const UniqueTime& time) override; |
| virtual bool OnProcessEnded(uint32_t process_id, |
| const UniqueTime& time) override; |
| virtual bool OnCodeBlockEntry(const BlockGraph::Block* block, |
| RelativeAddress address, |
| uint32_t process_id, |
| uint32_t thread_id, |
| const UniqueTime& time) override; |
| virtual bool CalculateReordering(const PEFile& pe_file, |
| const ImageLayout& image, |
| bool reorder_code, |
| bool reorder_data, |
| Order* order) override; |
| |
| private: |
| typedef std::vector<BlockCall> BlockCalls; |
| typedef std::map<size_t, BlockCalls> ProcessGroupBlockCalls; |
| typedef std::map<const BlockGraph::Block*, BlockCall> BlockCallMap; |
| typedef std::set<const BlockGraph::Block*> BlockSet; |
| |
| // Called by OnFunctionEntry to update block_calls_. |
| bool TouchBlock(const BlockCall& block_call); |
| |
| // Given a block, inserts the data blocks associated with it into |
| // the ordering. Will recursively traverse data blocks until the given |
| // maximum stack depth (that way, we include data referred to by data). |
| bool InsertDataBlocks(size_t max_recursion_depth, |
| const BlockGraph::Block* block, |
| Order* order, |
| BlockSet* inserted_blocks); |
| |
| // This is called to indicate a process group closure. |
| bool CloseProcessGroup(); |
| |
| // We assume that processes that co-exist are all part of a single run. |
| // So we divide up block calls per run. This counts the number of currently |
| // active processes, and when it reaches zero it means that we need to |
| // start a new process. |
| size_t active_process_count_; |
| |
| // This is for creating unique ids for groups of coexisting processes. |
| // This is incremented every time active_process_count transitions from 0 |
| // to 1. |
| size_t next_process_group_id_; |
| |
| // Stores the linearized block list per process group. |
| ProcessGroupBlockCalls process_group_calls_; |
| |
| // Stores pointers to blocks, and the first time at which they were accessed. |
| // There is one of these per 'process group'. |
| BlockCallMap block_call_map_; |
| }; |
| |
| struct LinearOrderGenerator::BlockCall { |
| const BlockGraph::Block* block; |
| uint32_t process_id; |
| uint32_t thread_id; |
| UniqueTime time; |
| |
| BlockCall(const BlockGraph::Block* block, |
| uint32_t process_id, |
| uint32_t thread_id, |
| const UniqueTime& time) |
| : block(block), |
| process_id(process_id), |
| thread_id(thread_id), |
| time(time) {} |
| }; |
| |
| } // namespace reorder |
| |
| #endif // SYZYGY_REORDER_LINEAR_ORDER_GENERATOR_H_ |