<commit_before>//===--- Linker.cpp -------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-linker"
#include "Linker.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
#include <functional>

using namespace swift;
using namespace Lowering;

STATISTIC(NumFuncLinked, "Number of SIL functions linked");

//===----------------------------------------------------------------------===//
//                                  Utility
//===----------------------------------------------------------------------===//

/// \return True if the function \p F should be imported into the current
/// module.
static bool shouldImportFunction(SILFunction *F) {
  // Skip functions that are marked with the 'no import' tag. These
  // are functions that we don't want to copy from the module.
  if (F->hasSemanticsAttr("stdlib_binary_only")) {
    // If we are importing a function declaration mark it as external since we
    // are not importing the body.
    if (F->isExternalDeclaration())
      F->setLinkage(SILLinkage::PublicExternal);
    return false;
  }

  return true;
}

//===----------------------------------------------------------------------===//
//                               Linker Helpers
//===----------------------------------------------------------------------===//

/// Process F, recursively deserializing any thing F may reference.
bool SILLinkerVisitor::processFunction(SILFunction *F) {
  if (Mode == LinkingMode::LinkNone)
    return false;

  if (!shouldImportFunction(F))
    return false;

  // If F is a declaration, first deserialize it.
  if (F->isExternalDeclaration()) {
    auto *NewFn = Loader->lookupSILFunction(F);

    if (!NewFn || NewFn->isExternalDeclaration())
      return false;

    F = NewFn;
  }

  ++NumFuncLinked;

  // Try to transitively deserialize everything referenced by this
  // function.
  Worklist.push_back(F);
  process();

  // Since we successfully processed at least one function, return true.
  return true;
}

/// Process Decl, recursively deserializing any thing Decl may reference.
bool SILLinkerVisitor::processDeclRef(SILDeclRef Decl) {
  if (Mode == LinkingMode::LinkNone)
    return false;

  // If F is a declaration, first deserialize it.
  auto *NewFn =
      isAvailableExternally(Decl.getLinkage(ForDefinition_t::NotForDefinition))
          ? Loader->lookupSILFunction(Decl)
          : nullptr;
  if (!NewFn || NewFn->isExternalDeclaration())
    return false;

  if (!shouldImportFunction(NewFn)) {
    return false;
  }

  ++NumFuncLinked;

  // Try to transitively deserialize everything referenced by NewFn.
  Worklist.push_back(NewFn);
  process();

  // Since we successfully processed at least one function, return true.
  return true;
}

/// Process Decl, recursively deserializing any thing Decl may reference.
bool SILLinkerVisitor::processFunction(StringRef Name) {
  if (Mode == LinkingMode::LinkNone)
    return false;

  // If F is a declaration, first deserialize it.
  auto *NewFn = Loader->lookupSILFunction(Name);

  if (!NewFn || NewFn->isExternalDeclaration())
    return false;

  ++NumFuncLinked;

  // Try to transitively deserialize everything referenced by NewFn.
  Worklist.push_back(NewFn);
  process();

  // Since we successfully processed at least one function, return true.
  return true;
}

/// Process Decl, recursively deserializing any thing Decl may reference.
SILFunction *SILLinkerVisitor::lookupFunction(StringRef Name,
                                              SILLinkage Linkage) {

  auto *NewFn = Loader->lookupSILFunction(Name, /* declarationOnly */ true,
                                          Linkage);

  if (!NewFn)
    return nullptr;

  assert(NewFn->isExternalDeclaration() &&
         "SIL function lookup should never read function bodies");

  return NewFn;
}

/// Deserialize the VTable mapped to C if it exists and all SIL the VTable
/// transitively references.
///
/// This method assumes that the caller made sure that no vtable existed in
/// Mod.
SILVTable *SILLinkerVisitor::processClassDecl(const ClassDecl *C) {
  // If we are not linking anything, bail.
  if (Mode == LinkingMode::LinkNone)
    return nullptr;

  // Attempt to load the VTable from the SerializedSILLoader. If we
  // fail... bail...
  SILVTable *Vtbl = Loader->lookupVTable(C);
  if (!Vtbl)
    return nullptr;

  // Otherwise, add all the vtable functions in Vtbl to the function
  // processing list...
  for (auto &E : Vtbl->getEntries())
    Worklist.push_back(E.second);

  // And then transitively deserialize all SIL referenced by those functions.
  process();

  // Return the deserialized Vtbl.
  return Vtbl;
}

bool SILLinkerVisitor::linkInVTable(ClassDecl *D) {
  // Attempt to lookup the Vtbl from the SILModule.
  SILVTable *Vtbl = Mod.lookUpVTable(D);

  // If the SILModule does not have the VTable, attempt to deserialize the
  // VTable. If we fail to do that as well, bail.
  if (!Vtbl || !(Vtbl = Loader->lookupVTable(D->getName())))
    return false;

  // Ok we found our VTable. Visit each function referenced by the VTable. If
  // any of the functions are external declarations, add them to the worklist
  // for processing.
  bool Result = false;
  for (auto P : Vtbl->getEntries()) {
    if (P.second->isExternalDeclaration()) {
      Result = true;
      addFunctionToWorklist(P.second);
    }
  }
  return Result;
}

//===----------------------------------------------------------------------===//
//                                  Visitors
//===----------------------------------------------------------------------===//

bool SILLinkerVisitor::visitApplyInst(ApplyInst *AI) {
  // Ok we have a function ref inst, grab the callee.
  SILFunction *Callee = AI->getReferencedFunction();
  if (!Callee)
    return false;

  // If the linking mode is not link all, AI is not transparent, and the
  // callee is not shared, we don't want to perform any linking.
  if (!isLinkAll() && !Callee->isTransparent() &&
      !hasSharedVisibility(Callee->getLinkage()))
    return false;

  // Otherwise we want to try and link in the callee... Add it to the callee
  // list and return true.
  addFunctionToWorklist(Callee);
  return true;
}

bool SILLinkerVisitor::visitPartialApplyInst(PartialApplyInst *PAI) {
  SILFunction *Callee = PAI->getReferencedFunction();
  if (!Callee)
    return false;
  if (!isLinkAll() && !Callee->isTransparent() &&
      !hasSharedVisibility(Callee->getLinkage()))
    return false;

  addFunctionToWorklist(Callee);
  return true;
}

bool SILLinkerVisitor::visitFunctionRefInst(FunctionRefInst *FRI) {
  // Needed to handle closures which are no longer applied, but are left
  // behind as dead code. This shouldn't happen, but if it does don't get into
  // an inconsistent state.
  SILFunction *Callee = FRI->getReferencedFunction();
  if (!isLinkAll() && !Callee->isTransparent() &&
      !hasSharedVisibility(Callee->getLinkage()))
    return false;

  addFunctionToWorklist(FRI->getReferencedFunction());
  return true;
}

bool SILLinkerVisitor::visitProtocolConformance(
    ProtocolConformanceRef ref, const Optional<SILDeclRef> &Member) {
  // If an abstract protocol conformance was passed in, just return false.
  if (ref.isAbstract())
    return false;

  // Otherwise try and lookup a witness table for C.
  auto C = ref.getConcrete();
  SILWitnessTable *WT = Mod.lookUpWitnessTable(C);

  // If we don't find any witness table for the conformance, bail and return
  // false.
  if (!WT) {
    Mod.createWitnessTableDeclaration(
        C, TypeConverter::getLinkageForProtocolConformance(
               C->getRootNormalConformance(), NotForDefinition));
    return false;
  }

  // If the looked up witness table is a declaration, there is nothing we can
  // do here. Just bail and return false.
  if (WT->isDeclaration())
    return false;

  bool performFuncDeserialization = false;
  // For each entry in the witness table...
  for (auto &E : WT->getEntries()) {
    // If the entry is a witness method...
    if (E.getKind() == SILWitnessTable::WitnessKind::Method) {
      // And we are only interested in deserializing a specific requirement
      // and don't have that requirement, don't deserialize this method.
      if (Member.hasValue() && E.getMethodWitness().Requirement != *Member)
        continue;

      // The witness could be removed by dead function elimination.
      if (!E.getMethodWitness().Witness)
        continue;

      // Otherwise if it is the requirement we are looking for or we just want
      // to deserialize everything, add the function to the list of functions
      // to deserialize.
      performFuncDeserialization = true;
      addFunctionToWorklist(E.getMethodWitness().Witness);
    }
  }

  return performFuncDeserialization;
}

bool SILLinkerVisitor::visitInitExistentialAddrInst(
    InitExistentialAddrInst *IEI) {
  // Link in all protocol conformances that this touches.
  //
  // TODO: There might be a two step solution where the init_existential_inst
  // causes the witness table to be brought in as a declaration and then the
  // protocol method inst causes the actual deserialization. For now we are
  // not going to be smart about this to enable avoiding any issues with
  // visiting the open_existential_addr/witness_method before the
  // init_existential_inst.
  bool performFuncDeserialization = false;
  for (ProtocolConformanceRef C : IEI->getConformances()) {
    performFuncDeserialization |=
        visitProtocolConformance(C, Optional<SILDeclRef>());
  }
  return performFuncDeserialization;
}

bool SILLinkerVisitor::visitInitExistentialRefInst(
    InitExistentialRefInst *IERI) {
  // Link in all protocol conformances that this touches.
  //
  // TODO: There might be a two step solution where the init_existential_inst
  // causes the witness table to be brought in as a declaration and then the
  // protocol method inst causes the actual deserialization. For now we are
  // not going to be smart about this to enable avoiding any issues with
  // visiting the protocol_method before the init_existential_inst.
  bool performFuncDeserialization = false;
  for (ProtocolConformanceRef C : IERI->getConformances()) {
    performFuncDeserialization |=
        visitProtocolConformance(C, Optional<SILDeclRef>());
  }
  return performFuncDeserialization;
}

bool SILLinkerVisitor::visitAllocRefInst(AllocRefInst *ARI) {
  // Grab the class decl from the alloc ref inst.
  ClassDecl *D = ARI->getType().getClassOrBoundGenericClass();
  if (!D)
    return false;

  return linkInVTable(D);
}

bool SILLinkerVisitor::visitMetatypeInst(MetatypeInst *MI) {
  CanType instTy = MI->getType().castTo<MetatypeType>().getInstanceType();
  ClassDecl *C = instTy.getClassOrBoundGenericClass();
  if (!C)
    return false;

  return linkInVTable(C);
}

//===----------------------------------------------------------------------===//
//                             Top Level Routine
//===----------------------------------------------------------------------===//

// Main loop of the visitor. Called by one of the other *visit* methods.
bool SILLinkerVisitor::process() {
  // Process everything transitively referenced by one of the functions in the
  // worklist.
  bool Result = false;
  while (!Worklist.empty()) {
    auto *Fn = Worklist.pop_back_val();

    if (!shouldImportFunction(Fn))
      continue;

    DEBUG(llvm::dbgs() << "Process imports in function: "
                       << Fn->getName() << "\n");

    for (auto &BB : *Fn) {
      for (auto &I : BB) {
        // Should we try linking?
        if (visit(&I)) {
          for (auto *F : FunctionDeserializationWorklist) {

            if (!shouldImportFunction(F))
              continue;

            DEBUG(llvm::dbgs() << "Imported function: "
                               << F->getName() << "\n");
            F->setBare(IsBare);

            if (F->isExternalDeclaration()) {
              if (auto *NewFn = Loader->lookupSILFunction(F)) {
                if (NewFn->isExternalDeclaration())
                  continue;

                NewFn->verify();
                Worklist.push_back(NewFn);
                Result = true;

                ++NumFuncLinked;
              }
            }
          }
          FunctionDeserializationWorklist.clear();
        } else {
          assert(FunctionDeserializationWorklist.empty() &&
                 "Worklist should "
                 "always be empty if visit does not return true.");
        }
      }
    }
  }

  // If we return true, we deserialized at least one function.
  return Result;
}
<commit_msg>SILLinker: Deserialize shared definitions too<commit_after>//===--- Linker.cpp -------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sil-linker"
#include "Linker.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Debug.h"
#include <functional>

using namespace swift;
using namespace Lowering;

STATISTIC(NumFuncLinked, "Number of SIL functions linked");

//===----------------------------------------------------------------------===//
//                                  Utility
//===----------------------------------------------------------------------===//

/// \return True if the function \p F should be imported into the current
/// module.
static bool shouldImportFunction(SILFunction *F) {
  // Skip functions that are marked with the 'no import' tag. These
  // are functions that we don't want to copy from the module.
  if (F->hasSemanticsAttr("stdlib_binary_only")) {
    // If we are importing a function declaration mark it as external since we
    // are not importing the body.
    if (F->isExternalDeclaration())
      F->setLinkage(SILLinkage::PublicExternal);
    return false;
  }

  return true;
}

//===----------------------------------------------------------------------===//
//                               Linker Helpers
//===----------------------------------------------------------------------===//

/// Process F, recursively deserializing any thing F may reference.
bool SILLinkerVisitor::processFunction(SILFunction *F) {
  if (Mode == LinkingMode::LinkNone)
    return false;

  if (!shouldImportFunction(F))
    return false;

  // If F is a declaration, first deserialize it.
  if (F->isExternalDeclaration()) {
    auto *NewFn = Loader->lookupSILFunction(F);

    if (!NewFn || NewFn->isExternalDeclaration())
      return false;

    F = NewFn;
  }

  ++NumFuncLinked;

  // Try to transitively deserialize everything referenced by this
  // function.
  Worklist.push_back(F);
  process();

  // Since we successfully processed at least one function, return true.
  return true;
}

/// Process Decl, recursively deserializing any thing Decl may reference.
bool SILLinkerVisitor::processDeclRef(SILDeclRef Decl) {
  if (Mode == LinkingMode::LinkNone)
    return false;

  // If F is a declaration, first deserialize it.
  auto *NewFn = Loader->lookupSILFunction(Decl);
  if (!NewFn || NewFn->isExternalDeclaration())
    return false;

  if (!shouldImportFunction(NewFn)) {
    return false;
  }

  ++NumFuncLinked;

  // Try to transitively deserialize everything referenced by NewFn.
  Worklist.push_back(NewFn);
  process();

  // Since we successfully processed at least one function, return true.
  return true;
}

/// Process Decl, recursively deserializing any thing Decl may reference.
bool SILLinkerVisitor::processFunction(StringRef Name) {
  if (Mode == LinkingMode::LinkNone)
    return false;

  // If F is a declaration, first deserialize it.
  auto *NewFn = Loader->lookupSILFunction(Name);

  if (!NewFn || NewFn->isExternalDeclaration())
    return false;

  ++NumFuncLinked;

  // Try to transitively deserialize everything referenced by NewFn.
  Worklist.push_back(NewFn);
  process();

  // Since we successfully processed at least one function, return true.
  return true;
}

/// Process Decl, recursively deserializing any thing Decl may reference.
SILFunction *SILLinkerVisitor::lookupFunction(StringRef Name,
                                              SILLinkage Linkage) {

  auto *NewFn = Loader->lookupSILFunction(Name, /* declarationOnly */ true,
                                          Linkage);

  if (!NewFn)
    return nullptr;

  assert(NewFn->isExternalDeclaration() &&
         "SIL function lookup should never read function bodies");

  return NewFn;
}

/// Deserialize the VTable mapped to C if it exists and all SIL the VTable
/// transitively references.
///
/// This method assumes that the caller made sure that no vtable existed in
/// Mod.
SILVTable *SILLinkerVisitor::processClassDecl(const ClassDecl *C) {
  // If we are not linking anything, bail.
  if (Mode == LinkingMode::LinkNone)
    return nullptr;

  // Attempt to load the VTable from the SerializedSILLoader. If we
  // fail... bail...
  SILVTable *Vtbl = Loader->lookupVTable(C);
  if (!Vtbl)
    return nullptr;

  // Otherwise, add all the vtable functions in Vtbl to the function
  // processing list...
  for (auto &E : Vtbl->getEntries())
    Worklist.push_back(E.second);

  // And then transitively deserialize all SIL referenced by those functions.
  process();

  // Return the deserialized Vtbl.
  return Vtbl;
}

bool SILLinkerVisitor::linkInVTable(ClassDecl *D) {
  // Attempt to lookup the Vtbl from the SILModule.
  SILVTable *Vtbl = Mod.lookUpVTable(D);

  // If the SILModule does not have the VTable, attempt to deserialize the
  // VTable. If we fail to do that as well, bail.
  if (!Vtbl || !(Vtbl = Loader->lookupVTable(D->getName())))
    return false;

  // Ok we found our VTable. Visit each function referenced by the VTable. If
  // any of the functions are external declarations, add them to the worklist
  // for processing.
  bool Result = false;
  for (auto P : Vtbl->getEntries()) {
    if (P.second->isExternalDeclaration()) {
      Result = true;
      addFunctionToWorklist(P.second);
    }
  }
  return Result;
}

//===----------------------------------------------------------------------===//
//                                  Visitors
//===----------------------------------------------------------------------===//

bool SILLinkerVisitor::visitApplyInst(ApplyInst *AI) {
  // Ok we have a function ref inst, grab the callee.
  SILFunction *Callee = AI->getReferencedFunction();
  if (!Callee)
    return false;

  // If the linking mode is not link all, AI is not transparent, and the
  // callee is not shared, we don't want to perform any linking.
  if (!isLinkAll() && !Callee->isTransparent() &&
      !hasSharedVisibility(Callee->getLinkage()))
    return false;

  // Otherwise we want to try and link in the callee... Add it to the callee
  // list and return true.
  addFunctionToWorklist(Callee);
  return true;
}

bool SILLinkerVisitor::visitPartialApplyInst(PartialApplyInst *PAI) {
  SILFunction *Callee = PAI->getReferencedFunction();
  if (!Callee)
    return false;
  if (!isLinkAll() && !Callee->isTransparent() &&
      !hasSharedVisibility(Callee->getLinkage()))
    return false;

  addFunctionToWorklist(Callee);
  return true;
}

bool SILLinkerVisitor::visitFunctionRefInst(FunctionRefInst *FRI) {
  // Needed to handle closures which are no longer applied, but are left
  // behind as dead code. This shouldn't happen, but if it does don't get into
  // an inconsistent state.
  SILFunction *Callee = FRI->getReferencedFunction();
  if (!isLinkAll() && !Callee->isTransparent() &&
      !hasSharedVisibility(Callee->getLinkage()))
    return false;

  addFunctionToWorklist(FRI->getReferencedFunction());
  return true;
}

bool SILLinkerVisitor::visitProtocolConformance(
    ProtocolConformanceRef ref, const Optional<SILDeclRef> &Member) {
  // If an abstract protocol conformance was passed in, just return false.
  if (ref.isAbstract())
    return false;

  // Otherwise try and lookup a witness table for C.
  auto C = ref.getConcrete();
  SILWitnessTable *WT = Mod.lookUpWitnessTable(C);

  // If we don't find any witness table for the conformance, bail and return
  // false.
  if (!WT) {
    Mod.createWitnessTableDeclaration(
        C, TypeConverter::getLinkageForProtocolConformance(
               C->getRootNormalConformance(), NotForDefinition));
    return false;
  }

  // If the looked up witness table is a declaration, there is nothing we can
  // do here. Just bail and return false.
  if (WT->isDeclaration())
    return false;

  bool performFuncDeserialization = false;
  // For each entry in the witness table...
  for (auto &E : WT->getEntries()) {
    // If the entry is a witness method...
    if (E.getKind() == SILWitnessTable::WitnessKind::Method) {
      // And we are only interested in deserializing a specific requirement
      // and don't have that requirement, don't deserialize this method.
      if (Member.hasValue() && E.getMethodWitness().Requirement != *Member)
        continue;

      // The witness could be removed by dead function elimination.
      if (!E.getMethodWitness().Witness)
        continue;

      // Otherwise if it is the requirement we are looking for or we just want
      // to deserialize everything, add the function to the list of functions
      // to deserialize.
      performFuncDeserialization = true;
      addFunctionToWorklist(E.getMethodWitness().Witness);
    }
  }

  return performFuncDeserialization;
}

bool SILLinkerVisitor::visitInitExistentialAddrInst(
    InitExistentialAddrInst *IEI) {
  // Link in all protocol conformances that this touches.
  //
  // TODO: There might be a two step solution where the init_existential_inst
  // causes the witness table to be brought in as a declaration and then the
  // protocol method inst causes the actual deserialization. For now we are
  // not going to be smart about this to enable avoiding any issues with
  // visiting the open_existential_addr/witness_method before the
  // init_existential_inst.
  bool performFuncDeserialization = false;
  for (ProtocolConformanceRef C : IEI->getConformances()) {
    performFuncDeserialization |=
        visitProtocolConformance(C, Optional<SILDeclRef>());
  }
  return performFuncDeserialization;
}

bool SILLinkerVisitor::visitInitExistentialRefInst(
    InitExistentialRefInst *IERI) {
  // Link in all protocol conformances that this touches.
  //
  // TODO: There might be a two step solution where the init_existential_inst
  // causes the witness table to be brought in as a declaration and then the
  // protocol method inst causes the actual deserialization. For now we are
  // not going to be smart about this to enable avoiding any issues with
  // visiting the protocol_method before the init_existential_inst.
  bool performFuncDeserialization = false;
  for (ProtocolConformanceRef C : IERI->getConformances()) {
    performFuncDeserialization |=
        visitProtocolConformance(C, Optional<SILDeclRef>());
  }
  return performFuncDeserialization;
}

bool SILLinkerVisitor::visitAllocRefInst(AllocRefInst *ARI) {
  // Grab the class decl from the alloc ref inst.
  ClassDecl *D = ARI->getType().getClassOrBoundGenericClass();
  if (!D)
    return false;

  return linkInVTable(D);
}

bool SILLinkerVisitor::visitMetatypeInst(MetatypeInst *MI) {
  CanType instTy = MI->getType().castTo<MetatypeType>().getInstanceType();
  ClassDecl *C = instTy.getClassOrBoundGenericClass();
  if (!C)
    return false;

  return linkInVTable(C);
}

//===----------------------------------------------------------------------===//
//                             Top Level Routine
//===----------------------------------------------------------------------===//

// Main loop of the visitor. Called by one of the other *visit* methods.
bool SILLinkerVisitor::process() {
  // Process everything transitively referenced by one of the functions in the
  // worklist.
  bool Result = false;
  while (!Worklist.empty()) {
    auto *Fn = Worklist.pop_back_val();

    if (!shouldImportFunction(Fn))
      continue;

    DEBUG(llvm::dbgs() << "Process imports in function: "
                       << Fn->getName() << "\n");

    for (auto &BB : *Fn) {
      for (auto &I : BB) {
        // Should we try linking?
        if (visit(&I)) {
          for (auto *F : FunctionDeserializationWorklist) {

            if (!shouldImportFunction(F))
              continue;

            DEBUG(llvm::dbgs() << "Imported function: "
                               << F->getName() << "\n");
            F->setBare(IsBare);

            if (F->isExternalDeclaration()) {
              if (auto *NewFn = Loader->lookupSILFunction(F)) {
                if (NewFn->isExternalDeclaration())
                  continue;

                NewFn->verify();
                Worklist.push_back(NewFn);
                Result = true;

                ++NumFuncLinked;
              }
            }
          }
          FunctionDeserializationWorklist.clear();
        } else {
          assert(FunctionDeserializationWorklist.empty() &&
                 "Worklist should "
                 "always be empty if visit does not return true.");
        }
      }
    }
  }

  // If we return true, we deserialized at least one function.
  return Result;
}
<|endoftext|>


<commit_before>#ifndef __STAN__GM__PARSER__PROGRAM_GRAMMAR_DEF__HPP__
#define __STAN__GM__PARSER__PROGRAM_GRAMMAR_DEF__HPP__

#include <cstddef>
#include <iomanip>
#include <iostream>
#include <istream>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <stdexcept>

#include <boost/spirit/include/qi.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi_numeric.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/recursive_variant.hpp>

#include <boost/spirit/include/version.hpp>
#include <boost/spirit/home/support/iterators/line_pos_iterator.hpp>

#include <stan/gm/ast.hpp>
#include <stan/gm/grammars/whitespace_grammar.hpp>
#include <stan/gm/grammars/expression_grammar.hpp>
#include <stan/gm/grammars/var_decls_grammar.hpp>
#include <stan/gm/grammars/statement_grammar.hpp>
#include <stan/gm/grammars/program_grammar.hpp>

namespace {
  // hack to pass pair into macro below to adapt; in namespace to hide
  struct DUMMY_STRUCT {
    typedef std::pair<std::vector<stan::gm::var_decl>,
                      std::vector<stan::gm::statement> > type;
  };
}

BOOST_FUSION_ADAPT_STRUCT(stan::gm::program,
                          (std::vector<stan::gm::var_decl>, data_decl_)
                          (DUMMY_STRUCT::type, derived_data_decl_)
                          (std::vector<stan::gm::var_decl>, parameter_decl_)
                          (DUMMY_STRUCT::type, derived_decl_)
                          (stan::gm::statement, statement_)
                          (DUMMY_STRUCT::type, generated_decl_) )

namespace stan {

  namespace gm {

    struct add_lp_var {
      template <typename T>
      struct result { typedef void type; };
      void operator()(variable_map& vm) const {
        vm.add("lp__",
               base_var_decl("lp__",std::vector<expression>(),DOUBLE_T),
               local_origin); // lp acts as a local where defined
      }
    };
    boost::phoenix::function<add_lp_var> add_lp_var_f;

    struct remove_lp_var {
      template <typename T>
      struct result { typedef void type; };
      void operator()(variable_map& vm) const {
        vm.remove("lp__");
      }
    };
    boost::phoenix::function<remove_lp_var> remove_lp_var_f;

    struct program_error {
      template <typename T1, typename T2, typename ,
        typename T4, typename T5, typename T6, typename T7>
      struct result { typedef void type; };

      template <class Iterator, class I>
      void operator()(
        Iterator _begin,
        Iterator _end,
        Iterator _where,
        I const& _info,
        std::string msg,
        variable_map& vm,
        std::stringstream& error_msgs) const {

        error_msgs << msg
                   << std::endl;

        using boost::phoenix::construct;
        using boost::phoenix::val;

        std::basic_stringstream<char> pre_error_section;
        pre_error_section << boost::make_iterator_range (_begin, _where);
        char last_char;
        std::string correct_section = "";
        while (!pre_error_section.eof()) {
          last_char = (char)pre_error_section.get();
          correct_section += last_char;
        }

        int indx = correct_section.size();
        correct_section = correct_section.erase(indx-1, indx);

        //
        //  Clean up whatever is before the error occurred
        //
        //  Would be better to use the parser to select which
        //  section in the stan file contains the parsing error.
        //

        std::vector<std::string> sections;
        sections.push_back("generated");
        sections.push_back("model");
        sections.push_back("transformed");
        sections.push_back("parameter");
        sections.push_back("data");

        //bool found_section = false; // FIXME: do something with found_section
        indx = 0;

        for (size_t i = 0; i < sections.size(); ++i) {
          std::string section = sections[i];
          indx = correct_section.find(section);
          if (!(indx == std::string::npos)) {
            if (i == 2) {
              // Check which transformed block we're dealing with.
              // If there is another transformed section, it must be
              // a 'transformed parameters' section
              int indx2 = correct_section.find("transformed", indx + 5);
              if (!(indx2 == std::string::npos)) {
                indx = indx2;
              } else {
                // No second transformed section, but maybe there
                // is a parameter block?
                indx2 = correct_section.find("parameters", indx2);
                if (!(indx2 == std::string::npos)) {
                  indx = indx2;
                }
                // Ok, we found a 'transformed data' block.
                // indx is pointing at it.
              }
            }
            //found_section = true;
            correct_section = correct_section.erase(0, indx);
            break;
          }
        }

        //
        //  Clean up whatever comes after the error occurred
        //
        std::basic_stringstream<char> error_section;
        error_section << boost::make_iterator_range (_where, _end);
        last_char = ' ';
        std::string rest_of_section = "";
        while (!error_section.eof() && !(last_char == '}')) {
          last_char = (char)error_section.get();
          rest_of_section += last_char;
          //std::cout << rest_of_section.size() << std::endl;
          if (error_section.eof() && rest_of_section.size() == 1) {
            rest_of_section = "'end of file'";
          }
        }

        if (!(get_line(_where) == -1)) {
          error_msgs
            << std::endl
            << "LOCATION OF PARSING ERROR (line = "
            << get_line(_where)
            << ", position = "
            << get_column(_begin, _where) - 1
            <<  "):"
            << std::endl
            << std::endl
            << "PARSED:"
            << std::endl
            << std::endl
            << correct_section
            << std::endl
            << std::endl
            << "EXPECTED: " << _info
            << " BUT FOUND: "
            << std::endl
            << std::endl
            << rest_of_section
            << std::endl;
        }
      }
    };
    boost::phoenix::function<program_error> program_error_f;

    template <typename Iterator>
    program_grammar<Iterator>::program_grammar(const std::string& model_name)
        : program_grammar::base_type(program_r),
          model_name_(model_name),
          var_map_(),
          error_msgs_(),
          expression_g(var_map_,error_msgs_),
          var_decls_g(var_map_,error_msgs_),
          statement_g(var_map_,error_msgs_) {

        using boost::spirit::qi::eps;
        using boost::spirit::qi::lit;

        // add model_name to var_map with special origin and no
        var_map_.add(model_name,
                     base_var_decl(),
                     model_name_origin);

        program_r.name("program");
        program_r
          %= -data_var_decls_r
          > -derived_data_var_decls_r
          > -param_var_decls_r
          // scope lp__ to "transformed params" and "model" only
          > eps[add_lp_var_f(boost::phoenix::ref(var_map_))]
          > -derived_var_decls_r
          > model_r
          > eps[remove_lp_var_f(boost::phoenix::ref(var_map_))]
          > -generated_var_decls_r
          ;

        model_r.name("model declaration");
        model_r
          %= lit("model")
          > statement_g(true,local_origin)  // assign only to locals
          ;

        data_var_decls_r.name("data variable declarations");
        data_var_decls_r
          %= lit("data")
          > lit('{')
          > var_decls_g(true,data_origin) // +constraints
          > lit('}');

        derived_data_var_decls_r.name("transformed data block");
        derived_data_var_decls_r
          %= ( lit("transformed")
               >> lit("data") )
          > lit('{')
          > var_decls_g(true,transformed_data_origin)  // -constraints
          > *statement_g(false,transformed_data_origin) // -sampling
          > lit('}');

        param_var_decls_r.name("parameter variable declarations");
        param_var_decls_r
          %= lit("parameters")
          > lit('{')
          > var_decls_g(true,parameter_origin) // +constraints
          > lit('}');

        derived_var_decls_r.name("derived variable declarations");
        derived_var_decls_r
          %= ( lit("transformed")
               >> lit("parameters") )
          > lit('{')
          > var_decls_g(true,transformed_parameter_origin) // -constraints
          > *statement_g(false,transformed_parameter_origin) // -sampling
          > lit('}');

        generated_var_decls_r.name("generated variable declarations");
        generated_var_decls_r
          %= lit("generated")
          > lit("quantities")
          > lit('{')
          > var_decls_g(true,derived_origin) // -constraints
          > *statement_g(false,derived_origin) // -sampling
          > lit('}');

        using boost::spirit::qi::on_error;
        using boost::spirit::qi::rethrow;
        using namespace boost::spirit::qi::labels;

        on_error<rethrow>(
          program_r,
          program_error_f(
            _1, _2, _3, _4 ,
            "",
            boost::phoenix::ref(var_map_),
            boost::phoenix::ref(error_msgs_)
          )
        );
    }

  }
}

#endif
<commit_msg>squashing more warnings<commit_after>#ifndef __STAN__GM__PARSER__PROGRAM_GRAMMAR_DEF__HPP__
#define __STAN__GM__PARSER__PROGRAM_GRAMMAR_DEF__HPP__

#include <cstddef>
#include <iomanip>
#include <iostream>
#include <istream>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include <stdexcept>

#include <boost/spirit/include/qi.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi_numeric.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/recursive_variant.hpp>

#include <boost/spirit/include/version.hpp>
#include <boost/spirit/home/support/iterators/line_pos_iterator.hpp>

#include <stan/gm/ast.hpp>
#include <stan/gm/grammars/whitespace_grammar.hpp>
#include <stan/gm/grammars/expression_grammar.hpp>
#include <stan/gm/grammars/var_decls_grammar.hpp>
#include <stan/gm/grammars/statement_grammar.hpp>
#include <stan/gm/grammars/program_grammar.hpp>

namespace {
  // hack to pass pair into macro below to adapt; in namespace to hide
  struct DUMMY_STRUCT {
    typedef std::pair<std::vector<stan::gm::var_decl>,
                      std::vector<stan::gm::statement> > type;
  };
}

BOOST_FUSION_ADAPT_STRUCT(stan::gm::program,
                          (std::vector<stan::gm::var_decl>, data_decl_)
                          (DUMMY_STRUCT::type, derived_data_decl_)
                          (std::vector<stan::gm::var_decl>, parameter_decl_)
                          (DUMMY_STRUCT::type, derived_decl_)
                          (stan::gm::statement, statement_)
                          (DUMMY_STRUCT::type, generated_decl_) )

namespace stan {

  namespace gm {

    struct add_lp_var {
      template <typename T>
      struct result { typedef void type; };
      void operator()(variable_map& vm) const {
        vm.add("lp__",
               base_var_decl("lp__",std::vector<expression>(),DOUBLE_T),
               local_origin); // lp acts as a local where defined
      }
    };
    boost::phoenix::function<add_lp_var> add_lp_var_f;

    struct remove_lp_var {
      template <typename T>
      struct result { typedef void type; };
      void operator()(variable_map& vm) const {
        vm.remove("lp__");
      }
    };
    boost::phoenix::function<remove_lp_var> remove_lp_var_f;

    struct program_error {
      template <typename T1, typename T2, typename ,
        typename T4, typename T5, typename T6, typename T7>
      struct result { typedef void type; };

      template <class Iterator, class I>
      void operator()(
        Iterator _begin,
        Iterator _end,
        Iterator _where,
        I const& _info,
        std::string msg,
        variable_map& vm,
        std::stringstream& error_msgs) const {

        error_msgs << msg
                   << std::endl;

        using boost::phoenix::construct;
        using boost::phoenix::val;

        std::basic_stringstream<char> pre_error_section;
        pre_error_section << boost::make_iterator_range (_begin, _where);
        char last_char;
        std::string correct_section = "";
        while (!pre_error_section.eof()) {
          last_char = (char)pre_error_section.get();
          correct_section += last_char;
        }

        size_t indx = correct_section.size();
        correct_section = correct_section.erase(indx-1, indx);

        //
        //  Clean up whatever is before the error occurred
        //
        //  Would be better to use the parser to select which
        //  section in the stan file contains the parsing error.
        //

        std::vector<std::string> sections;
        sections.push_back("generated");
        sections.push_back("model");
        sections.push_back("transformed");
        sections.push_back("parameter");
        sections.push_back("data");

        //bool found_section = false; // FIXME: do something with found_section
        indx = 0;

        for (size_t i = 0; i < sections.size(); ++i) {
          std::string section = sections[i];
          indx = correct_section.find(section);
          if (!(indx == std::string::npos)) {
            if (i == 2) {
              // Check which transformed block we're dealing with.
              // If there is another transformed section, it must be
              // a 'transformed parameters' section
              int indx2 = correct_section.find("transformed", indx + 5);
              if (!(indx2 == std::string::npos)) {
                indx = indx2;
              } else {
                // No second transformed section, but maybe there
                // is a parameter block?
                indx2 = correct_section.find("parameters", indx2);
                if (!(indx2 == std::string::npos)) {
                  indx = indx2;
                }
                // Ok, we found a 'transformed data' block.
                // indx is pointing at it.
              }
            }
            //found_section = true;
            correct_section = correct_section.erase(0, indx);
            break;
          }
        }

        //
        //  Clean up whatever comes after the error occurred
        //
        std::basic_stringstream<char> error_section;
        error_section << boost::make_iterator_range (_where, _end);
        last_char = ' ';
        std::string rest_of_section = "";
        while (!error_section.eof() && !(last_char == '}')) {
          last_char = (char)error_section.get();
          rest_of_section += last_char;
          //std::cout << rest_of_section.size() << std::endl;
          if (error_section.eof() && rest_of_section.size() == 1) {
            rest_of_section = "'end of file'";
          }
        }

        if (!(get_line(_where) == std::string::npos)) {
          error_msgs
            << std::endl
            << "LOCATION OF PARSING ERROR (line = "
            << get_line(_where)
            << ", position = "
            << get_column(_begin, _where) - 1
            <<  "):"
            << std::endl
            << std::endl
            << "PARSED:"
            << std::endl
            << std::endl
            << correct_section
            << std::endl
            << std::endl
            << "EXPECTED: " << _info
            << " BUT FOUND: "
            << std::endl
            << std::endl
            << rest_of_section
            << std::endl;
        }
      }
    };
    boost::phoenix::function<program_error> program_error_f;

    template <typename Iterator>
    program_grammar<Iterator>::program_grammar(const std::string& model_name)
        : program_grammar::base_type(program_r),
          model_name_(model_name),
          var_map_(),
          error_msgs_(),
          expression_g(var_map_,error_msgs_),
          var_decls_g(var_map_,error_msgs_),
          statement_g(var_map_,error_msgs_) {

        using boost::spirit::qi::eps;
        using boost::spirit::qi::lit;

        // add model_name to var_map with special origin and no
        var_map_.add(model_name,
                     base_var_decl(),
                     model_name_origin);

        program_r.name("program");
        program_r
          %= -data_var_decls_r
          > -derived_data_var_decls_r
          > -param_var_decls_r
          // scope lp__ to "transformed params" and "model" only
          > eps[add_lp_var_f(boost::phoenix::ref(var_map_))]
          > -derived_var_decls_r
          > model_r
          > eps[remove_lp_var_f(boost::phoenix::ref(var_map_))]
          > -generated_var_decls_r
          ;

        model_r.name("model declaration");
        model_r
          %= lit("model")
          > statement_g(true,local_origin)  // assign only to locals
          ;

        data_var_decls_r.name("data variable declarations");
        data_var_decls_r
          %= lit("data")
          > lit('{')
          > var_decls_g(true,data_origin) // +constraints
          > lit('}');

        derived_data_var_decls_r.name("transformed data block");
        derived_data_var_decls_r
          %= ( lit("transformed")
               >> lit("data") )
          > lit('{')
          > var_decls_g(true,transformed_data_origin)  // -constraints
          > *statement_g(false,transformed_data_origin) // -sampling
          > lit('}');

        param_var_decls_r.name("parameter variable declarations");
        param_var_decls_r
          %= lit("parameters")
          > lit('{')
          > var_decls_g(true,parameter_origin) // +constraints
          > lit('}');

        derived_var_decls_r.name("derived variable declarations");
        derived_var_decls_r
          %= ( lit("transformed")
               >> lit("parameters") )
          > lit('{')
          > var_decls_g(true,transformed_parameter_origin) // -constraints
          > *statement_g(false,transformed_parameter_origin) // -sampling
          > lit('}');

        generated_var_decls_r.name("generated variable declarations");
        generated_var_decls_r
          %= lit("generated")
          > lit("quantities")
          > lit('{')
          > var_decls_g(true,derived_origin) // -constraints
          > *statement_g(false,derived_origin) // -sampling
          > lit('}');

        using boost::spirit::qi::on_error;
        using boost::spirit::qi::rethrow;
        using namespace boost::spirit::qi::labels;

        on_error<rethrow>(
          program_r,
          program_error_f(
            _1, _2, _3, _4 ,
            "",
            boost::phoenix::ref(var_map_),
            boost::phoenix::ref(error_msgs_)
          )
        );
    }

  }
}

#endif
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <limits>

#include "chrome/browser/jankometer.h"

#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/histogram.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/stats_counters.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/watchdog.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/chrome_switches.h"

using base::TimeDelta;
using base::TimeTicks;

namespace {

// The maximum threshold of delay of the message  before considering it a delay.
// For a debug build, you may want to set IO delay around 500ms.
// For a release build, setting it around 350ms is sensible.
// Visit about:histograms to see what the distribution is on your system, with
// your build. Be sure to do some work to get interesting stats.
// The numbers below came from a warm start (you'll get about 5-10 alarms with
// a cold start), and running the page-cycler for 5 rounds.
#ifdef NDEBUG
const int kMaxUIMessageDelayMs = 350;
const int kMaxIOMessageDelayMs = 200;
#else
const int kMaxUIMessageDelayMs = 500;
const int kMaxIOMessageDelayMs = 400;
#endif

// Maximum processing time (excluding queueing delay) for a message before
// considering it delayed.
const int kMaxMessageProcessingMs = 100;

// TODO(brettw) Consider making this a pref.
const bool kPlaySounds = false;

//------------------------------------------------------------------------------
// Provide a special watchdog to make it easy to set the breakpoint on this
// class only.
class JankWatchdog : public Watchdog {
 public:
  JankWatchdog(const TimeDelta& duration,
               const std::string& thread_watched_name,
               bool enabled)
      : Watchdog(duration, thread_watched_name, enabled),
        thread_name_watched_(thread_watched_name),
        alarm_count_(0) {
  }

  virtual ~JankWatchdog() {}

  virtual void Alarm() {
    // Put break point here if you want to stop threads and look at what caused
    // the jankiness.
    alarm_count_++;
    Watchdog::Alarm();
  }

 private:
  std::string thread_name_watched_;
  int alarm_count_;

  DISALLOW_EVIL_CONSTRUCTORS(JankWatchdog);
};

//------------------------------------------------------------------------------
class JankObserver : public base::RefCountedThreadSafe<JankObserver>,
                     public MessageLoopForUI::Observer {
 public:
  JankObserver(const char* thread_name,
               const TimeDelta& excessive_duration,
               bool watchdog_enable)
      : MaxMessageDelay_(excessive_duration),
        slow_processing_counter_(std::string("Chrome.SlowMsg") + thread_name),
        queueing_delay_counter_(std::string("Chrome.DelayMsg") + thread_name),
        process_times_((std::wstring(L"Chrome.ProcMsgL ")
                        + ASCIIToWide(thread_name)).c_str(), 1, 3600000, 50),
        total_times_((std::wstring(L"Chrome.TotalMsgL ")
                      + ASCIIToWide(thread_name)).c_str(), 1, 3600000, 50),
        total_time_watchdog_(excessive_duration, ASCIIToWide(thread_name),
                             watchdog_enable) {
    process_times_.SetFlags(kUmaTargetedHistogramFlag);
    total_times_.SetFlags(kUmaTargetedHistogramFlag);
  }

  // Attaches the observer to the current thread's message loop. You can only
  // attach to the current thread, so this function can be invoked on another
  // thread to attach it.
  void AttachToCurrentThread() {
    // TODO(darin): support monitoring jankiness on non-UI threads!
    if (MessageLoop::current()->type() == MessageLoop::TYPE_UI)
      MessageLoopForUI::current()->AddObserver(this);
  }

  // Detaches the observer to the current thread's message loop.
  void DetachFromCurrentThread() {
    if (MessageLoop::current()->type() == MessageLoop::TYPE_UI)
      MessageLoopForUI::current()->RemoveObserver(this);
  }

  void WillProcessMessage(const MSG& msg) {
    begin_process_message_ = TimeTicks::Now();

    // GetMessageTime returns a LONG (signed 32-bit) and GetTickCount returns
    // a DWORD (unsigned 32-bit). They both wrap around when the time is longer
    // than they can hold. I'm not sure if GetMessageTime wraps around to 0,
    // or if the original time comes from GetTickCount, it might wrap around
    // to -1.
    //
    // Therefore, I cast to DWORD so if it wraps to -1 we will correct it. If
    // it doesn't, then our time delta will be negative if a message happens
    // to straddle the wraparound point, it will still be OK.
    DWORD cur_message_issue_time = static_cast<DWORD>(msg.time);
    DWORD cur_time = GetTickCount();
    queueing_time_ = TimeDelta::FromMilliseconds(cur_time
                                                 - cur_message_issue_time);
    // Simulate arming when the message entered the queue.
    total_time_watchdog_.ArmSomeTimeDeltaAgo(queueing_time_);
    if (queueing_time_ > MaxMessageDelay_) {
      // Message is too delayed.
      queueing_delay_counter_.Increment();
      if (kPlaySounds)
        MessageBeep(MB_ICONASTERISK);
    }
  }

  void DidProcessMessage(const MSG& msg) {
    total_time_watchdog_.Disarm();
    TimeTicks now = TimeTicks::Now();
    if (begin_process_message_ != TimeTicks()) {
      TimeDelta processing_time = now - begin_process_message_;
      process_times_.AddTime(processing_time);
      total_times_.AddTime(queueing_time_ + processing_time);
    }
    if (now - begin_process_message_ >
        TimeDelta::FromMilliseconds(kMaxMessageProcessingMs)) {
      // Message took too long to process.
      slow_processing_counter_.Increment();
      if (kPlaySounds)
        MessageBeep(MB_ICONHAND);
    }
  }

 private:
  const TimeDelta MaxMessageDelay_;
  TimeTicks begin_process_message_;
  TimeDelta queueing_time_;

  // Counters for the two types of jank we measure.
  StatsCounter slow_processing_counter_;  // Messages with long processing time.
  StatsCounter queueing_delay_counter_;   // Messages with long queueing delay.
  Histogram process_times_;           // Time spent processing task.
  Histogram total_times_;             // Total of queueing plus processing time.
  JankWatchdog total_time_watchdog_;  // Watching for excessive total_time.

  DISALLOW_EVIL_CONSTRUCTORS(JankObserver);
};

// These objects are created by InstallJankometer and leaked.
JankObserver* ui_observer = NULL;
JankObserver* io_observer = NULL;

}  // namespace

void InstallJankometer(const CommandLine &parsed_command_line) {
  if (ui_observer || io_observer) {
    NOTREACHED() << "Initializing jank-o-meter twice";
    return;
  }

  bool ui_watchdog_enabled = false;
  bool io_watchdog_enabled = false;
  if (parsed_command_line.HasSwitch(switches::kEnableWatchdog)) {
    std::wstring list =
        parsed_command_line.GetSwitchValue(switches::kEnableWatchdog);
    if (list.npos != list.find(L"ui"))
      ui_watchdog_enabled = true;
    if (list.npos != list.find(L"io"))
      io_watchdog_enabled = true;
  }

  // Install on the UI thread.
  ui_observer = new JankObserver(
      "UI",
      TimeDelta::FromMilliseconds(kMaxUIMessageDelayMs),
      ui_watchdog_enabled);
  ui_observer->AddRef();
  ui_observer->AttachToCurrentThread();

  // Now install on the I/O thread. Hiccups on that thread will block
  // interaction with web pages. We must proxy to that thread before we can
  // add our observer.
  io_observer = new JankObserver(
      "IO",
      TimeDelta::FromMilliseconds(kMaxIOMessageDelayMs),
      io_watchdog_enabled);
  io_observer->AddRef();
  base::Thread* io_thread = g_browser_process->io_thread();
  if (io_thread) {
    io_thread->message_loop()->PostTask(FROM_HERE,
        NewRunnableMethod(io_observer,
            &JankObserver::AttachToCurrentThread));
  }
}

void UninstallJankometer() {
  if (ui_observer) {
    ui_observer->DetachFromCurrentThread();
    ui_observer->Release();
    ui_observer = NULL;
  }
  if (io_observer) {
    // IO thread can't be running when we remove observers.
    DCHECK((!g_browser_process) || !(g_browser_process->io_thread()));
    io_observer->Release();
    io_observer = NULL;
  }
}

<commit_msg>Build fix.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <limits>

#include "chrome/browser/jankometer.h"

#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/histogram.h"
#include "base/message_loop.h"
#include "base/ref_counted.h"
#include "base/stats_counters.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/watchdog.h"
#include "chrome/browser/browser_process.h"
#include "chrome/common/chrome_switches.h"

using base::TimeDelta;
using base::TimeTicks;

namespace {

// The maximum threshold of delay of the message  before considering it a delay.
// For a debug build, you may want to set IO delay around 500ms.
// For a release build, setting it around 350ms is sensible.
// Visit about:histograms to see what the distribution is on your system, with
// your build. Be sure to do some work to get interesting stats.
// The numbers below came from a warm start (you'll get about 5-10 alarms with
// a cold start), and running the page-cycler for 5 rounds.
#ifdef NDEBUG
const int kMaxUIMessageDelayMs = 350;
const int kMaxIOMessageDelayMs = 200;
#else
const int kMaxUIMessageDelayMs = 500;
const int kMaxIOMessageDelayMs = 400;
#endif

// Maximum processing time (excluding queueing delay) for a message before
// considering it delayed.
const int kMaxMessageProcessingMs = 100;

// TODO(brettw) Consider making this a pref.
const bool kPlaySounds = false;

//------------------------------------------------------------------------------
// Provide a special watchdog to make it easy to set the breakpoint on this
// class only.
class JankWatchdog : public Watchdog {
 public:
  JankWatchdog(const TimeDelta& duration,
               const std::string& thread_watched_name,
               bool enabled)
      : Watchdog(duration, ASCIIToWide(thread_watched_name), enabled),
        thread_name_watched_(thread_watched_name),
        alarm_count_(0) {
  }

  virtual ~JankWatchdog() {}

  virtual void Alarm() {
    // Put break point here if you want to stop threads and look at what caused
    // the jankiness.
    alarm_count_++;
    Watchdog::Alarm();
  }

 private:
  std::string thread_name_watched_;
  int alarm_count_;

  DISALLOW_EVIL_CONSTRUCTORS(JankWatchdog);
};

//------------------------------------------------------------------------------
class JankObserver : public base::RefCountedThreadSafe<JankObserver>,
                     public MessageLoopForUI::Observer {
 public:
  JankObserver(const char* thread_name,
               const TimeDelta& excessive_duration,
               bool watchdog_enable)
      : MaxMessageDelay_(excessive_duration),
        slow_processing_counter_(std::string("Chrome.SlowMsg") + thread_name),
        queueing_delay_counter_(std::string("Chrome.DelayMsg") + thread_name),
        process_times_((std::wstring(L"Chrome.ProcMsgL ")
                        + ASCIIToWide(thread_name)).c_str(), 1, 3600000, 50),
        total_times_((std::wstring(L"Chrome.TotalMsgL ")
                      + ASCIIToWide(thread_name)).c_str(), 1, 3600000, 50),
        total_time_watchdog_(excessive_duration, ASCIIToWide(thread_name),
                             watchdog_enable) {
    process_times_.SetFlags(kUmaTargetedHistogramFlag);
    total_times_.SetFlags(kUmaTargetedHistogramFlag);
  }

  // Attaches the observer to the current thread's message loop. You can only
  // attach to the current thread, so this function can be invoked on another
  // thread to attach it.
  void AttachToCurrentThread() {
    // TODO(darin): support monitoring jankiness on non-UI threads!
    if (MessageLoop::current()->type() == MessageLoop::TYPE_UI)
      MessageLoopForUI::current()->AddObserver(this);
  }

  // Detaches the observer to the current thread's message loop.
  void DetachFromCurrentThread() {
    if (MessageLoop::current()->type() == MessageLoop::TYPE_UI)
      MessageLoopForUI::current()->RemoveObserver(this);
  }

  void WillProcessMessage(const MSG& msg) {
    begin_process_message_ = TimeTicks::Now();

    // GetMessageTime returns a LONG (signed 32-bit) and GetTickCount returns
    // a DWORD (unsigned 32-bit). They both wrap around when the time is longer
    // than they can hold. I'm not sure if GetMessageTime wraps around to 0,
    // or if the original time comes from GetTickCount, it might wrap around
    // to -1.
    //
    // Therefore, I cast to DWORD so if it wraps to -1 we will correct it. If
    // it doesn't, then our time delta will be negative if a message happens
    // to straddle the wraparound point, it will still be OK.
    DWORD cur_message_issue_time = static_cast<DWORD>(msg.time);
    DWORD cur_time = GetTickCount();
    queueing_time_ = TimeDelta::FromMilliseconds(cur_time
                                                 - cur_message_issue_time);
    // Simulate arming when the message entered the queue.
    total_time_watchdog_.ArmSomeTimeDeltaAgo(queueing_time_);
    if (queueing_time_ > MaxMessageDelay_) {
      // Message is too delayed.
      queueing_delay_counter_.Increment();
      if (kPlaySounds)
        MessageBeep(MB_ICONASTERISK);
    }
  }

  void DidProcessMessage(const MSG& msg) {
    total_time_watchdog_.Disarm();
    TimeTicks now = TimeTicks::Now();
    if (begin_process_message_ != TimeTicks()) {
      TimeDelta processing_time = now - begin_process_message_;
      process_times_.AddTime(processing_time);
      total_times_.AddTime(queueing_time_ + processing_time);
    }
    if (now - begin_process_message_ >
        TimeDelta::FromMilliseconds(kMaxMessageProcessingMs)) {
      // Message took too long to process.
      slow_processing_counter_.Increment();
      if (kPlaySounds)
        MessageBeep(MB_ICONHAND);
    }
  }

 private:
  const TimeDelta MaxMessageDelay_;
  TimeTicks begin_process_message_;
  TimeDelta queueing_time_;

  // Counters for the two types of jank we measure.
  StatsCounter slow_processing_counter_;  // Messages with long processing time.
  StatsCounter queueing_delay_counter_;   // Messages with long queueing delay.
  Histogram process_times_;           // Time spent processing task.
  Histogram total_times_;             // Total of queueing plus processing time.
  JankWatchdog total_time_watchdog_;  // Watching for excessive total_time.

  DISALLOW_EVIL_CONSTRUCTORS(JankObserver);
};

// These objects are created by InstallJankometer and leaked.
JankObserver* ui_observer = NULL;
JankObserver* io_observer = NULL;

}  // namespace

void InstallJankometer(const CommandLine &parsed_command_line) {
  if (ui_observer || io_observer) {
    NOTREACHED() << "Initializing jank-o-meter twice";
    return;
  }

  bool ui_watchdog_enabled = false;
  bool io_watchdog_enabled = false;
  if (parsed_command_line.HasSwitch(switches::kEnableWatchdog)) {
    std::wstring list =
        parsed_command_line.GetSwitchValue(switches::kEnableWatchdog);
    if (list.npos != list.find(L"ui"))
      ui_watchdog_enabled = true;
    if (list.npos != list.find(L"io"))
      io_watchdog_enabled = true;
  }

  // Install on the UI thread.
  ui_observer = new JankObserver(
      "UI",
      TimeDelta::FromMilliseconds(kMaxUIMessageDelayMs),
      ui_watchdog_enabled);
  ui_observer->AddRef();
  ui_observer->AttachToCurrentThread();

  // Now install on the I/O thread. Hiccups on that thread will block
  // interaction with web pages. We must proxy to that thread before we can
  // add our observer.
  io_observer = new JankObserver(
      "IO",
      TimeDelta::FromMilliseconds(kMaxIOMessageDelayMs),
      io_watchdog_enabled);
  io_observer->AddRef();
  base::Thread* io_thread = g_browser_process->io_thread();
  if (io_thread) {
    io_thread->message_loop()->PostTask(FROM_HERE,
        NewRunnableMethod(io_observer,
            &JankObserver::AttachToCurrentThread));
  }
}

void UninstallJankometer() {
  if (ui_observer) {
    ui_observer->DetachFromCurrentThread();
    ui_observer->Release();
    ui_observer = NULL;
  }
  if (io_observer) {
    // IO thread can't be running when we remove observers.
    DCHECK((!g_browser_process) || !(g_browser_process->io_thread()));
    io_observer->Release();
    io_observer = NULL;
  }
}

<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/ipc_logging.h"

#if defined(OS_POSIX)
#ifdef IPC_MESSAGE_LOG_ENABLED
// This will cause render_messages.h etc to define ViewMsgLog and friends.
#define IPC_MESSAGE_MACROS_LOG_ENABLED
#endif
#endif

#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/waitable_event.h"
#include "base/waitable_event_watcher.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/ipc_sync_message.h"
#include "chrome/common/ipc_message_utils.h"

// This include list should contain all _messages.h header files so that they
// can get *MsgLog function etc. This makes ipc logs much more informative.
#include "chrome/common/render_messages.h"
#include "chrome/test/automation/automation_messages.h"

#if defined(OS_WIN)
// Pulling this file in Mac/Linux causes a lot of binaries to need to bring in
// WebKit and all the dependencies, which results in a very large number of
// linker errors.
#include "chrome/common/plugin_messages.h"
#endif

#if defined(OS_POSIX)
#include "base/string_util.h"
#include <unistd.h>
#endif

#ifdef IPC_MESSAGE_LOG_ENABLED

using base::Time;

// IPC::Logging is allocated as a singleton, so we don't need any kind of
// special retention program.
template <>
struct RunnableMethodTraits<IPC::Logging> {
  static void RetainCallee(IPC::Logging*) {}
  static void ReleaseCallee(IPC::Logging*) {}
};

namespace IPC {

const wchar_t kLoggingEventName[] = L"ChromeIPCLog.%d";
const int kLogSendDelayMs = 100;

// We use a pointer to the function table to avoid any linker dependencies on
// all the traits used as IPC message parameters.
Logging::LogFunction *Logging::log_function_mapping_;

Logging::Logging()
    : logging_event_on_(NULL),
      logging_event_off_(NULL),
      enabled_(false),
      queue_invoke_later_pending_(false),
      sender_(NULL),
      main_thread_(MessageLoop::current()),
      consumer_(NULL) {
  // Create an event for this browser instance that's set when logging is
  // enabled, so child processes can know when logging is enabled.

#if defined(OS_WIN)
  // On Windows we have a couple of named events which switch logging on and
  // off.
  int browser_pid;
  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  std::wstring process_type =
    parsed_command_line.GetSwitchValue(switches::kProcessType);
  if (process_type.empty()) {
    browser_pid = GetCurrentProcessId();
  } else {
    std::wstring channel_name =
        parsed_command_line.GetSwitchValue(switches::kProcessChannelID);

    browser_pid = _wtoi(channel_name.c_str());
    DCHECK(browser_pid != 0);
  }

  std::wstring event_name = GetEventName(browser_pid, true);
  logging_event_on_.reset(new base::WaitableEvent(
      CreateEvent(NULL, TRUE, FALSE, event_name.c_str())));

  event_name = GetEventName(browser_pid, false);
  logging_event_off_.reset(new base::WaitableEvent(
      CreateEvent(NULL, TRUE, FALSE, event_name.c_str())));

  RegisterWaitForEvent(true);
#elif defined(OS_POSIX)
  if (getenv("CHROME_IPC_LOGGING"))
    enabled_ = true;
  SetLoggerFunctions(g_log_function_mapping);
#endif

  MessageLoop::current()->AddDestructionObserver(this);
}

Logging::~Logging() {
}

Logging* Logging::current() {
  return Singleton<Logging>::get();
}

void Logging::RegisterWaitForEvent(bool enabled) {
  watcher_.StopWatching();
  watcher_.StartWatching(
      enabled ? logging_event_on_.get() : logging_event_off_.get(), this);
}

void Logging::OnWaitableEventSignaled(base::WaitableEvent* event) {
  enabled_ = event == logging_event_on_.get();
  RegisterWaitForEvent(!enabled_);
}

void Logging::WillDestroyCurrentMessageLoop() {
  watcher_.StopWatching();
}

void Logging::SetLoggerFunctions(LogFunction *functions) {
  log_function_mapping_ = functions;
}

#if defined(OS_WIN)
std::wstring Logging::GetEventName(bool enabled) {
  return current()->GetEventName(GetCurrentProcessId(), enabled);
}
#endif

std::wstring Logging::GetEventName(int browser_pid, bool enabled) {
  std::wstring result = StringPrintf(kLoggingEventName, browser_pid);
  result += enabled ? L"on" : L"off";
  return result;
}

void Logging::SetConsumer(Consumer* consumer) {
  consumer_ = consumer;
}

void Logging::Enable() {
  logging_event_off_->Reset();
  logging_event_on_->Signal();
}

void Logging::Disable() {
  logging_event_on_->Reset();
  logging_event_off_->Signal();
}

void Logging::OnSendLogs() {
  queue_invoke_later_pending_ = false;
  if (!sender_)
    return;

  Message* msg = new Message(
      MSG_ROUTING_CONTROL, IPC_LOGGING_ID, Message::PRIORITY_NORMAL);
  WriteParam(msg, queued_logs_);
  queued_logs_.clear();
  sender_->Send(msg);
}

void Logging::SetIPCSender(IPC::Message::Sender* sender) {
  sender_ = sender;
}

void Logging::OnReceivedLoggingMessage(const Message& message) {
  std::vector<LogData> data;
  void* iter = NULL;
  if (!ReadParam(&message, &iter, &data))
    return;

  for (size_t i = 0; i < data.size(); ++i) {
    Log(data[i]);
  }
}

void Logging::OnSendMessage(Message* message, const std::string& channel_id) {
  if (!Enabled())
    return;

  if (message->is_reply()) {
    LogData* data = message->sync_log_data();
    if (!data)
      return;

    // This is actually the delayed reply to a sync message.  Create a string
    // of the output parameters, add it to the LogData that was earlier stashed
    // with the reply, and log the result.
    data->channel = channel_id;
    GenerateLogData("", *message, data);
    Log(*data);
    delete data;
    message->set_sync_log_data(NULL);
  } else {
    // If the time has already been set (i.e. by ChannelProxy), keep that time
    // instead as it's more accurate.
    if (!message->sent_time())
      message->set_sent_time(Time::Now().ToInternalValue());
  }
}

void Logging::OnPreDispatchMessage(const Message& message) {
  message.set_received_time(Time::Now().ToInternalValue());
}

void Logging::OnPostDispatchMessage(const Message& message,
                                    const std::string& channel_id) {
  if (!Enabled() ||
#if defined(OS_WIN)
      !message.sent_time() ||
#endif
      message.dont_log())
    return;

  LogData data;
  GenerateLogData(channel_id, message, &data);

  if (MessageLoop::current() == main_thread_) {
    Log(data);
  } else {
    main_thread_->PostTask(FROM_HERE, NewRunnableMethod(
        this, &Logging::Log, data));
  }
}

void Logging::GetMessageText(uint16 type, std::wstring* name,
                             const Message* message,
                             std::wstring* params) {
  if (!log_function_mapping_)
    return;

  int message_class = type >> 12;
  if (log_function_mapping_[message_class] != NULL) {
    log_function_mapping_[message_class](type, name, message, params);
  } else {
    DLOG(INFO) << "No logger function associated with message class " <<
        message_class;
  }
}

void Logging::Log(const LogData& data) {
#if defined(OS_WIN)
  if (consumer_) {
    // We're in the browser process.
    consumer_->Log(data);
  } else {
    // We're in the renderer or plugin processes.
    if (sender_) {
      queued_logs_.push_back(data);
      if (!queue_invoke_later_pending_) {
        queue_invoke_later_pending_ = true;
        MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
            this, &Logging::OnSendLogs), kLogSendDelayMs);
      }
    }
  }
#elif defined(OS_POSIX)
  // On POSIX, for now, we just dump the log to stderr
  fprintf(stderr, "ipc %s %d %d %s %s %s\n",
          data.channel.c_str(),
          data.routing_id,
          data.type,
          WideToUTF8(data.flags).c_str(),
          WideToUTF8(data.message_name).c_str(),
          WideToUTF8(data.params).c_str());
#endif
}

void GenerateLogData(const std::string& channel, const Message& message,
                     LogData* data) {
  if (message.is_reply()) {
    // "data" should already be filled in.
    std::wstring params;
    Logging::GetMessageText(data->type, NULL, &message, &params);

    if (!data->params.empty() && !params.empty())
      data->params += L", ";

    data->flags += L" DR";

    data->params += params;
  } else {
    std::wstring flags;
    if (message.is_sync())
      flags = L"S";

    if (message.is_reply())
      flags += L"R";

    if (message.is_reply_error())
      flags += L"E";

    std::wstring params, message_name;
    Logging::GetMessageText(message.type(), &message_name, &message, &params);

    data->channel = channel;
    data->routing_id = message.routing_id();
    data->type = message.type();
    data->flags = flags;
    data->sent = message.sent_time();
    data->receive = message.received_time();
    data->dispatch = Time::Now().ToInternalValue();
    data->params = params;
    data->message_name = message_name;
  }
}

}

#endif  // IPC_MESSAGE_LOG_ENABLED
<commit_msg>ipc: pull in more message headers into ipc_logging<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/ipc_logging.h"

#if defined(OS_POSIX)
#ifdef IPC_MESSAGE_LOG_ENABLED
// This will cause render_messages.h etc to define ViewMsgLog and friends.
#define IPC_MESSAGE_MACROS_LOG_ENABLED
#endif
#endif

#include "base/command_line.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/time.h"
#include "base/waitable_event.h"
#include "base/waitable_event_watcher.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/ipc_sync_message.h"
#include "chrome/common/ipc_message_utils.h"

// This include list should contain all _messages.h header files so that they
// can get *MsgLog function etc. This makes ipc logs much more informative.
#include "chrome/common/plugin_messages.h"
#include "chrome/common/render_messages.h"
#include "chrome/common/worker_messages.h"
#include "chrome/test/automation/automation_messages.h"

#if defined(OS_POSIX)
#include "base/string_util.h"
#include <unistd.h>
#endif

#ifdef IPC_MESSAGE_LOG_ENABLED

using base::Time;

// IPC::Logging is allocated as a singleton, so we don't need any kind of
// special retention program.
template <>
struct RunnableMethodTraits<IPC::Logging> {
  static void RetainCallee(IPC::Logging*) {}
  static void ReleaseCallee(IPC::Logging*) {}
};

namespace IPC {

const wchar_t kLoggingEventName[] = L"ChromeIPCLog.%d";
const int kLogSendDelayMs = 100;

// We use a pointer to the function table to avoid any linker dependencies on
// all the traits used as IPC message parameters.
Logging::LogFunction *Logging::log_function_mapping_;

Logging::Logging()
    : logging_event_on_(NULL),
      logging_event_off_(NULL),
      enabled_(false),
      queue_invoke_later_pending_(false),
      sender_(NULL),
      main_thread_(MessageLoop::current()),
      consumer_(NULL) {
  // Create an event for this browser instance that's set when logging is
  // enabled, so child processes can know when logging is enabled.

#if defined(OS_WIN)
  // On Windows we have a couple of named events which switch logging on and
  // off.
  int browser_pid;
  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  std::wstring process_type =
    parsed_command_line.GetSwitchValue(switches::kProcessType);
  if (process_type.empty()) {
    browser_pid = GetCurrentProcessId();
  } else {
    std::wstring channel_name =
        parsed_command_line.GetSwitchValue(switches::kProcessChannelID);

    browser_pid = _wtoi(channel_name.c_str());
    DCHECK(browser_pid != 0);
  }

  std::wstring event_name = GetEventName(browser_pid, true);
  logging_event_on_.reset(new base::WaitableEvent(
      CreateEvent(NULL, TRUE, FALSE, event_name.c_str())));

  event_name = GetEventName(browser_pid, false);
  logging_event_off_.reset(new base::WaitableEvent(
      CreateEvent(NULL, TRUE, FALSE, event_name.c_str())));

  RegisterWaitForEvent(true);
#elif defined(OS_POSIX)
  if (getenv("CHROME_IPC_LOGGING"))
    enabled_ = true;
  SetLoggerFunctions(g_log_function_mapping);
#endif

  MessageLoop::current()->AddDestructionObserver(this);
}

Logging::~Logging() {
}

Logging* Logging::current() {
  return Singleton<Logging>::get();
}

void Logging::RegisterWaitForEvent(bool enabled) {
  watcher_.StopWatching();
  watcher_.StartWatching(
      enabled ? logging_event_on_.get() : logging_event_off_.get(), this);
}

void Logging::OnWaitableEventSignaled(base::WaitableEvent* event) {
  enabled_ = event == logging_event_on_.get();
  RegisterWaitForEvent(!enabled_);
}

void Logging::WillDestroyCurrentMessageLoop() {
  watcher_.StopWatching();
}

void Logging::SetLoggerFunctions(LogFunction *functions) {
  log_function_mapping_ = functions;
}

#if defined(OS_WIN)
std::wstring Logging::GetEventName(bool enabled) {
  return current()->GetEventName(GetCurrentProcessId(), enabled);
}
#endif

std::wstring Logging::GetEventName(int browser_pid, bool enabled) {
  std::wstring result = StringPrintf(kLoggingEventName, browser_pid);
  result += enabled ? L"on" : L"off";
  return result;
}

void Logging::SetConsumer(Consumer* consumer) {
  consumer_ = consumer;
}

void Logging::Enable() {
  logging_event_off_->Reset();
  logging_event_on_->Signal();
}

void Logging::Disable() {
  logging_event_on_->Reset();
  logging_event_off_->Signal();
}

void Logging::OnSendLogs() {
  queue_invoke_later_pending_ = false;
  if (!sender_)
    return;

  Message* msg = new Message(
      MSG_ROUTING_CONTROL, IPC_LOGGING_ID, Message::PRIORITY_NORMAL);
  WriteParam(msg, queued_logs_);
  queued_logs_.clear();
  sender_->Send(msg);
}

void Logging::SetIPCSender(IPC::Message::Sender* sender) {
  sender_ = sender;
}

void Logging::OnReceivedLoggingMessage(const Message& message) {
  std::vector<LogData> data;
  void* iter = NULL;
  if (!ReadParam(&message, &iter, &data))
    return;

  for (size_t i = 0; i < data.size(); ++i) {
    Log(data[i]);
  }
}

void Logging::OnSendMessage(Message* message, const std::string& channel_id) {
  if (!Enabled())
    return;

  if (message->is_reply()) {
    LogData* data = message->sync_log_data();
    if (!data)
      return;

    // This is actually the delayed reply to a sync message.  Create a string
    // of the output parameters, add it to the LogData that was earlier stashed
    // with the reply, and log the result.
    data->channel = channel_id;
    GenerateLogData("", *message, data);
    Log(*data);
    delete data;
    message->set_sync_log_data(NULL);
  } else {
    // If the time has already been set (i.e. by ChannelProxy), keep that time
    // instead as it's more accurate.
    if (!message->sent_time())
      message->set_sent_time(Time::Now().ToInternalValue());
  }
}

void Logging::OnPreDispatchMessage(const Message& message) {
  message.set_received_time(Time::Now().ToInternalValue());
}

void Logging::OnPostDispatchMessage(const Message& message,
                                    const std::string& channel_id) {
  if (!Enabled() ||
#if defined(OS_WIN)
      !message.sent_time() ||
#endif
      message.dont_log())
    return;

  LogData data;
  GenerateLogData(channel_id, message, &data);

  if (MessageLoop::current() == main_thread_) {
    Log(data);
  } else {
    main_thread_->PostTask(FROM_HERE, NewRunnableMethod(
        this, &Logging::Log, data));
  }
}

void Logging::GetMessageText(uint16 type, std::wstring* name,
                             const Message* message,
                             std::wstring* params) {
  if (!log_function_mapping_)
    return;

  int message_class = type >> 12;
  if (log_function_mapping_[message_class] != NULL) {
    log_function_mapping_[message_class](type, name, message, params);
  } else {
    DLOG(INFO) << "No logger function associated with message class " <<
        message_class;
  }
}

void Logging::Log(const LogData& data) {
#if defined(OS_WIN)
  if (consumer_) {
    // We're in the browser process.
    consumer_->Log(data);
  } else {
    // We're in the renderer or plugin processes.
    if (sender_) {
      queued_logs_.push_back(data);
      if (!queue_invoke_later_pending_) {
        queue_invoke_later_pending_ = true;
        MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
            this, &Logging::OnSendLogs), kLogSendDelayMs);
      }
    }
  }
#elif defined(OS_POSIX)
  // On POSIX, for now, we just dump the log to stderr
  fprintf(stderr, "ipc %s %d %d %s %s %s\n",
          data.channel.c_str(),
          data.routing_id,
          data.type,
          WideToUTF8(data.flags).c_str(),
          WideToUTF8(data.message_name).c_str(),
          WideToUTF8(data.params).c_str());
#endif
}

void GenerateLogData(const std::string& channel, const Message& message,
                     LogData* data) {
  if (message.is_reply()) {
    // "data" should already be filled in.
    std::wstring params;
    Logging::GetMessageText(data->type, NULL, &message, &params);

    if (!data->params.empty() && !params.empty())
      data->params += L", ";

    data->flags += L" DR";

    data->params += params;
  } else {
    std::wstring flags;
    if (message.is_sync())
      flags = L"S";

    if (message.is_reply())
      flags += L"R";

    if (message.is_reply_error())
      flags += L"E";

    std::wstring params, message_name;
    Logging::GetMessageText(message.type(), &message_name, &message, &params);

    data->channel = channel;
    data->routing_id = message.routing_id();
    data->type = message.type();
    data->flags = flags;
    data->sent = message.sent_time();
    data->receive = message.received_time();
    data->dispatch = Time::Now().ToInternalValue();
    data->params = params;
    data->message_name = message_name;
  }
}

}

#endif  // IPC_MESSAGE_LOG_ENABLED
<|endoftext|>


<commit_before>#ifndef __ciri_errorcodes__
#define __ciri_errorcodes__

#include <unordered_map>

namespace ciri {
	namespace err {
		enum ErrorCode : int {
			CIRI_OK = 0,
			CIRI_UNKNOWN_ERROR					= -1,
			CIRI_FILE_NOT_FOUND					= -2,
			CIRI_PATH_NOT_FOUND					= -3,
			CIRI_SHADER_COMPILE_FAILED	=	-4,
			CIRI_SHADER_LINK_FAILED			=	-5,
			CIRI_SHADER_INCOMPLETE			=	-6,
			CIRI_SHADER_INVALID					=	-7,
			CIRI_INVALID_ARGUMENT				= -8,
			CIRI_NOT_IMPLEMENTED				=	-9
		};

		static std::unordered_map<ErrorCode, const char*> errorStrings = {
			{ CIRI_OK, "No error" },
			{ CIRI_UNKNOWN_ERROR, "Unknown error" },
			{ CIRI_FILE_NOT_FOUND, "File not found" },
			{ CIRI_PATH_NOT_FOUND, "Path not found" },
			{ CIRI_SHADER_COMPILE_FAILED, "Shader compile failed" },
			{ CIRI_SHADER_LINK_FAILED, "Shader link failed" },
			{ CIRI_SHADER_INCOMPLETE, "Shader data incomplete" },
			{ CIRI_SHADER_INVALID, "Shader is invalid" },
			{ CIRI_INVALID_ARGUMENT, "Invalid argument" },
			{ CIRI_NOT_IMPLEMENTED, "Not yet implemented" }
		};

		static bool success( const ErrorCode& code ) {
			return CIRI_OK == code;
		}

		static bool failed( const ErrorCode& code ) {
			return code != CIRI_OK;
		}

		static const char* getString( const ErrorCode& code ) {
			return errorStrings[code];
		}
	}
} // ciri

#endif /* __ciri_errorcodes__ */<commit_msg>Added two new error codes: CIRI_STATIC_BUFFER_AS_DYNAMIC for when attempting to remap a static buffer, and CIRI_BUFFER_MAP_FAILED for when mapping of an existing buffer fails (this currently does not happen in GL because subresource data is updated rather than using the DX-like mapping method, which I may switch to in the future, unsure right now).<commit_after>#ifndef __ciri_errorcodes__
#define __ciri_errorcodes__

#include <unordered_map>

namespace ciri {
	namespace err {
		enum ErrorCode : int {
			CIRI_OK = 0,
			CIRI_UNKNOWN_ERROR						= -1,
			CIRI_FILE_NOT_FOUND						= -2,
			CIRI_PATH_NOT_FOUND						= -3,
			CIRI_SHADER_COMPILE_FAILED		=	-4,
			CIRI_SHADER_LINK_FAILED				=	-5,
			CIRI_SHADER_INCOMPLETE				=	-6,
			CIRI_SHADER_INVALID						=	-7,
			CIRI_INVALID_ARGUMENT					= -8,
			CIRI_STATIC_BUFFER_AS_DYNAMIC = -9,
			CIRI_BUFFER_MAP_FAILED				= -10,
			CIRI_NOT_IMPLEMENTED					=	-11
		};

		static std::unordered_map<ErrorCode, const char*> errorStrings = {
			{ CIRI_OK, "No error" },
			{ CIRI_UNKNOWN_ERROR, "Unknown error" },
			{ CIRI_FILE_NOT_FOUND, "File not found" },
			{ CIRI_PATH_NOT_FOUND, "Path not found" },
			{ CIRI_SHADER_COMPILE_FAILED, "Shader compile failed" },
			{ CIRI_SHADER_LINK_FAILED, "Shader link failed" },
			{ CIRI_SHADER_INCOMPLETE, "Shader data incomplete" },
			{ CIRI_SHADER_INVALID, "Shader is invalid" },
			{ CIRI_INVALID_ARGUMENT, "Invalid argument" },
			{ CIRI_STATIC_BUFFER_AS_DYNAMIC, "Attempted to treat a static buffer as a dynamic buffer" },
			{ CIRI_BUFFER_MAP_FAILED, "Failed to map a buffer" },
			{ CIRI_NOT_IMPLEMENTED, "Not yet implemented" }
		};

		static bool success( const ErrorCode& code ) {
			return CIRI_OK == code;
		}

		static bool failed( const ErrorCode& code ) {
			return code != CIRI_OK;
		}

		static const char* getString( const ErrorCode& code ) {
			return errorStrings[code];
		}
	}
} // ciri

#endif /* __ciri_errorcodes__ */<|endoftext|>


<commit_before>#define MYSQLPP_NOT_HEADER
#include "platform.h"

#include "field_names.h"

#include "result2.hh"

void FieldNames::init(const ResUse *res) {
  int num = res->num_fields();
  reserve(num);
  for (int i = 0; i < num; i++) {
		std::string p(res->fields()[i].name); str_to_lwr(p);   push_back(p);
  }

}

<commit_msg>- #include filename fix - Code style improvements<commit_after>#define MYSQLPP_NOT_HEADER
#include "platform.h"

#include "field_names.h"

#include "result.h"

void FieldNames::init(const ResUse *res)
{
  int num = res->num_fields();
  reserve(num);
  for (int i = 0; i < num; i++) {
		std::string p(res->fields()[i].name);
		str_to_lwr(p);
		push_back(p);
  }
}

<|endoftext|>


<commit_before>#include <iostream>
#include <random>
#include <stdlib.h>
#define SIZEF 500

struct Position{
  int x = 0;
  int y = 0;
};

using namespace std;

int walk(Position *p,int (&board)[SIZEF][SIZEF],int size){
  //https://stackoverflow.com/questions/5008804/generating-random-integer-from-a-range
  random_device rd;
  mt19937_64 gen(rd());
  //http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
  uniform_real_distribution<> uni(0,99.9);
  // cout << uni(gen)<<"\n";
  double random = uni(gen);
  int pass = 0;
  while(1){
    random = fmod(random,100);
    // cout << board[1][2]<<" BOARD[1][2]\n";
    // cout << board[2][1]<<" BOARD[2][1]\n";
    // cout << p->x+1<<" p.x\n";
    // cout << p->y<<" p.y\n";
    // if ((random >= 25)&&(random < 37.5)) {
    //   cout << "rnd: "<<random<<"\n";
    // }
    if ((0 <= random)&&(random < 12.5)) { // move 1
      if((p->x-2>=0)&&(p->y+1<size)){
        if (board[p->x-2][p->y+1] == 0) {
          // cout << "oi!1" << '\n';
          p->x-=2;
          p->y+=1;
          return 0;
        }
      }
      pass++;
    }else if ((12.5 <= random)&&(random < 25)){ // move 2
      if((p->x-1>=0)&&(p->y+2<size)){
        if (board[p->x-1][p->y+2] == 0) {
          // cout << "oi!2" << '\n';
          p->x-=1;
          p->y+=2;
          return 0;
        }
      }
      pass++;
    }else if ((25 <= random)&&(random< 37.5)){ // move 3
      if((p->x+1<size)&&(p->y+2<size)){
        if (board[p->x+1][p->y+2] == 0) {
          // cout << "oi!3" << '\n';
          p->x+=1;
          p->y+=2;
          return 0;
        }
      }
      pass++;
    }else if ((37.5 <= random)&&(random < 50)){ // move 4
      if((p->x+2<size)&&(p->y+1<size)){
        if (board[p->x+2][p->y+1] == 0) {
          // cout << "oi!4" << '\n';
          p->x+=2;
          p->y+=1;
          return 0;
        }
      }
      pass++;
    }else if ((50 <= random)&&(random < 62.5)){ // move 5
      if((p->x+2<size)&&(p->y-1>=0)){
        if (board[p->x+2][p->y-1] == 0) {
          // cout << "oi!5" << '\n';
          p->x+=2;
          p->y-=1;
          return 0;
        }
      }
      pass++;
    }else if ((62.5 <= random)&&(random < 75)){ // move 6
      if((p->x+1<size)&&(p->y-2>=0)){
        if (board[p->x+1][p->y-2] == 0) {
          // cout << "oi!6" << '\n';
          p->x+=1;
          p->y-=2;
          return 0;
        }
      }
      pass++;
    }else if ((75 <= random)&&(random < 87.5)){ // move 7
      if((p->x-1>=0)&&(p->y-2>=0)){
        if (board[p->x-1][p->y-2] == 0) {
          // cout << "oi!7" << '\n';
          p->x-=1;
          p->y-=2;
          return 0;
        }
      }
      pass++;
    }else{ // move 8
      if((p->x-2>=0)&&(p->y-1>=0)){
        if (board[p->x-2][p->y-1] == 0) {
          // cout << "oi!8" << '\n';
          p->x-=2;
          p->y-=1;
          return 0;
        }
      }
      pass++;
    }

    random+=12.5;
    if (pass == 8) {
      return 1;
    }
  }

}

int main(int argc, char const *argv[]) {
  int size,count,end;
  int flag = 0, iter = 0;
  int i, j;
  // vector<Position> p;
  cin >> size;
  while (1) {
    printf("iter %i\n",iter );
    iter++;
    Position *p;
    p = (Position *) malloc(sizeof(Position));
    int board [SIZEF][SIZEF] = {0};
    board[0][0] = 1;
    count = 2;
    for (i = 0; i < size; i++){
      for (j = 0;j < size; j++){
        end = walk(p,board,size);
        if (end == 1) {
          flag = 0;
          // cout << "entrou no end" << '\n';
          for (i = 0; i < count; i++) {
            for (j = 0; j < count; j++) {
              if (board[i][j] == 0) {
                flag++;
              }
            }
          }
          if (flag == 0) {
            cout << "random is good!" << '\n';
            return 0;
          }
          cout << "random is mean" << '\n';
          break;
        }
        board[p->x][p->y] = count;
        count++;
      }
      if(flag != 0){
        free(p);
        // printf("free p!\n" );
        break;
      }
    }
  }
  return 0;
}
<commit_msg>works<commit_after>#include <iostream>
#include <random>
#include <stdlib.h>
#define SIZEF 500

struct Position{
  int x = 0;
  int y = 0;
};

using namespace std;

int walk(Position *p,int (&board)[SIZEF][SIZEF],int size){
  //https://stackoverflow.com/questions/5008804/generating-random-integer-from-a-range
  random_device rd;
  mt19937_64 gen(rd());
  //http://en.cppreference.com/w/cpp/numeric/random/uniform_int_distribution
  uniform_real_distribution<> uni(0,99.9);
  // cout << uni(gen)<<"\n";
  double random = uni(gen);
  int pass = 0;
  // printf("[%i],[%i]\n",p->x,p->y);
  while(1){
    random = fmod(random,100);
    // cout << board[1][2]<<" BOARD[1][2]\n";
    // cout << board[2][1]<<" BOARD[2][1]\n";
    // cout << p->x+1<<" p.x\n";
    // cout << p->y<<" p.y\n";
    // if ((random >= 25)&&(random < 37.5)) {
    //   cout << "rnd: "<<random<<"\n";
    // }
    if ((0 <= random)&&(random < 12.5)) { // move 1
      if((p->x-2>=0)&&(p->y+1<size)){
        if (board[p->x-2][p->y+1] == 0) {
          // cout << "oi!1" << '\n';
          p->x-=2;
          p->y+=1;
          return 0;
        }
      }
      pass++;
    }else if ((12.5 <= random)&&(random < 25)){ // move 2
      if((p->x-1>=0)&&(p->y+2<size)){
        if (board[p->x-1][p->y+2] == 0) {
          // cout << "oi!2" << '\n';
          p->x-=1;
          p->y+=2;
          return 0;
        }
      }
      pass++;
    }else if ((25 <= random)&&(random< 37.5)){ // move 3
      if((p->x+1<size)&&(p->y+2<size)){
        if (board[p->x+1][p->y+2] == 0) {
          // cout << "oi!3" << '\n';
          p->x+=1;
          p->y+=2;
          return 0;
        }
      }
      pass++;
    }else if ((37.5 <= random)&&(random < 50)){ // move 4
      if((p->x+2<size)&&(p->y+1<size)){
        if (board[p->x+2][p->y+1] == 0) {
          // cout << "oi!4" << '\n';
          p->x+=2;
          p->y+=1;
          return 0;
        }
      }
      pass++;
    }else if ((50 <= random)&&(random < 62.5)){ // move 5
      if((p->x+2<size)&&(p->y-1>=0)){
        if (board[p->x+2][p->y-1] == 0) {
          // cout << "oi!5" << '\n';
          p->x+=2;
          p->y-=1;
          return 0;
        }
      }
      pass++;
    }else if ((62.5 <= random)&&(random < 75)){ // move 6
      if((p->x+1<size)&&(p->y-2>=0)){
        if (board[p->x+1][p->y-2] == 0) {
          // cout << "oi!6" << '\n';
          p->x+=1;
          p->y-=2;
          return 0;
        }
      }
      pass++;
    }else if ((75 <= random)&&(random < 87.5)){ // move 7
      if((p->x-1>=0)&&(p->y-2>=0)){
        if (board[p->x-1][p->y-2] == 0) {
          // cout << "oi!7" << '\n';
          p->x-=1;
          p->y-=2;
          return 0;
        }
      }
      pass++;
    }else{ // move 8
      if((p->x-2>=0)&&(p->y-1>=0)){
        if (board[p->x-2][p->y-1] == 0) {
          // cout << "oi!8" << '\n';
          p->x-=2;
          p->y-=1;
          return 0;
        }
      }
      pass++;
    }

    random+=12.5;
    if (pass == 8) {
      return 1;
    }
  }

}

int main(int argc, char const *argv[]) {
  int size,count,end;
  int flag = 0, iter = 0;
  int i;
  // vector<Position> p;
  Position *p;
  p = (Position *) malloc(sizeof(Position));
  cin >> size;

  while (1) {
    // printf("iter %i\n",iter );
    iter++;
    int board [SIZEF][SIZEF] = {0};
    board[0][0] = 1;
    count = 2;
    for (i = 0; i < size*size; i++){
        end = walk(p,board,size);
        if (end == 1) {
          flag = 0;
          // cout << "entrou no end" << '\n';
          for (int i2 = 0; i2 < size; i2++) {
            for (int j2 = 0; j2 < size; j2++) {
              if (board[i2][j2] == 0) {
                flag++;
              }
            }
          }
          if (flag == 0) {
            cout << "random is good!" << '\n';
            return 0;
          }
          cout << "random is mean" << '\n';
          break;
        }
        board[p->x][p->y] = count;
        count++;
      }
      if(flag != 0){
        p->x=0;
        p->y=0;
        // printf("free p!\n" );
        // break;
      }
  }
  return 0;
}
<|endoftext|>