summaryrefslogtreecommitdiffstats
path: root/vespalib
diff options
context:
space:
mode:
authorHaavard <havardpe@yahoo-inc.com>2016-11-14 11:42:47 +0000
committerHaavard <havardpe@yahoo-inc.com>2016-11-14 12:38:59 +0000
commitc6f06f52d21f1cb42fb87a7a9f00dabdb417941f (patch)
treecbc7b7eaa5f332249020d4a1bdf199bec55e50b7 /vespalib
parentfc23b4c021ef8504ff77531bcbeecc0feff92ff1 (diff)
added support for pre-detecting function eval issues
Diffstat (limited to 'vespalib')
-rw-r--r--vespalib/src/tests/eval/compiled_function/compiled_function_test.cpp16
-rw-r--r--vespalib/src/tests/eval/interpreted_function/interpreted_function_test.cpp16
-rw-r--r--vespalib/src/vespa/vespalib/eval/function.h11
-rw-r--r--vespalib/src/vespa/vespalib/eval/interpreted_function.cpp19
-rw-r--r--vespalib/src/vespa/vespalib/eval/interpreted_function.h1
-rw-r--r--vespalib/src/vespa/vespalib/eval/llvm/compiled_function.cpp23
-rw-r--r--vespalib/src/vespa/vespalib/eval/llvm/compiled_function.h1
7 files changed, 87 insertions, 0 deletions
diff --git a/vespalib/src/tests/eval/compiled_function/compiled_function_test.cpp b/vespalib/src/tests/eval/compiled_function/compiled_function_test.cpp
index b3777a86df9..82dffd58cdc 100644
--- a/vespalib/src/tests/eval/compiled_function/compiled_function_test.cpp
+++ b/vespalib/src/tests/eval/compiled_function/compiled_function_test.cpp
@@ -6,6 +6,8 @@
#include <vespa/vespalib/eval/basic_nodes.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <cmath>
+#include <vespa/vespalib/test/insertion_operators.h>
+#include <iostream>
using namespace vespalib::eval;
@@ -169,4 +171,18 @@ TEST("require that tensor operations have sane numeric fallbacks") {
//-----------------------------------------------------------------------------
+TEST("require function issues can be detected") {
+ auto simple = Function::parse("a+b");
+ auto complex = Function::parse("join(a,b,f(a,b)(a+b))");
+ EXPECT_FALSE(simple.has_error());
+ EXPECT_FALSE(complex.has_error());
+ EXPECT_FALSE(CompiledFunction::detect_issues(simple));
+ EXPECT_TRUE(CompiledFunction::detect_issues(complex));
+ std::cerr << "Example function issues:" << std::endl
+ << CompiledFunction::detect_issues(complex).list
+ << std::endl;
+}
+
+//-----------------------------------------------------------------------------
+
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/eval/interpreted_function/interpreted_function_test.cpp b/vespalib/src/tests/eval/interpreted_function/interpreted_function_test.cpp
index 9d01488dda1..51aacfd2272 100644
--- a/vespalib/src/tests/eval/interpreted_function/interpreted_function_test.cpp
+++ b/vespalib/src/tests/eval/interpreted_function/interpreted_function_test.cpp
@@ -7,6 +7,8 @@
#include <vespa/vespalib/eval/basic_nodes.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/stash.h>
+#include <vespa/vespalib/test/insertion_operators.h>
+#include <iostream>
using namespace vespalib::eval;
using vespalib::Stash;
@@ -188,4 +190,18 @@ TEST("require that matrix multiplication works with tensor function") {
//-----------------------------------------------------------------------------
+TEST("require function issues can be detected") {
+ auto simple = Function::parse("a+b");
+ auto complex = Function::parse("join(a,b,f(a,b)(a+b))");
+ EXPECT_FALSE(simple.has_error());
+ EXPECT_FALSE(complex.has_error());
+ EXPECT_FALSE(InterpretedFunction::detect_issues(simple));
+ EXPECT_TRUE(InterpretedFunction::detect_issues(complex));
+ std::cerr << "Example function issues:" << std::endl
+ << InterpretedFunction::detect_issues(complex).list
+ << std::endl;
+}
+
+//-----------------------------------------------------------------------------
+
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/vespa/vespalib/eval/function.h b/vespalib/src/vespa/vespalib/eval/function.h
index a9e2b980025..35a89ce6512 100644
--- a/vespalib/src/vespa/vespalib/eval/function.h
+++ b/vespalib/src/vespa/vespalib/eval/function.h
@@ -67,6 +67,17 @@ public:
vespalib::string &wrapper,
vespalib::string &body,
vespalib::string &error);
+ /**
+ * Issues is used to report issues relating to the function
+ * structure, typically to explain why a function cannot be
+ * evaluated in a specific context due to it using features not
+ * supported in that context.
+ **/
+ struct Issues {
+ std::vector<vespalib::string> list;
+ operator bool() const { return !list.empty(); }
+ Issues(std::vector<vespalib::string> &&list_in) : list(std::move(list_in)) {}
+ };
};
} // namespace vespalib::eval
diff --git a/vespalib/src/vespa/vespalib/eval/interpreted_function.cpp b/vespalib/src/vespa/vespalib/eval/interpreted_function.cpp
index e1e04ca6ced..a4329f97de2 100644
--- a/vespalib/src/vespa/vespalib/eval/interpreted_function.cpp
+++ b/vespalib/src/vespa/vespalib/eval/interpreted_function.cpp
@@ -11,6 +11,7 @@
#include <set>
#include "tensor_spec.h"
#include "simple_tensor_engine.h"
+#include <vespa/vespalib/util/classname.h>
namespace vespalib {
namespace eval {
@@ -453,5 +454,23 @@ InterpretedFunction::eval(Context &ctx) const
return state.stack.back();
}
+Function::Issues
+InterpretedFunction::detect_issues(const Function &function)
+{
+ struct NotSupported : NodeTraverser {
+ std::vector<vespalib::string> issues;
+ bool open(const nodes::Node &) override { return true; }
+ void close(const nodes::Node &node) override {
+ if (nodes::check_type<nodes::TensorMap,
+ nodes::TensorJoin>(node)) {
+ issues.push_back(make_string("unsupported node type: %s",
+ getClassName(node).c_str()));
+ }
+ }
+ } checker;
+ function.root().traverse(checker);
+ return Function::Issues(std::move(checker.issues));
+}
+
} // namespace vespalib::eval
} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/eval/interpreted_function.h b/vespalib/src/vespa/vespalib/eval/interpreted_function.h
index 615f9d4eb82..fa1ea6580dd 100644
--- a/vespalib/src/vespa/vespalib/eval/interpreted_function.h
+++ b/vespalib/src/vespa/vespalib/eval/interpreted_function.h
@@ -94,6 +94,7 @@ public:
size_t program_size() const { return _program.size(); }
size_t num_params() const { return _num_params; }
const Value &eval(Context &ctx) const;
+ static Function::Issues detect_issues(const Function &function);
};
} // namespace vespalib::eval
diff --git a/vespalib/src/vespa/vespalib/eval/llvm/compiled_function.cpp b/vespalib/src/vespa/vespalib/eval/llvm/compiled_function.cpp
index 957df7503c3..9b120b677e2 100644
--- a/vespalib/src/vespa/vespalib/eval/llvm/compiled_function.cpp
+++ b/vespalib/src/vespa/vespalib/eval/llvm/compiled_function.cpp
@@ -3,6 +3,10 @@
#include <vespa/fastos/fastos.h>
#include "compiled_function.h"
#include <vespa/vespalib/util/benchmark_timer.h>
+#include <vespa/vespalib/eval/node_traverser.h>
+#include <vespa/vespalib/eval/check_type.h>
+#include <vespa/vespalib/eval/tensor_nodes.h>
+#include <vespa/vespalib/util/classname.h>
namespace vespalib {
namespace eval {
@@ -46,5 +50,24 @@ CompiledFunction::estimate_cost_us(const std::vector<double> &params) const
return BenchmarkTimer::benchmark(actual, baseline, 4.0) * 1000.0 * 1000.0;
}
+Function::Issues
+CompiledFunction::detect_issues(const Function &function)
+{
+ struct NotSupported : NodeTraverser {
+ std::vector<vespalib::string> issues;
+ bool open(const nodes::Node &) override { return true; }
+ void close(const nodes::Node &node) override {
+ if (nodes::check_type<nodes::TensorSum,
+ nodes::TensorMap,
+ nodes::TensorJoin>(node)) {
+ issues.push_back(make_string("unsupported node type: %s",
+ getClassName(node).c_str()));
+ }
+ }
+ } checker;
+ function.root().traverse(checker);
+ return Function::Issues(std::move(checker.issues));
+}
+
} // namespace vespalib::eval
} // namespace vespalib
diff --git a/vespalib/src/vespa/vespalib/eval/llvm/compiled_function.h b/vespalib/src/vespa/vespalib/eval/llvm/compiled_function.h
index cd7ae2189b8..3b10d9a20c5 100644
--- a/vespalib/src/vespa/vespalib/eval/llvm/compiled_function.h
+++ b/vespalib/src/vespa/vespalib/eval/llvm/compiled_function.h
@@ -56,6 +56,7 @@ public:
}
void dump() const { _llvm_wrapper.dump(); }
double estimate_cost_us(const std::vector<double> &params) const;
+ static Function::Issues detect_issues(const Function &function);
};
} // namespace vespalib::eval