Merge "trace_processor: properly handle how to bound filter int and float types"
diff --git a/src/trace_processor/sqlite_utils.h b/src/trace_processor/sqlite_utils.h
index 53d1e19..6ac7325 100644
--- a/src/trace_processor/sqlite_utils.h
+++ b/src/trace_processor/sqlite_utils.h
@@ -17,6 +17,7 @@
#ifndef SRC_TRACE_PROCESSOR_SQLITE_UTILS_H_
#define SRC_TRACE_PROCESSOR_SQLITE_UTILS_H_
+#include <math.h>
#include <sqlite3.h>
#include <functional>
@@ -137,6 +138,99 @@
#endif // PERFETTO_BUILDFLAG(PERFETTO_OS_MACOSX)
template <typename T>
+using is_float =
+ typename std::enable_if<std::is_floating_point<T>::value, T>::type;
+
+template <typename T>
+using is_int = typename std::enable_if<std::is_integral<T>::value, T>::type;
+
+// Greater bound for floating point numbers.
+template <typename T, typename sqlite_utils::is_float<T>* = nullptr>
+T FindGtBound(bool is_eq, sqlite3_value* sqlite_val) {
+ constexpr auto kMax = static_cast<long double>(std::numeric_limits<T>::max());
+ auto type = sqlite3_value_type(sqlite_val);
+ if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) {
+ return kMax;
+ }
+
+ // If this is a strict gt bound then just get the next highest float
+ // after value.
+ auto value = ExtractSqliteValue<T>(sqlite_val);
+ return is_eq ? value : nexttoward(value, kMax);
+}
+
+template <typename T, typename sqlite_utils::is_int<T>* = nullptr>
+T FindGtBound(bool is_eq, sqlite3_value* sqlite_val) {
+ auto type = sqlite3_value_type(sqlite_val);
+ if (type == SQLITE_INTEGER) {
+ auto value = ExtractSqliteValue<T>(sqlite_val);
+ return is_eq ? value : value + 1;
+ } else if (type == SQLITE_FLOAT) {
+ auto value = ExtractSqliteValue<double>(sqlite_val);
+ auto above = ceil(value);
+ auto cast = static_cast<T>(above);
+ return value < above ? cast : (is_eq ? cast : cast + 1);
+ } else {
+ return std::numeric_limits<T>::max();
+ }
+}
+
+template <typename T, typename sqlite_utils::is_float<T>* = nullptr>
+T FindLtBound(bool is_eq, sqlite3_value* sqlite_val) {
+ constexpr auto kMin =
+ static_cast<long double>(std::numeric_limits<T>::lowest());
+ auto type = sqlite3_value_type(sqlite_val);
+ if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) {
+ return kMin;
+ }
+
+ // If this is a strict lt bound then just get the next lowest float
+ // before value.
+ auto value = ExtractSqliteValue<T>(sqlite_val);
+ return is_eq ? value : nexttoward(value, kMin);
+}
+
+template <typename T, typename sqlite_utils::is_int<T>* = nullptr>
+T FindLtBound(bool is_eq, sqlite3_value* sqlite_val) {
+ auto type = sqlite3_value_type(sqlite_val);
+ if (type == SQLITE_INTEGER) {
+ auto value = ExtractSqliteValue<T>(sqlite_val);
+ return is_eq ? value : value - 1;
+ } else if (type == SQLITE_FLOAT) {
+ auto value = ExtractSqliteValue<double>(sqlite_val);
+ auto below = floor(value);
+ auto cast = static_cast<T>(below);
+ return value > below ? cast : (is_eq ? cast : cast - 1);
+ } else {
+ return std::numeric_limits<T>::max();
+ }
+}
+
+template <typename T, typename sqlite_utils::is_float<T>* = nullptr>
+T FindEqBound(sqlite3_value* sqlite_val) {
+ auto type = sqlite3_value_type(sqlite_val);
+ if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) {
+ return std::numeric_limits<T>::max();
+ }
+ return ExtractSqliteValue<T>(sqlite_val);
+}
+
+template <typename T, typename sqlite_utils::is_int<T>* = nullptr>
+T FindEqBound(sqlite3_value* sqlite_val) {
+ auto type = sqlite3_value_type(sqlite_val);
+ if (type == SQLITE_INTEGER) {
+ return ExtractSqliteValue<T>(sqlite_val);
+ } else if (type == SQLITE_FLOAT) {
+ auto value = ExtractSqliteValue<double>(sqlite_val);
+ auto below = floor(value);
+ auto cast = static_cast<T>(below);
+ return value > below ? std::numeric_limits<T>::max() : cast;
+ } else {
+ return std::numeric_limits<T>::max();
+ }
+}
+
+template <typename T>
void ReportSqliteResult(sqlite3_context*, T value);
template <>
diff --git a/src/trace_processor/storage_schema.h b/src/trace_processor/storage_schema.h
index ebca90f..739ff92 100644
--- a/src/trace_processor/storage_schema.h
+++ b/src/trace_processor/storage_schema.h
@@ -98,26 +98,24 @@
if (!is_naturally_ordered_)
return bounds;
- auto min = std::numeric_limits<T>::min();
- auto max = std::numeric_limits<T>::max();
-
// Makes the below code much more readable.
using namespace sqlite_utils;
- // Try and bound the min and max value based on the constraints.
- auto value = sqlite_utils::ExtractSqliteValue<T>(sqlite_val);
+ T min = kTMin;
+ T max = kTMax;
if (IsOpGe(op) || IsOpGt(op)) {
- min = IsOpGe(op) ? value : value + 1;
+ min = FindGtBound<T>(IsOpGe(op), sqlite_val);
} else if (IsOpLe(op) || IsOpLt(op)) {
- max = IsOpLe(op) ? value : value - 1;
+ max = FindLtBound<T>(IsOpLe(op), sqlite_val);
} else if (IsOpEq(op)) {
- min = value;
- max = value;
- } else {
- // We cannot bound on this constraint.
- return bounds;
+ auto val = FindEqBound<T>(sqlite_val);
+ min = val;
+ max = val;
}
+ if (min <= kTMin && max >= kTMax)
+ return bounds;
+
// Convert the values into indices into the deque.
auto min_it = std::lower_bound(deque_->begin(), deque_->end(), min);
bounds.min_idx =
@@ -175,6 +173,9 @@
}
private:
+ T kTMin = std::numeric_limits<T>::lowest();
+ T kTMax = std::numeric_limits<T>::max();
+
template <typename C>
Predicate FilterWithCast(int op, sqlite3_value* value) const {
auto binary_op = sqlite_utils::GetPredicateForOp<C>(op);