<commit_before>#include <algorithm>
#include <iomanip>
#include <ios>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <stdint.h>
#include <stdio.h>

namespace {

  const char kToplevel[] = "$total$";
  const char kOverhead[] = "$overhead$";
  const char kIgnore[] = "$ignore$";

  struct OpInfo {
    std::string op_type;
    std::string op_name;
    std::string parent_type;
    std::string parent_name;
    // number of times called
    int64_t count;
    // ticks used (processor specific, no fixed time interval)
    int64_t ticks;
    // nsec is actually only measured for $total$;
    // it's (approximated) calculated for all others
    double nsec;
    // percentage of total ticks, [0.0..1.0]
    double percent;
    // ticks/nsec/percent used by this op alone (not including callees)
    int64_t ticks_only;
    double nsec_only;
    double percent_only;

    OpInfo()
      : count(0),
        ticks(0),
        nsec(0.0),
        percent(0.0),
        ticks_only(0),
        nsec_only(0.0),
        percent_only(0.0) {}
  };

  // Outer map is keyed by function name,
  // inner map is keyed by op_type + op_name
  typedef std::map<std::string, OpInfo> OpInfoMap;
  typedef std::map<std::string, OpInfoMap> FuncInfoMap;

  std::string qualified_name(const std::string& op_type, const std::string& op_name) {
    // Arbitrary, just join type + name
    return op_type + ":" + op_name;
  }

  // How is it posible that there is no string-split function in the C++
  // standard library?
  std::vector<std::string> Split(const std::string& s, char delim) {
    std::vector<std::string> v;
    std::istringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        v.push_back(item);
    }
    return v;
  }

  bool HasOpt(char** begin, char** end, const std::string& opt) {
    return std::find(begin, end, opt) != end;
  }

  // look for string "opt"; if found, return subsequent string;
  // if not found, return empty string.
  std::string GetOpt(char** begin, char** end, const std::string& opt) {
    char** it = std::find(begin, end, opt);
    if (it != end && ++it != end) {
        return std::string(*it);
    }
    return std::string();
  }

  void ProcessLine(const std::string& s, FuncInfoMap& info, bool accumulate_runs) {
    std::vector<std::string> v = Split(s, ' ');
    if (v.size() < 8) {
      return;
    }
    // Some environments (e.g. Android logging) will emit a prefix
    // for each line; skip the first few words we see before
    // deciding to ignore the line.
    int first = -1;
    for (int i = 0; i < 4; ++i) {
      if (v[i] == "halide_profiler") {
        first = i;
        break;
      }
    }
    if (first < 0) {
      return;
    }
    const std::string& metric = v[first + 1];
    const std::string& func_name = v[first + 2];
    const std::string& op_type = v[first + 3];
    const std::string& op_name = v[first + 4];
    const std::string& parent_type = v[first + 5];
    const std::string& parent_name = v[first + 6];
    if (op_type == kIgnore || op_name == kIgnore) {
      return;
    }
    std::istringstream value_stream(v[first + 7]);
    int64_t value;
    value_stream >> value;
    OpInfoMap& op_info_map = info[func_name];
    OpInfo& op_info = op_info_map[qualified_name(op_type, op_name)];
    op_info.op_type = op_type;
    op_info.op_name = op_name;
    op_info.parent_type = parent_type;
    op_info.parent_name = parent_name;
    if (metric == "count") {
      op_info.count = (accumulate_runs ? op_info.count : 0) + value;
    } else if (metric == "ticks") {
      op_info.ticks = (accumulate_runs ? op_info.ticks : 0) + value;
    } else if (metric == "nsec") {
      op_info.nsec = (accumulate_runs ? op_info.nsec : 0) + value;
    }
  }

  typedef std::map<std::string, std::vector<OpInfo*> > ChildMap;

  int64_t AdjustOverhead(OpInfo& op_info, ChildMap& child_map, double overhead_ticks_avg) {
    int64_t overhead_ticks = op_info.count * overhead_ticks_avg;

    op_info.ticks_only -= overhead_ticks;

    std::string qual_name = qualified_name(op_info.op_type, op_info.op_name);
    const std::vector<OpInfo*>& children = child_map[qual_name];
    for (std::vector<OpInfo*>::const_iterator it = children.begin(); it != children.end(); ++it) {
      OpInfo* c = *it;
      int64_t child_overhead = AdjustOverhead(*c, child_map, overhead_ticks_avg);
      overhead_ticks += child_overhead;
    }

    op_info.ticks -= overhead_ticks;

    return overhead_ticks;
  }

  void FinishOpInfo(OpInfoMap& op_info_map, bool adjust_for_overhead) {

    std::string toplevel_qual_name = qualified_name(kToplevel, kToplevel);
    OpInfo& total = op_info_map[toplevel_qual_name];
    total.percent = 1.0;

    double ticks_per_nsec = (double)total.ticks / (double)total.nsec;

    // Note that overhead (if present) is measured outside the rest
    // of the "total", so it should not be included (or subtracted from)
    // the total.
    double overhead_ticks_avg = 0;
    std::string overhead_qual_name = qualified_name(kOverhead, kOverhead);
    OpInfoMap::iterator it = op_info_map.find(overhead_qual_name);
    if (it != op_info_map.end()) {
      OpInfo overhead = it->second;
      overhead_ticks_avg = (double)overhead.ticks / ((double)overhead.count * 2.0);
      op_info_map.erase(it);
    }

    ChildMap child_map;
    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      std::string parent_qual_name = qualified_name(op_info.parent_type, op_info.parent_name);
      child_map[parent_qual_name].push_back(&op_info);
    }

    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      op_info.ticks_only = op_info.ticks;
      const std::vector<OpInfo*>& children = child_map[o->first];
      for (std::vector<OpInfo*>::const_iterator it = children.begin(); it != children.end(); ++it) {
        OpInfo* c = *it;
        op_info.ticks_only -= c->ticks;
      }
    }

    if (adjust_for_overhead) {
      // Adjust values to account for profiling overhead
      AdjustOverhead(total, child_map, overhead_ticks_avg);
    }

    // Calc the derived fields
    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      op_info.nsec = op_info.ticks / ticks_per_nsec;
      op_info.nsec_only = op_info.ticks_only / ticks_per_nsec;
      op_info.percent = (double)op_info.ticks / (double)total.ticks;
      op_info.percent_only = (double)op_info.ticks_only / (double)total.ticks;
    }
  }

  template <typename CmpFunc>
  std::vector<OpInfo> SortOpInfo(const OpInfoMap& op_info_map, CmpFunc cmp) {
    std::vector<OpInfo> v;
    for (OpInfoMap::const_iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      v.push_back(o->second);
    }
    // Note: using reverse iterators to get a descending sort
    std::sort(v.rbegin(), v.rend(), cmp);
    return v;
  }

  bool by_count(const OpInfo& a, const OpInfo& b) { return a.count < b.count; }
  bool by_ticks(const OpInfo& a, const OpInfo& b) { return a.ticks < b.ticks; }
  bool by_ticks_only(const OpInfo& a, const OpInfo& b) { return a.ticks_only < b.ticks_only; }

}  // namespace

int main(int argc, char** argv) {

  if (HasOpt(argv, argv + argc, "-h")) {
    printf("HalideProf [-f funcname] [-sort c|t|to] [-top N] [-overhead=0|1] [-accumulate=[0|1]] < profiledata\n");
    return 0;
  }

  std::string func_name_filter = GetOpt(argv, argv + argc, "-f");

  bool (*sort_by_func)(const OpInfo& a, const OpInfo& b);
  std::string sort_by = GetOpt(argv, argv + argc, "-sort");
  if (sort_by.empty() || sort_by == "to") {
    sort_by_func = by_ticks_only;
  } else if (sort_by == "t") {
    sort_by_func = by_ticks;
  } else if (sort_by == "c") {
    sort_by_func = by_count;
  } else {
    std::cerr << "Unknown value for -sort: " << sort_by << "\n";
    exit(-1);
  }

  int32_t top_n = 10;
  std::string top_n_str = GetOpt(argv, argv + argc, "-top");
  if (!top_n_str.empty()) {
    std::istringstream(top_n_str) >> top_n;
  }

  // It's rare that you wouldn't want to try to adjust the times
  // to minimize the effect profiling overhead, but just in case,
  // allow -overhead 0
  int32_t adjust_for_overhead = 1;
  std::string adjust_for_overhead_str = GetOpt(argv, argv + argc, "-overhead");
  if (!adjust_for_overhead_str.empty()) {
    std::istringstream(adjust_for_overhead_str) >> adjust_for_overhead;
  }

  int32_t accumulate_runs = 0;
  std::string accumulate_runs_str = GetOpt(argv, argv + argc, "-accumulate");
  if (!accumulate_runs_str.empty()) {
    std::istringstream(accumulate_runs_str) >> accumulate_runs;
  }

  FuncInfoMap func_info_map;
  std::string line;
  while (std::getline(std::cin, line)) {
    ProcessLine(line, func_info_map, accumulate_runs);
  }

  for (FuncInfoMap::iterator f = func_info_map.begin(); f != func_info_map.end(); ++f) {
    FinishOpInfo(f->second, adjust_for_overhead != 0);
  }

  for (FuncInfoMap::iterator f = func_info_map.begin(); f != func_info_map.end(); ++f) {
    const std::string& func_name = f->first;
    if (!func_name_filter.empty() && func_name_filter != func_name) {
      continue;
    }
    std::cout << "Func: " << func_name << "\n";
    std::cout << "--------------------------\n";
    std::cout
      << std::setw(10) << std::left << "op_type"
      << std::setw(40) << std::left << "op_name"
      << std::setw(16) << std::right << "count"
      << std::setw(16) << "ticks-cum"
      << std::setw(12) << "msec-cum"
      << std::setw(8) << std::fixed << "%-cum"
      << std::setw(16) << "ticks-only"
      << std::setw(12) << "msec-only"
      << std::setw(8) << std::fixed << "%-only"
      << "\n";
    std::vector<OpInfo> op_info = SortOpInfo(f->second, sort_by_func);
    for (std::vector<OpInfo>::const_iterator o = op_info.begin(); o != op_info.end(); ++o) {
      const OpInfo& op_info = *o;
      std::cout
        << std::setw(10) << std::left << op_info.op_type
        << std::setw(40) << std::left << op_info.op_name
        << std::setw(16) << std::right << op_info.count
        << std::setw(16) << op_info.ticks
        << std::setw(12) << std::setprecision(2) << std::fixed << (op_info.nsec / 1000000.0)
        << std::setw(8) << std::setprecision(2) << std::fixed << (op_info.percent * 100.0)
        << std::setw(16) << op_info.ticks_only
        << std::setw(12) << std::setprecision(2) << std::fixed << (op_info.nsec_only / 1000000.0)
        << std::setw(8) << std::setprecision(2) << std::fixed << (op_info.percent_only * 100.0)
        << "\n";
      if (--top_n <= 0) {
        break;
      }
    }
  }
}
<commit_msg>Put overhead adjustment before ticks_only, so it does not need to be adjusted anymore<commit_after>#include <algorithm>
#include <iomanip>
#include <ios>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <stdint.h>
#include <stdio.h>

namespace {

  const char kToplevel[] = "$total$";
  const char kOverhead[] = "$overhead$";
  const char kIgnore[] = "$ignore$";

  struct OpInfo {
    std::string op_type;
    std::string op_name;
    std::string parent_type;
    std::string parent_name;
    // number of times called
    int64_t count;
    // ticks used (processor specific, no fixed time interval)
    int64_t ticks;
    // nsec is actually only measured for $total$;
    // it's (approximated) calculated for all others
    double nsec;
    // percentage of total ticks, [0.0..1.0]
    double percent;
    // ticks/nsec/percent used by this op alone (not including callees)
    int64_t ticks_only;
    double nsec_only;
    double percent_only;

    OpInfo()
      : count(0),
        ticks(0),
        nsec(0.0),
        percent(0.0),
        ticks_only(0),
        nsec_only(0.0),
        percent_only(0.0) {}
  };

  // Outer map is keyed by function name,
  // inner map is keyed by op_type + op_name
  typedef std::map<std::string, OpInfo> OpInfoMap;
  typedef std::map<std::string, OpInfoMap> FuncInfoMap;

  std::string qualified_name(const std::string& op_type, const std::string& op_name) {
    // Arbitrary, just join type + name
    return op_type + ":" + op_name;
  }

  // How is it posible that there is no string-split function in the C++
  // standard library?
  std::vector<std::string> Split(const std::string& s, char delim) {
    std::vector<std::string> v;
    std::istringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        v.push_back(item);
    }
    return v;
  }

  bool HasOpt(char** begin, char** end, const std::string& opt) {
    return std::find(begin, end, opt) != end;
  }

  // look for string "opt"; if found, return subsequent string;
  // if not found, return empty string.
  std::string GetOpt(char** begin, char** end, const std::string& opt) {
    char** it = std::find(begin, end, opt);
    if (it != end && ++it != end) {
        return std::string(*it);
    }
    return std::string();
  }

  void ProcessLine(const std::string& s, FuncInfoMap& info, bool accumulate_runs) {
    std::vector<std::string> v = Split(s, ' ');
    if (v.size() < 8) {
      return;
    }
    // Some environments (e.g. Android logging) will emit a prefix
    // for each line; skip the first few words we see before
    // deciding to ignore the line.
    int first = -1;
    for (int i = 0; i < 4; ++i) {
      if (v[i] == "halide_profiler") {
        first = i;
        break;
      }
    }
    if (first < 0) {
      return;
    }
    const std::string& metric = v[first + 1];
    const std::string& func_name = v[first + 2];
    const std::string& op_type = v[first + 3];
    const std::string& op_name = v[first + 4];
    const std::string& parent_type = v[first + 5];
    const std::string& parent_name = v[first + 6];
    if (op_type == kIgnore || op_name == kIgnore) {
      return;
    }
    std::istringstream value_stream(v[first + 7]);
    int64_t value;
    value_stream >> value;
    OpInfoMap& op_info_map = info[func_name];
    OpInfo& op_info = op_info_map[qualified_name(op_type, op_name)];
    op_info.op_type = op_type;
    op_info.op_name = op_name;
    op_info.parent_type = parent_type;
    op_info.parent_name = parent_name;
    if (metric == "count") {
      op_info.count = (accumulate_runs ? op_info.count : 0) + value;
    } else if (metric == "ticks") {
      op_info.ticks = (accumulate_runs ? op_info.ticks : 0) + value;
    } else if (metric == "nsec") {
      op_info.nsec = (accumulate_runs ? op_info.nsec : 0) + value;
    }
  }

  typedef std::map<std::string, std::vector<OpInfo*> > ChildMap;

  int64_t AdjustOverhead(OpInfo& op_info, ChildMap& child_map, double overhead_ticks_avg) {
    int64_t overhead_ticks = op_info.count * overhead_ticks_avg;

    std::string qual_name = qualified_name(op_info.op_type, op_info.op_name);
    const std::vector<OpInfo*>& children = child_map[qual_name];
    for (std::vector<OpInfo*>::const_iterator it = children.begin(); it != children.end(); ++it) {
      OpInfo* c = *it;
      int64_t child_overhead = AdjustOverhead(*c, child_map, overhead_ticks_avg);
      overhead_ticks += child_overhead;
    }

    op_info.ticks -= overhead_ticks;

    return overhead_ticks;
  }

  void FinishOpInfo(OpInfoMap& op_info_map, bool adjust_for_overhead) {

    std::string toplevel_qual_name = qualified_name(kToplevel, kToplevel);
    OpInfo& total = op_info_map[toplevel_qual_name];
    total.percent = 1.0;

    double ticks_per_nsec = (double)total.ticks / (double)total.nsec;

    // Note that overhead (if present) is measured outside the rest
    // of the "total", so it should not be included (or subtracted from)
    // the total.
    double overhead_ticks_avg = 0;
    std::string overhead_qual_name = qualified_name(kOverhead, kOverhead);
    OpInfoMap::iterator it = op_info_map.find(overhead_qual_name);
    if (it != op_info_map.end()) {
      OpInfo overhead = it->second;
      overhead_ticks_avg = (double)overhead.ticks / ((double)overhead.count * 2.0);
      op_info_map.erase(it);
    }

    ChildMap child_map;
    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      std::string parent_qual_name = qualified_name(op_info.parent_type, op_info.parent_name);
      child_map[parent_qual_name].push_back(&op_info);
    }

    if (adjust_for_overhead) {
      // Adjust values to account for profiling overhead
      AdjustOverhead(total, child_map, overhead_ticks_avg);
    }

    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      op_info.ticks_only = op_info.ticks;
      const std::vector<OpInfo*>& children = child_map[o->first];
      for (std::vector<OpInfo*>::const_iterator it = children.begin(); it != children.end(); ++it) {
        OpInfo* c = *it;
        op_info.ticks_only -= c->ticks;
      }
    }

    // Calc the derived fields
    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      op_info.nsec = op_info.ticks / ticks_per_nsec;
      op_info.nsec_only = op_info.ticks_only / ticks_per_nsec;
      op_info.percent = (double)op_info.ticks / (double)total.ticks;
      op_info.percent_only = (double)op_info.ticks_only / (double)total.ticks;
    }
  }

  template <typename CmpFunc>
  std::vector<OpInfo> SortOpInfo(const OpInfoMap& op_info_map, CmpFunc cmp) {
    std::vector<OpInfo> v;
    for (OpInfoMap::const_iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      v.push_back(o->second);
    }
    // Note: using reverse iterators to get a descending sort
    std::sort(v.rbegin(), v.rend(), cmp);
    return v;
  }

  bool by_count(const OpInfo& a, const OpInfo& b) { return a.count < b.count; }
  bool by_ticks(const OpInfo& a, const OpInfo& b) { return a.ticks < b.ticks; }
  bool by_ticks_only(const OpInfo& a, const OpInfo& b) { return a.ticks_only < b.ticks_only; }

}  // namespace

int main(int argc, char** argv) {

  if (HasOpt(argv, argv + argc, "-h")) {
    printf("HalideProf [-f funcname] [-sort c|t|to] [-top N] [-overhead=0|1] [-accumulate=[0|1]] < profiledata\n");
    return 0;
  }

  std::string func_name_filter = GetOpt(argv, argv + argc, "-f");

  bool (*sort_by_func)(const OpInfo& a, const OpInfo& b);
  std::string sort_by = GetOpt(argv, argv + argc, "-sort");
  if (sort_by.empty() || sort_by == "to") {
    sort_by_func = by_ticks_only;
  } else if (sort_by == "t") {
    sort_by_func = by_ticks;
  } else if (sort_by == "c") {
    sort_by_func = by_count;
  } else {
    std::cerr << "Unknown value for -sort: " << sort_by << "\n";
    exit(-1);
  }

  int32_t top_n = 10;
  std::string top_n_str = GetOpt(argv, argv + argc, "-top");
  if (!top_n_str.empty()) {
    std::istringstream(top_n_str) >> top_n;
  }

  // It's rare that you wouldn't want to try to adjust the times
  // to minimize the effect profiling overhead, but just in case,
  // allow -overhead 0
  int32_t adjust_for_overhead = 1;
  std::string adjust_for_overhead_str = GetOpt(argv, argv + argc, "-overhead");
  if (!adjust_for_overhead_str.empty()) {
    std::istringstream(adjust_for_overhead_str) >> adjust_for_overhead;
  }

  int32_t accumulate_runs = 0;
  std::string accumulate_runs_str = GetOpt(argv, argv + argc, "-accumulate");
  if (!accumulate_runs_str.empty()) {
    std::istringstream(accumulate_runs_str) >> accumulate_runs;
  }

  FuncInfoMap func_info_map;
  std::string line;
  while (std::getline(std::cin, line)) {
    ProcessLine(line, func_info_map, accumulate_runs);
  }

  for (FuncInfoMap::iterator f = func_info_map.begin(); f != func_info_map.end(); ++f) {
    FinishOpInfo(f->second, adjust_for_overhead != 0);
  }

  for (FuncInfoMap::iterator f = func_info_map.begin(); f != func_info_map.end(); ++f) {
    const std::string& func_name = f->first;
    if (!func_name_filter.empty() && func_name_filter != func_name) {
      continue;
    }
    std::cout << "Func: " << func_name << "\n";
    std::cout << "--------------------------\n";
    std::cout
      << std::setw(10) << std::left << "op_type"
      << std::setw(40) << std::left << "op_name"
      << std::setw(16) << std::right << "count"
      << std::setw(16) << "ticks-cum"
      << std::setw(12) << "msec-cum"
      << std::setw(8) << std::fixed << "%-cum"
      << std::setw(16) << "ticks-only"
      << std::setw(12) << "msec-only"
      << std::setw(8) << std::fixed << "%-only"
      << "\n";
    std::vector<OpInfo> op_info = SortOpInfo(f->second, sort_by_func);
    for (std::vector<OpInfo>::const_iterator o = op_info.begin(); o != op_info.end(); ++o) {
      const OpInfo& op_info = *o;
      std::cout
        << std::setw(10) << std::left << op_info.op_type
        << std::setw(40) << std::left << op_info.op_name
        << std::setw(16) << std::right << op_info.count
        << std::setw(16) << op_info.ticks
        << std::setw(12) << std::setprecision(2) << std::fixed << (op_info.nsec / 1000000.0)
        << std::setw(8) << std::setprecision(2) << std::fixed << (op_info.percent * 100.0)
        << std::setw(16) << op_info.ticks_only
        << std::setw(12) << std::setprecision(2) << std::fixed << (op_info.nsec_only / 1000000.0)
        << std::setw(8) << std::setprecision(2) << std::fixed << (op_info.percent_only * 100.0)
        << "\n";
      if (--top_n <= 0) {
        break;
      }
    }
  }
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <iomanip>
#include <ios>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <stdint.h>
#include <stdio.h>

namespace {

  const char kToplevel[] = "$total$";
  const char kOverhead[] = "$overhead$";
  const char kIgnore[] = "$ignore$";

  struct OpInfo {
    std::string op_type;
    std::string op_name;
    std::string parent_type;
    std::string parent_name;
    // number of times called
    int64_t count;
    // ticks used (processor specific, no fixed time interval)
    int64_t ticks;
    // nsec is actually only measured for $total$;
    // it's (approximated) calculated for all others
    double nsec;
    // percentage of total ticks, [0.0..1.0]
    double percent;
    // ticks/nsec/percent used by this op alone (not including callees)
    int64_t ticks_only;
    double nsec_only;
    double percent_only;

    OpInfo()
      : count(0),
        ticks(0),
        nsec(0.0),
        percent(0.0),
        ticks_only(0),
        nsec_only(0.0),
        percent_only(0.0) {}
  };

  // Outer map is keyed by function name,
  // inner map is keyed by op_type + op_name
  typedef std::map<std::string, OpInfo> OpInfoMap;
  typedef std::map<std::string, OpInfoMap> FuncInfoMap;

  std::string qualified_name(const std::string& op_type, const std::string& op_name) {
    // Arbitrary, just join type + name
    return op_type + ":" + op_name;
  }

  // How is it posible that there is no string-split function in the C++
  // standard library?
  std::vector<std::string> Split(const std::string& s, char delim) {
    std::vector<std::string> v;
    std::istringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        v.push_back(item);
    }
    return v;
  }

  bool HasOpt(char** begin, char** end, const std::string& opt) {
    return std::find(begin, end, opt) != end;
  }

  // look for string "opt"; if found, return subsequent string;
  // if not found, return empty string.
  std::string GetOpt(char** begin, char** end, const std::string& opt) {
    char** it = std::find(begin, end, opt);
    if (it != end && ++it != end) {
        return std::string(*it);
    }
    return std::string();
  }

  void ProcessLine(const std::string& s, FuncInfoMap& info, bool accumulate_runs) {
    std::vector<std::string> v = Split(s, ' ');
    if (v.size() < 8) {
      return;
    }
    // Some environments (e.g. Android logging) will emit a prefix
    // for each line; just check all the words on the line.
    int first = -1;
    // We know v.size() >= 8 due to earlier check, so this will never underflow.
    for (int i = 0; i < v.size() - 8; ++i) {
      if (v[i] == "halide_profiler") {
        first = i;
        break;
      }
    }
    if (first < 0) {
      return;
    }
    const std::string& metric = v[first + 1];
    const std::string& func_name = v[first + 2];
    const std::string& op_type = v[first + 3];
    const std::string& op_name = v[first + 4];
    const std::string& parent_type = v[first + 5];
    const std::string& parent_name = v[first + 6];
    if (op_type == kIgnore || op_name == kIgnore) {
      return;
    }
    std::istringstream value_stream(v[first + 7]);
    int64_t value;
    value_stream >> value;
    OpInfoMap& op_info_map = info[func_name];
    OpInfo& op_info = op_info_map[qualified_name(op_type, op_name)];
    op_info.op_type = op_type;
    op_info.op_name = op_name;
    op_info.parent_type = parent_type;
    op_info.parent_name = parent_name;
    if (metric == "count") {
      op_info.count = (accumulate_runs ? op_info.count : 0) + value;
    } else if (metric == "ticks") {
      op_info.ticks = (accumulate_runs ? op_info.ticks : 0) + value;
    } else if (metric == "nsec") {
      op_info.nsec = (accumulate_runs ? op_info.nsec : 0) + value;
    }
  }

  typedef std::map<std::string, std::vector<OpInfo*> > ChildMap;

  int64_t AdjustOverhead(OpInfo& op_info, ChildMap& child_map, double overhead_ticks_avg) {
    int64_t overhead_local = op_info.count * overhead_ticks_avg;
    int64_t overhead_ticks = overhead_local;

    std::string qual_name = qualified_name(op_info.op_type, op_info.op_name);
    const std::vector<OpInfo*>& children = child_map[qual_name];
    for (std::vector<OpInfo*>::const_iterator it = children.begin(); it != children.end(); ++it) {
      OpInfo* c = *it;
      int64_t child_overhead = AdjustOverhead(*c, child_map, overhead_ticks_avg);
      overhead_ticks += child_overhead;
    }

    op_info.ticks -= overhead_ticks;

    // double the overhead of this level
    return overhead_ticks + overhead_local;
  }

  void FinishOpInfo(OpInfoMap& op_info_map, bool adjust_for_overhead) {

    std::string toplevel_qual_name = qualified_name(kToplevel, kToplevel);
    OpInfo& total = op_info_map[toplevel_qual_name];
    total.percent = 1.0;

    double ticks_per_nsec = (double)total.ticks / (double)total.nsec;

    // Note that overhead (if present) is measured outside the rest
    // of the "total", so it should not be included (or subtracted from)
    // the total.
    double overhead_ticks_avg = 0;
    std::string overhead_qual_name = qualified_name(kOverhead, kOverhead);
    OpInfoMap::iterator it = op_info_map.find(overhead_qual_name);
    if (it != op_info_map.end()) {
      OpInfo overhead = it->second;
      overhead_ticks_avg = (double)overhead.ticks / ((double)overhead.count * 2.0);
      op_info_map.erase(it);
    }

    ChildMap child_map;
    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      std::string parent_qual_name = qualified_name(op_info.parent_type, op_info.parent_name);
      child_map[parent_qual_name].push_back(&op_info);
    }

    if (adjust_for_overhead) {
      // Adjust values to account for profiling overhead
      AdjustOverhead(total, child_map, overhead_ticks_avg);
    }

    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      op_info.ticks_only = op_info.ticks;
      const std::vector<OpInfo*>& children = child_map[o->first];
      for (std::vector<OpInfo*>::const_iterator it = children.begin(); it != children.end(); ++it) {
        OpInfo* c = *it;
        op_info.ticks_only -= c->ticks;
      }
    }

    // Calc the derived fields
    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      op_info.nsec = op_info.ticks / ticks_per_nsec;
      op_info.nsec_only = op_info.ticks_only / ticks_per_nsec;
      op_info.percent = (double)op_info.ticks / (double)total.ticks;
      op_info.percent_only = (double)op_info.ticks_only / (double)total.ticks;
    }
  }

  template <typename CmpFunc>
  std::vector<OpInfo> SortOpInfo(const OpInfoMap& op_info_map, CmpFunc cmp) {
    std::vector<OpInfo> v;
    for (OpInfoMap::const_iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      v.push_back(o->second);
    }
    // Note: using reverse iterators to get a descending sort
    std::sort(v.rbegin(), v.rend(), cmp);
    return v;
  }

  bool by_count(const OpInfo& a, const OpInfo& b) { return a.count < b.count; }
  bool by_ticks(const OpInfo& a, const OpInfo& b) { return a.ticks < b.ticks; }
  bool by_ticks_only(const OpInfo& a, const OpInfo& b) { return a.ticks_only < b.ticks_only; }

}  // namespace

int main(int argc, char** argv) {

  if (HasOpt(argv, argv + argc, "-h")) {
    printf("HalideProf [-f funcname] [-sort c|t|to] [-top N] [-overhead=0|1] [-accumulate=[0|1]] < profiledata\n");
    return 0;
  }

  std::string func_name_filter = GetOpt(argv, argv + argc, "-f");

  bool (*sort_by_func)(const OpInfo& a, const OpInfo& b);
  std::string sort_by = GetOpt(argv, argv + argc, "-sort");
  if (sort_by.empty() || sort_by == "to") {
    sort_by_func = by_ticks_only;
  } else if (sort_by == "t") {
    sort_by_func = by_ticks;
  } else if (sort_by == "c") {
    sort_by_func = by_count;
  } else {
    std::cerr << "Unknown value for -sort: " << sort_by << "\n";
    exit(-1);
  }

  int32_t top_n = 10;
  std::string top_n_str = GetOpt(argv, argv + argc, "-top");
  if (!top_n_str.empty()) {
    std::istringstream(top_n_str) >> top_n;
  }

  // It's rare that you wouldn't want to try to adjust the times
  // to minimize the effect profiling overhead, but just in case,
  // allow -overhead 0
  int32_t adjust_for_overhead = 1;
  std::string adjust_for_overhead_str = GetOpt(argv, argv + argc, "-overhead");
  if (!adjust_for_overhead_str.empty()) {
    std::istringstream(adjust_for_overhead_str) >> adjust_for_overhead;
  }

  int32_t accumulate_runs = 0;
  std::string accumulate_runs_str = GetOpt(argv, argv + argc, "-accumulate");
  if (!accumulate_runs_str.empty()) {
    std::istringstream(accumulate_runs_str) >> accumulate_runs;
  }

  FuncInfoMap func_info_map;
  std::string line;
  while (std::getline(std::cin, line)) {
    ProcessLine(line, func_info_map, accumulate_runs);
  }

  for (FuncInfoMap::iterator f = func_info_map.begin(); f != func_info_map.end(); ++f) {
    FinishOpInfo(f->second, adjust_for_overhead != 0);
  }

  for (FuncInfoMap::iterator f = func_info_map.begin(); f != func_info_map.end(); ++f) {
    const std::string& func_name = f->first;
    if (!func_name_filter.empty() && func_name_filter != func_name) {
      continue;
    }
    std::cout << "Func: " << func_name << "\n";
    std::cout << "--------------------------\n";
    std::cout
      << std::setw(10) << std::left << "op_type"
      << std::setw(40) << std::left << "op_name"
      << std::setw(16) << std::right << "count"
      << std::setw(16) << "ticks-cum"
      << std::setw(12) << "msec-cum"
      << std::setw(8) << std::fixed << "%-cum"
      << std::setw(16) << "ticks-only"
      << std::setw(12) << "msec-only"
      << std::setw(8) << std::fixed << "%-only"
      << "\n";
    std::vector<OpInfo> op_info = SortOpInfo(f->second, sort_by_func);
    for (std::vector<OpInfo>::const_iterator o = op_info.begin(); o != op_info.end(); ++o) {
      const OpInfo& op_info = *o;
      std::cout
        << std::setw(10) << std::left << op_info.op_type
        << std::setw(40) << std::left << op_info.op_name
        << std::setw(16) << std::right << op_info.count
        << std::setw(16) << op_info.ticks
        << std::setw(12) << std::setprecision(2) << std::fixed << (op_info.nsec / 1000000.0)
        << std::setw(8) << std::setprecision(2) << std::fixed << (op_info.percent * 100.0)
        << std::setw(16) << op_info.ticks_only
        << std::setw(12) << std::setprecision(2) << std::fixed << (op_info.nsec_only / 1000000.0)
        << std::setw(8) << std::setprecision(2) << std::fixed << (op_info.percent_only * 100.0)
        << "\n";
      if (--top_n <= 0) {
        break;
      }
    }
  }
}
<commit_msg>Followup fix for off-by-one error inHalideProf.cpp<commit_after>#include <algorithm>
#include <iomanip>
#include <ios>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include <stdint.h>
#include <stdio.h>

namespace {

  const char kToplevel[] = "$total$";
  const char kOverhead[] = "$overhead$";
  const char kIgnore[] = "$ignore$";

  struct OpInfo {
    std::string op_type;
    std::string op_name;
    std::string parent_type;
    std::string parent_name;
    // number of times called
    int64_t count;
    // ticks used (processor specific, no fixed time interval)
    int64_t ticks;
    // nsec is actually only measured for $total$;
    // it's (approximated) calculated for all others
    double nsec;
    // percentage of total ticks, [0.0..1.0]
    double percent;
    // ticks/nsec/percent used by this op alone (not including callees)
    int64_t ticks_only;
    double nsec_only;
    double percent_only;

    OpInfo()
      : count(0),
        ticks(0),
        nsec(0.0),
        percent(0.0),
        ticks_only(0),
        nsec_only(0.0),
        percent_only(0.0) {}
  };

  // Outer map is keyed by function name,
  // inner map is keyed by op_type + op_name
  typedef std::map<std::string, OpInfo> OpInfoMap;
  typedef std::map<std::string, OpInfoMap> FuncInfoMap;

  std::string qualified_name(const std::string& op_type, const std::string& op_name) {
    // Arbitrary, just join type + name
    return op_type + ":" + op_name;
  }

  // How is it posible that there is no string-split function in the C++
  // standard library?
  std::vector<std::string> Split(const std::string& s, char delim) {
    std::vector<std::string> v;
    std::istringstream ss(s);
    std::string item;
    while (std::getline(ss, item, delim)) {
        v.push_back(item);
    }
    return v;
  }

  bool HasOpt(char** begin, char** end, const std::string& opt) {
    return std::find(begin, end, opt) != end;
  }

  // look for string "opt"; if found, return subsequent string;
  // if not found, return empty string.
  std::string GetOpt(char** begin, char** end, const std::string& opt) {
    char** it = std::find(begin, end, opt);
    if (it != end && ++it != end) {
        return std::string(*it);
    }
    return std::string();
  }

  void ProcessLine(const std::string& s, FuncInfoMap& info, bool accumulate_runs) {
    std::vector<std::string> v = Split(s, ' ');
    if (v.size() < 8) {
      return;
    }
    // Some environments (e.g. Android logging) will emit a prefix
    // for each line; just check all the words on the line.
    int first = -1;
    // We know v.size() >= 8 due to earlier check, so this will never underflow.
    // This is size-7 (rather than size-8) since we expect 7 entries *after*
    // we find the halide_profiler keyword.
    for (int i = 0; i < v.size() - 7; ++i) {
      if (v[i] == "halide_profiler") {
        first = i;
        break;
      }
    }
    if (first < 0) {
      return;
    }
    const std::string& metric = v[first + 1];
    const std::string& func_name = v[first + 2];
    const std::string& op_type = v[first + 3];
    const std::string& op_name = v[first + 4];
    const std::string& parent_type = v[first + 5];
    const std::string& parent_name = v[first + 6];
    if (op_type == kIgnore || op_name == kIgnore) {
      return;
    }
    std::istringstream value_stream(v[first + 7]);
    int64_t value;
    value_stream >> value;
    OpInfoMap& op_info_map = info[func_name];
    OpInfo& op_info = op_info_map[qualified_name(op_type, op_name)];
    op_info.op_type = op_type;
    op_info.op_name = op_name;
    op_info.parent_type = parent_type;
    op_info.parent_name = parent_name;
    if (metric == "count") {
      op_info.count = (accumulate_runs ? op_info.count : 0) + value;
    } else if (metric == "ticks") {
      op_info.ticks = (accumulate_runs ? op_info.ticks : 0) + value;
    } else if (metric == "nsec") {
      op_info.nsec = (accumulate_runs ? op_info.nsec : 0) + value;
    }
  }

  typedef std::map<std::string, std::vector<OpInfo*> > ChildMap;

  int64_t AdjustOverhead(OpInfo& op_info, ChildMap& child_map, double overhead_ticks_avg) {
    int64_t overhead_local = op_info.count * overhead_ticks_avg;
    int64_t overhead_ticks = overhead_local;

    std::string qual_name = qualified_name(op_info.op_type, op_info.op_name);
    const std::vector<OpInfo*>& children = child_map[qual_name];
    for (std::vector<OpInfo*>::const_iterator it = children.begin(); it != children.end(); ++it) {
      OpInfo* c = *it;
      int64_t child_overhead = AdjustOverhead(*c, child_map, overhead_ticks_avg);
      overhead_ticks += child_overhead;
    }

    op_info.ticks -= overhead_ticks;

    // double the overhead of this level
    return overhead_ticks + overhead_local;
  }

  void FinishOpInfo(OpInfoMap& op_info_map, bool adjust_for_overhead) {

    std::string toplevel_qual_name = qualified_name(kToplevel, kToplevel);
    OpInfo& total = op_info_map[toplevel_qual_name];
    total.percent = 1.0;

    double ticks_per_nsec = (double)total.ticks / (double)total.nsec;

    // Note that overhead (if present) is measured outside the rest
    // of the "total", so it should not be included (or subtracted from)
    // the total.
    double overhead_ticks_avg = 0;
    std::string overhead_qual_name = qualified_name(kOverhead, kOverhead);
    OpInfoMap::iterator it = op_info_map.find(overhead_qual_name);
    if (it != op_info_map.end()) {
      OpInfo overhead = it->second;
      overhead_ticks_avg = (double)overhead.ticks / ((double)overhead.count * 2.0);
      op_info_map.erase(it);
    }

    ChildMap child_map;
    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      std::string parent_qual_name = qualified_name(op_info.parent_type, op_info.parent_name);
      child_map[parent_qual_name].push_back(&op_info);
    }

    if (adjust_for_overhead) {
      // Adjust values to account for profiling overhead
      AdjustOverhead(total, child_map, overhead_ticks_avg);
    }

    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      op_info.ticks_only = op_info.ticks;
      const std::vector<OpInfo*>& children = child_map[o->first];
      for (std::vector<OpInfo*>::const_iterator it = children.begin(); it != children.end(); ++it) {
        OpInfo* c = *it;
        op_info.ticks_only -= c->ticks;
      }
    }

    // Calc the derived fields
    for (OpInfoMap::iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      OpInfo& op_info = o->second;
      op_info.nsec = op_info.ticks / ticks_per_nsec;
      op_info.nsec_only = op_info.ticks_only / ticks_per_nsec;
      op_info.percent = (double)op_info.ticks / (double)total.ticks;
      op_info.percent_only = (double)op_info.ticks_only / (double)total.ticks;
    }
  }

  template <typename CmpFunc>
  std::vector<OpInfo> SortOpInfo(const OpInfoMap& op_info_map, CmpFunc cmp) {
    std::vector<OpInfo> v;
    for (OpInfoMap::const_iterator o = op_info_map.begin(); o != op_info_map.end(); ++o) {
      v.push_back(o->second);
    }
    // Note: using reverse iterators to get a descending sort
    std::sort(v.rbegin(), v.rend(), cmp);
    return v;
  }

  bool by_count(const OpInfo& a, const OpInfo& b) { return a.count < b.count; }
  bool by_ticks(const OpInfo& a, const OpInfo& b) { return a.ticks < b.ticks; }
  bool by_ticks_only(const OpInfo& a, const OpInfo& b) { return a.ticks_only < b.ticks_only; }

}  // namespace

int main(int argc, char** argv) {

  if (HasOpt(argv, argv + argc, "-h")) {
    printf("HalideProf [-f funcname] [-sort c|t|to] [-top N] [-overhead=0|1] [-accumulate=[0|1]] < profiledata\n");
    return 0;
  }

  std::string func_name_filter = GetOpt(argv, argv + argc, "-f");

  bool (*sort_by_func)(const OpInfo& a, const OpInfo& b);
  std::string sort_by = GetOpt(argv, argv + argc, "-sort");
  if (sort_by.empty() || sort_by == "to") {
    sort_by_func = by_ticks_only;
  } else if (sort_by == "t") {
    sort_by_func = by_ticks;
  } else if (sort_by == "c") {
    sort_by_func = by_count;
  } else {
    std::cerr << "Unknown value for -sort: " << sort_by << "\n";
    exit(-1);
  }

  int32_t top_n = 10;
  std::string top_n_str = GetOpt(argv, argv + argc, "-top");
  if (!top_n_str.empty()) {
    std::istringstream(top_n_str) >> top_n;
  }

  // It's rare that you wouldn't want to try to adjust the times
  // to minimize the effect profiling overhead, but just in case,
  // allow -overhead 0
  int32_t adjust_for_overhead = 1;
  std::string adjust_for_overhead_str = GetOpt(argv, argv + argc, "-overhead");
  if (!adjust_for_overhead_str.empty()) {
    std::istringstream(adjust_for_overhead_str) >> adjust_for_overhead;
  }

  int32_t accumulate_runs = 0;
  std::string accumulate_runs_str = GetOpt(argv, argv + argc, "-accumulate");
  if (!accumulate_runs_str.empty()) {
    std::istringstream(accumulate_runs_str) >> accumulate_runs;
  }

  FuncInfoMap func_info_map;
  std::string line;
  while (std::getline(std::cin, line)) {
    ProcessLine(line, func_info_map, accumulate_runs);
  }

  for (FuncInfoMap::iterator f = func_info_map.begin(); f != func_info_map.end(); ++f) {
    FinishOpInfo(f->second, adjust_for_overhead != 0);
  }

  for (FuncInfoMap::iterator f = func_info_map.begin(); f != func_info_map.end(); ++f) {
    const std::string& func_name = f->first;
    if (!func_name_filter.empty() && func_name_filter != func_name) {
      continue;
    }
    std::cout << "Func: " << func_name << "\n";
    std::cout << "--------------------------\n";
    std::cout
      << std::setw(10) << std::left << "op_type"
      << std::setw(40) << std::left << "op_name"
      << std::setw(16) << std::right << "count"
      << std::setw(16) << "ticks-cum"
      << std::setw(12) << "msec-cum"
      << std::setw(8) << std::fixed << "%-cum"
      << std::setw(16) << "ticks-only"
      << std::setw(12) << "msec-only"
      << std::setw(8) << std::fixed << "%-only"
      << "\n";
    std::vector<OpInfo> op_info = SortOpInfo(f->second, sort_by_func);
    for (std::vector<OpInfo>::const_iterator o = op_info.begin(); o != op_info.end(); ++o) {
      const OpInfo& op_info = *o;
      std::cout
        << std::setw(10) << std::left << op_info.op_type
        << std::setw(40) << std::left << op_info.op_name
        << std::setw(16) << std::right << op_info.count
        << std::setw(16) << op_info.ticks
        << std::setw(12) << std::setprecision(2) << std::fixed << (op_info.nsec / 1000000.0)
        << std::setw(8) << std::setprecision(2) << std::fixed << (op_info.percent * 100.0)
        << std::setw(16) << op_info.ticks_only
        << std::setw(12) << std::setprecision(2) << std::fixed << (op_info.nsec_only / 1000000.0)
        << std::setw(8) << std::setprecision(2) << std::fixed << (op_info.percent_only * 100.0)
        << "\n";
      if (--top_n <= 0) {
        break;
      }
    }
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file ir_constant_folding.cpp
 * Replace constant-valued expressions with references to constant values.
 */

#define NULL 0
#include "ir.h"
#include "ir_visitor.h"
#include "ir_optimization.h"
#include "glsl_types.h"

/**
 * Visitor class for replacing expressions with ir_constant values.
 */

class ir_constant_folding_visitor : public ir_visitor {
public:
   ir_constant_folding_visitor()
   {
      /* empty */
   }

   virtual ~ir_constant_folding_visitor()
   {
      /* empty */
   }

   /**
    * \name Visit methods
    *
    * As typical for the visitor pattern, there must be one \c visit method for
    * each concrete subclass of \c ir_instruction.  Virtual base classes within
    * the hierarchy should not have \c visit methods.
    */
   /*@{*/
   virtual void visit(ir_variable *);
   virtual void visit(ir_function_signature *);
   virtual void visit(ir_function *);
   virtual void visit(ir_expression *);
   virtual void visit(ir_swizzle *);
   virtual void visit(ir_dereference_variable *);
   virtual void visit(ir_dereference_array *);
   virtual void visit(ir_dereference_record *);
   virtual void visit(ir_assignment *);
   virtual void visit(ir_constant *);
   virtual void visit(ir_call *);
   virtual void visit(ir_return *);
   virtual void visit(ir_if *);
   virtual void visit(ir_loop *);
   virtual void visit(ir_loop_jump *);
   /*@}*/
};

void
ir_constant_folding_visitor::visit(ir_variable *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_function_signature *ir)
{
   visit_exec_list(&ir->body, this);
}

void
ir_constant_folding_visitor::visit(ir_function *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_expression *ir)
{
   ir_constant *op[2];
   unsigned int operand;

   for (operand = 0; operand < ir->get_num_operands(); operand++) {
      op[operand] = ir->operands[operand]->constant_expression_value();
      if (op[operand]) {
	 ir->operands[operand] = op[operand];
      } else {
	 ir->operands[operand]->accept(this);
      }
   }
}

void
ir_constant_folding_visitor::visit(ir_swizzle *ir)
{
   ir->val->accept(this);
}

void
ir_constant_folding_visitor::visit(ir_dereference_variable *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_dereference_array *ir)
{
   ir_constant *const_val =
      ir->array_index->constant_expression_value();

   if (const_val)
      ir->array_index = const_val;
   else
      ir->array_index->accept(this);

   ir->array->accept(this);
}

void
ir_constant_folding_visitor::visit(ir_dereference_record *ir)
{
   ir->record->accept(this);
}

void
ir_constant_folding_visitor::visit(ir_assignment *ir)
{
   ir_constant *const_val = ir->rhs->constant_expression_value();
   if (const_val)
      ir->rhs = const_val;
   else
      ir->rhs->accept(this);
}

void
ir_constant_folding_visitor::visit(ir_constant *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_call *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_return *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_if *ir)
{
   ir_constant *const_val = ir->condition->constant_expression_value();
   if (const_val)
      ir->condition = const_val;
   else
      ir->condition->accept(this);

   visit_exec_list(&ir->then_instructions, this);
   visit_exec_list(&ir->else_instructions, this);
}

void
ir_constant_folding_visitor::visit(ir_loop *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_loop_jump *ir)
{
   (void) ir;
}

bool
do_constant_folding(exec_list *instructions)
{
   ir_constant_folding_visitor constant_folding;

   visit_exec_list(instructions, &constant_folding);

   /* FINISHME: Return real progress. */
   return false;
}
<commit_msg>ir_constant_folding: Look at instructions in functions.<commit_after>/*
 * Copyright © 2010 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

/**
 * \file ir_constant_folding.cpp
 * Replace constant-valued expressions with references to constant values.
 */

#define NULL 0
#include "ir.h"
#include "ir_visitor.h"
#include "ir_optimization.h"
#include "glsl_types.h"

/**
 * Visitor class for replacing expressions with ir_constant values.
 */

class ir_constant_folding_visitor : public ir_visitor {
public:
   ir_constant_folding_visitor()
   {
      /* empty */
   }

   virtual ~ir_constant_folding_visitor()
   {
      /* empty */
   }

   /**
    * \name Visit methods
    *
    * As typical for the visitor pattern, there must be one \c visit method for
    * each concrete subclass of \c ir_instruction.  Virtual base classes within
    * the hierarchy should not have \c visit methods.
    */
   /*@{*/
   virtual void visit(ir_variable *);
   virtual void visit(ir_function_signature *);
   virtual void visit(ir_function *);
   virtual void visit(ir_expression *);
   virtual void visit(ir_swizzle *);
   virtual void visit(ir_dereference_variable *);
   virtual void visit(ir_dereference_array *);
   virtual void visit(ir_dereference_record *);
   virtual void visit(ir_assignment *);
   virtual void visit(ir_constant *);
   virtual void visit(ir_call *);
   virtual void visit(ir_return *);
   virtual void visit(ir_if *);
   virtual void visit(ir_loop *);
   virtual void visit(ir_loop_jump *);
   /*@}*/
};

void
ir_constant_folding_visitor::visit(ir_variable *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_function_signature *ir)
{
   visit_exec_list(&ir->body, this);
}

void
ir_constant_folding_visitor::visit(ir_function *ir)
{
   foreach_iter(exec_list_iterator, iter, *ir) {
      ir_function_signature *const sig = (ir_function_signature *) iter.get();
      sig->accept(this);
   }
}

void
ir_constant_folding_visitor::visit(ir_expression *ir)
{
   ir_constant *op[2];
   unsigned int operand;

   for (operand = 0; operand < ir->get_num_operands(); operand++) {
      op[operand] = ir->operands[operand]->constant_expression_value();
      if (op[operand]) {
	 ir->operands[operand] = op[operand];
      } else {
	 ir->operands[operand]->accept(this);
      }
   }
}

void
ir_constant_folding_visitor::visit(ir_swizzle *ir)
{
   ir->val->accept(this);
}

void
ir_constant_folding_visitor::visit(ir_dereference_variable *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_dereference_array *ir)
{
   ir_constant *const_val =
      ir->array_index->constant_expression_value();

   if (const_val)
      ir->array_index = const_val;
   else
      ir->array_index->accept(this);

   ir->array->accept(this);
}

void
ir_constant_folding_visitor::visit(ir_dereference_record *ir)
{
   ir->record->accept(this);
}

void
ir_constant_folding_visitor::visit(ir_assignment *ir)
{
   ir_constant *const_val = ir->rhs->constant_expression_value();
   if (const_val)
      ir->rhs = const_val;
   else
      ir->rhs->accept(this);
}

void
ir_constant_folding_visitor::visit(ir_constant *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_call *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_return *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_if *ir)
{
   ir_constant *const_val = ir->condition->constant_expression_value();
   if (const_val)
      ir->condition = const_val;
   else
      ir->condition->accept(this);

   visit_exec_list(&ir->then_instructions, this);
   visit_exec_list(&ir->else_instructions, this);
}

void
ir_constant_folding_visitor::visit(ir_loop *ir)
{
   (void) ir;
}

void
ir_constant_folding_visitor::visit(ir_loop_jump *ir)
{
   (void) ir;
}

bool
do_constant_folding(exec_list *instructions)
{
   ir_constant_folding_visitor constant_folding;

   visit_exec_list(instructions, &constant_folding);

   /* FINISHME: Return real progress. */
   return false;
}
<|endoftext|>


<commit_before>#include "result.h"

VALUE cBigDecimal;
VALUE cStringIO;
VALUE cSwiftResult;

VALUE fNew, fToDate;

void result_mark(ResultWrapper *handle) {
  if (handle)
    rb_gc_mark(handle->adapter);
}

void result_free(ResultWrapper *handle) {
  if (handle) {
    if (handle->free) {
      handle->result->cleanup();
      delete handle->result;
    }
    delete handle;
  }
}

VALUE result_alloc(VALUE klass) {
  ResultWrapper *handle = 0;
  return Data_Wrap_Struct(klass, result_mark, result_free, handle);
}

VALUE result_wrap_handle(VALUE klass, VALUE adapter, dbi::AbstractResult *result, bool free) {
  ResultWrapper *handle = new ResultWrapper;
  handle->result  = result;
  handle->adapter = adapter;
  handle->free    = free;

  VALUE obj = Data_Wrap_Struct(klass, result_mark, result_free, handle);
  if (!NIL_P(adapter))
    rb_iv_set(obj, "@timezone", rb_iv_get(adapter, "@timezone"));

  return obj;
}

dbi::AbstractResult* result_handle(VALUE self) {
  ResultWrapper *handle;
  Data_Get_Struct(self, ResultWrapper, handle);
  if (!handle) rb_raise(eSwiftRuntimeError, "Invalid object, did you forget to call #super?");

  return handle->result;
}

// TODO:
static VALUE result_clone(VALUE self) {
  rb_raise(eSwiftRuntimeError, "clone is not allowed.");
}

// TODO:
static VALUE result_dup(VALUE self) {
  rb_raise(eSwiftRuntimeError, "dup is not allowed.");
}

VALUE result_each(VALUE self) {
  uint64_t length;
  const char *data;

  dbi::AbstractResult *result = result_handle(self);
  VALUE scheme   = rb_iv_get(self, "@scheme");
  VALUE timezone = rb_iv_get(self, "@timezone");

  try {
    VALUE fields                      = rb_ary_new();
    std::vector<string> result_fields = result->fields();
    std::vector<int>    result_types  = result->types();
    for (uint32_t i = 0; i < result_fields.size(); i++) {
      rb_ary_push(fields, ID2SYM(rb_intern(result_fields[i].c_str())));
    }

    result->seek(0);
    for (uint32_t row = 0; row < result->rows(); row++) {
      VALUE tuple = rb_hash_new();
      for (uint32_t column = 0; column < result->columns(); column++) {
        data = (const char*)result->read(row, column, &length);
        if (data) {
          rb_hash_aset(
            tuple,
            rb_ary_entry(fields, column),
            typecast_field(result_types[column], data, length, timezone)
          );
        }
        else {
          rb_hash_aset(tuple, rb_ary_entry(fields, column), Qnil);
        }
      } // column loop
      NIL_P(scheme) ? rb_yield(tuple) : rb_yield(rb_funcall(scheme, rb_intern("load"), 1, tuple));
    } // row loop
  }
  CATCH_DBI_EXCEPTIONS();

  return Qnil;
}

static VALUE result_finish(VALUE self) {
  dbi::AbstractResult *result = result_handle(self);
  try {
    result->finish();
  }
  CATCH_DBI_EXCEPTIONS();
}

// Calculates local offset at a given time, including dst.
int64_t client_tzoffset(int64_t local, int isdst) {
  struct tm tm;
  gmtime_r((const time_t*)&local, &tm);
  // TODO: This won't work in Lord Howe Island, Australia which uses half hour shift.
  return (int64_t)(local + (isdst ? 3600 : 0) - mktime(&tm));
}

// Calculates server offset at a given time, including dst.
int64_t server_tzoffset(struct tm* tm, const char *zone) {
  uint64_t local;
  int64_t  offset;
  char buffer[512];
  char *old, saved[512];
  struct tm tm_copy;

  // save current zone setting.
  if ((old = getenv("TZ"))) {
    strncpy(saved, old, 512);
    saved[511] = 0;
  }

  // setup.
  snprintf(buffer, 512, ":%s", zone);
  setenv("TZ", buffer, 1);
  tzset();

  // pretend we're on server timezone and calculate offset.
  memcpy(&tm_copy, tm, sizeof(struct tm));
  tm_copy.tm_isdst = -1;
  local  = mktime(&tm_copy);
  offset = client_tzoffset(local, tm_copy.tm_isdst);

  // reset timezone to what it was before.
  old ? setenv("TZ", saved, 1) : unsetenv("TZ");
  tzset();

  return offset;
}

VALUE typecast_timestamp(const char *data, uint64_t len, VALUE timezone) {
  struct tm tm;
  int64_t epoch, adjust, offset;

  char tzsign = 0;
  int tzhour  = 0, tzmin = 0;
  long double sec_fraction = 0;
  const char *zone  = NIL_P(timezone) ? "" : CSTRING(timezone);

  memset(&tm, 0, sizeof(struct tm));
  if (strchr(data, '.')) {
    sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%Lf%c%02d:%02d",
      &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
      &sec_fraction, &tzsign, &tzhour, &tzmin);
  }
  else {
    sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%c%02d:%02d",
      &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
      &tzsign, &tzhour, &tzmin);
  }

  tm.tm_year  -= 1900;
  tm.tm_mon   -= 1;
  tm.tm_isdst = -1;
  if (tm.tm_mday > 0) {
    epoch  = mktime(&tm);
    adjust = client_tzoffset(epoch, tm.tm_isdst);
    offset = adjust;

    if (tzsign == '+' || tzsign == '-') {
      offset = tzsign == '+'
        ? (time_t)tzhour *  3600 + (time_t)tzmin *  60
        : (time_t)tzhour * -3600 + (time_t)tzmin * -60;
    }
    else if (*zone) {
      if (strncasecmp(zone, "UTC", 3) == 0 || strncasecmp(zone, "GMT", 3) == 0)
        offset = 0;
      else if (sscanf(zone, "%03d%02d",  &tzhour, &tzmin) < 2 && sscanf(zone, "%03d:%02d", &tzhour, &tzmin) < 1)
        offset = server_tzoffset(&tm, zone);
      else
        offset = tzhour*3600 + tzmin*60*tzhour/abs(tzhour);
    }

    return rb_time_new(epoch+adjust-offset, (uint64_t)(sec_fraction*1000000L));
  }

  // TODO: throw a warning ?
  return rb_str_new(data, len);
}

#define typecast_date(data,len,tz)   rb_funcall(typecast_timestamp(data,len,tz), fToDate, 0)

VALUE typecast_field(int type, const char *data, uint64_t length, VALUE timezone) {
  // This is my wish list below for rubycore - to be built into core ruby.
  // 1. Time class represents time - time zone invariant
  // 2. Date class represents a date - time zone invariant
  // 3. DateTime class represents a timestamp with full zoneinfo support.
  switch(type) {
    case DBI_TYPE_BOOLEAN:
      return (data && (data[0] =='t' || data[0] == '1')) ? Qtrue : Qfalse;
    case DBI_TYPE_INT:
      return rb_cstr2inum(data, 10);
    case DBI_TYPE_BLOB:
      return rb_funcall(cStringIO, fNew, 1, rb_str_new(data, length));
    // I'm undecided on typecasting TIME only types into native ruby types due to lack
    // of support in core.
    case DBI_TYPE_TIME:
    case DBI_TYPE_TEXT:
      return rb_enc_str_new(data, length, rb_utf8_encoding());
    case DBI_TYPE_TIMESTAMP:
      return typecast_timestamp(data, length, timezone);
    case DBI_TYPE_DATE:
      return typecast_date(data, length, timezone);
    case DBI_TYPE_NUMERIC:
      return rb_funcall(cBigDecimal, fNew, 1, rb_str_new2(data));
    case DBI_TYPE_FLOAT:
      return rb_float_new(atof(data));
  }
}

VALUE result_insert_id(VALUE self) {
  dbi::AbstractResult *result = result_handle(self);
  try {
    return SIZET2NUM(result->lastInsertID());
  }
  CATCH_DBI_EXCEPTIONS();
  return Qnil;
}

VALUE result_rows(VALUE self) {
  dbi::AbstractResult *result = result_handle(self);
  try {
    return SIZET2NUM(result->rows());
  }
  CATCH_DBI_EXCEPTIONS();
}

VALUE result_columns(VALUE self) {
  dbi::AbstractResult *result = result_handle(self);
  try {
    return SIZET2NUM(result->columns());
  }
  CATCH_DBI_EXCEPTIONS();
}

VALUE result_fields(VALUE self) {
  dbi::AbstractResult *result = result_handle(self);
  try {
    std::vector<string> result_fields = result->fields();
    VALUE fields = rb_ary_new();
    for (int i = 0; i < result_fields.size(); i++)
      rb_ary_push(fields, ID2SYM(rb_intern(result_fields[i].c_str())));
    return fields;
  }
  CATCH_DBI_EXCEPTIONS();
}

void init_swift_result() {
  rb_require("bigdecimal");
  rb_require("stringio");
  rb_require("date");

  VALUE mSwift = rb_define_module("Swift");
  cSwiftResult = rb_define_class_under(mSwift, "Result", rb_cObject);
  cStringIO    = CONST_GET(rb_mKernel, "StringIO");
  cBigDecimal  = CONST_GET(rb_mKernel, "BigDecimal");

  fNew         = rb_intern("new");
  fToDate      = rb_intern("to_date");

  rb_define_alloc_func(cSwiftResult, result_alloc);
  rb_include_module(cSwiftResult, CONST_GET(rb_mKernel, "Enumerable"));

  rb_define_method(cSwiftResult, "clone",      RUBY_METHOD_FUNC(result_clone),     0);
  rb_define_method(cSwiftResult, "dup",        RUBY_METHOD_FUNC(result_dup),       0);
  rb_define_method(cSwiftResult, "each",       RUBY_METHOD_FUNC(result_each),      0);
  rb_define_method(cSwiftResult, "finish",     RUBY_METHOD_FUNC(result_finish),    0);
  rb_define_method(cSwiftResult, "insert_id",  RUBY_METHOD_FUNC(result_insert_id), 0);
  rb_define_method(cSwiftResult, "rows",       RUBY_METHOD_FUNC(result_rows),      0);
  rb_define_method(cSwiftResult, "columns",    RUBY_METHOD_FUNC(result_columns),   0);
  rb_define_method(cSwiftResult, "fields",     RUBY_METHOD_FUNC(result_fields),    0);
}

<commit_msg>timestamp parsing - cleanup<commit_after>#include "result.h"

VALUE cBigDecimal;
VALUE cStringIO;
VALUE cSwiftResult;

VALUE fNew, fToDate;

void result_mark(ResultWrapper *handle) {
  if (handle)
    rb_gc_mark(handle->adapter);
}

void result_free(ResultWrapper *handle) {
  if (handle) {
    if (handle->free) {
      handle->result->cleanup();
      delete handle->result;
    }
    delete handle;
  }
}

VALUE result_alloc(VALUE klass) {
  ResultWrapper *handle = 0;
  return Data_Wrap_Struct(klass, result_mark, result_free, handle);
}

VALUE result_wrap_handle(VALUE klass, VALUE adapter, dbi::AbstractResult *result, bool free) {
  ResultWrapper *handle = new ResultWrapper;
  handle->result  = result;
  handle->adapter = adapter;
  handle->free    = free;

  VALUE obj = Data_Wrap_Struct(klass, result_mark, result_free, handle);
  if (!NIL_P(adapter))
    rb_iv_set(obj, "@timezone", rb_iv_get(adapter, "@timezone"));

  return obj;
}

dbi::AbstractResult* result_handle(VALUE self) {
  ResultWrapper *handle;
  Data_Get_Struct(self, ResultWrapper, handle);
  if (!handle) rb_raise(eSwiftRuntimeError, "Invalid object, did you forget to call #super?");

  return handle->result;
}

// TODO:
static VALUE result_clone(VALUE self) {
  rb_raise(eSwiftRuntimeError, "clone is not allowed.");
}

// TODO:
static VALUE result_dup(VALUE self) {
  rb_raise(eSwiftRuntimeError, "dup is not allowed.");
}

VALUE result_each(VALUE self) {
  uint64_t length;
  const char *data;

  dbi::AbstractResult *result = result_handle(self);
  VALUE scheme   = rb_iv_get(self, "@scheme");
  VALUE timezone = rb_iv_get(self, "@timezone");

  try {
    VALUE fields                      = rb_ary_new();
    std::vector<string> result_fields = result->fields();
    std::vector<int>    result_types  = result->types();
    for (uint32_t i = 0; i < result_fields.size(); i++) {
      rb_ary_push(fields, ID2SYM(rb_intern(result_fields[i].c_str())));
    }

    result->seek(0);
    for (uint32_t row = 0; row < result->rows(); row++) {
      VALUE tuple = rb_hash_new();
      for (uint32_t column = 0; column < result->columns(); column++) {
        data = (const char*)result->read(row, column, &length);
        if (data) {
          rb_hash_aset(
            tuple,
            rb_ary_entry(fields, column),
            typecast_field(result_types[column], data, length, timezone)
          );
        }
        else {
          rb_hash_aset(tuple, rb_ary_entry(fields, column), Qnil);
        }
      } // column loop
      NIL_P(scheme) ? rb_yield(tuple) : rb_yield(rb_funcall(scheme, rb_intern("load"), 1, tuple));
    } // row loop
  }
  CATCH_DBI_EXCEPTIONS();

  return Qnil;
}

static VALUE result_finish(VALUE self) {
  dbi::AbstractResult *result = result_handle(self);
  try {
    result->finish();
  }
  CATCH_DBI_EXCEPTIONS();
}

// Calculates local offset at a given time, including dst.
int64_t client_tzoffset(int64_t local, int isdst) {
  struct tm tm;
  gmtime_r((const time_t*)&local, &tm);
  // TODO: This won't work in Lord Howe Island, Australia which uses half hour shift.
  return (int64_t)(local + (isdst ? 3600 : 0) - mktime(&tm));
}

// Calculates server offset at a given time, including dst.
int64_t server_tzoffset(struct tm* tm, const char *zone) {
  uint64_t local;
  int64_t  offset;
  char buffer[512];
  char *old, saved[512];
  struct tm tm_copy;

  // save current zone setting.
  if ((old = getenv("TZ"))) {
    strncpy(saved, old, 512);
    saved[511] = 0;
  }

  // setup.
  snprintf(buffer, 512, ":%s", zone);
  setenv("TZ", buffer, 1);
  tzset();

  // pretend we're on server timezone and calculate offset.
  memcpy(&tm_copy, tm, sizeof(struct tm));
  tm_copy.tm_isdst = -1;
  local  = mktime(&tm_copy);
  offset = client_tzoffset(local, tm_copy.tm_isdst);

  // reset timezone to what it was before.
  old ? setenv("TZ", saved, 1) : unsetenv("TZ");
  tzset();

  return offset;
}

VALUE typecast_timestamp(const char *data, uint64_t len, VALUE timezone) {
  struct tm tm;
  int64_t epoch, adjust, offset;

  char tzsign = 0;
  int tzhour  = 0, tzmin = 0;
  long double sec_fraction = 0;
  const char *zone  = NIL_P(timezone) ? "" : CSTRING(timezone);

  memset(&tm, 0, sizeof(struct tm));
  if (strchr(data, '.')) {
    sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%Lf%c%02d:%02d",
      &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
      &sec_fraction, &tzsign, &tzhour, &tzmin);
  }
  else {
    sscanf(data, "%04d-%02d-%02d %02d:%02d:%02d%c%02d:%02d",
      &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
      &tzsign, &tzhour, &tzmin);
  }

  tm.tm_year  -= 1900;
  tm.tm_mon   -= 1;
  tm.tm_isdst = -1;
  if (tm.tm_mday > 0) {
    epoch  = mktime(&tm);
    adjust = client_tzoffset(epoch, tm.tm_isdst);
    offset = adjust;

    if (tzsign == '+' || tzsign == '-') {
      offset = tzsign == '+'
        ? (time_t)tzhour *  3600 + (time_t)tzmin *  60
        : (time_t)tzhour * -3600 + (time_t)tzmin * -60;
    }
    else if (*zone) {
      if (strncasecmp(zone, "UTC", 3) == 0 || strncasecmp(zone, "GMT", 3) == 0)
        offset = 0;
      else if (strcmp(zone, "+00:00") == 0 || strcmp(zone, "+0000") == 0)
        offset = 0;
      else if (sscanf(zone, "%c%02d%02d",  &tzsign, &tzhour, &tzmin) == 3)
        offset = tzsign == '+' ? (time_t)tzhour*3600 + (time_t)tzmin*60 : -1*((time_t)tzhour*3600 + (time_t)tzmin*60);
      else if (sscanf(zone, "%c%02d:%02d", &tzsign, &tzhour, &tzmin) >= 2)
        offset = tzsign == '+' ? (time_t)tzhour*3600 + (time_t)tzmin*60 : -1*((time_t)tzhour*3600 + (time_t)tzmin*60);
      else
        offset = server_tzoffset(&tm, zone);
    }

    return rb_time_new(epoch+adjust-offset, (uint64_t)(sec_fraction*1000000L));
  }

  // TODO: throw a warning ?
  return rb_str_new(data, len);
}

#define typecast_date(data,len,tz)   rb_funcall(typecast_timestamp(data,len,tz), fToDate, 0)

VALUE typecast_field(int type, const char *data, uint64_t length, VALUE timezone) {
  // This is my wish list below for rubycore - to be built into core ruby.
  // 1. Time class represents time - time zone invariant
  // 2. Date class represents a date - time zone invariant
  // 3. DateTime class represents a timestamp with full zoneinfo support.
  switch(type) {
    case DBI_TYPE_BOOLEAN:
      return (data && (data[0] =='t' || data[0] == '1')) ? Qtrue : Qfalse;
    case DBI_TYPE_INT:
      return rb_cstr2inum(data, 10);
    case DBI_TYPE_BLOB:
      return rb_funcall(cStringIO, fNew, 1, rb_str_new(data, length));
    // I'm undecided on typecasting TIME only types into native ruby types due to lack
    // of support in core.
    case DBI_TYPE_TIME:
    case DBI_TYPE_TEXT:
      return rb_enc_str_new(data, length, rb_utf8_encoding());
    case DBI_TYPE_TIMESTAMP:
      return typecast_timestamp(data, length, timezone);
    case DBI_TYPE_DATE:
      return typecast_date(data, length, timezone);
    case DBI_TYPE_NUMERIC:
      return rb_funcall(cBigDecimal, fNew, 1, rb_str_new2(data));
    case DBI_TYPE_FLOAT:
      return rb_float_new(atof(data));
  }
}

VALUE result_insert_id(VALUE self) {
  dbi::AbstractResult *result = result_handle(self);
  try {
    return SIZET2NUM(result->lastInsertID());
  }
  CATCH_DBI_EXCEPTIONS();
  return Qnil;
}

VALUE result_rows(VALUE self) {
  dbi::AbstractResult *result = result_handle(self);
  try {
    return SIZET2NUM(result->rows());
  }
  CATCH_DBI_EXCEPTIONS();
}

VALUE result_columns(VALUE self) {
  dbi::AbstractResult *result = result_handle(self);
  try {
    return SIZET2NUM(result->columns());
  }
  CATCH_DBI_EXCEPTIONS();
}

VALUE result_fields(VALUE self) {
  dbi::AbstractResult *result = result_handle(self);
  try {
    std::vector<string> result_fields = result->fields();
    VALUE fields = rb_ary_new();
    for (int i = 0; i < result_fields.size(); i++)
      rb_ary_push(fields, ID2SYM(rb_intern(result_fields[i].c_str())));
    return fields;
  }
  CATCH_DBI_EXCEPTIONS();
}

void init_swift_result() {
  rb_require("bigdecimal");
  rb_require("stringio");
  rb_require("date");

  VALUE mSwift = rb_define_module("Swift");
  cSwiftResult = rb_define_class_under(mSwift, "Result", rb_cObject);
  cStringIO    = CONST_GET(rb_mKernel, "StringIO");
  cBigDecimal  = CONST_GET(rb_mKernel, "BigDecimal");

  fNew         = rb_intern("new");
  fToDate      = rb_intern("to_date");

  rb_define_alloc_func(cSwiftResult, result_alloc);
  rb_include_module(cSwiftResult, CONST_GET(rb_mKernel, "Enumerable"));

  rb_define_method(cSwiftResult, "clone",      RUBY_METHOD_FUNC(result_clone),     0);
  rb_define_method(cSwiftResult, "dup",        RUBY_METHOD_FUNC(result_dup),       0);
  rb_define_method(cSwiftResult, "each",       RUBY_METHOD_FUNC(result_each),      0);
  rb_define_method(cSwiftResult, "finish",     RUBY_METHOD_FUNC(result_finish),    0);
  rb_define_method(cSwiftResult, "insert_id",  RUBY_METHOD_FUNC(result_insert_id), 0);
  rb_define_method(cSwiftResult, "rows",       RUBY_METHOD_FUNC(result_rows),      0);
  rb_define_method(cSwiftResult, "columns",    RUBY_METHOD_FUNC(result_columns),   0);
  rb_define_method(cSwiftResult, "fields",     RUBY_METHOD_FUNC(result_fields),    0);
}

<|endoftext|>


<commit_before>#include "ViewClient.hpp"

#include <lcm/lcm-cpp.hpp>
#include <lcmtypes/drc/map_octree_t.hpp>
#include <lcmtypes/drc/map_cloud_t.hpp>
#include <lcmtypes/drc/map_image_t.hpp>
#include <lcmtypes/drc/map_catalog_t.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <drc_utils/Clock.hpp>

#include "PointCloudView.hpp"
#include "OctreeView.hpp"
#include "DepthImageView.hpp"
#include "LcmTranslator.hpp"
#include "ThreadSafeQueue.hpp"
#include "BotWrapper.hpp"
#include "Utils.hpp"

using namespace maps;

struct ViewClient::Worker {

  enum State {
    StateIdle,
    StateRunning,
    StateShutdown
  };

  struct Message {
    enum Type {
      TypeOctree,
      TypeCloud,
      TypeDepth,
      TypeCatalog
    };
    Type mType;
    int64_t mId;
    boost::shared_ptr<void> mPayload;
  };

  ViewClient* mClient;
  BotWrapper::Ptr mBotWrapper;
  State mState;
  lcm::Subscription* mOctreeSubscription;
  lcm::Subscription* mCloudSubscription;
  lcm::Subscription* mDepthSubscription;
  lcm::Subscription* mCatalogSubscription;
  ThreadSafeQueue<Message> mMessageQueue;
  boost::mutex mMutex;
  boost::condition_variable mCondition;
  boost::thread mThread;

  Worker(ViewClient* iClient) {
    mClient = iClient;
    mOctreeSubscription = NULL;
    mCloudSubscription = NULL;
    mDepthSubscription = NULL;
    mCatalogSubscription = NULL;
    mState = StateIdle;
    mThread = boost::thread(boost::ref(*this));
  }

  ~Worker() {
    boost::mutex::scoped_lock lock(mMutex);
    if (mBotWrapper != NULL) {
      if (mBotWrapper->getLcm() != NULL) {
        mBotWrapper->getLcm()->unsubscribe(mOctreeSubscription);
        mBotWrapper->getLcm()->unsubscribe(mCloudSubscription);
        mBotWrapper->getLcm()->unsubscribe(mDepthSubscription);
        mBotWrapper->getLcm()->unsubscribe(mCatalogSubscription);
      }
    }
    mState = StateShutdown;
    lock.unlock();
    mCondition.notify_one();
    mMessageQueue.unblock();
    try { mThread.join(); }
    catch (const boost::thread_interrupted&) {}
  }

  bool start() {
    boost::mutex::scoped_lock lock(mMutex);
    if (mState == StateRunning) {
      return false;
    }
    if ((mBotWrapper == NULL) || (mBotWrapper->getLcm() == NULL)) {
      return false;
    }
    mState = StateRunning;
    mCondition.notify_one();
    lock.unlock();
    mOctreeSubscription = mBotWrapper->getLcm()->
      subscribe(mClient->mOctreeChannel, &Worker::onOctree, this);
    mCloudSubscription = mBotWrapper->getLcm()->
      subscribe(mClient->mCloudChannel, &Worker::onCloud, this);
    mDepthSubscription = mBotWrapper->getLcm()->
      subscribe(mClient->mDepthChannel, &Worker::onDepth, this);
    mCatalogSubscription = mBotWrapper->getLcm()->
      subscribe(mClient->mCatalogChannel, &Worker::onCatalog, this);
    return true;
  }

  bool stop() {
    boost::mutex::scoped_lock lock(mMutex);
    if (mState != StateRunning) {
      return false;
    }
    if (mBotWrapper != NULL) {
      if (mBotWrapper->getLcm() != NULL) {
        mBotWrapper->getLcm()->unsubscribe(mOctreeSubscription);
        mBotWrapper->getLcm()->unsubscribe(mCloudSubscription);
        mBotWrapper->getLcm()->unsubscribe(mDepthSubscription);
        mBotWrapper->getLcm()->unsubscribe(mCatalogSubscription);
      }
    }
    mState = StateIdle;
    lock.unlock();
    mCondition.notify_one();
    mMessageQueue.clear();
    return true;
  }

  void onOctree(const lcm::ReceiveBuffer* iBuf,
                const std::string& iChannel,
                const drc::map_octree_t* iMessage) {
    Message msg;
    msg.mType = Message::TypeOctree;
    msg.mId = iMessage->view_id;
    boost::shared_ptr<drc::map_octree_t>
      payload(new drc::map_octree_t(*iMessage));
    msg.mPayload = boost::static_pointer_cast<void>(payload);
    mMessageQueue.push(msg);
  }

  void onCloud(const lcm::ReceiveBuffer* iBuf,
               const std::string& iChannel,
               const drc::map_cloud_t* iMessage) {
    Message msg;
    msg.mType = Message::TypeCloud;
    msg.mId = iMessage->view_id;
    boost::shared_ptr<drc::map_cloud_t>
      payload(new drc::map_cloud_t(*iMessage));
    msg.mPayload = boost::static_pointer_cast<void>(payload);
    mMessageQueue.push(msg);
  }

  void onDepth(const lcm::ReceiveBuffer* iBuf,
               const std::string& iChannel,
               const drc::map_image_t* iMessage) {
    Message msg;
    msg.mType = Message::TypeDepth;
    msg.mId = iMessage->view_id;
    boost::shared_ptr<drc::map_image_t>
      payload(new drc::map_image_t(*iMessage));
    msg.mPayload = boost::static_pointer_cast<void>(payload);
    mMessageQueue.push(msg);
  }

  void onCatalog(const lcm::ReceiveBuffer* iBuf,
                 const std::string& iChannel,
                 const drc::map_catalog_t* iMessage) {
    Message msg;
    msg.mType = Message::TypeCatalog;
    msg.mId = 0;
    boost::shared_ptr<drc::map_catalog_t>
      payload(new drc::map_catalog_t(*iMessage));
    msg.mPayload = boost::static_pointer_cast<void>(payload);
    mMessageQueue.push(msg);
  }

  void operator()() {
    while (mState != StateShutdown) {

      {
        boost::mutex::scoped_lock lock(mMutex);
        while (mState == StateIdle) {
          mCondition.wait(lock);
        }
      }

      if (mState != StateRunning) {
        continue;
      }

      // wait for new message
      Message msg;
      if (!mMessageQueue.waitForData(msg)) {
        continue;
      }

      // handle catalog
      if (msg.mType == Message::TypeCatalog) {
        boost::shared_ptr<drc::map_catalog_t> catalog =
          boost::static_pointer_cast<drc::map_catalog_t>(msg.mPayload);
        bool changed = false;
        std::set<int64_t> catalogIds;
        for (int i = 0; i < catalog->views.size(); ++i) {
          ViewBase::Spec spec;
          LcmTranslator::fromLcm(catalog->views[i], spec);
          int64_t id = spec.mViewId;
          catalogIds.insert(id);
          SpecCollection::const_iterator item = mClient->mCatalog.find(id);
          if ((item == mClient->mCatalog.end()) || (spec != item->second)) {
            changed = true;
          }
          mClient->mCatalog[id] = spec;
        }
        for (ViewCollection::const_iterator iter = mClient->mViews.begin();
             iter != mClient->mViews.end(); ) {
          if (catalogIds.find(iter->second->getId()) == catalogIds.end()) {
            mClient->mViews.erase(iter++);
            changed = true;
          }
          else {
            ++iter;
          }
        }
        for (SpecCollection::const_iterator iter = mClient->mCatalog.begin();
             iter != mClient->mCatalog.end(); ) {
          if (catalogIds.find(iter->second.mViewId) == catalogIds.end()) {
            mClient->mCatalog.erase(iter++);
            changed = true;
          }
          else {
            ++iter;
          }
        }
        mClient->notifyCatalogListeners(changed);
        continue;
      }

      // find view or insert new one for this id
      SpecCollection::const_iterator item = mClient->mCatalog.find(msg.mId);
      if (item == mClient->mCatalog.end()) {
        ViewBase::Spec spec;
        spec.mViewId = msg.mId;
        mClient->mCatalog[msg.mId] = spec;
        mClient->notifyCatalogListeners(true);
      }
      ViewPtr view;

      // handle octree
      if (msg.mType == Message::TypeOctree) {
        boost::shared_ptr<drc::map_octree_t> payload =
          boost::static_pointer_cast<drc::map_octree_t>(msg.mPayload);
        OctreeView* octreeView = new OctreeView();
        LcmTranslator::fromLcm(*payload, *octreeView);
        view.reset(octreeView);
        view->setUpdateTime(payload->utime);
      }

      // handle cloud
      else if (msg.mType == Message::TypeCloud) {
        boost::shared_ptr<drc::map_cloud_t> payload =
          boost::static_pointer_cast<drc::map_cloud_t>(msg.mPayload);
        PointCloudView* cloudView = new PointCloudView();
        LcmTranslator::fromLcm(*payload, *cloudView);
        view.reset(cloudView);
        view->setUpdateTime(payload->utime);
      }

      // handle depth image
      else if (msg.mType == Message::TypeDepth) {
        boost::shared_ptr<drc::map_image_t> payload =
          boost::static_pointer_cast<drc::map_image_t>(msg.mPayload);
        DepthImageView* depthView = new DepthImageView();
        LcmTranslator::fromLcm(*payload, *depthView);
        view.reset(depthView);
        view->setUpdateTime(payload->utime);
      }

      if (view != NULL) mClient->mViews[msg.mId] = view;

      // notify subscribers
      mClient->notifyDataListeners(msg.mId);
    }
  }
};

ViewClient::
ViewClient() {
  setRequestChannel("MAP_REQUEST");
  setOctreeChannel("MAP_OCTREE");
  setCloudChannel("MAP_CLOUD");
  setDepthChannel("MAP_DEPTH");
  setCatalogChannel("MAP_CATALOG");
  mWorker.reset(new Worker(this));
}

ViewClient::
~ViewClient() {
  stop();
}

void ViewClient::
setBotWrapper(const boost::shared_ptr<BotWrapper>& iWrapper) {
  mBotWrapper = iWrapper;
  mWorker->mBotWrapper = iWrapper;
}

void ViewClient::
setRequestChannel(const std::string& iChannel) {
  mRequestChannel = iChannel;
}

void ViewClient::
setOctreeChannel(const std::string& iChannel) {
  mOctreeChannel = iChannel;
}

void ViewClient::
setCloudChannel(const std::string& iChannel) {
  mCloudChannel = iChannel;
}

void ViewClient::
setDepthChannel(const std::string& iChannel) {
  mDepthChannel = iChannel;
}

void ViewClient::
setCatalogChannel(const std::string& iChannel) {
  mCatalogChannel = iChannel;
}

int64_t ViewClient::request(const ViewBase::Spec& iSpec) {
  drc::map_request_t message;
  LcmTranslator::toLcm(iSpec, message);
  message.utime = drc::Clock::instance()->getCurrentTime();
  if (message.view_id < 0) {
    message.view_id = (Utils::rand64() >> 1);
  }
  mBotWrapper->getLcm()->publish(mRequestChannel, &message);
  return message.view_id;
}

ViewClient::ViewPtr ViewClient::
getView(const int64_t iId) const {
  ViewCollection::const_iterator item = mViews.find(iId);
  if (item != mViews.end()) {
    return item->second;
  }
  return ViewPtr();
}

std::vector<ViewClient::ViewPtr> ViewClient::
getAllViews() const {
  std::vector<ViewPtr> views;
  views.reserve(mViews.size());
  ViewCollection::const_iterator iter;
  for (iter = mViews.begin(); iter != mViews.end(); ++iter) {
    views.push_back(iter->second);
  }
  return views;
}

bool ViewClient::
getSpec(const int64_t iId, ViewBase::Spec& oSpec) const {
  SpecCollection::const_iterator item = mCatalog.find(iId);
  if (item == mCatalog.end()) {
    return false;
  }
  oSpec = item->second;
  return true;
}

std::vector<ViewBase::Spec> ViewClient::
getAllSpecs() const {
  std::vector<ViewBase::Spec> specs;
  specs.reserve(mCatalog.size());
  SpecCollection::const_iterator iter;
  for (iter = mCatalog.begin(); iter != mCatalog.end(); ++iter) {
    specs.push_back(iter->second);
  }
  return specs;
}

void ViewClient::
clearAll() {
  mViews.clear();
  mCatalog.clear();
  notifyCatalogListeners(true);
}

bool ViewClient::
addListener(const Listener* iListener) {
  return (mListeners.insert((Listener*)iListener).second);
}

bool ViewClient::
removeListener(const Listener* iListener) {
  return (mListeners.erase((Listener*)iListener) > 0);
}

bool ViewClient::
removeAllListeners() {
  mListeners.clear();
  return true;
}

bool ViewClient::
start() {
  return mWorker->start();
}

bool ViewClient::
stop() {
  return mWorker->stop();
}

void ViewClient::
notifyCatalogListeners(const bool iChanged) {
  for (std::set<Listener*>::iterator iter = mListeners.begin();
       iter != mListeners.end(); ++iter) {
    if (*iter != NULL) {
      (*iter)->notifyCatalog(iChanged);
    }
  }
}

void ViewClient::
notifyDataListeners(const int64_t iId) {
  for (std::set<Listener*>::iterator iter = mListeners.begin();
       iter != mListeners.end(); ++iter) {
    if (*iter != NULL) {
      (*iter)->notifyData(iId);
    }
  }
}
<commit_msg>investigating crash (only in matlab mex, only in debug) related to notify_one call<commit_after>#include "ViewClient.hpp"

#include <lcm/lcm-cpp.hpp>
#include <lcmtypes/drc/map_octree_t.hpp>
#include <lcmtypes/drc/map_cloud_t.hpp>
#include <lcmtypes/drc/map_image_t.hpp>
#include <lcmtypes/drc/map_catalog_t.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <drc_utils/Clock.hpp>

#include "PointCloudView.hpp"
#include "OctreeView.hpp"
#include "DepthImageView.hpp"
#include "LcmTranslator.hpp"
#include "ThreadSafeQueue.hpp"
#include "BotWrapper.hpp"
#include "Utils.hpp"

using namespace maps;

struct ViewClient::Worker {

  enum State {
    StateIdle,
    StateRunning,
    StateShutdown
  };

  struct Message {
    enum Type {
      TypeOctree,
      TypeCloud,
      TypeDepth,
      TypeCatalog
    };
    Type mType;
    int64_t mId;
    boost::shared_ptr<void> mPayload;
  };

  ViewClient* mClient;
  BotWrapper::Ptr mBotWrapper;
  State mState;
  lcm::Subscription* mOctreeSubscription;
  lcm::Subscription* mCloudSubscription;
  lcm::Subscription* mDepthSubscription;
  lcm::Subscription* mCatalogSubscription;
  ThreadSafeQueue<Message> mMessageQueue;
  boost::mutex mMutex;
  boost::condition_variable mCondition;
  boost::thread mThread;

  Worker(ViewClient* iClient) {
    mClient = iClient;
    mOctreeSubscription = NULL;
    mCloudSubscription = NULL;
    mDepthSubscription = NULL;
    mCatalogSubscription = NULL;
    mState = StateIdle;
    mThread = boost::thread(boost::ref(*this));
  }

  ~Worker() {
    boost::mutex::scoped_lock lock(mMutex);
    if (mBotWrapper != NULL) {
      if (mBotWrapper->getLcm() != NULL) {
        mBotWrapper->getLcm()->unsubscribe(mOctreeSubscription);
        mBotWrapper->getLcm()->unsubscribe(mCloudSubscription);
        mBotWrapper->getLcm()->unsubscribe(mDepthSubscription);
        mBotWrapper->getLcm()->unsubscribe(mCatalogSubscription);
      }
    }
    mState = StateShutdown;
    lock.unlock();
    mCondition.notify_one();
    mMessageQueue.unblock();
    try { mThread.join(); }
    catch (const boost::thread_interrupted&) {}
  }

  bool start() {
    boost::mutex::scoped_lock lock(mMutex);
    if (mState == StateRunning) {
      return false;
    }
    if ((mBotWrapper == NULL) || (mBotWrapper->getLcm() == NULL)) {
      return false;
    }
    mState = StateRunning;
    lock.unlock();
    mCondition.notify_one();
    mOctreeSubscription = mBotWrapper->getLcm()->
      subscribe(mClient->mOctreeChannel, &Worker::onOctree, this);
    mCloudSubscription = mBotWrapper->getLcm()->
      subscribe(mClient->mCloudChannel, &Worker::onCloud, this);
    mDepthSubscription = mBotWrapper->getLcm()->
      subscribe(mClient->mDepthChannel, &Worker::onDepth, this);
    mCatalogSubscription = mBotWrapper->getLcm()->
      subscribe(mClient->mCatalogChannel, &Worker::onCatalog, this);
    return true;
  }

  bool stop() {
    boost::mutex::scoped_lock lock(mMutex);
    if (mState != StateRunning) {
      return false;
    }
    if (mBotWrapper != NULL) {
      if (mBotWrapper->getLcm() != NULL) {
        mBotWrapper->getLcm()->unsubscribe(mOctreeSubscription);
        mBotWrapper->getLcm()->unsubscribe(mCloudSubscription);
        mBotWrapper->getLcm()->unsubscribe(mDepthSubscription);
        mBotWrapper->getLcm()->unsubscribe(mCatalogSubscription);
      }
    }
    mState = StateIdle;
    lock.unlock();
    mCondition.notify_one();
    mMessageQueue.clear();
    return true;
  }

  void onOctree(const lcm::ReceiveBuffer* iBuf,
                const std::string& iChannel,
                const drc::map_octree_t* iMessage) {
    Message msg;
    msg.mType = Message::TypeOctree;
    msg.mId = iMessage->view_id;
    boost::shared_ptr<drc::map_octree_t>
      payload(new drc::map_octree_t(*iMessage));
    msg.mPayload = boost::static_pointer_cast<void>(payload);
    mMessageQueue.push(msg);
  }

  void onCloud(const lcm::ReceiveBuffer* iBuf,
               const std::string& iChannel,
               const drc::map_cloud_t* iMessage) {
    Message msg;
    msg.mType = Message::TypeCloud;
    msg.mId = iMessage->view_id;
    boost::shared_ptr<drc::map_cloud_t>
      payload(new drc::map_cloud_t(*iMessage));
    msg.mPayload = boost::static_pointer_cast<void>(payload);
    mMessageQueue.push(msg);
  }

  void onDepth(const lcm::ReceiveBuffer* iBuf,
               const std::string& iChannel,
               const drc::map_image_t* iMessage) {
    Message msg;
    msg.mType = Message::TypeDepth;
    msg.mId = iMessage->view_id;
    boost::shared_ptr<drc::map_image_t>
      payload(new drc::map_image_t(*iMessage));
    msg.mPayload = boost::static_pointer_cast<void>(payload);
    mMessageQueue.push(msg);
  }

  void onCatalog(const lcm::ReceiveBuffer* iBuf,
                 const std::string& iChannel,
                 const drc::map_catalog_t* iMessage) {
    Message msg;
    msg.mType = Message::TypeCatalog;
    msg.mId = 0;
    boost::shared_ptr<drc::map_catalog_t>
      payload(new drc::map_catalog_t(*iMessage));
    msg.mPayload = boost::static_pointer_cast<void>(payload);
    mMessageQueue.push(msg);
  }

  void operator()() {
    while (mState != StateShutdown) {

      {
        boost::mutex::scoped_lock lock(mMutex);
        while (mState == StateIdle) {
          mCondition.wait(lock);
        }
      }

      if (mState != StateRunning) {
        continue;
      }

      // wait for new message
      Message msg;
      if (!mMessageQueue.waitForData(msg)) {
        continue;
      }

      // handle catalog
      if (msg.mType == Message::TypeCatalog) {
        boost::shared_ptr<drc::map_catalog_t> catalog =
          boost::static_pointer_cast<drc::map_catalog_t>(msg.mPayload);
        bool changed = false;
        std::set<int64_t> catalogIds;
        for (int i = 0; i < catalog->views.size(); ++i) {
          ViewBase::Spec spec;
          LcmTranslator::fromLcm(catalog->views[i], spec);
          int64_t id = spec.mViewId;
          catalogIds.insert(id);
          SpecCollection::const_iterator item = mClient->mCatalog.find(id);
          if ((item == mClient->mCatalog.end()) || (spec != item->second)) {
            changed = true;
          }
          mClient->mCatalog[id] = spec;
        }
        for (ViewCollection::const_iterator iter = mClient->mViews.begin();
             iter != mClient->mViews.end(); ) {
          if (catalogIds.find(iter->second->getId()) == catalogIds.end()) {
            mClient->mViews.erase(iter++);
            changed = true;
          }
          else {
            ++iter;
          }
        }
        for (SpecCollection::const_iterator iter = mClient->mCatalog.begin();
             iter != mClient->mCatalog.end(); ) {
          if (catalogIds.find(iter->second.mViewId) == catalogIds.end()) {
            mClient->mCatalog.erase(iter++);
            changed = true;
          }
          else {
            ++iter;
          }
        }
        mClient->notifyCatalogListeners(changed);
        continue;
      }

      // find view or insert new one for this id
      SpecCollection::const_iterator item = mClient->mCatalog.find(msg.mId);
      if (item == mClient->mCatalog.end()) {
        ViewBase::Spec spec;
        spec.mViewId = msg.mId;
        mClient->mCatalog[msg.mId] = spec;
        mClient->notifyCatalogListeners(true);
      }
      ViewPtr view;

      // handle octree
      if (msg.mType == Message::TypeOctree) {
        boost::shared_ptr<drc::map_octree_t> payload =
          boost::static_pointer_cast<drc::map_octree_t>(msg.mPayload);
        OctreeView* octreeView = new OctreeView();
        LcmTranslator::fromLcm(*payload, *octreeView);
        view.reset(octreeView);
        view->setUpdateTime(payload->utime);
      }

      // handle cloud
      else if (msg.mType == Message::TypeCloud) {
        boost::shared_ptr<drc::map_cloud_t> payload =
          boost::static_pointer_cast<drc::map_cloud_t>(msg.mPayload);
        PointCloudView* cloudView = new PointCloudView();
        LcmTranslator::fromLcm(*payload, *cloudView);
        view.reset(cloudView);
        view->setUpdateTime(payload->utime);
      }

      // handle depth image
      else if (msg.mType == Message::TypeDepth) {
        boost::shared_ptr<drc::map_image_t> payload =
          boost::static_pointer_cast<drc::map_image_t>(msg.mPayload);
        DepthImageView* depthView = new DepthImageView();
        LcmTranslator::fromLcm(*payload, *depthView);
        view.reset(depthView);
        view->setUpdateTime(payload->utime);
      }

      if (view != NULL) mClient->mViews[msg.mId] = view;

      // notify subscribers
      mClient->notifyDataListeners(msg.mId);
    }
  }
};

ViewClient::
ViewClient() {
  setRequestChannel("MAP_REQUEST");
  setOctreeChannel("MAP_OCTREE");
  setCloudChannel("MAP_CLOUD");
  setDepthChannel("MAP_DEPTH");
  setCatalogChannel("MAP_CATALOG");
  mWorker.reset(new Worker(this));
}

ViewClient::
~ViewClient() {
  stop();
}

void ViewClient::
setBotWrapper(const boost::shared_ptr<BotWrapper>& iWrapper) {
  mBotWrapper = iWrapper;
  mWorker->mBotWrapper = iWrapper;
}

void ViewClient::
setRequestChannel(const std::string& iChannel) {
  mRequestChannel = iChannel;
}

void ViewClient::
setOctreeChannel(const std::string& iChannel) {
  mOctreeChannel = iChannel;
}

void ViewClient::
setCloudChannel(const std::string& iChannel) {
  mCloudChannel = iChannel;
}

void ViewClient::
setDepthChannel(const std::string& iChannel) {
  mDepthChannel = iChannel;
}

void ViewClient::
setCatalogChannel(const std::string& iChannel) {
  mCatalogChannel = iChannel;
}

int64_t ViewClient::request(const ViewBase::Spec& iSpec) {
  drc::map_request_t message;
  LcmTranslator::toLcm(iSpec, message);
  message.utime = drc::Clock::instance()->getCurrentTime();
  if (message.view_id < 0) {
    message.view_id = (Utils::rand64() >> 1);
  }
  mBotWrapper->getLcm()->publish(mRequestChannel, &message);
  return message.view_id;
}

ViewClient::ViewPtr ViewClient::
getView(const int64_t iId) const {
  ViewCollection::const_iterator item = mViews.find(iId);
  if (item != mViews.end()) {
    return item->second;
  }
  return ViewPtr();
}

std::vector<ViewClient::ViewPtr> ViewClient::
getAllViews() const {
  std::vector<ViewPtr> views;
  views.reserve(mViews.size());
  ViewCollection::const_iterator iter;
  for (iter = mViews.begin(); iter != mViews.end(); ++iter) {
    views.push_back(iter->second);
  }
  return views;
}

bool ViewClient::
getSpec(const int64_t iId, ViewBase::Spec& oSpec) const {
  SpecCollection::const_iterator item = mCatalog.find(iId);
  if (item == mCatalog.end()) {
    return false;
  }
  oSpec = item->second;
  return true;
}

std::vector<ViewBase::Spec> ViewClient::
getAllSpecs() const {
  std::vector<ViewBase::Spec> specs;
  specs.reserve(mCatalog.size());
  SpecCollection::const_iterator iter;
  for (iter = mCatalog.begin(); iter != mCatalog.end(); ++iter) {
    specs.push_back(iter->second);
  }
  return specs;
}

void ViewClient::
clearAll() {
  mViews.clear();
  mCatalog.clear();
  notifyCatalogListeners(true);
}

bool ViewClient::
addListener(const Listener* iListener) {
  return (mListeners.insert((Listener*)iListener).second);
}

bool ViewClient::
removeListener(const Listener* iListener) {
  return (mListeners.erase((Listener*)iListener) > 0);
}

bool ViewClient::
removeAllListeners() {
  mListeners.clear();
  return true;
}

bool ViewClient::
start() {
  return mWorker->start();
}

bool ViewClient::
stop() {
  return mWorker->stop();
}

void ViewClient::
notifyCatalogListeners(const bool iChanged) {
  for (std::set<Listener*>::iterator iter = mListeners.begin();
       iter != mListeners.end(); ++iter) {
    if (*iter != NULL) {
      (*iter)->notifyCatalog(iChanged);
    }
  }
}

void ViewClient::
notifyDataListeners(const int64_t iId) {
  for (std::set<Listener*>::iterator iter = mListeners.begin();
       iter != mListeners.end(); ++iter) {
    if (*iter != NULL) {
      (*iter)->notifyData(iId);
    }
  }
}
<|endoftext|>


<commit_before>#include <stan/agrad/rev/operators/operator_unary_not.hpp>
#include <test/unit/agrad/util.hpp>
#include <gtest/gtest.h>

TEST(AgradRev,not_a) {
  AVAR a(6.0);
  EXPECT_EQ(0, !a);
  AVAR b(0.0);
  EXPECT_EQ(1, !b);
}
<commit_msg>added NaN test for operator_unary_not<commit_after>#include <stan/agrad/rev/operators/operator_unary_not.hpp>
#include <test/unit/agrad/util.hpp>
#include <gtest/gtest.h>

TEST(AgradRev,not_a) {
  AVAR a(6.0);
  EXPECT_EQ(0, !a);
  AVAR b(0.0);
  EXPECT_EQ(1, !b);
}

TEST(AgradRev,not_nan) {
  stan::agrad::var nan = std::numeric_limits<double>::quiet_NaN();
  EXPECT_FALSE(!nan);
}
<|endoftext|>