blob: bd0a760780fb6daa8e83a933d5d9c3d509b02412 [file] [log] [blame]
// 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_