Coverage for /Syzygy/grinder/grinders/indexed_frequency_data_grinder.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
74.3%781050.C++source

Line-by-line coverage:

   1    :  // Copyright 2013 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/grinder/grinders/indexed_frequency_data_grinder.h"
  16    :  
  17    :  #include <limits>
  18    :  
  19    :  #include "base/files/file_path.h"
  20    :  #include "base/json/json_reader.h"
  21    :  #include "syzygy/common/indexed_frequency_data.h"
  22    :  #include "syzygy/core/json_file_writer.h"
  23    :  #include "syzygy/pdb/pdb_reader.h"
  24    :  #include "syzygy/pdb/pdb_util.h"
  25    :  #include "syzygy/pe/find.h"
  26    :  #include "syzygy/pe/metadata.h"
  27    :  #include "syzygy/pe/pe_file.h"
  28    :  #include "syzygy/version/syzygy_version.h"
  29    :  
  30    :  namespace grinder {
  31    :  namespace grinders {
  32    :  
  33    :  IndexedFrequencyDataGrinder::IndexedFrequencyDataGrinder()
  34    :      : parser_(NULL),
  35  E :        event_handler_errored_(false) {
  36  E :  }
  37    :  
  38    :  bool IndexedFrequencyDataGrinder::ParseCommandLine(
  39  E :      const base::CommandLine* command_line) {
  40  E :    serializer_.set_pretty_print(command_line->HasSwitch("pretty-print"));
  41  E :    return true;
  42  E :  }
  43    :  
  44  E :  void IndexedFrequencyDataGrinder::SetParser(Parser* parser) {
  45  E :    DCHECK(parser != NULL);
  46  E :    parser_ = parser;
  47  E :  }
  48    :  
  49  E :  bool IndexedFrequencyDataGrinder::Grind() {
  50  E :    if (frequency_data_map_.empty()) {
  51  E :      LOG(ERROR) << "No basic-block frequency data was encountered.";
  52  E :      return false;
  53    :    }
  54    :  
  55  E :    return true;
  56  E :  }
  57    :  
  58  E :  bool IndexedFrequencyDataGrinder::OutputData(FILE* file) {
  59  E :    DCHECK(file != NULL);
  60  E :    if (!serializer_.SaveAsJson(frequency_data_map_, file))
  61  i :      return false;
  62  E :    return true;
  63  E :  }
  64    :  
  65    :  void IndexedFrequencyDataGrinder::OnIndexedFrequency(
  66    :      base::Time time,
  67    :      DWORD process_id,
  68    :      DWORD thread_id,
  69  E :      const TraceIndexedFrequencyData* data) {
  70  E :    DCHECK(data != NULL);
  71  E :    DCHECK(parser_ != NULL);
  72  E :    DCHECK_NE(0U, data->num_columns);
  73    :  
  74  E :    if (data->num_entries == 0) {
  75  i :      LOG(INFO) << "Skipping empty basic block frequency data.";
  76  i :      return;
  77    :    }
  78    :  
  79  E :    if (!basic_block_util::IsValidFrequencySize(data->frequency_size)) {
  80  i :      LOG(ERROR) << "Basic block frequency data has invalid frequency_size ("
  81    :                 << data->frequency_size << ").";
  82  i :      event_handler_errored_ = true;
  83  i :      return;
  84    :    }
  85    :  
  86    :    using trace::parser::AbsoluteAddress64;
  87    :  
  88    :    // Get the module information for which this BB frequency data belongs.
  89    :    const ModuleInformation* module_info = parser_->GetModuleInformation(
  90  E :        process_id, AbsoluteAddress64(data->module_base_addr));
  91  E :    if (module_info == NULL) {
  92  i :      LOG(ERROR) << "Failed to find module information.";
  93  i :      event_handler_errored_ = true;
  94  i :      return;
  95    :    }
  96    :  
  97    :    const InstrumentedModuleInformation* instrumented_module =
  98  E :        FindOrCreateInstrumentedModule(module_info);
  99  E :    if (instrumented_module == NULL) {
 100  i :      LOG(ERROR) << "Failed to find instrumented module "
 101    :                 << module_info->path;
 102  i :      event_handler_errored_ = true;
 103  i :      return;
 104    :    }
 105    :  
 106  E :    if (data->num_entries != instrumented_module->block_ranges.size()) {
 107  i :      LOG(ERROR) << "Unexpected data size for instrumented module "
 108    :                 << module_info->path;
 109  i :      event_handler_errored_ = true;
 110  i :      return;
 111    :    }
 112    :  
 113  E :    UpdateBasicBlockFrequencyData(*instrumented_module, data);
 114  E :  }
 115    :  
 116    :  void IndexedFrequencyDataGrinder::UpdateBasicBlockFrequencyData(
 117    :      const InstrumentedModuleInformation& instrumented_module,
 118  E :      const TraceIndexedFrequencyData* data) {
 119    :    using basic_block_util::BasicBlockOffset;
 120    :    using basic_block_util::EntryCountType;
 121    :    using basic_block_util::GetFrequency;
 122    :    using basic_block_util::IndexedFrequencyInformation;
 123    :    using basic_block_util::IndexedFrequencyMap;
 124    :    using basic_block_util::RelativeAddress;
 125    :  
 126  E :    DCHECK(data != NULL);
 127  E :    DCHECK_NE(0U, data->num_entries);
 128  E :    DCHECK_NE(0U, data->num_columns);
 129    :  
 130    :    // Find the entry for this module.
 131    :    ModuleIndexedFrequencyMap::iterator look =
 132  E :        frequency_data_map_.find(instrumented_module.original_module);
 133    :  
 134  E :    if (look == frequency_data_map_.end()) {
 135  E :      IndexedFrequencyInformation info = {};
 136  E :      info.num_entries = data->num_entries;
 137  E :      info.num_columns = data->num_columns;
 138  E :      info.frequency_size = data->frequency_size;
 139    :      info.data_type =
 140  E :          static_cast<common::IndexedFrequencyData::DataType>(data->data_type);
 141    :  
 142    :      look = frequency_data_map_.insert(
 143    :          std::make_pair(instrumented_module.original_module,
 144  E :                         info)).first;
 145  E :    }
 146    :  
 147    :    // Validate fields are compatible to be grinded together.
 148  E :    IndexedFrequencyInformation& info = look->second;
 149    :    if (info.num_entries != data->num_entries ||
 150    :        info.num_columns != data->num_columns ||
 151    :        info.frequency_size != data->frequency_size ||
 152  E :        info.data_type != data->data_type) {
 153  i :      event_handler_errored_ = true;
 154  i :      return;
 155    :    }
 156    :  
 157    :    // Run over the BB frequency data and increment values for each basic block
 158    :    // using saturation arithmetic.
 159  E :    IndexedFrequencyMap& bb_entries = info.frequency_map;
 160  E :    for (size_t bb_id = 0; bb_id < data->num_entries; ++bb_id) {
 161  E :      for (size_t column = 0; column < data->num_columns; ++column) {
 162  E :        EntryCountType amount = GetFrequency(data, bb_id, column);
 163  E :        if (amount != 0) {
 164    :          BasicBlockOffset offs =
 165  E :              instrumented_module.block_ranges[bb_id].start().value();
 166    :  
 167    :          EntryCountType& value = bb_entries[
 168  E :              std::make_pair(RelativeAddress(offs), column)];
 169  E :          if (amount < 0) {
 170    :            // We need to detect uint32 to int32 overflow because JSON file output
 171    :            // int32 and basic block agent use an uint32 counter.
 172  i :            value = std::numeric_limits<EntryCountType>::max();
 173  i :          } else {
 174    :            value += std::min(
 175  E :                amount, std::numeric_limits<EntryCountType>::max() - value);
 176    :          }
 177    :        }
 178  E :      }
 179  E :    }
 180  E :  }
 181    :  
 182    :  const IndexedFrequencyDataGrinder::InstrumentedModuleInformation*
 183    :  IndexedFrequencyDataGrinder::FindOrCreateInstrumentedModule(
 184  E :      const ModuleInformation* module_info) {
 185    :    // See if we already encountered this instrumented module.
 186  E :    InstrumentedModuleMap::iterator it(instrumented_modules_.find(*module_info));
 187  E :    if (it != instrumented_modules_.end())
 188  i :      return &it->second;
 189    :  
 190    :    // Get the original file's metadata.
 191  E :    base::FilePath module_path(module_info->path);
 192  E :    pe::PEFile instrumented_module;
 193  E :    if (!instrumented_module.Init(module_path)) {
 194  i :      LOG(ERROR) << "Unable to locate instrumented module: "
 195    :                 << module_path.value();
 196  i :      return NULL;
 197    :    }
 198    :  
 199  E :    pe::Metadata metadata;
 200  E :    if (!metadata.LoadFromPE(instrumented_module)) {
 201  i :      LOG(ERROR) << "Unable to load metadata from module: "
 202    :                 << module_path.value();
 203  i :      return NULL;
 204    :    }
 205    :  
 206    :    // Find the PDB file for the module.
 207  E :    base::FilePath pdb_path;
 208  E :    if (!pe::FindPdbForModule(module_path, &pdb_path) || pdb_path.empty()) {
 209  i :      LOG(ERROR) << "Failed to find PDB for module: " << module_path.value();
 210  i :      return NULL;
 211    :    }
 212    :  
 213  E :    RelativeAddressRangeVector block_ranges;
 214    :    // This logs verbosely for us.
 215  E :    if (!basic_block_util::LoadBasicBlockRanges(pdb_path, &block_ranges)) {
 216  i :      return NULL;
 217    :    }
 218    :  
 219    :    // We've located all the information we need, create and initialize the
 220    :    // record.
 221  E :    InstrumentedModuleInformation& info = instrumented_modules_[*module_info];
 222  E :    info.original_module = metadata.module_signature();
 223  E :    info.block_ranges.swap(block_ranges);
 224    :  
 225  E :    return &info;
 226  E :  }
 227    :  
 228    :  }  // namespace grinders
 229    :  }  // namespace grinder

Coverage information generated Thu Jan 14 17:40:38 2016.