From 0408677cb2d3d7c06fe9bb6c5f41100d5c646150 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 7 Dec 2023 00:12:20 +0000 Subject: Update dependency io.dropwizard.metrics:metrics-core to v4.2.22 --- dependency-versions/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency-versions/pom.xml b/dependency-versions/pom.xml index 3ae42efb144..51645de7aa9 100644 --- a/dependency-versions/pom.xml +++ b/dependency-versions/pom.xml @@ -91,7 +91,7 @@ 1.25.0 1.6.0 5.5.0 - 4.1.12.1 + 4.2.22 11.1.0 0.9.0.M2 7.0.5 -- cgit v1.2.3 From 4e5a706fcae158feeab82f2a127e9ae431549452 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 15 Dec 2023 11:53:59 +0000 Subject: Update netty monorepo to v4.1.104.Final --- dependency-versions/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency-versions/pom.xml b/dependency-versions/pom.xml index 16602bcb452..6d51712cb3c 100644 --- a/dependency-versions/pom.xml +++ b/dependency-versions/pom.xml @@ -120,7 +120,7 @@ 1.10.0 5.8.0 2.4.0 - 4.1.101.Final + 4.1.104.Final 2.0.62.Final 1.16.3 2.3.1 -- cgit v1.2.3 From 2b1d2954fa67bbb8ebbcd1caea6bc3bf3c7c690c Mon Sep 17 00:00:00 2001 From: jonmv Date: Tue, 19 Dec 2023 09:08:11 +0100 Subject: Set socket timeout when intended --- .../java/ai/vespa/util/http/hc5/VespaHttpClientBuilder.java | 12 ++++++------ .../ai/vespa/metricsproxy/service/HttpMetricFetcher.java | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/http-utils/src/main/java/ai/vespa/util/http/hc5/VespaHttpClientBuilder.java b/http-utils/src/main/java/ai/vespa/util/http/hc5/VespaHttpClientBuilder.java index edd10f9297a..4e4e6f2956a 100644 --- a/http-utils/src/main/java/ai/vespa/util/http/hc5/VespaHttpClientBuilder.java +++ b/http-utils/src/main/java/ai/vespa/util/http/hc5/VespaHttpClientBuilder.java @@ -69,16 +69,16 @@ public class VespaHttpClientBuilder { connectionConfigBuilder.setConnectTimeout(connectTimeout); return this; } - public VespaHttpClientBuilder socketTimeout(long connectTimeout, TimeUnit timeUnit) { - connectionConfigBuilder.setConnectTimeout(connectTimeout, timeUnit); + public VespaHttpClientBuilder socketTimeout(int socketTimeout, TimeUnit timeUnit) { + connectionConfigBuilder.setSocketTimeout(socketTimeout, timeUnit); return this; } - public VespaHttpClientBuilder validateAfterInactivity(TimeValue validateAfterInactivity) { - connectionConfigBuilder.setValidateAfterInactivity(validateAfterInactivity); + public VespaHttpClientBuilder socketTimeout(Timeout socketTimeout) { + connectionConfigBuilder.setSocketTimeout(socketTimeout); return this; } - public VespaHttpClientBuilder socketTimeout(Timeout connectTimeout) { - connectionConfigBuilder.setConnectTimeout(connectTimeout); + public VespaHttpClientBuilder validateAfterInactivity(TimeValue validateAfterInactivity) { + connectionConfigBuilder.setValidateAfterInactivity(validateAfterInactivity); return this; } diff --git a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/HttpMetricFetcher.java b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/HttpMetricFetcher.java index db53c2db266..ac9063a045f 100644 --- a/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/HttpMetricFetcher.java +++ b/metrics-proxy/src/main/java/ai/vespa/metricsproxy/service/HttpMetricFetcher.java @@ -82,11 +82,11 @@ public abstract class HttpMetricFetcher { private static CloseableHttpClient createHttpClient() { return VespaHttpClientBuilder.custom() .connectTimeout(Timeout.ofMilliseconds(CONNECTION_TIMEOUT)) - .socketTimeout(Timeout.ofMilliseconds(CONNECTION_TIMEOUT)) + .socketTimeout(Timeout.ofMilliseconds(SOCKET_TIMEOUT)) .apacheBuilder() .setUserAgent("metrics-proxy-http-client") .setDefaultRequestConfig(RequestConfig.custom() - .setConnectionRequestTimeout(Timeout.ofMilliseconds(SOCKET_TIMEOUT)) + .setConnectionRequestTimeout(Timeout.ofMilliseconds(CONNECTION_TIMEOUT)) .setResponseTimeout(Timeout.ofMilliseconds(SOCKET_TIMEOUT)) .build()) .build(); -- cgit v1.2.3 From 1b3e88f972a4c3e2fe4cd4ea3caeba5358f05d76 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 08:27:52 +0000 Subject: Update dependency org.openrewrite.maven:rewrite-maven-plugin to v5.16.1 --- parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parent/pom.xml b/parent/pom.xml index 45ea90fdb41..afcde6dd930 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -317,7 +317,7 @@ --> org.openrewrite.maven rewrite-maven-plugin - 5.16.0 + 5.16.1 org.openrewrite.java.testing.junit5.JUnit5BestPractices -- cgit v1.2.3 From b462a8ee3568a00e8d650e892fe4cf5384f6e075 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 08:28:01 +0000 Subject: Update dependency org.apache.maven.plugins:maven-compiler-plugin to v3.12.0 --- dependency-versions/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency-versions/pom.xml b/dependency-versions/pom.xml index 40d1caab492..3dfd1b43682 100644 --- a/dependency-versions/pom.xml +++ b/dependency-versions/pom.xml @@ -153,7 +153,7 @@ 3.1.0 3.6.0 5.1.9 - 3.11.0 + 3.12.0 3.9.6 3.6.1 3.1.1 -- cgit v1.2.3 From 046e6b13d12668692bad991c97a5615eae5de558 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 19 Dec 2023 10:40:33 +0000 Subject: Update dependency io.dropwizard.metrics:metrics-core to v4.2.23 --- dependency-versions/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependency-versions/pom.xml b/dependency-versions/pom.xml index ca575e49202..a4849558253 100644 --- a/dependency-versions/pom.xml +++ b/dependency-versions/pom.xml @@ -91,7 +91,7 @@ 1.25.0 1.6.0 5.5.0 - 4.2.22 + 4.2.23 11.1.0 0.9.0.M2 7.0.5 -- cgit v1.2.3 From 9c9962463492d26623dfbd8aa838018ac53a8aa7 Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Tue, 19 Dec 2023 10:45:57 +0000 Subject: Add feature flag for allow sorting blueprints by cost estimate instead of est_hits. --- .../src/tests/proton/matching/query_test.cpp | 351 +++++++-------------- .../searchcore/proton/matching/match_tools.cpp | 2 +- .../src/vespa/searchcore/proton/matching/query.cpp | 3 +- .../src/vespa/searchcore/proton/matching/query.h | 2 +- .../src/vespa/searchlib/fef/indexproperties.cpp | 6 + .../src/vespa/searchlib/fef/indexproperties.h | 9 + searchlib/src/vespa/searchlib/fef/ranksetup.cpp | 2 + searchlib/src/vespa/searchlib/fef/ranksetup.h | 2 + .../src/tests/hwaccelrated/hwaccelrated_test.cpp | 34 ++ 9 files changed, 176 insertions(+), 235 deletions(-) diff --git a/searchcore/src/tests/proton/matching/query_test.cpp b/searchcore/src/tests/proton/matching/query_test.cpp index bf574af725d..e798f87dd12 100644 --- a/searchcore/src/tests/proton/matching/query_test.cpp +++ b/searchcore/src/tests/proton/matching/query_test.cpp @@ -30,11 +30,11 @@ #include #include #include - #include +#include + #include LOG_SETUP("query_test"); -#include using document::PositionDataType; using search::fef::FieldInfo; @@ -80,70 +80,6 @@ using CollectionType = FieldInfo::CollectionType; namespace proton::matching { namespace { -class Test : public vespalib::TestApp { - MatchData::UP _match_data; - Blueprint::UP _blueprint; - FakeRequestContext _requestContext; - - void setUp(); - void tearDown(); - - void requireThatMatchDataIsReserved(); - void requireThatMatchDataIsReservedForEachFieldInAView(); - void requireThatTermsAreLookedUp(); - void requireThatTermsAreLookedUpInMultipleFieldsFromAView(); - void requireThatAttributeTermsAreLookedUpInAttributeSource(); - void requireThatAttributeTermDataHandlesAreAllocated(); - void requireThatTermDataIsFilledIn(); - - SearchIterator::UP getIterator(Node &node, ISearchContext &context); - - void requireThatSingleIndexCanUseBlendingAsBlacklisting(); - void requireThatIteratorsAreBuiltWithBlending(); - void requireThatIteratorsAreBuiltForAllTermNodes(); - void requireThatNearIteratorsCanBeBuilt(); - void requireThatONearIteratorsCanBeBuilt(); - void requireThatPhraseIteratorsCanBeBuilt(); - - void requireThatUnknownFieldActsEmpty(); - void requireThatIllegalFieldsAreIgnored(); - void requireThatQueryGluesEverythingTogether(); - void requireThatLocationIsAddedTheCorrectPlace(); - void requireThatQueryAddsLocation(); - void requireThatQueryAddsLocationCutoff(); - void requireThatFakeFieldSearchDumpsDiffer(); - void requireThatNoDocsGiveZeroDocFrequency(); - void requireThatWeakAndBlueprintsAreCreatedCorrectly(); - void requireThatParallelWandBlueprintsAreCreatedCorrectly(); - void requireThatWhiteListBlueprintCanBeUsed(); - void requireThatRankBlueprintStaysOnTopAfterWhiteListing(); - void requireThatAndNotBlueprintStaysOnTopAfterWhiteListing(); - void requireThatSameElementTermsAreProperlyPrefixed(); - void requireThatSameElementAllocatesMatchData(); - void requireThatSameElementIteratorsCanBeBuilt(); - void requireThatConstBoolBlueprintsAreCreatedCorrectly(); - void global_filter_is_calculated_and_handled(); - -public: - ~Test() override; - int Main() override; -}; - -#define TEST_CALL(func) \ - TEST_DO(setUp()); \ - TEST_DO(func()); \ - TEST_DO(tearDown()) - -void Test::setUp() { - _match_data.reset(); - _blueprint.reset(); -} - -void Test::tearDown() { - _match_data.reset(); - _blueprint.reset(); -} - const string field = "field"; const string loc_field = "location"; const string resolved_field1 = "resolved1"; @@ -167,6 +103,55 @@ fef_test::IndexEnvironment plain_index_env; fef_test::IndexEnvironment resolved_index_env; fef_test::IndexEnvironment attribute_index_env; +void setupIndexEnvironments() +{ + plain_index_env.getFields().emplace_back(FieldType::INDEX, CollectionType::SINGLE, field, field_id); + + resolved_index_env.getFields().emplace_back(FieldType::INDEX, CollectionType::SINGLE, resolved_field1, field_id); + resolved_index_env.getFields().emplace_back(FieldType::INDEX, CollectionType::SINGLE, resolved_field2, field_id + 1); + + attribute_index_env.getFields().emplace_back(FieldType::ATTRIBUTE, CollectionType::SINGLE, field, 0); + FieldInfo loc_field_info = FieldInfo(FieldType::ATTRIBUTE, CollectionType::SINGLE, + PositionDataType::getZCurveFieldName(loc_field), field_id + 1); + plain_index_env.getFields().push_back(loc_field_info); + attribute_index_env.getFields().push_back(loc_field_info); +} +struct InitializeGlobals { + InitializeGlobals() { setupIndexEnvironments(); } +}; + +InitializeGlobals globals; + +struct Fixture { + Fixture(); + SearchIterator::UP getIterator(Node &node, ISearchContext &context); + MatchData::UP _match_data; + Blueprint::UP _blueprint; + FakeRequestContext _requestContext; +}; + +Fixture::Fixture() + : _match_data(), + _blueprint(), + _requestContext() +{ +} + +SearchIterator::UP +Fixture::getIterator(Node &node, ISearchContext &context) { + MatchDataLayout mdl; + MatchDataReserveVisitor mdr_visitor(mdl); + node.accept(mdr_visitor); + _match_data = mdl.createMatchData(); + + _blueprint = BlueprintBuilder::build(_requestContext, node, context); + + _blueprint->fetchPostings(ExecuteInfo::TRUE); + SearchIterator::UP search(_blueprint->createSearch(*_match_data, true)); + search->initFullRange(); + return search; +} + vespalib::ThreadBundle &ttb() { return vespalib::ThreadBundle::trivial(); } vespalib::string @@ -180,23 +165,6 @@ termAsString(const vespalib::string & term) { return term; } -void setupIndexEnvironments() -{ - FieldInfo field_info(FieldType::INDEX, CollectionType::SINGLE, field, field_id); - plain_index_env.getFields().push_back(field_info); - - FieldInfo field_info1(FieldType::INDEX, CollectionType::SINGLE, resolved_field1, field_id); - resolved_index_env.getFields().push_back(field_info1); - FieldInfo field_info2(FieldType::INDEX, CollectionType::SINGLE, resolved_field2, field_id + 1); - resolved_index_env.getFields().push_back(field_info2); - - FieldInfo attr_info(FieldType::ATTRIBUTE, CollectionType::SINGLE, field, 0); - attribute_index_env.getFields().push_back(attr_info); - FieldInfo loc_field_info = FieldInfo(FieldType::ATTRIBUTE, CollectionType::SINGLE, - PositionDataType::getZCurveFieldName(loc_field), field_id + 1); - plain_index_env.getFields().push_back(loc_field_info); - attribute_index_env.getFields().push_back(loc_field_info); -} Node::UP buildQueryTree(const ViewResolver &resolver, const search::fef::IIndexEnvironment &idxEnv) @@ -234,7 +202,7 @@ Node::UP buildSameElementQueryTree(const ViewResolver &resolver, return node; } -void Test::requireThatMatchDataIsReserved() { +TEST("requireThatMatchDataIsReserved") { Node::UP node = buildQueryTree(ViewResolver(), plain_index_env); MatchDataLayout mdl; @@ -252,7 +220,7 @@ ViewResolver getViewResolver() { return resolver; } -void Test::requireThatMatchDataIsReservedForEachFieldInAView() { +TEST("requireThatMatchDataIsReservedForEachFieldInAView") { Node::UP node = buildQueryTree(getViewResolver(), resolved_index_env); MatchDataLayout mdl; @@ -265,8 +233,6 @@ void Test::requireThatMatchDataIsReservedForEachFieldInAView() { class LookupTestCheckerVisitor : public CustomTypeTermVisitor { - int Main() { return 0; } - public: template void checkNode(const TermType &n, int estimatedHitCount, bool empty) { @@ -292,7 +258,7 @@ public: void visit(ProtonInTerm&) override {} }; -void Test::requireThatTermsAreLookedUp() { +TEST("requireThatTermsAreLookedUp") { FakeRequestContext requestContext; Node::UP node = buildQueryTree(ViewResolver(), plain_index_env); @@ -326,7 +292,7 @@ void Test::requireThatTermsAreLookedUp() { TEST_DO(node->accept(checker)); } -void Test::requireThatTermsAreLookedUpInMultipleFieldsFromAView() { +TEST("requireThatTermsAreLookedUpInMultipleFieldsFromAView") { Node::UP node = buildQueryTree(getViewResolver(), resolved_index_env); FakeRequestContext requestContext; @@ -362,7 +328,7 @@ void Test::requireThatTermsAreLookedUpInMultipleFieldsFromAView() { TEST_DO(node->accept(checker)); } -void Test::requireThatAttributeTermsAreLookedUpInAttributeSource() { +TEST("requireThatAttributeTermsAreLookedUpInAttributeSource") { const string term = "bar"; ProtonStringTerm node(term, field, 1, Weight(2)); node.resolve(ViewResolver(), attribute_index_env); @@ -377,12 +343,11 @@ void Test::requireThatAttributeTermsAreLookedUpInAttributeSource() { node.accept(visitor); Blueprint::UP blueprint = BlueprintBuilder::build(requestContext, node, context); - EXPECT_TRUE(!blueprint->getState().estimate().empty); EXPECT_EQUAL(1u, blueprint->getState().estimate().estHits); } -void Test::requireThatAttributeTermDataHandlesAreAllocated() { +TEST("requireThatAttributeTermDataHandlesAreAllocated") { const string term = "bar"; ProtonStringTerm node(term, field, 1, Weight(2)); node.resolve(ViewResolver(), attribute_index_env); @@ -395,9 +360,7 @@ void Test::requireThatAttributeTermDataHandlesAreAllocated() { node.accept(reserve_visitor); Blueprint::UP blueprint = BlueprintBuilder::build(requestContext, node, context); - MatchData::UP match_data = mdl.createMatchData(); - EXPECT_EQUAL(1u, match_data->getNumTermFields()); EXPECT_TRUE(node.field(0).attribute_field); } @@ -406,8 +369,6 @@ void Test::requireThatAttributeTermDataHandlesAreAllocated() { class SetUpTermDataTestCheckerVisitor : public CustomTypeTermVisitor { - int Main() { return 0; } - public: void visit(ProtonNumberTerm &) override {} void visit(ProtonLocationTerm &) override {} @@ -416,8 +377,7 @@ public: void visit(ProtonStringTerm &n) override { const ITermData &term_data = n; - EXPECT_EQUAL(string_weight.percent(), - term_data.getWeight().percent()); + EXPECT_EQUAL(string_weight.percent(), term_data.getWeight().percent()); EXPECT_EQUAL(1u, term_data.getPhraseLength()); EXPECT_EQUAL(string_id, term_data.getUniqueId()); EXPECT_EQUAL(term_data.numFields(), n.numFields()); @@ -445,7 +405,7 @@ public: void visit(ProtonInTerm&) override { } }; -void Test::requireThatTermDataIsFilledIn() { +TEST("requireThatTermDataIsFilledIn") { Node::UP node = buildQueryTree(getViewResolver(), resolved_index_env); FakeRequestContext requestContext; @@ -467,20 +427,6 @@ void Test::requireThatTermDataIsFilledIn() { ); } -SearchIterator::UP Test::getIterator(Node &node, ISearchContext &context) { - MatchDataLayout mdl; - MatchDataReserveVisitor mdr_visitor(mdl); - node.accept(mdr_visitor); - _match_data = mdl.createMatchData(); - - _blueprint = BlueprintBuilder::build(_requestContext, node, context); - - _blueprint->fetchPostings(ExecuteInfo::TRUE); - SearchIterator::UP search(_blueprint->createSearch(*_match_data, true)); - search->initFullRange(); - return search; -} - FakeIndexSearchable getFakeSearchable(const string &term, int doc1, int doc2) { FakeIndexSearchable source; source.getFake().addResult(field, term, @@ -488,31 +434,31 @@ FakeIndexSearchable getFakeSearchable(const string &term, int doc1, int doc2) { return source; } -void Test::requireThatSingleIndexCanUseBlendingAsBlacklisting() { +TEST_F("requireThatSingleIndexCanUseBlendingAsBlacklisting", Fixture) { QueryBuilder builder; builder.addStringTerm(string_term, field, 1, Weight(2)) .resolve(ViewResolver(), plain_index_env); Node::UP node = builder.build(); - ASSERT_TRUE(node.get()); + ASSERT_TRUE(node); FakeSearchContext context; context.addIdx(1).idx(0) = getFakeSearchable(string_term, 2, 5); context.selector().setSource(5, 1); - SearchIterator::UP iterator = getIterator(*node, context); - ASSERT_TRUE(iterator.get()); + SearchIterator::UP iterator = f.getIterator(*node, context); + ASSERT_TRUE(iterator); EXPECT_TRUE(!iterator->seek(1)); EXPECT_TRUE(!iterator->seek(2)); EXPECT_TRUE(iterator->seek(5)); iterator->unpack(5); } -void Test::requireThatIteratorsAreBuiltWithBlending() { +TEST_F("requireThatIteratorsAreBuiltWithBlending", Fixture) { QueryBuilder builder; builder.addStringTerm(string_term, field, 1, Weight(2)) .resolve(ViewResolver(), plain_index_env); Node::UP node = builder.build(); - ASSERT_TRUE(node.get()); + ASSERT_TRUE(node); FakeSearchContext context; context.addIdx(1).idx(0) = getFakeSearchable(string_term, 3, 7); @@ -520,8 +466,8 @@ void Test::requireThatIteratorsAreBuiltWithBlending() { context.selector().setSource(3, 1); context.selector().setSource(7, 1); - SearchIterator::UP iterator = getIterator(*node, context); - ASSERT_TRUE(iterator.get()); + SearchIterator::UP iterator = f.getIterator(*node, context); + ASSERT_TRUE(iterator); EXPECT_TRUE(!iterator->seek(1)); EXPECT_TRUE(iterator->seek(2)); @@ -530,9 +476,9 @@ void Test::requireThatIteratorsAreBuiltWithBlending() { EXPECT_TRUE(iterator->seek(7)); } -void Test::requireThatIteratorsAreBuiltForAllTermNodes() { +TEST_F("requireThatIteratorsAreBuiltForAllTermNodes", Fixture) { Node::UP node = buildQueryTree(ViewResolver(), plain_index_env); - ASSERT_TRUE(node.get()); + ASSERT_TRUE(node); FakeSearchContext context(42); context.addIdx(0).idx(0).getFake() @@ -547,8 +493,8 @@ void Test::requireThatIteratorsAreBuiltForAllTermNodes() { .addResult(field, substring_term, FakeResult().doc(23).pos(2)) .addResult(field, suffix_term, FakeResult().doc(42).pos(2)); - SearchIterator::UP iterator = getIterator(*node, context); - ASSERT_TRUE(iterator.get()); + SearchIterator::UP iterator = f.getIterator(*node, context); + ASSERT_TRUE(iterator); EXPECT_TRUE(!iterator->seek(1)); EXPECT_TRUE(iterator->seek(2)); @@ -560,7 +506,7 @@ void Test::requireThatIteratorsAreBuiltForAllTermNodes() { EXPECT_TRUE(iterator->seek(42)); } -void Test::requireThatNearIteratorsCanBeBuilt() { +TEST_F("requireThatNearIteratorsCanBeBuilt", Fixture) { QueryBuilder builder; builder.addNear(2, 4); builder.addStringTerm(string_term, field, 1, Weight(2)); @@ -569,7 +515,7 @@ void Test::requireThatNearIteratorsCanBeBuilt() { ViewResolver resolver; ResolveViewVisitor visitor(resolver, plain_index_env); node->accept(visitor); - ASSERT_TRUE(node.get()); + ASSERT_TRUE(node); FakeSearchContext context(8); context.addIdx(0).idx(0).getFake() @@ -578,13 +524,13 @@ void Test::requireThatNearIteratorsCanBeBuilt() { .addResult(field, string_term, FakeResult() .doc(4).pos(40).len(50).doc(8).pos(5).len(50)); - SearchIterator::UP iterator = getIterator(*node, context); - ASSERT_TRUE(iterator.get()); + SearchIterator::UP iterator = f.getIterator(*node, context); + ASSERT_TRUE(iterator); EXPECT_TRUE(!iterator->seek(4)); EXPECT_TRUE(iterator->seek(8)); } -void Test::requireThatONearIteratorsCanBeBuilt() { +TEST_F("requireThatONearIteratorsCanBeBuilt", Fixture) { QueryBuilder builder; builder.addONear(2, 4); builder.addStringTerm(string_term, field, 1, Weight(2)); @@ -593,7 +539,7 @@ void Test::requireThatONearIteratorsCanBeBuilt() { ViewResolver resolver; ResolveViewVisitor visitor(resolver, plain_index_env); node->accept(visitor); - ASSERT_TRUE(node.get()); + ASSERT_TRUE(node); FakeSearchContext context(8); context.addIdx(0).idx(0).getFake() @@ -602,13 +548,13 @@ void Test::requireThatONearIteratorsCanBeBuilt() { .addResult(field, prefix_term, FakeResult() .doc(4).pos(2).len(50).doc(8).pos(5).len(50)); - SearchIterator::UP iterator = getIterator(*node, context); - ASSERT_TRUE(iterator.get()); + SearchIterator::UP iterator = f.getIterator(*node, context); + ASSERT_TRUE(iterator); EXPECT_TRUE(!iterator->seek(4)); EXPECT_TRUE(iterator->seek(8)); } -void Test::requireThatPhraseIteratorsCanBeBuilt() { +TEST_F("requireThatPhraseIteratorsCanBeBuilt", Fixture) { QueryBuilder builder; builder.addPhrase(3, field, 0, Weight(42)); builder.addStringTerm(string_term, field, 1, Weight(2)); @@ -618,7 +564,7 @@ void Test::requireThatPhraseIteratorsCanBeBuilt() { ViewResolver resolver; ResolveViewVisitor visitor(resolver, plain_index_env); node->accept(visitor); - ASSERT_TRUE(node.get()); + ASSERT_TRUE(node); FakeSearchContext context(9); context.addIdx(0).idx(0).getFake() @@ -636,8 +582,8 @@ void Test::requireThatPhraseIteratorsCanBeBuilt() { .doc(5).pos(5).len(50) .doc(8).pos(4).len(50)); - SearchIterator::UP iterator = getIterator(*node, context); - ASSERT_TRUE(iterator.get()); + SearchIterator::UP iterator = f.getIterator(*node, context); + ASSERT_TRUE(iterator); EXPECT_TRUE(!iterator->seek(4)); EXPECT_TRUE(!iterator->seek(5)); EXPECT_TRUE(iterator->seek(8)); @@ -645,8 +591,7 @@ void Test::requireThatPhraseIteratorsCanBeBuilt() { EXPECT_TRUE(iterator->isAtEnd()); } -void -Test::requireThatUnknownFieldActsEmpty() +TEST_F("requireThatUnknownFieldActsEmpty", Fixture) { FakeSearchContext context; context.addIdx(0).idx(0).getFake() @@ -654,28 +599,25 @@ Test::requireThatUnknownFieldActsEmpty() .doc(4).pos(3).len(50) .doc(5).pos(2).len(50)); - ProtonNodeTypes::StringTerm - node(string_term, unknown_field, string_id, string_weight); + ProtonNodeTypes::StringTerm node(string_term, unknown_field, string_id, string_weight); node.resolve(ViewResolver(), plain_index_env); std::vector terms; TermDataExtractor::extractTerms(node, terms); - SearchIterator::UP iterator = getIterator(node, context); + SearchIterator::UP iterator = f.getIterator(node, context); ASSERT_TRUE(EXPECT_EQUAL(1u, terms.size())); EXPECT_EQUAL(0u, terms[0]->numFields()); - ASSERT_TRUE(iterator.get()); + ASSERT_TRUE(iterator); EXPECT_TRUE(!iterator->seek(1)); EXPECT_TRUE(iterator->isAtEnd()); } -void -Test::requireThatIllegalFieldsAreIgnored() +TEST("requireThatIllegalFieldsAreIgnored") { - ProtonNodeTypes::StringTerm - node(string_term, unknown_field, string_id, string_weight); + ProtonNodeTypes::StringTerm node(string_term, unknown_field, string_id, string_weight); node.resolve(ViewResolver(), plain_index_env); FakeRequestContext requestContext; @@ -686,14 +628,12 @@ Test::requireThatIllegalFieldsAreIgnored() node.accept(reserve_visitor); Blueprint::UP blueprint = BlueprintBuilder::build(requestContext, node, context); - EXPECT_EQUAL(0u, node.numFields()); - MatchData::UP match_data = mdl.createMatchData(); EXPECT_EQUAL(0u, match_data->getNumTermFields()); } -void Test::requireThatQueryGluesEverythingTogether() { +TEST("requireThatQueryGluesEverythingTogether") { QueryBuilder builder; builder.addStringTerm(string_term, field, 1, Weight(2)); string stack_dump = StackDumpCreator::create(*builder.build()); @@ -712,19 +652,18 @@ void Test::requireThatQueryGluesEverythingTogether() { MatchData::UP md = mdl.createMatchData(); EXPECT_EQUAL(1u, md->getNumTermFields()); - query.optimize(); + query.optimize(true); query.fetchPostings(ExecuteInfo::TRUE); SearchIterator::UP search = query.createSearch(*md); - ASSERT_TRUE(search.get()); + ASSERT_TRUE(search); } -void checkQueryAddsLocation(const string &loc_in, const string &loc_out) { +void +checkQueryAddsLocation(const string &loc_in, const string &loc_out) { fef_test::IndexEnvironment index_environment; - FieldInfo field_info(FieldType::INDEX, CollectionType::SINGLE, field, 0); - index_environment.getFields().push_back(field_info); - field_info = FieldInfo(FieldType::ATTRIBUTE, CollectionType::SINGLE, - PositionDataType::getZCurveFieldName(loc_field), 1); - index_environment.getFields().push_back(field_info); + index_environment.getFields().emplace_back(FieldType::INDEX, CollectionType::SINGLE, field, 0); + index_environment.getFields().emplace_back(FieldType::ATTRIBUTE, CollectionType::SINGLE, + PositionDataType::getZCurveFieldName(loc_field), 1); QueryBuilder builder; builder.addStringTerm(string_term, field, 1, Weight(2)); @@ -748,7 +687,7 @@ void checkQueryAddsLocation(const string &loc_in, const string &loc_out) { query.fetchPostings(ExecuteInfo::TRUE); SearchIterator::UP search = query.createSearch(*md); - ASSERT_TRUE(search.get()); + ASSERT_TRUE(search); if (!EXPECT_NOT_EQUAL(string::npos, search->asString().find(loc_out))) { fprintf(stderr, "search (missing loc_out '%s'): %s", loc_out.c_str(), search->asString().c_str()); @@ -794,7 +733,7 @@ void verifyThatRankBlueprintAndAndNotStaysOnTopAfterLocation(QueryBuilder(&root->getChild(1))); } -void Test::requireThatLocationIsAddedTheCorrectPlace() { +TEST("requireThatLocationIsAddedTheCorrectPlace") { { QueryBuilder builder; builder.addRank(2); @@ -809,20 +748,19 @@ void Test::requireThatLocationIsAddedTheCorrectPlace() { } } -void Test::requireThatQueryAddsLocation() { +TEST("requireThatQueryAddsLocation") { checkQueryAddsLocation("(2,10,10,3,0,1,0,0)", "{p:{x:10,y:10},r:3,b:{x:[7,13],y:[7,13]}}"); checkQueryAddsLocation("{p:{x:10,y:10},r:3}", "{p:{x:10,y:10},r:3,b:{x:[7,13],y:[7,13]}}"); checkQueryAddsLocation("{b:{x:[6,11],y:[8,15]},p:{x:10,y:10},r:3}", "{p:{x:10,y:10},r:3,b:{x:[7,11],y:[8,13]}}"); checkQueryAddsLocation("{a:12345,b:{x:[8,10],y:[8,10]},p:{x:10,y:10},r:3}", "{p:{x:10,y:10},r:3,a:12345,b:{x:[8,10],y:[8,10]}}"); } -void Test::requireThatQueryAddsLocationCutoff() { +TEST("requireThatQueryAddsLocationCutoff") { checkQueryAddsLocation("[2,10,11,23,24]", "{b:{x:[10,23],y:[11,24]}}"); checkQueryAddsLocation("{b:{y:[11,24],x:[10,23]}}", "{b:{x:[10,23],y:[11,24]}}"); } -void -Test::requireThatFakeFieldSearchDumpsDiffer() +TEST("requireThatFakeFieldSearchDumpsDiffer") { FakeRequestContext requestContext; uint32_t fieldId = 0; @@ -865,7 +803,7 @@ Test::requireThatFakeFieldSearchDumpsDiffer() EXPECT_NOT_EQUAL(s1->asString(), s4->asString()); } -void Test::requireThatNoDocsGiveZeroDocFrequency() { +TEST("requireThatNoDocsGiveZeroDocFrequency") { ProtonStringTerm node(string_term, field, string_id, string_weight); node.resolve(ViewResolver(), plain_index_env); FakeSearchContext context; @@ -882,7 +820,7 @@ void Test::requireThatNoDocsGiveZeroDocFrequency() { EXPECT_EQUAL(0.0, node.field(0).getDocFreq()); } -void Test::requireThatWeakAndBlueprintsAreCreatedCorrectly() { +TEST("requireThatWeakAndBlueprintsAreCreatedCorrectly") { using search::queryeval::WeakAndBlueprint; ProtonWeakAnd wand(123, "view"); @@ -915,7 +853,7 @@ void Test::requireThatWeakAndBlueprintsAreCreatedCorrectly() { EXPECT_EQUAL(3u, wbp->getChild(1).getState().estimate().estHits); } -void Test::requireThatParallelWandBlueprintsAreCreatedCorrectly() { +TEST("requireThatParallelWandBlueprintsAreCreatedCorrectly") { using search::queryeval::WeakAndBlueprint; ProtonWandTerm wand(2, field, 42, Weight(100), 123, 9000, 1.25); @@ -945,8 +883,7 @@ void Test::requireThatParallelWandBlueprintsAreCreatedCorrectly() { EXPECT_EQUAL(1000u, wbp->get_docid_limit()); } -void -Test::requireThatWhiteListBlueprintCanBeUsed() +TEST("requireThatWhiteListBlueprintCanBeUsed") { QueryBuilder builder; builder.addStringTerm("foo", field, field_id, string_weight); @@ -960,14 +897,14 @@ Test::requireThatWhiteListBlueprintCanBeUsed() .addResult(field, "foo", FakeResult().doc(1).doc(3).doc(5).doc(7).doc(9).doc(11)); context.setLimit(42); - query.setWhiteListBlueprint(SimpleBlueprint::UP(new SimpleBlueprint(SimpleResult().addHit(1).addHit(2).addHit(4).addHit(5).addHit(6).addHit(7).addHit(8).addHit(10).addHit(11).addHit(12)))); + query.setWhiteListBlueprint(std::make_unique(SimpleResult().addHit(1).addHit(2).addHit(4).addHit(5).addHit(6).addHit(7).addHit(8).addHit(10).addHit(11).addHit(12))); FakeRequestContext requestContext; MatchDataLayout mdl; query.reserveHandles(requestContext, context, mdl); MatchData::UP md = mdl.createMatchData(); - query.optimize(); + query.optimize(true); query.fetchPostings(ExecuteInfo::TRUE); SearchIterator::UP search = query.createSearch(*md); SimpleResult exp = SimpleResult().addHit(1).addHit(5).addHit(7).addHit(11); @@ -1009,14 +946,14 @@ void verifyThatRankBlueprintAndAndNotStaysOnTopAfterWhiteListing(QueryBuilder(&root->getChild(1))); } -void Test::requireThatRankBlueprintStaysOnTopAfterWhiteListing() { +TEST("requireThatRankBlueprintStaysOnTopAfterWhiteListing") { QueryBuilder builder; builder.addRank(2); builder.addAndNot(2); verifyThatRankBlueprintAndAndNotStaysOnTopAfterWhiteListing(builder); } -void Test::requireThatAndNotBlueprintStaysOnTopAfterWhiteListing() { +TEST("requireThatAndNotBlueprintStaysOnTopAfterWhiteListing") { QueryBuilder builder; builder.addAndNot(2); builder.addRank(2); @@ -1039,8 +976,7 @@ make_same_element_stack_dump(const vespalib::string &prefix, const vespalib::str return query; } -void -Test::requireThatSameElementTermsAreProperlyPrefixed() +TEST("requireThatSameElementTermsAreProperlyPrefixed") { search::query::Node::UP query = make_same_element_stack_dump("", ""); auto * root = dynamic_cast(query.get()); @@ -1071,8 +1007,7 @@ Test::requireThatSameElementTermsAreProperlyPrefixed() EXPECT_EQUAL(dynamic_cast(root->getChildren()[1])->getView(), "abc.abc.f2"); } -void -Test::requireThatSameElementAllocatesMatchData() +TEST("requireThatSameElementAllocatesMatchData") { Node::UP node = buildSameElementQueryTree(ViewResolver(), plain_index_env); MatchDataLayout mdl; @@ -1082,8 +1017,7 @@ Test::requireThatSameElementAllocatesMatchData() EXPECT_EQUAL(1u, match_data->getNumTermFields()); } -void -Test::requireThatSameElementIteratorsCanBeBuilt() { +TEST_F("requireThatSameElementIteratorsCanBeBuilt", Fixture) { Node::UP node = buildSameElementQueryTree(ViewResolver(), plain_index_env); FakeSearchContext context(10); context.addIdx(0).idx(0).getFake() @@ -1091,13 +1025,13 @@ Test::requireThatSameElementIteratorsCanBeBuilt() { .doc(4).elem(1).pos(0).doc(8).elem(1).pos(0)) .addResult(field, prefix_term, FakeResult() .doc(4).elem(2).pos(0).doc(8).elem(1).pos(1)); - SearchIterator::UP iterator = getIterator(*node, context); - ASSERT_TRUE(iterator.get()); + SearchIterator::UP iterator = f.getIterator(*node, context); + ASSERT_TRUE(iterator); EXPECT_TRUE(!iterator->seek(4)); EXPECT_TRUE(iterator->seek(8)); } -void Test::requireThatConstBoolBlueprintsAreCreatedCorrectly() { +TEST("requireThatConstBoolBlueprintsAreCreatedCorrectly") { using search::queryeval::AlwaysTrueBlueprint; using search::queryeval::EmptyBlueprint; @@ -1123,8 +1057,7 @@ class GlobalFilterBlueprint : public SimpleBlueprint { public: std::shared_ptr filter; double estimated_hit_ratio; - GlobalFilterBlueprint(const SimpleResult& result, - bool want_global_filter) + GlobalFilterBlueprint(const SimpleResult& result, bool want_global_filter) : search::queryeval::SimpleBlueprint(result), filter(), estimated_hit_ratio(-1.0) @@ -1140,8 +1073,7 @@ public: GlobalFilterBlueprint::~GlobalFilterBlueprint() = default; -void -Test::global_filter_is_calculated_and_handled() +TEST("global_filter_is_calculated_and_handled") { // estimated hits = 3, estimated hit ratio = 0.3 auto result = SimpleResult().addHit(3).addHit(5).addHit(7); @@ -1183,52 +1115,7 @@ Test::global_filter_is_calculated_and_handled() } } -Test::~Test() = default; - -int -Test::Main() -{ - setupIndexEnvironments(); - - TEST_INIT("query_test"); - - TEST_CALL(requireThatMatchDataIsReserved); - TEST_CALL(requireThatMatchDataIsReservedForEachFieldInAView); - TEST_CALL(requireThatTermsAreLookedUp); - TEST_CALL(requireThatTermsAreLookedUpInMultipleFieldsFromAView); - TEST_CALL(requireThatAttributeTermsAreLookedUpInAttributeSource); - TEST_CALL(requireThatAttributeTermDataHandlesAreAllocated); - TEST_CALL(requireThatTermDataIsFilledIn); - TEST_CALL(requireThatSingleIndexCanUseBlendingAsBlacklisting); - TEST_CALL(requireThatIteratorsAreBuiltWithBlending); - TEST_CALL(requireThatIteratorsAreBuiltForAllTermNodes); - TEST_CALL(requireThatNearIteratorsCanBeBuilt); - TEST_CALL(requireThatONearIteratorsCanBeBuilt); - TEST_CALL(requireThatPhraseIteratorsCanBeBuilt); - TEST_CALL(requireThatUnknownFieldActsEmpty); - TEST_CALL(requireThatIllegalFieldsAreIgnored); - TEST_CALL(requireThatQueryGluesEverythingTogether); - TEST_CALL(requireThatLocationIsAddedTheCorrectPlace); - TEST_CALL(requireThatQueryAddsLocation); - TEST_CALL(requireThatQueryAddsLocationCutoff); - TEST_CALL(requireThatFakeFieldSearchDumpsDiffer); - TEST_CALL(requireThatNoDocsGiveZeroDocFrequency); - TEST_CALL(requireThatWeakAndBlueprintsAreCreatedCorrectly); - TEST_CALL(requireThatParallelWandBlueprintsAreCreatedCorrectly); - TEST_CALL(requireThatWhiteListBlueprintCanBeUsed); - TEST_CALL(requireThatRankBlueprintStaysOnTopAfterWhiteListing); - TEST_CALL(requireThatAndNotBlueprintStaysOnTopAfterWhiteListing); - TEST_CALL(requireThatSameElementTermsAreProperlyPrefixed); - TEST_CALL(requireThatSameElementAllocatesMatchData); - TEST_CALL(requireThatSameElementIteratorsCanBeBuilt); - TEST_CALL(requireThatConstBoolBlueprintsAreCreatedCorrectly); - TEST_CALL(global_filter_is_calculated_and_handled); - - TEST_DONE(); -} - - } // namespace } // namespace proton::matching -TEST_APPHOOK(proton::matching::Test); +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp b/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp index 68bda1eacbb..71a6475b0fb 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp +++ b/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp @@ -203,7 +203,7 @@ MatchToolsFactory(QueryLimiter & queryLimiter, trace.addEvent(5, "Build query execution plan"); _query.reserveHandles(_requestContext, searchContext, _mdl); trace.addEvent(5, "Optimize query execution plan"); - _query.optimize(); + _query.optimize(SortBlueprintsByEstimate::check(_queryEnv.getProperties(), rankSetup.sort_blueprints_by_estimate())); trace.addEvent(4, "Perform dictionary lookups and posting lists initialization"); double hitRate = std::min(1.0, double(maxNumHits)/double(searchContext.getDocIdLimit())); bool create_postinglist_when_non_strict = CreatePostingListWhenNonStrict::check(_queryEnv.getProperties(), rankSetup.create_postinglist_when_non_strict()); diff --git a/searchcore/src/vespa/searchcore/proton/matching/query.cpp b/searchcore/src/vespa/searchcore/proton/matching/query.cpp index 192be93d9b8..b86ee931a53 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/query.cpp +++ b/searchcore/src/vespa/searchcore/proton/matching/query.cpp @@ -198,8 +198,9 @@ Query::reserveHandles(const IRequestContext & requestContext, ISearchContext &co } void -Query::optimize() +Query::optimize(bool sort_by_estimate) { + (void) sort_by_estimate; _blueprint = Blueprint::optimize(std::move(_blueprint)); LOG(debug, "optimized blueprint:\n%s\n", _blueprint->asString().c_str()); } diff --git a/searchcore/src/vespa/searchcore/proton/matching/query.h b/searchcore/src/vespa/searchcore/proton/matching/query.h index 97402d766ea..5148f8ba402 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/query.h +++ b/searchcore/src/vespa/searchcore/proton/matching/query.h @@ -103,7 +103,7 @@ public: * testing becomes harder. Not calling this function enables the * test to verify the original query without optimization. **/ - void optimize(); + void optimize(bool sort_by_estimate); void fetchPostings(const ExecuteInfo & executeInfo) ; void handle_global_filter(const IRequestContext & requestContext, uint32_t docid_limit, diff --git a/searchlib/src/vespa/searchlib/fef/indexproperties.cpp b/searchlib/src/vespa/searchlib/fef/indexproperties.cpp index cd9dbff99cb..65e31a2bc60 100644 --- a/searchlib/src/vespa/searchlib/fef/indexproperties.cpp +++ b/searchlib/src/vespa/searchlib/fef/indexproperties.cpp @@ -455,6 +455,12 @@ FuzzyAlgorithm::lookup(const Properties& props, vespalib::FuzzyMatchingAlgorithm return vespalib::fuzzy_matching_algorithm_from_string(value, default_value); } +const vespalib::string SortBlueprintsByEstimate::NAME("vespa.matching.sort_blueprints_by_estimate"); +const bool SortBlueprintsByEstimate::DEFAULT_VALUE(false); +bool SortBlueprintsByEstimate::check(const Properties &props, bool fallback) { + return lookupBool(props, NAME, fallback); +} + const vespalib::string AlwaysMarkPhraseExpensive::NAME("vespa.matching.always_mark_phrase_expensive"); const bool AlwaysMarkPhraseExpensive::DEFAULT_VALUE(false); bool AlwaysMarkPhraseExpensive::check(const Properties &props, bool fallback) { diff --git a/searchlib/src/vespa/searchlib/fef/indexproperties.h b/searchlib/src/vespa/searchlib/fef/indexproperties.h index 0183fdf1a13..13e053c8dcf 100644 --- a/searchlib/src/vespa/searchlib/fef/indexproperties.h +++ b/searchlib/src/vespa/searchlib/fef/indexproperties.h @@ -336,6 +336,15 @@ namespace matching { static vespalib::FuzzyMatchingAlgorithm lookup(const Properties& props); static vespalib::FuzzyMatchingAlgorithm lookup(const Properties& props, vespalib::FuzzyMatchingAlgorithm default_value); }; + /** + * Sort blueprints based on relative cost estimate rather than est_hits + **/ + struct SortBlueprintsByEstimate { + static const vespalib::string NAME; + static const bool DEFAULT_VALUE; + static bool check(const Properties &props) { return check(props, DEFAULT_VALUE); } + static bool check(const Properties &props, bool fallback); + }; /** * When enabled, the unpacking part of the phrase iterator will be tagged as expensive diff --git a/searchlib/src/vespa/searchlib/fef/ranksetup.cpp b/searchlib/src/vespa/searchlib/fef/ranksetup.cpp index 5c28f1814d5..0353879be14 100644 --- a/searchlib/src/vespa/searchlib/fef/ranksetup.cpp +++ b/searchlib/src/vespa/searchlib/fef/ranksetup.cpp @@ -56,6 +56,7 @@ RankSetup::RankSetup(const BlueprintFactory &factory, const IIndexEnvironment &i _dumpFeatures(), _warnings(), _feature_rename_map(), + _sort_blueprints_by_estimate(false), _ignoreDefaultRankFeatures(false), _compiled(false), _compileError(false), @@ -137,6 +138,7 @@ RankSetup::configure() _mutateOnSummary._attribute = mutate::on_summary::Attribute::lookup(_indexEnv.getProperties()); _mutateOnSummary._operation = mutate::on_summary::Operation::lookup(_indexEnv.getProperties()); _mutateAllowQueryOverride = mutate::AllowQueryOverride::check(_indexEnv.getProperties()); + _sort_blueprints_by_estimate = matching::SortBlueprintsByEstimate::check(_indexEnv.getProperties()); _always_mark_phrase_expensive = matching::AlwaysMarkPhraseExpensive::check(_indexEnv.getProperties()); _create_postinglist_when_non_strict = matching::CreatePostingListWhenNonStrict::check(_indexEnv.getProperties()); _use_estimate_for_fetch_postings = matching::UseEstimateForFetchPostings::check(_indexEnv.getProperties()); diff --git a/searchlib/src/vespa/searchlib/fef/ranksetup.h b/searchlib/src/vespa/searchlib/fef/ranksetup.h index 04659955490..f90ce2b0475 100644 --- a/searchlib/src/vespa/searchlib/fef/ranksetup.h +++ b/searchlib/src/vespa/searchlib/fef/ranksetup.h @@ -65,6 +65,7 @@ private: std::vector _dumpFeatures; Warnings _warnings; StringStringMap _feature_rename_map; + bool _sort_blueprints_by_estimate; bool _ignoreDefaultRankFeatures; bool _compiled; bool _compileError; @@ -465,6 +466,7 @@ public: const MutateOperation & getMutateOnSummary() const { return _mutateOnSummary; } bool allowMutateQueryOverride() const { return _mutateAllowQueryOverride; } + bool sort_blueprints_by_estimate() const noexcept { return _sort_blueprints_by_estimate; } }; } diff --git a/vespalib/src/tests/hwaccelrated/hwaccelrated_test.cpp b/vespalib/src/tests/hwaccelrated/hwaccelrated_test.cpp index e35efb20c1a..19c5ad53d46 100644 --- a/vespalib/src/tests/hwaccelrated/hwaccelrated_test.cpp +++ b/vespalib/src/tests/hwaccelrated/hwaccelrated_test.cpp @@ -47,4 +47,38 @@ TEST("test euclidean distance") { TEST_DO(verifyEuclideanDistance(hwaccelrated::IAccelrated::getAccelerator(), TEST_LENGTH)); } +void +verifyAnd64(const hwaccelrated::IAccelrated & accelrator, std::vector> v, + const char * expected, char * dest) +{ + accelrator.and64(0, v, dest); + EXPECT_EQUAL(0, memcmp(expected, dest, 64)); +} + +void +verifyAnd64(const hwaccelrated::IAccelrated & accelrator, std::vector> v, const char * expected) +{ + char c[64]; + memset(c, 0, sizeof(c)); + verifyAnd64(accelrator, v, expected, c); + memset(c, 0xff, sizeof(c)); + verifyAnd64(accelrator, v, expected, c); +} + +TEST("test 64 byte and with multiple vectors") { + char a[64]; + char b[64]; + memset(a, 0x55, sizeof(a)); + memset(b, 0xff, sizeof(b)); + std::vector> v; + v.emplace_back(a, false); + v.emplace_back(b, false); + + verifyAnd64(hwaccelrated::GenericAccelrator(), v, a); + verifyAnd64(hwaccelrated::IAccelrated::getAccelerator(), v, a); + std::reverse(v.begin(), v.end()); + verifyAnd64(hwaccelrated::GenericAccelrator(), v, a); + verifyAnd64(hwaccelrated::IAccelrated::getAccelerator(), v, a); +} + TEST_MAIN() { TEST_RUN_ALL(); } -- cgit v1.2.3 From aa0dc89f655654435d84d075f268754378b377aa Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Tue, 19 Dec 2023 12:01:52 +0100 Subject: Wire in sort-blueprints-by-estimate feature flag --- config-model-api/abi-spec.json | 3 ++- .../src/main/java/com/yahoo/config/model/api/ModelContext.java | 1 + .../src/main/java/com/yahoo/schema/derived/RawRankProfile.java | 5 +++++ .../com/yahoo/vespa/config/server/deploy/ModelContextImpl.java | 3 +++ flags/src/main/java/com/yahoo/vespa/flags/Flags.java | 7 +++++++ 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json index a8aaf0f57ef..72c89b8b1ff 100644 --- a/config-model-api/abi-spec.json +++ b/config-model-api/abi-spec.json @@ -1293,7 +1293,8 @@ "public boolean createPostinglistWhenNonStrict()", "public boolean useEstimateForFetchPostings()", "public boolean useThreadBundleForFetchPostings()", - "public boolean restartOnDeployWhenOnnxModelChanges()" + "public boolean restartOnDeployWhenOnnxModelChanges()", + "public boolean sortBlueprintsByEstimate()" ], "fields" : [ ] }, diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java index 852e02dab36..d535c8948d1 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java @@ -120,6 +120,7 @@ public interface ModelContext { @ModelFeatureFlag(owners = {"baldersheim"}) default boolean useEstimateForFetchPostings() { return false; } @ModelFeatureFlag(owners = {"baldersheim"}) default boolean useThreadBundleForFetchPostings() { return false; } @ModelFeatureFlag(owners = {"hmusum"}) default boolean restartOnDeployWhenOnnxModelChanges() { return false; } + @ModelFeatureFlag(owners = {"baldersheim"}) default boolean sortBlueprintsByEstimate() { return false; } } /** Warning: As elsewhere in this package, do not make backwards incompatible changes that will break old config models! */ diff --git a/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java b/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java index dad39e74c37..48a0eb6ded9 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java @@ -170,6 +170,7 @@ public class RawRankProfile implements RankProfilesConfig.Producer { private final OptionalDouble approximateThreshold; private final OptionalDouble targetHitsMaxAdjustmentFactor; private final double rankScoreDropLimit; + private final boolean sortBlueprintsByEstimate; private final boolean alwaysMarkPhraseExpensive; private final boolean createPostinglistWhenNonStrict; private final boolean useEstimateForFetchPostings; @@ -215,6 +216,7 @@ public class RawRankProfile implements RankProfilesConfig.Producer { minHitsPerThread = compiled.getMinHitsPerThread(); numSearchPartitions = compiled.getNumSearchPartitions(); termwiseLimit = compiled.getTermwiseLimit().orElse(deployProperties.featureFlags().defaultTermwiseLimit()); + sortBlueprintsByEstimate = deployProperties.featureFlags().sortBlueprintsByEstimate(); alwaysMarkPhraseExpensive = deployProperties.featureFlags().alwaysMarkPhraseExpensive(); createPostinglistWhenNonStrict = deployProperties.featureFlags().createPostinglistWhenNonStrict(); useEstimateForFetchPostings = deployProperties.featureFlags().useEstimateForFetchPostings(); @@ -469,6 +471,9 @@ public class RawRankProfile implements RankProfilesConfig.Producer { if (termwiseLimit < 1.0) { properties.add(new Pair<>("vespa.matching.termwise_limit", termwiseLimit + "")); } + if (sortBlueprintsByEstimate) { + properties.add(new Pair<>("vespa.matching.sort_blueprints_by_estimate", String.valueOf(sortBlueprintsByEstimate))); + } if (alwaysMarkPhraseExpensive) { properties.add(new Pair<>("vespa.matching.always_mark_phrase_expensive", String.valueOf(alwaysMarkPhraseExpensive))); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java index 43594c943e3..da8e954c638 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java @@ -201,6 +201,7 @@ public class ModelContextImpl implements ModelContext { private final int rpc_events_before_wakeup; private final int heapPercentage; private final String summaryDecodePolicy; + private boolean sortBlueprintsByEstimate; private final boolean alwaysMarkPhraseExpensive; private final boolean createPostinglistWhenNonStrict; private final boolean useEstimateForFetchPostings; @@ -260,6 +261,7 @@ public class ModelContextImpl implements ModelContext { this.useEstimateForFetchPostings = flagValue(source, appId, version, Flags.USE_ESTIMATE_FOR_FETCH_POSTINGS); this.useThreadBundleForFetchPostings = flagValue(source, appId, version, Flags.USE_THREAD_BUNDLE_FOR_FETCH_POSTINGS); this.restartOnDeployWhenOnnxModelChanges = flagValue(source, appId, version, Flags.RESTART_ON_DEPLOY_WHEN_ONNX_MODEL_CHANGES); + this.sortBlueprintsByEstimate = flagValue(source, appId, version, Flags.SORT_BLUEPRINTS_BY_ESTIMATE); } @Override public int heapSizePercentage() { return heapPercentage; } @@ -316,6 +318,7 @@ public class ModelContextImpl implements ModelContext { @Override public long mergingMaxMemoryUsagePerNode() { return mergingMaxMemoryUsagePerNode; } @Override public boolean usePerDocumentThrottledDeleteBucket() { return usePerDocumentThrottledDeleteBucket; } @Override public boolean restartOnDeployWhenOnnxModelChanges() { return restartOnDeployWhenOnnxModelChanges; } + @Override public boolean sortBlueprintsByEstimate() { return sortBlueprintsByEstimate; } private static V flagValue(FlagSource source, ApplicationId appId, Version vespaVersion, UnboundFlag flag) { return flag.bindTo(source) diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index e5227a86cfb..6b437d2b8d2 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -325,6 +325,13 @@ public class Flags { "Where specified, CNAME records are used instead of the default ALIAS records, which have a default 60s TTL.", "Takes effect at redeployment from controller"); + public static final UnboundBooleanFlag SORT_BLUEPRINTS_BY_ESTIMATE = defineFeatureFlag( + "sort-blueprints-by-estimate", false, + List.of("baldersheim"), "2023-12-19", "2024-02-29", + "If true blueprints are sorted based on cost estimate, rather that est_hits", + "Takes effect at redeployment", + INSTANCE_ID); + public static final UnboundBooleanFlag ALWAYS_MARK_PHRASE_EXPENSIVE = defineFeatureFlag( "always-mark-phrase-expensive", false, List.of("baldersheim"), "2023-11-20", "2023-12-31", -- cgit v1.2.3 From fa695765be1c79f897830455d492946d93adff4e Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Tue, 19 Dec 2023 13:40:44 +0100 Subject: Estimate => Cost --- config-model-api/abi-spec.json | 2 +- .../src/main/java/com/yahoo/config/model/api/ModelContext.java | 2 +- .../src/main/java/com/yahoo/schema/derived/RawRankProfile.java | 8 ++++---- .../com/yahoo/vespa/config/server/deploy/ModelContextImpl.java | 6 +++--- flags/src/main/java/com/yahoo/vespa/flags/Flags.java | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json index 72c89b8b1ff..d05360b8d1a 100644 --- a/config-model-api/abi-spec.json +++ b/config-model-api/abi-spec.json @@ -1294,7 +1294,7 @@ "public boolean useEstimateForFetchPostings()", "public boolean useThreadBundleForFetchPostings()", "public boolean restartOnDeployWhenOnnxModelChanges()", - "public boolean sortBlueprintsByEstimate()" + "public boolean sortBlueprintsByCost()" ], "fields" : [ ] }, diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java index d535c8948d1..008a661a316 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java @@ -120,7 +120,7 @@ public interface ModelContext { @ModelFeatureFlag(owners = {"baldersheim"}) default boolean useEstimateForFetchPostings() { return false; } @ModelFeatureFlag(owners = {"baldersheim"}) default boolean useThreadBundleForFetchPostings() { return false; } @ModelFeatureFlag(owners = {"hmusum"}) default boolean restartOnDeployWhenOnnxModelChanges() { return false; } - @ModelFeatureFlag(owners = {"baldersheim"}) default boolean sortBlueprintsByEstimate() { return false; } + @ModelFeatureFlag(owners = {"baldersheim"}) default boolean sortBlueprintsByCost() { return false; } } /** Warning: As elsewhere in this package, do not make backwards incompatible changes that will break old config models! */ diff --git a/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java b/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java index 48a0eb6ded9..a99fa8b7710 100644 --- a/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java +++ b/config-model/src/main/java/com/yahoo/schema/derived/RawRankProfile.java @@ -170,7 +170,7 @@ public class RawRankProfile implements RankProfilesConfig.Producer { private final OptionalDouble approximateThreshold; private final OptionalDouble targetHitsMaxAdjustmentFactor; private final double rankScoreDropLimit; - private final boolean sortBlueprintsByEstimate; + private final boolean sortBlueprintsByCost; private final boolean alwaysMarkPhraseExpensive; private final boolean createPostinglistWhenNonStrict; private final boolean useEstimateForFetchPostings; @@ -216,7 +216,7 @@ public class RawRankProfile implements RankProfilesConfig.Producer { minHitsPerThread = compiled.getMinHitsPerThread(); numSearchPartitions = compiled.getNumSearchPartitions(); termwiseLimit = compiled.getTermwiseLimit().orElse(deployProperties.featureFlags().defaultTermwiseLimit()); - sortBlueprintsByEstimate = deployProperties.featureFlags().sortBlueprintsByEstimate(); + sortBlueprintsByCost = deployProperties.featureFlags().sortBlueprintsByCost(); alwaysMarkPhraseExpensive = deployProperties.featureFlags().alwaysMarkPhraseExpensive(); createPostinglistWhenNonStrict = deployProperties.featureFlags().createPostinglistWhenNonStrict(); useEstimateForFetchPostings = deployProperties.featureFlags().useEstimateForFetchPostings(); @@ -471,8 +471,8 @@ public class RawRankProfile implements RankProfilesConfig.Producer { if (termwiseLimit < 1.0) { properties.add(new Pair<>("vespa.matching.termwise_limit", termwiseLimit + "")); } - if (sortBlueprintsByEstimate) { - properties.add(new Pair<>("vespa.matching.sort_blueprints_by_estimate", String.valueOf(sortBlueprintsByEstimate))); + if (sortBlueprintsByCost) { + properties.add(new Pair<>("vespa.matching.sort_blueprints_by_cost", String.valueOf(sortBlueprintsByCost))); } if (alwaysMarkPhraseExpensive) { properties.add(new Pair<>("vespa.matching.always_mark_phrase_expensive", String.valueOf(alwaysMarkPhraseExpensive))); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java index da8e954c638..0c387e38afb 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java @@ -201,7 +201,7 @@ public class ModelContextImpl implements ModelContext { private final int rpc_events_before_wakeup; private final int heapPercentage; private final String summaryDecodePolicy; - private boolean sortBlueprintsByEstimate; + private boolean sortBlueprintsByCost; private final boolean alwaysMarkPhraseExpensive; private final boolean createPostinglistWhenNonStrict; private final boolean useEstimateForFetchPostings; @@ -261,7 +261,7 @@ public class ModelContextImpl implements ModelContext { this.useEstimateForFetchPostings = flagValue(source, appId, version, Flags.USE_ESTIMATE_FOR_FETCH_POSTINGS); this.useThreadBundleForFetchPostings = flagValue(source, appId, version, Flags.USE_THREAD_BUNDLE_FOR_FETCH_POSTINGS); this.restartOnDeployWhenOnnxModelChanges = flagValue(source, appId, version, Flags.RESTART_ON_DEPLOY_WHEN_ONNX_MODEL_CHANGES); - this.sortBlueprintsByEstimate = flagValue(source, appId, version, Flags.SORT_BLUEPRINTS_BY_ESTIMATE); + this.sortBlueprintsByCost = flagValue(source, appId, version, Flags.SORT_BLUEPRINTS_BY_COST); } @Override public int heapSizePercentage() { return heapPercentage; } @@ -318,7 +318,7 @@ public class ModelContextImpl implements ModelContext { @Override public long mergingMaxMemoryUsagePerNode() { return mergingMaxMemoryUsagePerNode; } @Override public boolean usePerDocumentThrottledDeleteBucket() { return usePerDocumentThrottledDeleteBucket; } @Override public boolean restartOnDeployWhenOnnxModelChanges() { return restartOnDeployWhenOnnxModelChanges; } - @Override public boolean sortBlueprintsByEstimate() { return sortBlueprintsByEstimate; } + @Override public boolean sortBlueprintsByCost() { return sortBlueprintsByCost; } private static V flagValue(FlagSource source, ApplicationId appId, Version vespaVersion, UnboundFlag flag) { return flag.bindTo(source) diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index 6b437d2b8d2..a32ed75d67b 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -325,10 +325,10 @@ public class Flags { "Where specified, CNAME records are used instead of the default ALIAS records, which have a default 60s TTL.", "Takes effect at redeployment from controller"); - public static final UnboundBooleanFlag SORT_BLUEPRINTS_BY_ESTIMATE = defineFeatureFlag( - "sort-blueprints-by-estimate", false, + public static final UnboundBooleanFlag SORT_BLUEPRINTS_BY_COST = defineFeatureFlag( + "sort-blueprints-by-cost", false, List.of("baldersheim"), "2023-12-19", "2024-02-29", - "If true blueprints are sorted based on cost estimate, rather that est_hits", + "If true blueprints are sorted based on cost estimate, rather that absolute estimated hits", "Takes effect at redeployment", INSTANCE_ID); -- cgit v1.2.3 From 83f42a92ff767452aaf209a15bde9c462381754b Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Tue, 19 Dec 2023 12:47:31 +0000 Subject: Estimate => Cost --- searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp | 2 +- searchcore/src/vespa/searchcore/proton/matching/query.cpp | 4 ++-- searchcore/src/vespa/searchcore/proton/matching/query.h | 2 +- searchlib/src/vespa/searchlib/fef/indexproperties.cpp | 6 +++--- searchlib/src/vespa/searchlib/fef/indexproperties.h | 2 +- searchlib/src/vespa/searchlib/fef/ranksetup.cpp | 4 ++-- searchlib/src/vespa/searchlib/fef/ranksetup.h | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp b/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp index 71a6475b0fb..b5224281724 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp +++ b/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp @@ -203,7 +203,7 @@ MatchToolsFactory(QueryLimiter & queryLimiter, trace.addEvent(5, "Build query execution plan"); _query.reserveHandles(_requestContext, searchContext, _mdl); trace.addEvent(5, "Optimize query execution plan"); - _query.optimize(SortBlueprintsByEstimate::check(_queryEnv.getProperties(), rankSetup.sort_blueprints_by_estimate())); + _query.optimize(SortBlueprintsByCost::check(_queryEnv.getProperties(), rankSetup.sort_blueprints_by_cost())); trace.addEvent(4, "Perform dictionary lookups and posting lists initialization"); double hitRate = std::min(1.0, double(maxNumHits)/double(searchContext.getDocIdLimit())); bool create_postinglist_when_non_strict = CreatePostingListWhenNonStrict::check(_queryEnv.getProperties(), rankSetup.create_postinglist_when_non_strict()); diff --git a/searchcore/src/vespa/searchcore/proton/matching/query.cpp b/searchcore/src/vespa/searchcore/proton/matching/query.cpp index b86ee931a53..149828b0a91 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/query.cpp +++ b/searchcore/src/vespa/searchcore/proton/matching/query.cpp @@ -198,9 +198,9 @@ Query::reserveHandles(const IRequestContext & requestContext, ISearchContext &co } void -Query::optimize(bool sort_by_estimate) +Query::optimize(bool sort_by_cost) { - (void) sort_by_estimate; + (void) sort_by_cost; _blueprint = Blueprint::optimize(std::move(_blueprint)); LOG(debug, "optimized blueprint:\n%s\n", _blueprint->asString().c_str()); } diff --git a/searchcore/src/vespa/searchcore/proton/matching/query.h b/searchcore/src/vespa/searchcore/proton/matching/query.h index 5148f8ba402..8062f12b70d 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/query.h +++ b/searchcore/src/vespa/searchcore/proton/matching/query.h @@ -103,7 +103,7 @@ public: * testing becomes harder. Not calling this function enables the * test to verify the original query without optimization. **/ - void optimize(bool sort_by_estimate); + void optimize(bool sort_by_cost); void fetchPostings(const ExecuteInfo & executeInfo) ; void handle_global_filter(const IRequestContext & requestContext, uint32_t docid_limit, diff --git a/searchlib/src/vespa/searchlib/fef/indexproperties.cpp b/searchlib/src/vespa/searchlib/fef/indexproperties.cpp index 65e31a2bc60..1344a30e239 100644 --- a/searchlib/src/vespa/searchlib/fef/indexproperties.cpp +++ b/searchlib/src/vespa/searchlib/fef/indexproperties.cpp @@ -455,9 +455,9 @@ FuzzyAlgorithm::lookup(const Properties& props, vespalib::FuzzyMatchingAlgorithm return vespalib::fuzzy_matching_algorithm_from_string(value, default_value); } -const vespalib::string SortBlueprintsByEstimate::NAME("vespa.matching.sort_blueprints_by_estimate"); -const bool SortBlueprintsByEstimate::DEFAULT_VALUE(false); -bool SortBlueprintsByEstimate::check(const Properties &props, bool fallback) { +const vespalib::string SortBlueprintsByCost::NAME("vespa.matching.sort_blueprints_by_cost"); +const bool SortBlueprintsByCost::DEFAULT_VALUE(false); +bool SortBlueprintsByCost::check(const Properties &props, bool fallback) { return lookupBool(props, NAME, fallback); } diff --git a/searchlib/src/vespa/searchlib/fef/indexproperties.h b/searchlib/src/vespa/searchlib/fef/indexproperties.h index 13e053c8dcf..e0fee951670 100644 --- a/searchlib/src/vespa/searchlib/fef/indexproperties.h +++ b/searchlib/src/vespa/searchlib/fef/indexproperties.h @@ -339,7 +339,7 @@ namespace matching { /** * Sort blueprints based on relative cost estimate rather than est_hits **/ - struct SortBlueprintsByEstimate { + struct SortBlueprintsByCost { static const vespalib::string NAME; static const bool DEFAULT_VALUE; static bool check(const Properties &props) { return check(props, DEFAULT_VALUE); } diff --git a/searchlib/src/vespa/searchlib/fef/ranksetup.cpp b/searchlib/src/vespa/searchlib/fef/ranksetup.cpp index 0353879be14..e4a31d27fb1 100644 --- a/searchlib/src/vespa/searchlib/fef/ranksetup.cpp +++ b/searchlib/src/vespa/searchlib/fef/ranksetup.cpp @@ -56,7 +56,7 @@ RankSetup::RankSetup(const BlueprintFactory &factory, const IIndexEnvironment &i _dumpFeatures(), _warnings(), _feature_rename_map(), - _sort_blueprints_by_estimate(false), + _sort_blueprints_by_cost(false), _ignoreDefaultRankFeatures(false), _compiled(false), _compileError(false), @@ -138,7 +138,7 @@ RankSetup::configure() _mutateOnSummary._attribute = mutate::on_summary::Attribute::lookup(_indexEnv.getProperties()); _mutateOnSummary._operation = mutate::on_summary::Operation::lookup(_indexEnv.getProperties()); _mutateAllowQueryOverride = mutate::AllowQueryOverride::check(_indexEnv.getProperties()); - _sort_blueprints_by_estimate = matching::SortBlueprintsByEstimate::check(_indexEnv.getProperties()); + _sort_blueprints_by_cost = matching::SortBlueprintsByCost::check(_indexEnv.getProperties()); _always_mark_phrase_expensive = matching::AlwaysMarkPhraseExpensive::check(_indexEnv.getProperties()); _create_postinglist_when_non_strict = matching::CreatePostingListWhenNonStrict::check(_indexEnv.getProperties()); _use_estimate_for_fetch_postings = matching::UseEstimateForFetchPostings::check(_indexEnv.getProperties()); diff --git a/searchlib/src/vespa/searchlib/fef/ranksetup.h b/searchlib/src/vespa/searchlib/fef/ranksetup.h index f90ce2b0475..a74bf3335c6 100644 --- a/searchlib/src/vespa/searchlib/fef/ranksetup.h +++ b/searchlib/src/vespa/searchlib/fef/ranksetup.h @@ -65,7 +65,7 @@ private: std::vector _dumpFeatures; Warnings _warnings; StringStringMap _feature_rename_map; - bool _sort_blueprints_by_estimate; + bool _sort_blueprints_by_cost; bool _ignoreDefaultRankFeatures; bool _compiled; bool _compileError; @@ -466,7 +466,7 @@ public: const MutateOperation & getMutateOnSummary() const { return _mutateOnSummary; } bool allowMutateQueryOverride() const { return _mutateAllowQueryOverride; } - bool sort_blueprints_by_estimate() const noexcept { return _sort_blueprints_by_estimate; } + bool sort_blueprints_by_cost() const noexcept { return _sort_blueprints_by_cost; } }; } -- cgit v1.2.3 From 29a322a5ed88935cf225b913ec652be0cdb056ef Mon Sep 17 00:00:00 2001 From: Geir Storli Date: Tue, 19 Dec 2023 12:48:19 +0000 Subject: Support TermFieldMatchData where doUnpack() sets docid. This will be needed for an InTerm used for ranking, e.g. the matches rank feature. --- .../multi_term_or_filter_search_test.cpp | 8 ++++- .../attribute/multi_term_or_filter_search.cpp | 36 ++++++++++++++++------ .../attribute/multi_term_or_filter_search.h | 2 ++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/searchlib/src/tests/attribute/multi_term_or_filter_search/multi_term_or_filter_search_test.cpp b/searchlib/src/tests/attribute/multi_term_or_filter_search/multi_term_or_filter_search_test.cpp index dea2702ef0d..552a128c518 100644 --- a/searchlib/src/tests/attribute/multi_term_or_filter_search/multi_term_or_filter_search_test.cpp +++ b/searchlib/src/tests/attribute/multi_term_or_filter_search/multi_term_or_filter_search_test.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #define ENABLE_GTEST_MIGRATION @@ -11,13 +12,16 @@ using PostingList = search::attribute::PostingListTraits::PostingStoreBase; using Iterator = search::attribute::PostingListTraits::const_iterator; using KeyData = PostingList::KeyDataType; + using search::BitVector; using search::attribute::MultiTermOrFilterSearch; +using search::fef::TermFieldMatchData; using search::queryeval::SearchIterator; using vespalib::datastore::EntryRef; class MultiTermOrFilterSearchTest : public ::testing::Test { PostingList _postings; + mutable TermFieldMatchData _tfmd; vespalib::GenerationHandler _gens; std::vector _trees; uint32_t _range_start; @@ -62,7 +66,7 @@ public: for (size_t i = 0; i < num_trees(); ++i) { iterators.emplace_back(get_tree(i)); } - auto result = MultiTermOrFilterSearch::create(std::move(iterators)); + auto result = MultiTermOrFilterSearch::create(std::move(iterators), _tfmd); result->initRange(_range_start, _range_end); return result; }; @@ -73,6 +77,8 @@ public: while (doc_id < _range_end) { if (iterator.seek(doc_id)) { result.emplace_back(doc_id); + iterator.unpack(doc_id); + EXPECT_EQ(doc_id, _tfmd.getDocId()); ++doc_id; } else { doc_id = std::max(doc_id + 1, iterator.getDocId()); diff --git a/searchlib/src/vespa/searchlib/attribute/multi_term_or_filter_search.cpp b/searchlib/src/vespa/searchlib/attribute/multi_term_or_filter_search.cpp index 19668522e17..214851e9681 100644 --- a/searchlib/src/vespa/searchlib/attribute/multi_term_or_filter_search.cpp +++ b/searchlib/src/vespa/searchlib/attribute/multi_term_or_filter_search.cpp @@ -15,14 +15,19 @@ template class MultiTermOrFilterSearchImpl : public MultiTermOrFilterSearch { IteratorPack _children; + fef::TermFieldMatchData* _tfmd; void seek_all(uint32_t docId); public: - explicit MultiTermOrFilterSearchImpl(IteratorPack&& children); + explicit MultiTermOrFilterSearchImpl(IteratorPack&& children, fef::TermFieldMatchData* tfmd); ~MultiTermOrFilterSearchImpl() override; void doSeek(uint32_t docId) override; - void doUnpack(uint32_t) override { } + void doUnpack(uint32_t docid) override { + if (_tfmd != nullptr) { + _tfmd->resetOnlyDocId(docid); + } + } void initRange(uint32_t begin, uint32_t end) override { SearchIterator::initRange(begin, end); @@ -46,9 +51,10 @@ public: }; template -MultiTermOrFilterSearchImpl::MultiTermOrFilterSearchImpl(IteratorPack&& children) +MultiTermOrFilterSearchImpl::MultiTermOrFilterSearchImpl(IteratorPack&& children, fef::TermFieldMatchData* tfmd) : MultiTermOrFilterSearch(), - _children(std::move(children)) + _children(std::move(children)), + _tfmd(tfmd) { } @@ -89,7 +95,7 @@ namespace { template std::unique_ptr -create_helper(std::vector&& children) +create_helper(std::vector&& children, fef::TermFieldMatchData* tfmd) { if (children.empty()) { return std::make_unique(); @@ -97,7 +103,7 @@ create_helper(std::vector&& children) std::sort(children.begin(), children.end(), [](const auto & a, const auto & b) { return a.size() > b.size(); }); using OrFilter = MultiTermOrFilterSearchImpl; - return std::make_unique(IteratorPackType(std::move(children))); + return std::make_unique(IteratorPackType(std::move(children)), tfmd); } } @@ -106,13 +112,25 @@ create_helper(std::vector&& children) std::unique_ptr MultiTermOrFilterSearch::create(std::vector&& children) { - return create_helper(std::move(children)); + return create_helper(std::move(children), nullptr); +} + +std::unique_ptr +MultiTermOrFilterSearch::create(std::vector&& children, fef::TermFieldMatchData& tfmd) +{ + return create_helper(std::move(children), &tfmd); } std::unique_ptr MultiTermOrFilterSearch::create(std::vector&& children) { - return create_helper(std::move(children)); + return create_helper(std::move(children), nullptr); +} + +std::unique_ptr +MultiTermOrFilterSearch::create(std::vector&& children, fef::TermFieldMatchData& tfmd) +{ + return create_helper(std::move(children), &tfmd); } std::unique_ptr @@ -123,7 +141,7 @@ MultiTermOrFilterSearch::create(const std::vector& children, return std::make_unique(); } else { using OrFilter = MultiTermOrFilterSearchImpl; - return std::make_unique(SearchIteratorPack(children, std::move(md))); + return std::make_unique(SearchIteratorPack(children, std::move(md)), nullptr); } } diff --git a/searchlib/src/vespa/searchlib/attribute/multi_term_or_filter_search.h b/searchlib/src/vespa/searchlib/attribute/multi_term_or_filter_search.h index 42eb33d2eed..1e8227c3007 100644 --- a/searchlib/src/vespa/searchlib/attribute/multi_term_or_filter_search.h +++ b/searchlib/src/vespa/searchlib/attribute/multi_term_or_filter_search.h @@ -18,7 +18,9 @@ protected: MultiTermOrFilterSearch() = default; public: static std::unique_ptr create(std::vector&& children); + static std::unique_ptr create(std::vector&& children, fef::TermFieldMatchData& tfmd); static std::unique_ptr create(std::vector&& children); + static std::unique_ptr create(std::vector&& children, fef::TermFieldMatchData& tfmd); static std::unique_ptr create(const std::vector& children, std::unique_ptr md); }; -- cgit v1.2.3 From f226abe38abd9900891d512c46d3bceb37f25a84 Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Tue, 19 Dec 2023 12:48:38 +0000 Subject: Avoid unrelated code change --- .../src/tests/hwaccelrated/hwaccelrated_test.cpp | 34 ---------------------- 1 file changed, 34 deletions(-) diff --git a/vespalib/src/tests/hwaccelrated/hwaccelrated_test.cpp b/vespalib/src/tests/hwaccelrated/hwaccelrated_test.cpp index 19c5ad53d46..e35efb20c1a 100644 --- a/vespalib/src/tests/hwaccelrated/hwaccelrated_test.cpp +++ b/vespalib/src/tests/hwaccelrated/hwaccelrated_test.cpp @@ -47,38 +47,4 @@ TEST("test euclidean distance") { TEST_DO(verifyEuclideanDistance(hwaccelrated::IAccelrated::getAccelerator(), TEST_LENGTH)); } -void -verifyAnd64(const hwaccelrated::IAccelrated & accelrator, std::vector> v, - const char * expected, char * dest) -{ - accelrator.and64(0, v, dest); - EXPECT_EQUAL(0, memcmp(expected, dest, 64)); -} - -void -verifyAnd64(const hwaccelrated::IAccelrated & accelrator, std::vector> v, const char * expected) -{ - char c[64]; - memset(c, 0, sizeof(c)); - verifyAnd64(accelrator, v, expected, c); - memset(c, 0xff, sizeof(c)); - verifyAnd64(accelrator, v, expected, c); -} - -TEST("test 64 byte and with multiple vectors") { - char a[64]; - char b[64]; - memset(a, 0x55, sizeof(a)); - memset(b, 0xff, sizeof(b)); - std::vector> v; - v.emplace_back(a, false); - v.emplace_back(b, false); - - verifyAnd64(hwaccelrated::GenericAccelrator(), v, a); - verifyAnd64(hwaccelrated::IAccelrated::getAccelerator(), v, a); - std::reverse(v.begin(), v.end()); - verifyAnd64(hwaccelrated::GenericAccelrator(), v, a); - verifyAnd64(hwaccelrated::IAccelrated::getAccelerator(), v, a); -} - TEST_MAIN() { TEST_RUN_ALL(); } -- cgit v1.2.3 From b6368d66d4169e93c98df5fc6fe4df7cc9986c8b Mon Sep 17 00:00:00 2001 From: Morten Tokle Date: Mon, 18 Dec 2023 15:35:09 +0100 Subject: Fix more xxe prevention --- .../provider/FilesApplicationPackage.java | 4 ++- .../java/com/yahoo/searchlib/gbdt/XmlHelper.java | 36 +++++++++++++--------- vespajlib/src/main/java/com/yahoo/text/XML.java | 15 +++++++++ 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java index 3df11855f75..ab5645eb50d 100644 --- a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java +++ b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java @@ -27,6 +27,7 @@ import com.yahoo.io.IOUtils; import com.yahoo.io.reader.NamedReader; import com.yahoo.path.Path; import com.yahoo.text.Utf8; +import com.yahoo.text.XML; import com.yahoo.vespa.config.ConfigDefinition; import com.yahoo.vespa.config.ConfigDefinitionBuilder; import com.yahoo.vespa.config.ConfigDefinitionKey; @@ -36,6 +37,7 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; + import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; @@ -166,7 +168,7 @@ public class FilesApplicationPackage extends AbstractApplicationPackage { configDefsDir = applicationFile(appDir, CONFIG_DEFINITIONS_DIR); addUserIncludeDirs(); this.metaData = metaData; - transformerFactory = TransformerFactory.newInstance(); + this.transformerFactory = XML.createTransformerFactory(); } @Override diff --git a/searchlib/src/main/java/com/yahoo/searchlib/gbdt/XmlHelper.java b/searchlib/src/main/java/com/yahoo/searchlib/gbdt/XmlHelper.java index fce0485f41a..60617687f44 100644 --- a/searchlib/src/main/java/com/yahoo/searchlib/gbdt/XmlHelper.java +++ b/searchlib/src/main/java/com/yahoo/searchlib/gbdt/XmlHelper.java @@ -7,6 +7,7 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -15,21 +16,21 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.LinkedList; import java.util.List; import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; /** * @author Simon Thoresen Hult */ abstract class XmlHelper { - - private static final Charset UTF8 = Charset.forName("UTF-8"); - public static Element parseXml(String xml) throws ParserConfigurationException, IOException, SAXException { - return parseXmlStream(new ByteArrayInputStream(xml.getBytes(UTF8))); + return parseXmlStream(new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8))); } public static Element parseXmlFile(String fileName) @@ -41,22 +42,27 @@ abstract class XmlHelper { public static Element parseXmlStream(InputStream in) throws ParserConfigurationException, IOException, SAXException { - DocumentBuilderFactory factory = createDocumentBuilderFactory(); - DocumentBuilder builder = factory.newDocumentBuilder(); + DocumentBuilder builder = createDocumentBuilderFactory().newDocumentBuilder(); Document doc = builder.parse(in); return doc.getDocumentElement(); } - private static DocumentBuilderFactory createDocumentBuilderFactory() throws ParserConfigurationException { - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setXIncludeAware(false); + private static DocumentBuilderFactory createDocumentBuilderFactory() { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setXIncludeAware(false); + factory.setExpandEntityReferences(false); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); - // XXE prevention - factory.setFeature("http://xml.org/sax/features/external-general-entities", false); - factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); - factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); - return factory; + // XXE prevention + factory.setFeature("http://xml.org/sax/features/external-general-entities", false); + factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); + factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); + return factory; + } catch (ParserConfigurationException e) { + throw new RuntimeException("Failed to initialize XML parser", e); + } } public static String getAttributeText(Node node, String name) { diff --git a/vespajlib/src/main/java/com/yahoo/text/XML.java b/vespajlib/src/main/java/com/yahoo/text/XML.java index a6e36a0c3e1..72a2dba54e1 100644 --- a/vespajlib/src/main/java/com/yahoo/text/XML.java +++ b/vespajlib/src/main/java/com/yahoo/text/XML.java @@ -9,9 +9,11 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerFactory; import java.io.File; import java.io.IOException; import java.io.Reader; @@ -445,6 +447,19 @@ public class XML { return valid; } + /** + * Creates a new XML TransformerFactory. + * + * @return a TransformerFactory + */ + public static TransformerFactory createTransformerFactory() { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); + return transformerFactory; + } + + /** * The point of this weird class and the jumble of abstract methods is * linking the scan for characters that must be quoted into the quoting -- cgit v1.2.3 From d125a1c2d5c9920a5fe3f9b2875b8912a06f3942 Mon Sep 17 00:00:00 2001 From: Harald Musum Date: Tue, 19 Dec 2023 14:12:36 +0100 Subject: Cosmetic changes --- ...RestartOnDeployForOnnxModelChangesValidator.java | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java index 1205ae4e939..8da7f34048b 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java @@ -109,21 +109,26 @@ public class RestartOnDeployForOnnxModelChangesValidator implements ChangeValida double nextModelCostInGb = onnxModelCostInGb(cluster); double totalMemory = cluster.getContainers().get(0).getHostResource().realResources().memoryGb(); - double availableMemory = Math.max(0, totalMemory - Host.memoryOverheadGb - currentModelCostInGb - nextModelCostInGb); - if (availableMemory <= 0.0) - return false; + double memoryUsedByModels = currentModelCostInGb + nextModelCostInGb; + double availableMemory = Math.max(0, totalMemory - Host.memoryOverheadGb - memoryUsedByModels); var availableMemoryPercentage = cluster.availableMemoryPercentage(); int memoryPercentage = (int) (availableMemory / totalMemory * availableMemoryPercentage); - if (memoryPercentage < percentLimit || availableMemory < gbLimit) { - deployLogger.log(INFO, "Validating %s, not enough memory (%s) to avoid restart (models require %s), consider a flavor with more memory to avoid this" - .formatted(cluster, availableMemory, currentModelCostInGb + nextModelCostInGb)); + if (memoryPercentage < percentLimit) { + deployLogger.log(INFO, "Validating %s, percentage of available memory too low (%d < %d) to avoid restart, consider a flavor with more memory to avoid this" + .formatted(cluster, memoryPercentage, percentLimit)); + return false; + } + + if (availableMemory < gbLimit) { + deployLogger.log(INFO, "Validating %s, available memory too low (%.2f Gb < %.2f Gb) to avoid restart, consider a flavor with more memory to avoid this" + .formatted(cluster, availableMemory, gbLimit)); return false; } - log.log(FINE, "Validating " + cluster + ", enough memory (%s) to avoid restart (models require %s)" - .formatted(availableMemory, currentModelCostInGb + nextModelCostInGb)); + log.log(FINE, "Validating %s, enough available memory (%.2f Gb) to avoid restart (models use %.2f Gb)" + .formatted(cluster, availableMemory, memoryUsedByModels)); return true; } -- cgit v1.2.3 From 6d9b72a6459af8a514d2507abea457de7d49d6a6 Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Thu, 14 Dec 2023 14:14:16 +0100 Subject: Store GPU metrics and load separately --- .../hosted/provision/autoscale/ClusterModel.java | 12 +++-- .../autoscale/ClusterNodesTimeseries.java | 3 +- .../vespa/hosted/provision/autoscale/Load.java | 63 +++++++++++----------- .../provision/autoscale/MetricsResponse.java | 45 ++++++++++++---- .../hosted/provision/autoscale/QuestMetricsDb.java | 13 ++++- .../persistence/ApplicationSerializer.java | 8 ++- .../provision/testutils/MockNodeRepository.java | 5 +- .../vespa/hosted/provision/NodeRepoStatsTest.java | 21 ++++---- .../provision/autoscale/AutoscalingTest.java | 52 +++++++++--------- .../vespa/hosted/provision/autoscale/Loader.java | 4 +- .../autoscale/MetricsV2MetricsFetcherTest.java | 2 + .../provision/autoscale/NodeMetricsDbTest.java | 2 +- .../provision/autoscale/QuestMetricsDbTest.java | 6 ++- .../maintenance/AutoscalingMaintainerTester.java | 2 +- .../provision/maintenance/MetricsReporterTest.java | 2 +- .../ScalingSuggestionsMaintainerTest.java | 2 +- .../persistence/ApplicationSerializerTest.java | 4 +- 17 files changed, 147 insertions(+), 99 deletions(-) diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java index 1e4a11fdea2..986ab830283 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java @@ -233,11 +233,13 @@ public class ClusterModel { double queryCpu = queryCpuPerGroup * groupCount() / groups; double writeCpu = (double)groupSize() / groupSize; return new Load(cpu.queryFraction() * queryCpu + (1 - cpu.queryFraction()) * writeCpu, - (1 - memory.fixedFraction()) * (double)groupSize() / groupSize + memory.fixedFraction() * 1, - (double)groupSize() / groupSize); + (1 - memory.fixedFraction()) * (double) groupSize() / groupSize + memory.fixedFraction() * 1, + (double)groupSize() / groupSize, + 1, + 1); } else { - return new Load((double)nodeCount() / nodes, 1, 1); + return new Load((double) nodeCount() / nodes, 1, 1, 1, 1); } } @@ -246,7 +248,7 @@ public class ClusterModel { * if one of the nodes go down. */ public Load idealLoad() { - var ideal = new Load(cpu.idealLoad(), memory.idealLoad(), disk.idealLoad()).divide(redundancyAdjustment()); + var ideal = new Load(cpu.idealLoad(), memory.idealLoad(), disk.idealLoad(), cpu.idealLoad(), memory.idealLoad()).divide(redundancyAdjustment()); if ( !cluster.bcpGroupInfo().isEmpty() && cluster.bcpGroupInfo().queryRate() > 0) { // Since we have little local information, use information about query cost in other groups Load bcpGroupIdeal = adjustQueryDependentIdealLoadByBcpGroupInfo(ideal); @@ -392,7 +394,7 @@ public class ClusterModel { if (averageQueryRate().isEmpty() || averageQueryRate().getAsDouble() == 0.0) return OptionalDouble.empty(); // TODO: Query rate should generally be sampled at the time where we see the peak resource usage int fanOut = clusterSpec.type().isContainer() ? 1 : groupSize(); - return OptionalDouble.of(peakLoad().cpu() * cpu.queryFraction() * fanOut * nodes.not().retired().first().get().resources().vcpu() + return OptionalDouble.of(peakLoad().cpu() * cpu.queryFraction() * fanOut * nodes.not().retired().first().get().resources().vcpu() / averageQueryRate().getAsDouble() / groupCount()); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java index e1ef21ebd13..6978e269c3d 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java @@ -67,7 +67,8 @@ public class ClusterNodesTimeseries { * the average of the highest reading for that dimension on each node. */ public Load peakLoad() { - return new Load(peakLoad(Load.Dimension.cpu), peakLoad(Load.Dimension.memory), peakLoad(Load.Dimension.disk)); + return new Load(peakLoad(Load.Dimension.cpu), peakLoad(Load.Dimension.memory), peakLoad(Load.Dimension.disk), + peakLoad(Load.Dimension.gpu), peakLoad(Load.Dimension.gpuMemory)); } private double peakLoad(Load.Dimension dimension) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java index 799ed621807..22c13795d18 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java @@ -3,9 +3,7 @@ package com.yahoo.vespa.hosted.provision.autoscale; import com.yahoo.config.provision.NodeResources; -import java.util.Objects; import java.util.function.DoubleBinaryOperator; -import java.util.function.DoubleFunction; import java.util.function.DoubleUnaryOperator; import java.util.function.Predicate; @@ -14,32 +12,36 @@ import java.util.function.Predicate; * * @author bratseth */ -public class Load { +public record Load(double cpu, double memory, double disk, double gpu, double gpuMemory) { - public enum Dimension { cpu, memory, disk } + public enum Dimension { cpu, memory, disk, gpu, gpuMemory } - private final double cpu, memory, disk; - - public Load(double cpu, double memory, double disk) { + public Load(double cpu, double memory, double disk, double gpu, double gpuMemory) { this.cpu = requireNormalized(cpu, "cpu"); this.memory = requireNormalized(memory, "memory"); this.disk = requireNormalized(disk, "disk"); + this.gpu = requireNormalized(gpu, "gpu"); + this.gpuMemory = requireNormalized(gpuMemory, "gpuMemory"); } public double cpu() { return cpu; } public double memory() { return memory; } public double disk() { return disk; } + public double gpu() { return gpu; } + public double gpuMemory() { return gpuMemory; } - public Load withCpu(double cpu) { return new Load(cpu, memory, disk); } - public Load withMemory(double memory) { return new Load(cpu, memory, disk); } - public Load withDisk(double disk) { return new Load(cpu, memory, disk); } + public Load withCpu(double cpu) { return new Load(cpu, memory, disk, gpu, gpuMemory); } + public Load withMemory(double memory) { return new Load(cpu, memory, disk, gpu, gpuMemory); } + public Load withDisk(double disk) { return new Load(cpu, memory, disk, gpu, gpuMemory); } + public Load withGpu(double gpu) { return new Load(cpu, memory, disk, gpu, gpuMemory); } + public Load withGpuMemory(double gpuMemory) { return new Load(cpu, memory, disk, gpu, gpuMemory); } public Load add(Load other) { return join(other, (a, b) -> a + b); } public Load multiply(NodeResources resources) { - return new Load(cpu * resources.vcpu(), memory * resources.memoryGb(), disk * resources.diskGb()); + return new Load(cpu * resources.vcpu(), memory * resources.memoryGb(), disk * resources.diskGb(), gpu * resources.gpuResources().count(), gpu * resources.gpuResources().memoryGb()); } public Load multiply(double factor) { return map(v -> v * factor); @@ -55,21 +57,25 @@ public class Load { return map(v -> divide(v, divisor)); } public Load divide(NodeResources resources) { - return new Load(divide(cpu, resources.vcpu()), divide(memory, resources.memoryGb()), divide(disk, resources.diskGb())); + return new Load(divide(cpu, resources.vcpu()), divide(memory, resources.memoryGb()), divide(disk, resources.diskGb()), divide(gpu, resources.gpuResources().count()), divide(gpuMemory, resources.gpuResources().memoryGb())); } /** Returns the load where the given function is applied to each dimension of this. */ public Load map(DoubleUnaryOperator f) { return new Load(f.applyAsDouble(cpu), f.applyAsDouble(memory), - f.applyAsDouble(disk)); + f.applyAsDouble(disk), + f.applyAsDouble(gpu), + f.applyAsDouble(gpuMemory)); } /** Returns the load where the given function is applied to each dimension of this and the given load. */ public Load join(Load other, DoubleBinaryOperator f) { return new Load(f.applyAsDouble(this.cpu(), other.cpu()), f.applyAsDouble(this.memory(), other.memory()), - f.applyAsDouble(this.disk(), other.disk())); + f.applyAsDouble(this.disk(), other.disk()), + f.applyAsDouble(this.gpu(), other.gpu()), + f.applyAsDouble(this.gpuMemory(), other.gpuMemory())); } /** Returns true if any dimension matches the predicate. */ @@ -88,6 +94,8 @@ public class Load { case cpu -> cpu(); case memory -> memory(); case disk -> disk(); + case gpu -> gpu(); + case gpuMemory -> gpuMemory(); }; } @@ -95,7 +103,7 @@ public class Load { if (Double.isNaN(value)) throw new IllegalArgumentException(name + " must be a number but is NaN"); if (value < 0) - throw new IllegalArgumentException(name + " must be zero or lager, but is " + value); + throw new IllegalArgumentException(name + " must be zero or larger, but is " + value); return value; } @@ -104,29 +112,20 @@ public class Load { return a / b; } - @Override - public boolean equals(Object o) { - if (o == this) return true; - if ( ! (o instanceof Load other)) return false; - if (other.cpu() != this.cpu()) return false; - if (other.memory() != this.memory()) return false; - if (other.disk() != this.disk()) return false; - return true; - } - - @Override - public int hashCode() { return Objects.hash(cpu, memory, disk); } - @Override public String toString() { - return "load: " + cpu + " cpu, " + memory + " memory, " + disk + " disk"; + return "load: " + cpu + " cpu, " + memory + " memory, " + disk + " disk," + gpu + " gpu," + gpuMemory + " gpuMemory"; } - public static Load zero() { return new Load(0, 0, 0); } - public static Load one() { return new Load(1, 1, 1); } + public static Load zero() { return new Load(0, 0, 0, 0, 0); } + public static Load one() { return new Load(1, 1, 1, 1, 1); } public static Load byDividing(NodeResources a, NodeResources b) { - return new Load(divide(a.vcpu(), b.vcpu()), divide(a.memoryGb(), b.memoryGb()), divide(a.diskGb(), b.diskGb())); + return new Load(divide(a.vcpu(), b.vcpu()), + divide(a.memoryGb(), b.memoryGb()), + divide(a.diskGb(), b.diskGb()), + divide(a.gpuResources().count(), b.gpuResources().count()), + divide(a.gpuResources().memoryGb(), b.gpuResources().memoryGb())); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java index a6882e49efa..f35879d0b24 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java @@ -76,8 +76,10 @@ public class MetricsResponse { nodeMetrics.add(new Pair<>(hostname, new NodeMetricSnapshot(at, new Load(Metric.cpu.from(nodeValues), Metric.memory.from(nodeValues), - Metric.disk.from(nodeValues)), - (long)Metric.generation.from(nodeValues), + Metric.disk.from(nodeValues), + Metric.gpu.from(nodeValues), + Metric.gpuMemory.from(nodeValues)), + (long) Metric.generation.from(nodeValues), Metric.inService.from(nodeValues) > 0, clusterIsStable(node.get(), applicationNodes, nodeValues), Metric.queryRate.from(nodeValues)))); @@ -126,6 +128,7 @@ public class MetricsResponse { @Override public List metricResponseNames() { + // TODO(mpolden): Track only CPU util once we support proper GPU scaling return List.of(HostedNodeAdminMetrics.CPU_UTIL.baseName(), HostedNodeAdminMetrics.GPU_UTIL.baseName()); } @@ -139,6 +142,7 @@ public class MetricsResponse { @Override public List metricResponseNames() { + // TODO(mpolden): Track only CPU memory once we support proper GPU scaling return List.of(HostedNodeAdminMetrics.MEM_UTIL.baseName(), SearchNodeMetrics.CONTENT_PROTON_RESOURCE_USAGE_MEMORY.average(), HostedNodeAdminMetrics.GPU_MEM_USED.baseName(), @@ -147,7 +151,7 @@ public class MetricsResponse { @Override double computeFinal(ListMap values) { - return Math.max(gpuMemUtil(values), cpuMemUtil(values)); + return Math.max(cpuMemUtil(values), gpuMemory.computeFinal(values)); } private double cpuMemUtil(ListMap values) { @@ -160,12 +164,6 @@ public class MetricsResponse { return 0; } - private double gpuMemUtil(ListMap values) { - var usedGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_USED.baseName()).stream().mapToDouble(v -> v).sum(); - var totalGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()).stream().mapToDouble(v -> v).sum(); - return totalGpuMemory > 0 ? usedGpuMemory / totalGpuMemory : 0; - } - }, disk { // a node resource @@ -186,6 +184,35 @@ public class MetricsResponse { return 0; } + }, + gpu { // a node resource + + @Override + public List metricResponseNames() { + return List.of(HostedNodeAdminMetrics.GPU_UTIL.baseName()); + } + + @Override + double computeFinal(ListMap values) { + return values.values().stream().flatMap(List::stream).mapToDouble(v -> v).max().orElse(0) / 100; // % to ratio + } + + }, + gpuMemory { // a node resource + + @Override + public List metricResponseNames() { + return List.of(HostedNodeAdminMetrics.GPU_MEM_USED.baseName(), + HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()); + } + + @Override + double computeFinal(ListMap values) { + var usedGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_USED.baseName()).stream().mapToDouble(v -> v).sum(); + var totalGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()).stream().mapToDouble(v -> v).sum(); + return totalGpuMemory > 0 ? usedGpuMemory / totalGpuMemory : 0; + } + }, generation { // application config generation active on the node diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java index 38127fa3093..c0de9a43f7f 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java @@ -144,6 +144,8 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { row.putBool(6, snapshot.getSecond().inService()); row.putBool(7, snapshot.getSecond().stable()); row.putFloat(8, (float) snapshot.getSecond().queryRate()); + row.putFloat(9, (float) snapshot.getSecond().load().gpu()); + row.putFloat(10, (float) snapshot.getSecond().load().gpuMemory()); row.append(); } writer.commit(); @@ -243,6 +245,9 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { private void ensureNodeTableIsUpdated() { try { // Example: nodeTable.ensureColumnExists("write_rate", "float"); + // TODO(mpolden): Remove after January 2024 + nodeTable.ensureColumnExists("gpu_util", "float"); + nodeTable.ensureColumnExists("gpu_mem_total_util", "float"); } catch (Exception e) { nodeTable.repair(e); } @@ -262,7 +267,9 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { try { issue("create table " + nodeTable.name + " (hostname string, at timestamp, cpu_util float, mem_total_util float, disk_util float," + - " application_generation long, inService boolean, stable boolean, queries_rate float)" + + " application_generation long, inService boolean, stable boolean, queries_rate float," + + " gpu_util float, gpu_mem_total_util float" + + " )" + " timestamp(at)" + "PARTITION BY DAY;", newContext()); @@ -311,7 +318,9 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { new NodeMetricSnapshot(Instant.ofEpochMilli(record.getTimestamp(1) / 1000), new Load(record.getFloat(2), record.getFloat(3), - record.getFloat(4)), + record.getFloat(4), + record.getFloat(9), + record.getFloat(10)), record.getLong(5), record.getBool(6), record.getBool(7), diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java index c4e7d3b9acc..6f325700401 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java @@ -76,6 +76,8 @@ public class ApplicationSerializer { private static final String cpuKey = "cpu"; private static final String memoryKey = "memory"; private static final String diskKey = "disk"; + private static final String gpuKey = "gpu"; + private static final String gpuMemory = "gpuMemory"; private static final String fromKey = "from"; private static final String toKey = "to"; private static final String generationKey = "generation"; @@ -201,12 +203,16 @@ public class ApplicationSerializer { loadObject.setDouble(cpuKey, load.cpu()); loadObject.setDouble(memoryKey, load.memory()); loadObject.setDouble(diskKey, load.disk()); + loadObject.setDouble(gpuKey, load.gpu()); + loadObject.setDouble(gpuMemory, load.gpuMemory()); } private static Load loadFromSlime(Inspector loadObject) { return new Load(loadObject.field(cpuKey).asDouble(), loadObject.field(memoryKey).asDouble(), - loadObject.field(diskKey).asDouble()); + loadObject.field(diskKey).asDouble(), + loadObject.field(gpuKey).asDouble(), + loadObject.field(gpuMemory).asDouble()); } private static void toSlime(Autoscaling.Metrics metrics, Cursor metricsObject) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java index fe6b204ed31..d3b88997059 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java @@ -40,7 +40,6 @@ import com.yahoo.vespa.hosted.provision.applications.Cluster; import com.yahoo.vespa.hosted.provision.autoscale.Autoscaling; import com.yahoo.vespa.hosted.provision.autoscale.Load; import com.yahoo.vespa.hosted.provision.autoscale.MemoryMetricsDb; -import com.yahoo.vespa.hosted.provision.lb.LoadBalancerService; import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.node.Status; @@ -239,8 +238,8 @@ public class MockNodeRepository extends NodeRepository { Optional.of(new ClusterResources(4, 1, new NodeResources(3, 16, 100, 1))), clock().instant(), - new Load(0.1, 0.2, 0.3), - new Load(0.4, 0.5, 0.6), + new Load(0.1, 0.2, 0.3, 0, 0), + new Load(0.4, 0.5, 0.6, 0, 0), new Autoscaling.Metrics(0.7, 0.8, 0.9))); try (Mutex lock = applications().lock(app1Id)) { applications().put(app1.with(cluster1), lock); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java index 0a26678d37e..b2e04ba2233 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java @@ -15,7 +15,6 @@ import com.yahoo.vespa.hosted.provision.autoscale.NodeMetricSnapshot; import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester; import org.junit.Test; -import java.time.Duration; import java.util.List; import static org.junit.Assert.assertEquals; @@ -99,7 +98,7 @@ public class NodeRepoStatsTest { else { loadFactor = loadApp3; } - var snapshot = new NodeMetricSnapshot(now, new Load(1.0, 0.9, 0.8).multiply(loadFactor), 1, true, true, 1.0 ); + var snapshot = new NodeMetricSnapshot(now, new Load(1.0, 0.9, 0.8, 0, 0).multiply(loadFactor), 1, true, true, 1.0 ); tester.nodeRepository().metricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(), snapshot))); } @@ -108,8 +107,8 @@ public class NodeRepoStatsTest { assertEquals(26, stats.totalCost(), delta); assertEquals(8.319999999999999, stats.totalAllocatedCost(), delta); - assertLoad(new Load(0.6180,0.5562,0.4944), stats.load()); - assertLoad(new Load(0.4682,0.4214,0.3745), stats.activeLoad()); + assertLoad(new Load(0.6180,0.5562,0.4944, 0, 0), stats.load()); + assertLoad(new Load(0.4682,0.4214,0.3745, 0, 0), stats.activeLoad()); var app1Stats = stats.applicationStats().get(0); var app2Stats = stats.applicationStats().get(2); @@ -119,25 +118,27 @@ public class NodeRepoStatsTest { assertEquals(3.6400, app1Stats.cost(), delta); assertEquals(0.8676, app1Stats.utilizedCost(), delta); assertEquals(2.7724, app1Stats.unutilizedCost(), delta); - assertLoad(new Load(0.2571, 0.2314, 0.2057), app1Stats.load()); + assertLoad(new Load(0.2571, 0.2314, 0.2057, 0, 0), app1Stats.load()); assertEquals(app2, app2Stats.id()); assertEquals(2.0799, app2Stats.cost(), delta); assertEquals(0.7712, app2Stats.utilizedCost(), delta); assertEquals(1.3087, app2Stats.unutilizedCost(), delta); - assertLoad(new Load(.40, 0.36, 0.32), app2Stats.load()); + assertLoad(new Load(.40, 0.36, 0.32, 0, 0), app2Stats.load()); assertEquals(app3, app3Stats.id()); assertEquals(2.6000, app3Stats.cost(), delta); assertEquals(1.2049, app3Stats.utilizedCost(), delta); assertEquals(1.3950, app3Stats.unutilizedCost(), delta); - assertLoad(new Load(0.5, 0.45, 0.40), app3Stats.load()); + assertLoad(new Load(0.5, 0.45, 0.40, 0, 0), app3Stats.load()); } private static void assertLoad(Load expected, Load actual) { - assertEquals("cpu", expected.cpu(), actual.cpu(), delta); - assertEquals("memory", expected.memory(), actual.memory(), delta); - assertEquals("disk", expected.disk(), actual.disk(), delta); + assertEquals("cpu", expected.cpu(), actual.cpu(), delta); + assertEquals("memory", expected.memory(), actual.memory(), delta); + assertEquals("disk", expected.disk(), actual.disk(), delta); + assertEquals("gpu", expected.gpu(), actual.gpu(), delta); + assertEquals("gpuMemory", expected.gpuMemory(), actual.gpuMemory(), delta); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java index d4d34ab66e5..4236f7ac968 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java @@ -44,7 +44,7 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max)) .build(); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12), 1, true, true, 100); + fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12, 0, 0), 1, true, true, 100); var result = fixture.autoscale(); assertTrue(result.resources().isEmpty()); assertEquals(Autoscaling.Status.insufficient, result.status()); @@ -63,13 +63,13 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max)) .build(); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12), 1, true, true, 100); + fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12, 0, 0), 1, true, true, 100); var result = fixture.autoscale(); assertTrue(result.resources().isEmpty()); assertEquals(Autoscaling.Status.insufficient, result.status()); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.08f, 0.17, 0.12), 1, true, true, 100); + fixture.loader().applyLoad(new Load(0.08f, 0.17, 0.12, 0, 0), 1, true, true, 100); fixture.tester().assertResources("Scaling down", 8, 1, 16, 32, 200, fixture.autoscale()); @@ -128,8 +128,8 @@ public class AutoscalingTest { @Test public void test_autoscaling_up_is_fast() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); - fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1), 3); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 1); + fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1, 0, 0), 3); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 1); fixture.tester().assertResources("Scaling up since resource usage is too high", 8, 1, 5.3, 17.0, 75.1, fixture.autoscale()); @@ -148,7 +148,7 @@ public class AutoscalingTest { .build(); fixture.tester().setScalingDuration(fixture.applicationId(), fixture.clusterSpec.id(), Duration.ofMinutes(5)); - fixture.loader().applyLoad(new Load(0.01, 0.38, 0), 5); + fixture.loader().applyLoad(new Load(0.01, 0.38, 0, 0, 0), 5); fixture.tester().assertResources("Scaling down", 2, 1, 4, 8, 50, fixture.autoscale()); @@ -190,7 +190,7 @@ public class AutoscalingTest { public void test_only_autoscaling_up_quickly() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.setScalingDuration(Duration.ofHours(12)); // Fixture sets last completion to be 1 day into the past - fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0), 10); + fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0, 0, 0), 10); fixture.tester().assertResources("Scaling up (only) since resource usage is too high", 5, 1, 11.7, 14.9, 131.5, fixture.autoscale()); @@ -202,7 +202,7 @@ public class AutoscalingTest { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.setScalingDuration(Duration.ofHours(12)); // Fixture sets last completion to be 1 day into the past fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0), 10); + fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0, 0, 0), 10); fixture.tester().assertResources("Scaling cpu and disk up and memory down", 5, 1, 11.7, 4.0, 131.5, fixture.autoscale()); @@ -213,7 +213,7 @@ public class AutoscalingTest { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(false).build(); fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0), 10); + fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0, 0, 0), 10); fixture.tester().assertResources("Scaling cpu and disk up, memory follows", 16, 1, 4, 8.0, 28.3, fixture.autoscale()); @@ -264,7 +264,7 @@ public class AutoscalingTest { .clusterType(ClusterSpec.Type.container) .awsProdSetup(false) .build(); - var duration = fixture.loader().addMeasurements(new Load(0.04, 0.39, 0.01), 20); + var duration = fixture.loader().addMeasurements(new Load(0.04, 0.39, 0.01, 0, 0), 20); fixture.tester().clock().advance(duration.negated()); fixture.loader().zeroTraffic(20, 1); fixture.tester().assertResources("Scaled down", @@ -358,7 +358,7 @@ public class AutoscalingTest { fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester().clock().advance(Duration.ofDays(1)); - fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95), 120); + fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95, 0, 0), 120); fixture.tester().assertResources("Scaling up to limit since resource usage is too high", 6, 1, 2.4, 78.0, 79.0, fixture.autoscale()); @@ -372,7 +372,7 @@ public class AutoscalingTest { // deploy fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.05f, 0.05f, 0.05f), 120); + fixture.loader().applyLoad(new Load(0.05f, 0.05f, 0.05f, 0, 0), 120); fixture.tester().assertResources("Scaling down to limit since resource usage is low", 4, 1, 1.8, 7.4, 23.4, fixture.autoscale()); @@ -395,7 +395,7 @@ public class AutoscalingTest { 2, 1, defaultResources, fixture.nodes().toResources()); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95), 120); + fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95, 0, 0), 120); fixture.tester().assertResources("Scaling up", 5, 1, defaultResources.vcpu(), defaultResources.memoryGb(), defaultResources.diskGb(), @@ -461,7 +461,7 @@ public class AutoscalingTest { .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.01, 0.01, 0.01), 120); + fixture.loader().applyLoad(new Load(0.01, 0.01, 0.01, 0, 0), 120); Autoscaling suggestion = fixture.suggest(); fixture.tester().assertResources("Choosing the remote disk flavor as it has less disk", 2, 1, 3.0, 100.0, 10.0, @@ -498,7 +498,7 @@ public class AutoscalingTest { public void not_using_out_of_service_measurements() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7), 1, false, true, 120); + fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7, 0, 0), 1, false, true, 120); assertTrue("Not scaling up since nodes were measured while cluster was out of service", fixture.autoscale().resources().isEmpty()); } @@ -507,7 +507,7 @@ public class AutoscalingTest { public void not_using_unstable_measurements() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7), 1, true, false, 120); + fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7, 0, 0), 1, true, false, 120); assertTrue("Not scaling up since nodes were measured while cluster was unstable", fixture.autoscale().resources().isEmpty()); } @@ -536,7 +536,7 @@ public class AutoscalingTest { .build(); fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1), 120); + fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1, 0, 0), 120); fixture.tester().assertResources("Suggesting resources where disk is 3x memory (this is a content cluster)", 11, 1, 13.0, 60.0, 179.9, fixture.tester().suggest(fixture.applicationId, fixture.clusterSpec.id(), min, min)); @@ -557,7 +557,7 @@ public class AutoscalingTest { .build(); fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1), 120); + fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1, 0, 0), 120); fixture.tester().assertResources("Suggesting resources where disk is 3x memory (this is a content cluster)", 13, 1, 36.0, 72.0, 900.0, fixture.tester().suggest(fixture.applicationId, fixture.clusterSpec.id(), min, min)); @@ -668,7 +668,7 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max)) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.16, 0.02, 0.5), 120); + fixture.loader().applyLoad(new Load(0.16, 0.02, 0.5, 0, 0), 120); fixture.tester().assertResources("Scaling down memory", 6, 1, 2.1, 4.0, 96.2, fixture.autoscale()); @@ -826,7 +826,7 @@ public class AutoscalingTest { .zone(new Zone(Environment.dev, RegionName.from("us-east"))) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); assertTrue("Not attempting to scale up because policies dictate we'll only get one node", fixture.autoscale().resources().isEmpty()); } @@ -842,7 +842,7 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max, IntRange.of(3, 5), false, true, Optional.empty(), ClusterInfo.empty())) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); assertEquals("Don't autoscale: Autoscaling is disabled in single node clusters", fixture.autoscale().toString()); } @@ -866,7 +866,7 @@ public class AutoscalingTest { .zone(new Zone(Environment.dev, RegionName.from("us-east"))) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); fixture.tester().assertResources("We scale even in dev because resources are 'required'", 3, 1, 1.0, 13.4, 62.5, fixture.autoscale()); @@ -889,7 +889,7 @@ public class AutoscalingTest { .zone(new Zone(Environment.dev, RegionName.from("us-east"))) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); fixture.tester().assertResources("We scale even in dev because resources are required", 3, 1, 1.5, 8, 50, fixture.autoscale()); @@ -927,13 +927,13 @@ public class AutoscalingTest { fixture.currentResources().advertisedResources()); fixture.tester().deploy(fixture.applicationId(), clusterSpec(false), fixture.capacity()); - fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1), 5); + fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1, 0, 0), 5); fixture.tester().assertResources("Exclusive nodes makes no difference here", 2, 1, 4, 8, 100.0, fixture.autoscale()); fixture.tester().deploy(fixture.applicationId(), clusterSpec(true), fixture.capacity()); - fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1), 5); + fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1, 0, 0), 5); fixture.tester().assertResources("Reverts to the initial resources", 2, 1, 4, 8, 100, fixture.currentResources().advertisedResources()); @@ -952,7 +952,7 @@ public class AutoscalingTest { .build(); var initialNodes = fixture.nodes().asList(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.06, 0.52, 0.27), 100); + fixture.loader().applyLoad(new Load(0.06, 0.52, 0.27, 0, 0), 100); var autoscaling = fixture.autoscale(); fixture.tester().assertResources("Scaling down", 7, 1, 2, 15.8, 384.0, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java index 2e953a0f67c..8dc3945223f 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java @@ -49,7 +49,7 @@ public class Loader { var idealLoad = fixture.clusterModel().idealLoad(); NodeList nodes = fixture.nodes(); float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size()); - Load load = new Load(value, idealLoad.memory(), idealLoad.disk()).multiply(oneExtraNodeFactor); + Load load = new Load(value, idealLoad.memory(), idealLoad.disk(), 0, 0).multiply(oneExtraNodeFactor); Instant initialTime = fixture.tester().clock().instant(); for (int i = 0; i < count; i++) { fixture.tester().clock().advance(samplingInterval); @@ -101,7 +101,7 @@ public class Loader { var idealLoad = fixture.clusterModel().idealLoad(); NodeList nodes = fixture.nodes(); float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size()); - Load load = new Load(idealLoad.cpu(), value, idealLoad.disk()).multiply(oneExtraNodeFactor); + Load load = new Load(idealLoad.cpu(), value, idealLoad.disk(), 0, 0).multiply(oneExtraNodeFactor); for (int i = 0; i < count; i++) { fixture.tester().clock().advance(samplingInterval); for (Node node : nodes) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java index 4ec4ecd6d84..a984306b577 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java @@ -99,6 +99,8 @@ public class MetricsV2MetricsFetcherTest { assertEquals("host-3.yahoo.com", values.get(0).getFirst()); assertEquals(0.13, values.get(0).getSecond().load().cpu(), delta); assertEquals(0.9375, values.get(0).getSecond().load().memory(), delta); + assertEquals(0.13, values.get(0).getSecond().load().gpu(), delta); + assertEquals(0.9375, values.get(0).getSecond().load().gpuMemory(), delta); assertFalse("Unstable because buckets are being merged", values.get(0).getSecond().stable()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java index e8d1368de71..71ed5bafc3d 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java @@ -40,7 +40,7 @@ public class NodeMetricsDbTest { Collection> values = new ArrayList<>(); for (int i = 0; i < 40; i++) { values.add(new Pair<>(node0, new NodeMetricSnapshot(clock.instant(), - new Load(0.9, 0.6, 0.6), + new Load(0.9, 0.6, 0.6, 0, 0), 0, true, false, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java index d52ec12d486..96588250674 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java @@ -57,6 +57,8 @@ public class QuestMetricsDbTest { assertEquals(0.1, snapshot.load().cpu(), delta); assertEquals(0.2, snapshot.load().memory(), delta); assertEquals(0.4, snapshot.load().disk(), delta); + assertEquals(0.5, snapshot.load().gpu(), delta); + assertEquals(0.6, snapshot.load().gpuMemory(), delta); assertEquals(1, snapshot.generation(), delta); assertEquals(30, snapshot.queryRate(), delta); @@ -230,7 +232,7 @@ public class QuestMetricsDbTest { for (int i = 1; i <= countPerHost; i++) { for (String host : hosts) timeseries.add(new Pair<>(host, new NodeMetricSnapshot(clock.instant(), - new Load(i * 0.1, i * 0.2, i * 0.4), + new Load(i * 0.1, i * 0.2, i * 0.4, i * 0.5, i * 0.6), i % 100, true, true, @@ -244,7 +246,7 @@ public class QuestMetricsDbTest { Collection> timeseries = new ArrayList<>(); for (int i = 1; i <= countPerHost; i++) { for (String host : hosts) - timeseries.add(new Pair<>(host, new NodeMetricSnapshot(at, new Load(i * 0.1, i * 0.2, i * 0.4), + timeseries.add(new Pair<>(host, new NodeMetricSnapshot(at, new Load(i * 0.1, i * 0.2, i * 0.4, i * 0.5, i * 0.6), i % 100, true, false, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java index e4a712d3898..4f9b2de4da0 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java @@ -77,7 +77,7 @@ public class AutoscalingMaintainerTester { for (Node node : nodes) nodeRepository().metricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(), new NodeMetricSnapshot(clock().instant(), - new Load(cpu, mem, disk), + new Load(cpu, mem, disk, 0, 0), generation, true, true, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java index d4771594569..152f743900b 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java @@ -270,7 +270,7 @@ public class MetricsReporterTest { Optional.empty(), tester.clock().instant(), Load.zero(), - new Load(0.1, 0.2, 0.3), + new Load(0.1, 0.2, 0.3, 0, 0), Autoscaling.Metrics.zero())); tester.nodeRepository().applications().put(application.with(cluster), tester.nodeRepository().applications().lock(applicationId)); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java index 0a78874405d..f8be27300fe 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java @@ -139,7 +139,7 @@ public class ScalingSuggestionsMaintainerTest { for (Node node : nodes) nodeRepository.metricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(), new NodeMetricSnapshot(nodeRepository.clock().instant(), - new Load(cpu, memory, disk), + new Load(cpu, memory, disk, 0, 0), generation, true, true, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java index 7a00c84faf6..918a9043c93 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java @@ -57,8 +57,8 @@ public class ApplicationSerializerTest { Optional.of(new ClusterResources(20, 10, new NodeResources(0.5, 4, 14, 16))), Instant.ofEpochMilli(1234L), - new Load(0.1, 0.2, 0.3), - new Load(0.4, 0.5, 0.6), + new Load(0.1, 0.2, 0.3, 0.4, 0.5), + new Load(0.4, 0.5, 0.6, 0.7, 0.8), new Autoscaling.Metrics(0.7, 0.8, 0.9)), new Autoscaling(Autoscaling.Status.insufficient, "Autoscaling status", -- cgit v1.2.3 From b7ff96ba960a89826bd9fa206b8c97636d9c6c74 Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Thu, 14 Dec 2023 14:15:59 +0100 Subject: Expose GPU load in nodes API --- .../provision/restapi/ApplicationSerializer.java | 2 ++ .../provision/restapi/NodesV2ApiHandler.java | 2 ++ .../provision/restapi/responses/application1.json | 16 +++++++++++---- .../provision/restapi/responses/application2.json | 8 ++++++-- .../hosted/provision/restapi/responses/stats.json | 24 ++++++++++++++++------ 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java index 225eb3e4e8d..89853896104 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java @@ -98,6 +98,8 @@ public class ApplicationSerializer { loadObject.setDouble("cpu", load.cpu()); loadObject.setDouble("memory", load.memory()); loadObject.setDouble("disk", load.disk()); + loadObject.setDouble("gpu", load.gpu()); + loadObject.setDouble("gpuMemory", load.gpuMemory()); } private static void toSlime(Autoscaling.Metrics metrics, Cursor metricsObject) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java index 9080030f026..0b157e8635b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java @@ -502,6 +502,8 @@ public class NodesV2ApiHandler extends ThreadedHttpRequestHandler { object.setDouble("cpu", load.cpu()); object.setDouble("memory", load.memory()); object.setDouble("disk", load.disk()); + object.setDouble("gpu", load.gpu()); + object.setDouble("gpuMemory", load.gpuMemory()); } /** Returns a copy of the given URI with the host and port from the given URI and the path set to the given path */ diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json index 28bde7bd966..7b2cf1dc8e4 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json @@ -63,12 +63,16 @@ "peak" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0 + "disk" : 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "ideal" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0 + "disk" : 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "metrics" : { "queryRate" : 0.0, @@ -96,12 +100,16 @@ "peak" : { "cpu" : 0.1, "memory" : 0.2, - "disk" : 0.3 + "disk" : 0.3, + "gpu": 0.0, + "gpuMemory": 0.0 }, "ideal" : { "cpu" : 0.4, "memory" : 0.5, - "disk" : 0.6 + "disk" : 0.6, + "gpu": 0.0, + "gpuMemory": 0.0 }, "metrics" : { "queryRate" : 0.7, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json index 05a62ff944d..10173089f75 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json @@ -50,12 +50,16 @@ "peak" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0 + "disk" : 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "ideal" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0 + "disk" : 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "metrics" : { "queryRate" : 0.0, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json index 788eb6d359f..b031e0deba0 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json @@ -4,12 +4,16 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "activeLoad": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "applications": [ { @@ -17,7 +21,9 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 @@ -27,7 +33,9 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 @@ -37,7 +45,9 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 @@ -47,7 +57,9 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 -- cgit v1.2.3 From 38aec6891b86a2a2aa7664eab5c73c546a02fd24 Mon Sep 17 00:00:00 2001 From: Morten Tokle Date: Tue, 19 Dec 2023 14:33:17 +0100 Subject: Update abispec --- vespajlib/abi-spec.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vespajlib/abi-spec.json b/vespajlib/abi-spec.json index a97950415e4..10b0478b5b0 100644 --- a/vespajlib/abi-spec.json +++ b/vespajlib/abi-spec.json @@ -3420,7 +3420,8 @@ "public static org.w3c.dom.Element getChild(org.w3c.dom.Element, java.lang.String)", "public static java.util.Optional getChildValue(org.w3c.dom.Element, java.lang.String)", "public static java.lang.String getNodePath(org.w3c.dom.Node, java.lang.String)", - "public static boolean isName(java.lang.CharSequence)" + "public static boolean isName(java.lang.CharSequence)", + "public static javax.xml.transform.TransformerFactory createTransformerFactory()" ], "fields" : [ ] }, -- cgit v1.2.3 From 5348bb4a85e8a1364971f83f81f3ac458631d7f3 Mon Sep 17 00:00:00 2001 From: Geir Storli Date: Tue, 19 Dec 2023 13:41:57 +0000 Subject: Align naming of test and iterator for low-level posting list access. --- searchlib/CMakeLists.txt | 2 +- .../tests/attribute/bitvector/bitvector_test.cpp | 4 +- .../attribute/direct_posting_store/.gitignore | 1 + .../attribute/direct_posting_store/CMakeLists.txt | 9 + .../direct_posting_store_test.cpp | 226 +++++++++++++++++++++ .../attribute/document_weight_iterator/.gitignore | 1 - .../document_weight_iterator/CMakeLists.txt | 9 - .../document_weight_iterator_test.cpp | 226 --------------------- .../attribute_searchable_adapter_test.cpp | 6 +- .../parallel_weak_and/parallel_weak_and_test.cpp | 4 +- .../attribute/attribute_blueprint_factory.cpp | 4 +- .../src/vespa/searchlib/queryeval/CMakeLists.txt | 2 +- .../docid_with_weight_search_iterator.cpp | 3 + .../queryeval/docid_with_weight_search_iterator.h | 60 ++++++ .../queryeval/document_weight_search_iterator.cpp | 3 - .../queryeval/document_weight_search_iterator.h | 55 ----- .../queryeval/wand/parallel_weak_and_search.cpp | 4 +- 17 files changed, 312 insertions(+), 307 deletions(-) create mode 100644 searchlib/src/tests/attribute/direct_posting_store/.gitignore create mode 100644 searchlib/src/tests/attribute/direct_posting_store/CMakeLists.txt create mode 100644 searchlib/src/tests/attribute/direct_posting_store/direct_posting_store_test.cpp delete mode 100644 searchlib/src/tests/attribute/document_weight_iterator/.gitignore delete mode 100644 searchlib/src/tests/attribute/document_weight_iterator/CMakeLists.txt delete mode 100644 searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp create mode 100644 searchlib/src/vespa/searchlib/queryeval/docid_with_weight_search_iterator.cpp create mode 100644 searchlib/src/vespa/searchlib/queryeval/docid_with_weight_search_iterator.h delete mode 100644 searchlib/src/vespa/searchlib/queryeval/document_weight_search_iterator.cpp delete mode 100644 searchlib/src/vespa/searchlib/queryeval/document_weight_search_iterator.h diff --git a/searchlib/CMakeLists.txt b/searchlib/CMakeLists.txt index c9e19b76cef..5628db99171 100644 --- a/searchlib/CMakeLists.txt +++ b/searchlib/CMakeLists.txt @@ -77,7 +77,7 @@ vespa_define_module( src/tests/attribute/compaction src/tests/attribute/dfa_fuzzy_matcher src/tests/attribute/direct_multi_term_blueprint - src/tests/attribute/document_weight_iterator + src/tests/attribute/direct_posting_store src/tests/attribute/enum_attribute_compaction src/tests/attribute/enum_comparator src/tests/attribute/enumeratedsave diff --git a/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp b/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp index 181c0fdf110..f612bdda87f 100644 --- a/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp +++ b/searchlib/src/tests/attribute/bitvector/bitvector_test.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -432,7 +432,7 @@ BitVectorTest::test(BasicType bt, CollectionType ct, const vespalib::string &pre const auto* dww = v->as_docid_with_weight_posting_store(); if (dww != nullptr) { auto lres = dww->lookup(getSearchStr(), dww->get_dictionary_snapshot()); - using DWSI = search::queryeval::DocumentWeightSearchIterator; + using DWSI = search::queryeval::DocidWithWeightSearchIterator; TermFieldMatchData md; auto dwsi = std::make_unique(md, *dww, lres); if (!filter) { diff --git a/searchlib/src/tests/attribute/direct_posting_store/.gitignore b/searchlib/src/tests/attribute/direct_posting_store/.gitignore new file mode 100644 index 00000000000..5516bc721c7 --- /dev/null +++ b/searchlib/src/tests/attribute/direct_posting_store/.gitignore @@ -0,0 +1 @@ +searchlib_direct_posting_store_test_app diff --git a/searchlib/src/tests/attribute/direct_posting_store/CMakeLists.txt b/searchlib/src/tests/attribute/direct_posting_store/CMakeLists.txt new file mode 100644 index 00000000000..0cb45e6b18f --- /dev/null +++ b/searchlib/src/tests/attribute/direct_posting_store/CMakeLists.txt @@ -0,0 +1,9 @@ +# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +vespa_add_executable(searchlib_direct_posting_store_test_app TEST + SOURCES + direct_posting_store_test.cpp + DEPENDS + searchlib + searchlib_test +) +vespa_add_test(NAME searchlib_direct_posting_store_test_app COMMAND searchlib_direct_posting_store_test_app) diff --git a/searchlib/src/tests/attribute/direct_posting_store/direct_posting_store_test.cpp b/searchlib/src/tests/attribute/direct_posting_store/direct_posting_store_test.cpp new file mode 100644 index 00000000000..d6b0ff2a4b6 --- /dev/null +++ b/searchlib/src/tests/attribute/direct_posting_store/direct_posting_store_test.cpp @@ -0,0 +1,226 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +LOG_SETUP("direct_posting_store_test"); + +using namespace search; +using namespace search::attribute; + +AttributeVector::SP make_attribute(BasicType type, CollectionType collection, bool fast_search) { + Config cfg(type, collection); + cfg.setFastSearch(fast_search); + return AttributeFactory::createAttribute("my_attribute", cfg); +} + +void add_docs(AttributeVector::SP attr_ptr, size_t limit = 1000) { + AttributeVector::DocId docid; + for (size_t i = 0; i < limit; ++i) { + attr_ptr->addDoc(docid); + } + attr_ptr->commit(); + ASSERT_EQUAL((limit - 1), docid); +} + +template +void set_doc(ATTR *attr, uint32_t docid, KEY key, int32_t weight) { + attr->clearDoc(docid); + attr->append(docid, key, weight); + attr->commit(); +} + +void populate_long(AttributeVector::SP attr_ptr) { + IntegerAttribute *attr = static_cast(attr_ptr.get()); + set_doc(attr, 1, int64_t(111), 20); + set_doc(attr, 5, int64_t(111), 5); + set_doc(attr, 7, int64_t(111), 10); +} + +void populate_string(AttributeVector::SP attr_ptr) { + StringAttribute *attr = static_cast(attr_ptr.get()); + set_doc(attr, 1, "foo", 20); + set_doc(attr, 5, "foo", 5); + set_doc(attr, 7, "foo", 10); +} + +struct LongFixture { + AttributeVector::SP attr; + const IDocidWithWeightPostingStore *api; + LongFixture() : attr(make_attribute(BasicType::INT64, CollectionType::WSET, true)), + api(attr->as_docid_with_weight_posting_store()) + { + ASSERT_TRUE(api != nullptr); + add_docs(attr); + populate_long(attr); + } +}; + +struct StringFixture { + AttributeVector::SP attr; + const IDocidWithWeightPostingStore *api; + StringFixture() : attr(make_attribute(BasicType::STRING, CollectionType::WSET, true)), + api(attr->as_docid_with_weight_posting_store()) + { + ASSERT_TRUE(api != nullptr); + add_docs(attr); + populate_string(attr); + } +}; + +TEST("require that appropriate attributes support the IDocidWithWeightPostingStore interface") { + EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::WSET, true)->as_docid_with_weight_posting_store() != nullptr); + EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::WSET, true)->as_docid_with_weight_posting_store() != nullptr); +} + +TEST("require that inappropriate attributes do not support the IDocidWithWeightPostingStore interface") { + EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::SINGLE, false)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::ARRAY, false)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::WSET, false)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::SINGLE, true)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::ARRAY, true)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::SINGLE, false)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::ARRAY, false)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::WSET, false)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::SINGLE, true)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::ARRAY, true)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::INT32, CollectionType::WSET, true)->as_docid_with_weight_posting_store() == nullptr); + EXPECT_TRUE(make_attribute(BasicType::DOUBLE, CollectionType::WSET, true)->as_docid_with_weight_posting_store() == nullptr); +} + +void verify_valid_lookup(IDirectPostingStore::LookupResult result) { + EXPECT_TRUE(result.posting_idx.valid()); + EXPECT_EQUAL(3u, result.posting_size); + EXPECT_EQUAL(5, result.min_weight); + EXPECT_EQUAL(20, result.max_weight); +} + +void verify_invalid_lookup(IDirectPostingStore::LookupResult result) { + EXPECT_FALSE(result.posting_idx.valid()); + EXPECT_EQUAL(0u, result.posting_size); + EXPECT_EQUAL(0, result.min_weight); + EXPECT_EQUAL(0, result.max_weight); +} + +TEST_F("require that integer lookup works correctly", LongFixture) { + verify_valid_lookup(f1.api->lookup("111", f1.api->get_dictionary_snapshot())); + verify_invalid_lookup(f1.api->lookup("222", f1.api->get_dictionary_snapshot())); +} + +TEST_F("require string lookup works correctly", StringFixture) { + verify_valid_lookup(f1.api->lookup("foo", f1.api->get_dictionary_snapshot())); + verify_invalid_lookup(f1.api->lookup("bar", f1.api->get_dictionary_snapshot())); +} + +void verify_posting(const IDocidWithWeightPostingStore &api, const char *term) { + auto result = api.lookup(term, api.get_dictionary_snapshot()); + ASSERT_TRUE(result.posting_idx.valid()); + std::vector itr_store; + api.create(result.posting_idx, itr_store); + ASSERT_EQUAL(1u, itr_store.size()); + { + DocidWithWeightIterator &itr = itr_store[0]; + if (itr.valid() && itr.getKey() < 1) { + itr.linearSeek(1); + } + ASSERT_TRUE(itr.valid()); + EXPECT_EQUAL(1u, itr.getKey()); // docid + EXPECT_EQUAL(20, itr.getData()); // weight + itr.linearSeek(2); + ASSERT_TRUE(itr.valid()); + EXPECT_EQUAL(5u, itr.getKey()); // docid + EXPECT_EQUAL(5, itr.getData()); // weight + itr.linearSeek(6); + ASSERT_TRUE(itr.valid()); + EXPECT_EQUAL(7u, itr.getKey()); // docid + EXPECT_EQUAL(10, itr.getData()); // weight + itr.linearSeek(8); + EXPECT_FALSE(itr.valid()); + } +} + +TEST_F("require that integer iterators are created correctly", LongFixture) { + verify_posting(*f1.api, "111"); +} + +TEST_F("require that string iterators are created correctly", StringFixture) { + verify_posting(*f1.api, "foo"); +} + +TEST_F("require that collect_folded works for string", StringFixture) +{ + StringAttribute *attr = static_cast(f1.attr.get()); + set_doc(attr, 2, "bar", 30); + attr->commit(); + set_doc(attr, 3, "FOO", 30); + attr->commit(); + auto dictionary_snapshot = f1.api->get_dictionary_snapshot(); + auto lookup1 = f1.api->lookup("foo", dictionary_snapshot); + std::vector folded; + std::function save_folded = [&folded,attr](vespalib::datastore::EntryRef enum_idx) { folded.emplace_back(attr->getFromEnum(enum_idx.ref())); }; + f1.api->collect_folded(lookup1.enum_idx, dictionary_snapshot, save_folded); + std::vector expected_folded{"FOO", "foo"}; + EXPECT_EQUAL(expected_folded, folded); +} + +TEST_F("require that collect_folded works for integers", LongFixture) +{ + IntegerAttributeTemplate *attr = dynamic_cast *>(f1.attr.get()); + set_doc(attr, 2, int64_t(112), 30); + attr->commit(); + auto dictionary_snapshot = f1.api->get_dictionary_snapshot(); + auto lookup1 = f1.api->lookup("111", dictionary_snapshot); + std::vector folded; + std::function save_folded = [&folded,attr](vespalib::datastore::EntryRef enum_idx) { folded.emplace_back(attr->getFromEnum(enum_idx.ref())); }; + f1.api->collect_folded(lookup1.enum_idx, dictionary_snapshot, save_folded); + std::vector expected_folded{int64_t(111)}; + EXPECT_EQUAL(expected_folded, folded); +} + +class Verifier : public search::test::SearchIteratorVerifier { +public: + Verifier(); + ~Verifier(); + SearchIterator::UP create(bool strict) const override { + (void) strict; + const auto* api = _attr->as_docid_with_weight_posting_store(); + ASSERT_TRUE(api != nullptr); + auto dict_entry = api->lookup("123", api->get_dictionary_snapshot()); + ASSERT_TRUE(dict_entry.posting_idx.valid()); + return std::make_unique(_tfmd, *api, dict_entry); + } +private: + mutable fef::TermFieldMatchData _tfmd; + AttributeVector::SP _attr; +}; + +Verifier::Verifier() + : _attr(make_attribute(BasicType::INT64, CollectionType::WSET, true)) +{ + add_docs(_attr, getDocIdLimit()); + auto docids = getExpectedDocIds(); + IntegerAttribute *int_attr = static_cast(_attr.get()); + for (auto docid: docids) { + set_doc(int_attr, docid, int64_t(123), 1); + } +} +Verifier::~Verifier() {} + +TEST("verify document weight search iterator") { + Verifier verifier; + verifier.verify(); +} + +TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/searchlib/src/tests/attribute/document_weight_iterator/.gitignore b/searchlib/src/tests/attribute/document_weight_iterator/.gitignore deleted file mode 100644 index 08cae9a48df..00000000000 --- a/searchlib/src/tests/attribute/document_weight_iterator/.gitignore +++ /dev/null @@ -1 +0,0 @@ -searchlib_document_weight_iterator_test_app diff --git a/searchlib/src/tests/attribute/document_weight_iterator/CMakeLists.txt b/searchlib/src/tests/attribute/document_weight_iterator/CMakeLists.txt deleted file mode 100644 index 4cb480068e3..00000000000 --- a/searchlib/src/tests/attribute/document_weight_iterator/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -# Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -vespa_add_executable(searchlib_document_weight_iterator_test_app TEST - SOURCES - document_weight_iterator_test.cpp - DEPENDS - searchlib - searchlib_test -) -vespa_add_test(NAME searchlib_document_weight_iterator_test_app COMMAND searchlib_document_weight_iterator_test_app) diff --git a/searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp b/searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp deleted file mode 100644 index 28416d09d6f..00000000000 --- a/searchlib/src/tests/attribute/document_weight_iterator/document_weight_iterator_test.cpp +++ /dev/null @@ -1,226 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -LOG_SETUP("document_weight_iterator_test"); - -using namespace search; -using namespace search::attribute; - -AttributeVector::SP make_attribute(BasicType type, CollectionType collection, bool fast_search) { - Config cfg(type, collection); - cfg.setFastSearch(fast_search); - return AttributeFactory::createAttribute("my_attribute", cfg); -} - -void add_docs(AttributeVector::SP attr_ptr, size_t limit = 1000) { - AttributeVector::DocId docid; - for (size_t i = 0; i < limit; ++i) { - attr_ptr->addDoc(docid); - } - attr_ptr->commit(); - ASSERT_EQUAL((limit - 1), docid); -} - -template -void set_doc(ATTR *attr, uint32_t docid, KEY key, int32_t weight) { - attr->clearDoc(docid); - attr->append(docid, key, weight); - attr->commit(); -} - -void populate_long(AttributeVector::SP attr_ptr) { - IntegerAttribute *attr = static_cast(attr_ptr.get()); - set_doc(attr, 1, int64_t(111), 20); - set_doc(attr, 5, int64_t(111), 5); - set_doc(attr, 7, int64_t(111), 10); -} - -void populate_string(AttributeVector::SP attr_ptr) { - StringAttribute *attr = static_cast(attr_ptr.get()); - set_doc(attr, 1, "foo", 20); - set_doc(attr, 5, "foo", 5); - set_doc(attr, 7, "foo", 10); -} - -struct LongFixture { - AttributeVector::SP attr; - const IDocidWithWeightPostingStore *api; - LongFixture() : attr(make_attribute(BasicType::INT64, CollectionType::WSET, true)), - api(attr->as_docid_with_weight_posting_store()) - { - ASSERT_TRUE(api != nullptr); - add_docs(attr); - populate_long(attr); - } -}; - -struct StringFixture { - AttributeVector::SP attr; - const IDocidWithWeightPostingStore *api; - StringFixture() : attr(make_attribute(BasicType::STRING, CollectionType::WSET, true)), - api(attr->as_docid_with_weight_posting_store()) - { - ASSERT_TRUE(api != nullptr); - add_docs(attr); - populate_string(attr); - } -}; - -TEST("require that appropriate attributes support the document weight attribute interface") { - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::WSET, true)->as_docid_with_weight_posting_store() != nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::WSET, true)->as_docid_with_weight_posting_store() != nullptr); -} - -TEST("require that inappropriate attributes do not support the document weight attribute interface") { - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::SINGLE, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::ARRAY, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::WSET, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::SINGLE, true)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::INT64, CollectionType::ARRAY, true)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::SINGLE, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::ARRAY, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::WSET, false)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::SINGLE, true)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::STRING, CollectionType::ARRAY, true)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::INT32, CollectionType::WSET, true)->as_docid_with_weight_posting_store() == nullptr); - EXPECT_TRUE(make_attribute(BasicType::DOUBLE, CollectionType::WSET, true)->as_docid_with_weight_posting_store() == nullptr); -} - -void verify_valid_lookup(IDirectPostingStore::LookupResult result) { - EXPECT_TRUE(result.posting_idx.valid()); - EXPECT_EQUAL(3u, result.posting_size); - EXPECT_EQUAL(5, result.min_weight); - EXPECT_EQUAL(20, result.max_weight); -} - -void verify_invalid_lookup(IDirectPostingStore::LookupResult result) { - EXPECT_FALSE(result.posting_idx.valid()); - EXPECT_EQUAL(0u, result.posting_size); - EXPECT_EQUAL(0, result.min_weight); - EXPECT_EQUAL(0, result.max_weight); -} - -TEST_F("require that integer lookup works correctly", LongFixture) { - verify_valid_lookup(f1.api->lookup("111", f1.api->get_dictionary_snapshot())); - verify_invalid_lookup(f1.api->lookup("222", f1.api->get_dictionary_snapshot())); -} - -TEST_F("require string lookup works correctly", StringFixture) { - verify_valid_lookup(f1.api->lookup("foo", f1.api->get_dictionary_snapshot())); - verify_invalid_lookup(f1.api->lookup("bar", f1.api->get_dictionary_snapshot())); -} - -void verify_posting(const IDocidWithWeightPostingStore &api, const char *term) { - auto result = api.lookup(term, api.get_dictionary_snapshot()); - ASSERT_TRUE(result.posting_idx.valid()); - std::vector itr_store; - api.create(result.posting_idx, itr_store); - ASSERT_EQUAL(1u, itr_store.size()); - { - DocidWithWeightIterator &itr = itr_store[0]; - if (itr.valid() && itr.getKey() < 1) { - itr.linearSeek(1); - } - ASSERT_TRUE(itr.valid()); - EXPECT_EQUAL(1u, itr.getKey()); // docid - EXPECT_EQUAL(20, itr.getData()); // weight - itr.linearSeek(2); - ASSERT_TRUE(itr.valid()); - EXPECT_EQUAL(5u, itr.getKey()); // docid - EXPECT_EQUAL(5, itr.getData()); // weight - itr.linearSeek(6); - ASSERT_TRUE(itr.valid()); - EXPECT_EQUAL(7u, itr.getKey()); // docid - EXPECT_EQUAL(10, itr.getData()); // weight - itr.linearSeek(8); - EXPECT_FALSE(itr.valid()); - } -} - -TEST_F("require that integer iterators are created correctly", LongFixture) { - verify_posting(*f1.api, "111"); -} - -TEST_F("require that string iterators are created correctly", StringFixture) { - verify_posting(*f1.api, "foo"); -} - -TEST_F("require that collect_folded works for string", StringFixture) -{ - StringAttribute *attr = static_cast(f1.attr.get()); - set_doc(attr, 2, "bar", 30); - attr->commit(); - set_doc(attr, 3, "FOO", 30); - attr->commit(); - auto dictionary_snapshot = f1.api->get_dictionary_snapshot(); - auto lookup1 = f1.api->lookup("foo", dictionary_snapshot); - std::vector folded; - std::function save_folded = [&folded,attr](vespalib::datastore::EntryRef enum_idx) { folded.emplace_back(attr->getFromEnum(enum_idx.ref())); }; - f1.api->collect_folded(lookup1.enum_idx, dictionary_snapshot, save_folded); - std::vector expected_folded{"FOO", "foo"}; - EXPECT_EQUAL(expected_folded, folded); -} - -TEST_F("require that collect_folded works for integers", LongFixture) -{ - IntegerAttributeTemplate *attr = dynamic_cast *>(f1.attr.get()); - set_doc(attr, 2, int64_t(112), 30); - attr->commit(); - auto dictionary_snapshot = f1.api->get_dictionary_snapshot(); - auto lookup1 = f1.api->lookup("111", dictionary_snapshot); - std::vector folded; - std::function save_folded = [&folded,attr](vespalib::datastore::EntryRef enum_idx) { folded.emplace_back(attr->getFromEnum(enum_idx.ref())); }; - f1.api->collect_folded(lookup1.enum_idx, dictionary_snapshot, save_folded); - std::vector expected_folded{int64_t(111)}; - EXPECT_EQUAL(expected_folded, folded); -} - -class Verifier : public search::test::SearchIteratorVerifier { -public: - Verifier(); - ~Verifier(); - SearchIterator::UP create(bool strict) const override { - (void) strict; - const auto* api = _attr->as_docid_with_weight_posting_store(); - ASSERT_TRUE(api != nullptr); - auto dict_entry = api->lookup("123", api->get_dictionary_snapshot()); - ASSERT_TRUE(dict_entry.posting_idx.valid()); - return std::make_unique(_tfmd, *api, dict_entry); - } -private: - mutable fef::TermFieldMatchData _tfmd; - AttributeVector::SP _attr; -}; - -Verifier::Verifier() - : _attr(make_attribute(BasicType::INT64, CollectionType::WSET, true)) -{ - add_docs(_attr, getDocIdLimit()); - auto docids = getExpectedDocIds(); - IntegerAttribute *int_attr = static_cast(_attr.get()); - for (auto docid: docids) { - set_doc(int_attr, docid, int64_t(123), 1); - } -} -Verifier::~Verifier() {} - -TEST("verify document weight search iterator") { - Verifier verifier; - verifier.verify(); -} - -TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp b/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp index 8831bd1ec75..ecc03ac54c5 100644 --- a/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp +++ b/searchlib/src/tests/attribute/searchable/attribute_searchable_adapter_test.cpp @@ -488,11 +488,11 @@ TEST("require that direct attribute iterators work") { EXPECT_TRUE(result.has_minmax); EXPECT_EQUAL(100, result.min_weight); EXPECT_EQUAL(1000, result.max_weight); - EXPECT_TRUE(result.iterator_dump.find("DocumentWeightSearchIterator") != vespalib::string::npos); + EXPECT_TRUE(result.iterator_dump.find("DocidWithWeightSearchIterator") != vespalib::string::npos); } else { EXPECT_EQUAL(num_docs, result.est_hits); EXPECT_FALSE(result.has_minmax); - EXPECT_TRUE(result.iterator_dump.find("DocumentWeightSearchIterator") == vespalib::string::npos); + EXPECT_TRUE(result.iterator_dump.find("DocidWithWeightSearchIterator") == vespalib::string::npos); } ASSERT_EQUAL(3u, result.hits.size()); EXPECT_FALSE(result.est_empty); @@ -513,7 +513,7 @@ TEST("require that single weighted set turns filter on filter fields") { SimpleStringTerm node("foo", "", 0, Weight(1)); Result result = do_search(attribute_manager, node, strict); EXPECT_EQUAL(3u, result.est_hits); - EXPECT_TRUE(result.iterator_dump.find("DocumentWeightSearchIterator") == vespalib::string::npos); + EXPECT_TRUE(result.iterator_dump.find("DocidWithWeightSearchIterator") == vespalib::string::npos); EXPECT_TRUE(result.iterator_dump.find("FilterAttributePostingListIteratorT") != vespalib::string::npos); ASSERT_EQUAL(3u, result.hits.size()); EXPECT_FALSE(result.est_empty); diff --git a/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp b/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp index fa12b453d8c..0e27c77feae 100644 --- a/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp +++ b/searchlib/src/tests/queryeval/parallel_weak_and/parallel_weak_and_test.cpp @@ -1,6 +1,6 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include -#include +#include #include #include #include @@ -661,7 +661,7 @@ SearchIterator::UP create_wand(bool use_dww, assert(childrenMatchData->getNumTermFields() == dict_entries.size()); wand::Terms terms; for (size_t i = 0; i < dict_entries.size(); ++i) { - terms.push_back(wand::Term(new DocumentWeightSearchIterator(*(childrenMatchData->resolveTermField(handles[i])), attr, dict_entries[i]), + terms.push_back(wand::Term(new DocidWithWeightSearchIterator(*(childrenMatchData->resolveTermField(handles[i])), attr, dict_entries[i]), weights[i], dict_entries[i].posting_size, childrenMatchData->resolveTermField(handles[i]))); diff --git a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp index b9adcf3b093..037285fedf0 100644 --- a/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp +++ b/searchlib/src/vespa/searchlib/attribute/attribute_blueprint_factory.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -527,7 +527,7 @@ public: } } if (_attr.has_btree_iterator(_dict_entry.posting_idx)) { - return std::make_unique(*tfmda[0], _attr, _dict_entry); + return std::make_unique(*tfmda[0], _attr, _dict_entry); } else { return _attr.make_bitvector_iterator(_dict_entry.posting_idx, get_docid_limit(), *tfmda[0], strict); } diff --git a/searchlib/src/vespa/searchlib/queryeval/CMakeLists.txt b/searchlib/src/vespa/searchlib/queryeval/CMakeLists.txt index 5e6d31d3761..51fe2d12637 100644 --- a/searchlib/src/vespa/searchlib/queryeval/CMakeLists.txt +++ b/searchlib/src/vespa/searchlib/queryeval/CMakeLists.txt @@ -7,7 +7,7 @@ vespa_add_library(searchlib_queryeval OBJECT booleanmatchiteratorwrapper.cpp children_iterators.cpp create_blueprint_visitor_helper.cpp - document_weight_search_iterator.cpp + docid_with_weight_search_iterator.cpp dot_product_blueprint.cpp dot_product_search.cpp elementiterator.cpp diff --git a/searchlib/src/vespa/searchlib/queryeval/docid_with_weight_search_iterator.cpp b/searchlib/src/vespa/searchlib/queryeval/docid_with_weight_search_iterator.cpp new file mode 100644 index 00000000000..85bd751df27 --- /dev/null +++ b/searchlib/src/vespa/searchlib/queryeval/docid_with_weight_search_iterator.cpp @@ -0,0 +1,3 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#include "docid_with_weight_search_iterator.h" diff --git a/searchlib/src/vespa/searchlib/queryeval/docid_with_weight_search_iterator.h b/searchlib/src/vespa/searchlib/queryeval/docid_with_weight_search_iterator.h new file mode 100644 index 00000000000..8201c6a78b8 --- /dev/null +++ b/searchlib/src/vespa/searchlib/queryeval/docid_with_weight_search_iterator.h @@ -0,0 +1,60 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. + +#pragma once + +#include "searchiterator.h" +#include +#include + +namespace search::queryeval { + +/** + * SearchIterator implementation over a low-level posting list with {docid, weight} tuples. + * + * This is used by the parallel weak AND search iterator. + */ +class DocidWithWeightSearchIterator : public SearchIterator +{ +private: + fef::TermFieldMatchData &_tfmd; + fef::TermFieldMatchDataPosition * _matchPosition; + DocidWithWeightIterator _iterator; + queryeval::MinMaxPostingInfo _postingInfo; + +public: + DocidWithWeightSearchIterator(fef::TermFieldMatchData &tfmd, + const IDocidWithWeightPostingStore &attr, + IDirectPostingStore::LookupResult dict_entry) + : _tfmd(tfmd), + _matchPosition(_tfmd.populate_fixed()), + _iterator(attr.create(dict_entry.posting_idx)), + _postingInfo(queryeval::MinMaxPostingInfo(dict_entry.min_weight, dict_entry.max_weight)) + { } + void initRange(uint32_t begin, uint32_t end) override { + SearchIterator::initRange(begin, end); + _iterator.lower_bound(begin); + updateDocId(); + } + void updateDocId() { + if (_iterator.valid()) { + setDocId(_iterator.getKey()); + } else { + setAtEnd(); + } + } + + void doSeek(uint32_t docId) override { + _iterator.linearSeek(docId); + updateDocId(); + } + + void doUnpack(uint32_t docId) override { + _tfmd.resetOnlyDocId(docId); + _matchPosition->setElementWeight(_iterator.getData()); + } + + const queryeval::PostingInfo *getPostingInfo() const override { return &_postingInfo; } + Trinary is_strict() const override { return Trinary::True; } +}; + +} diff --git a/searchlib/src/vespa/searchlib/queryeval/document_weight_search_iterator.cpp b/searchlib/src/vespa/searchlib/queryeval/document_weight_search_iterator.cpp deleted file mode 100644 index 6b0bd3ec7fc..00000000000 --- a/searchlib/src/vespa/searchlib/queryeval/document_weight_search_iterator.cpp +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#include "document_weight_search_iterator.h" diff --git a/searchlib/src/vespa/searchlib/queryeval/document_weight_search_iterator.h b/searchlib/src/vespa/searchlib/queryeval/document_weight_search_iterator.h deleted file mode 100644 index 448f1c8f2b4..00000000000 --- a/searchlib/src/vespa/searchlib/queryeval/document_weight_search_iterator.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - -#pragma once - -#include "searchiterator.h" -#include -#include - -namespace search::queryeval { - -class DocumentWeightSearchIterator : public SearchIterator -{ -private: - fef::TermFieldMatchData &_tfmd; - fef::TermFieldMatchDataPosition * _matchPosition; - DocidWithWeightIterator _iterator; - queryeval::MinMaxPostingInfo _postingInfo; - -public: - DocumentWeightSearchIterator(fef::TermFieldMatchData &tfmd, - const IDocidWithWeightPostingStore &attr, - IDirectPostingStore::LookupResult dict_entry) - : _tfmd(tfmd), - _matchPosition(_tfmd.populate_fixed()), - _iterator(attr.create(dict_entry.posting_idx)), - _postingInfo(queryeval::MinMaxPostingInfo(dict_entry.min_weight, dict_entry.max_weight)) - { } - void initRange(uint32_t begin, uint32_t end) override { - SearchIterator::initRange(begin, end); - _iterator.lower_bound(begin); - updateDocId(); - } - void updateDocId() { - if (_iterator.valid()) { - setDocId(_iterator.getKey()); - } else { - setAtEnd(); - } - } - - void doSeek(uint32_t docId) override { - _iterator.linearSeek(docId); - updateDocId(); - } - - void doUnpack(uint32_t docId) override { - _tfmd.resetOnlyDocId(docId); - _matchPosition->setElementWeight(_iterator.getData()); - } - - const queryeval::PostingInfo *getPostingInfo() const override { return &_postingInfo; } - Trinary is_strict() const override { return Trinary::True; } -}; - -} diff --git a/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_search.cpp b/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_search.cpp index 828ca4be08d..f3028f5159a 100644 --- a/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_search.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/wand/parallel_weak_and_search.cpp @@ -1,7 +1,7 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "parallel_weak_and_search.h" -#include +#include #include #include #include @@ -243,7 +243,7 @@ ParallelWeakAndSearch::create(search::fef::TermFieldMatchData &tfmd, assert(childrenMatchData->getNumTermFields() == dict_entries.size()); wand::Terms terms; for (size_t i = 0; i < dict_entries.size(); ++i) { - terms.push_back(wand::Term(new DocumentWeightSearchIterator(*(childrenMatchData->resolveTermField(handles[i])), attr, dict_entries[i]), + terms.push_back(wand::Term(new DocidWithWeightSearchIterator(*(childrenMatchData->resolveTermField(handles[i])), attr, dict_entries[i]), weights[i], dict_entries[i].posting_size, childrenMatchData->resolveTermField(handles[i]))); -- cgit v1.2.3 From 26bc03248dd4340b1d9e62317fd7f42c8a91e48b Mon Sep 17 00:00:00 2001 From: Harald Musum Date: Tue, 19 Dec 2023 15:13:06 +0100 Subject: GC dead code --- .../yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java index b2db5977109..c78ad2b0da6 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java @@ -91,10 +91,7 @@ public class CapacityPolicies { } public NodeResources specifyFully(NodeResources resources, ClusterSpec clusterSpec, ApplicationId applicationId) { - NodeResources amended = resources.withUnspecifiedFieldsFrom(defaultResources(clusterSpec, applicationId).with(DiskSpeed.any)); - // TODO jonmv: remove this after all apps are 8.248.8 or above; architecture for admin nodes was not picked up before this. - if (clusterSpec.vespaVersion().isBefore(Version.fromString("8.248.8"))) amended = amended.with(resources.architecture()); - return amended; + return resources.withUnspecifiedFieldsFrom(defaultResources(clusterSpec, applicationId).with(DiskSpeed.any)); } private NodeResources defaultResources(ClusterSpec clusterSpec, ApplicationId applicationId) { -- cgit v1.2.3 From 10a8162be6cae6a30be24ac7c8ca2e5adc62f4f7 Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Fri, 15 Dec 2023 16:46:06 +0100 Subject: Precompute 1024 bits, 128 bytes, 2 cachelines for intel, and 1 for arm64. --- searchlib/src/vespa/searchlib/common/bitvector.cpp | 2 +- .../searchlib/queryeval/multibitvectoriterator.cpp | 9 ++++----- .../searchlib/queryeval/multibitvectoriterator.h | 2 +- vespalib/src/vespa/vespalib/hwaccelrated/avx2.cpp | 8 ++++---- vespalib/src/vespa/vespalib/hwaccelrated/avx2.h | 4 ++-- vespalib/src/vespa/vespalib/hwaccelrated/avx512.cpp | 8 ++++---- vespalib/src/vespa/vespalib/hwaccelrated/avx512.h | 4 ++-- vespalib/src/vespa/vespalib/hwaccelrated/generic.cpp | 8 ++++---- vespalib/src/vespa/vespalib/hwaccelrated/generic.h | 4 ++-- .../src/vespa/vespalib/hwaccelrated/iaccelrated.cpp | 20 ++++++++++---------- .../src/vespa/vespalib/hwaccelrated/iaccelrated.h | 8 ++++---- .../vespa/vespalib/hwaccelrated/private_helpers.hpp | 4 ++-- 12 files changed, 40 insertions(+), 41 deletions(-) diff --git a/searchlib/src/vespa/searchlib/common/bitvector.cpp b/searchlib/src/vespa/searchlib/common/bitvector.cpp index b79703a8e5c..a75066a67a9 100644 --- a/searchlib/src/vespa/searchlib/common/bitvector.cpp +++ b/searchlib/src/vespa/searchlib/common/bitvector.cpp @@ -39,7 +39,7 @@ BitVector::allocatePaddedAndAligned(Index start, Index end, Index capacity, cons { assert(capacity >= end); uint32_t words = numActiveWords(start, capacity); - words += (-words & 15); // Pad to 64 byte alignment + words += (-words & 15); // Pad to 128 byte alignment const size_t sz(words * sizeof(Word)); Alloc alloc = (init_alloc != nullptr) ? init_alloc->create(sz) : Alloc::alloc(sz, MMAP_LIMIT); assert(alloc.size()/sizeof(Word) >= words); diff --git a/searchlib/src/vespa/searchlib/queryeval/multibitvectoriterator.cpp b/searchlib/src/vespa/searchlib/queryeval/multibitvectoriterator.cpp index 66f505581c7..e90156868fb 100644 --- a/searchlib/src/vespa/searchlib/queryeval/multibitvectoriterator.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/multibitvectoriterator.cpp @@ -4,7 +4,6 @@ #include "andsearch.h" #include "andnotsearch.h" #include "sourceblendersearch.h" -#include #include namespace search::queryeval { @@ -18,7 +17,7 @@ namespace { struct And { using Word = BitWord::Word; void operator () (const IAccelrated & accel, size_t offset, const std::vector & src, void *dest) noexcept { - accel.and64(offset, src, dest); + accel.and128(offset, src, dest); } static constexpr bool isAnd() noexcept { return true; } }; @@ -26,7 +25,7 @@ struct And { struct Or { using Word = BitWord::Word; void operator () (const IAccelrated & accel, size_t offset, const std::vector & src, void *dest) noexcept { - accel.or64(offset, src, dest); + accel.or128(offset, src, dest); } static constexpr bool isAnd() noexcept { return false; } }; @@ -56,8 +55,8 @@ MultiBitVector::MultiBitVector(size_t reserved) _accel(IAccelrated::getAccelerator()), _lastWords() { - static_assert(sizeof(_lastWords) == 64, "Lastwords should have 64 byte size"); - static_assert(NumWordsInBatch == 8, "Batch size should be 8 words."); + static_assert(sizeof(_lastWords) == 128, "Lastwords should have 128 byte size"); + static_assert(NumWordsInBatch == 16, "Batch size should be 16 words."); memset(_lastWords, 0, sizeof(_lastWords)); } diff --git a/searchlib/src/vespa/searchlib/queryeval/multibitvectoriterator.h b/searchlib/src/vespa/searchlib/queryeval/multibitvectoriterator.h index 0d9e2c4f25f..0ecf9d85b92 100644 --- a/searchlib/src/vespa/searchlib/queryeval/multibitvectoriterator.h +++ b/searchlib/src/vespa/searchlib/queryeval/multibitvectoriterator.h @@ -50,7 +50,7 @@ private: Update _update; const IAccelrated & _accel; - alignas(64) Word _lastWords[8]; + alignas(64) Word _lastWords[16]; static constexpr size_t NumWordsInBatch = sizeof(_lastWords) / sizeof(Word); }; diff --git a/vespalib/src/vespa/vespalib/hwaccelrated/avx2.cpp b/vespalib/src/vespa/vespalib/hwaccelrated/avx2.cpp index bbba4109fc2..66441b3c08b 100644 --- a/vespalib/src/vespa/vespalib/hwaccelrated/avx2.cpp +++ b/vespalib/src/vespa/vespalib/hwaccelrated/avx2.cpp @@ -26,13 +26,13 @@ Avx2Accelrator::squaredEuclideanDistance(const double * a, const double * b, siz } void -Avx2Accelrator::and64(size_t offset, const std::vector> &src, void *dest) const noexcept { - helper::andChunks<32u, 2u>(offset, src, dest); +Avx2Accelrator::and128(size_t offset, const std::vector> &src, void *dest) const noexcept { + helper::andChunks<32u, 4u>(offset, src, dest); } void -Avx2Accelrator::or64(size_t offset, const std::vector> &src, void *dest) const noexcept { - helper::orChunks<32u, 2u>(offset, src, dest); +Avx2Accelrator::or128(size_t offset, const std::vector> &src, void *dest) const noexcept { + helper::orChunks<32u, 4u>(offset, src, dest); } } diff --git a/vespalib/src/vespa/vespalib/hwaccelrated/avx2.h b/vespalib/src/vespa/vespalib/hwaccelrated/avx2.h index 934d815d67b..af46035666c 100644 --- a/vespalib/src/vespa/vespalib/hwaccelrated/avx2.h +++ b/vespalib/src/vespa/vespalib/hwaccelrated/avx2.h @@ -16,8 +16,8 @@ public: double squaredEuclideanDistance(const int8_t * a, const int8_t * b, size_t sz) const noexcept override; double squaredEuclideanDistance(const float * a, const float * b, size_t sz) const noexcept override; double squaredEuclideanDistance(const double * a, const double * b, size_t sz) const noexcept override; - void and64(size_t offset, const std::vector> &src, void *dest) const noexcept override; - void or64(size_t offset, const std::vector> &src, void *dest) const noexcept override; + void and128(size_t offset, const std::vector> &src, void *dest) const noexcept override; + void or128(size_t offset, const std::vector> &src, void *dest) const noexcept override; }; } diff --git a/vespalib/src/vespa/vespalib/hwaccelrated/avx512.cpp b/vespalib/src/vespa/vespalib/hwaccelrated/avx512.cpp index 035f33cb25e..5f408c05fef 100644 --- a/vespalib/src/vespa/vespalib/hwaccelrated/avx512.cpp +++ b/vespalib/src/vespa/vespalib/hwaccelrated/avx512.cpp @@ -36,13 +36,13 @@ Avx512Accelrator::squaredEuclideanDistance(const double * a, const double * b, s } void -Avx512Accelrator::and64(size_t offset, const std::vector> &src, void *dest) const noexcept { - helper::andChunks<64, 1>(offset, src, dest); +Avx512Accelrator::and128(size_t offset, const std::vector> &src, void *dest) const noexcept { + helper::andChunks<64, 2>(offset, src, dest); } void -Avx512Accelrator::or64(size_t offset, const std::vector> &src, void *dest) const noexcept { - helper::orChunks<64, 1>(offset, src, dest); +Avx512Accelrator::or128(size_t offset, const std::vector> &src, void *dest) const noexcept { + helper::orChunks<64, 2>(offset, src, dest); } } diff --git a/vespalib/src/vespa/vespalib/hwaccelrated/avx512.h b/vespalib/src/vespa/vespalib/hwaccelrated/avx512.h index 38eab0a2549..a86a2787d5a 100644 --- a/vespalib/src/vespa/vespalib/hwaccelrated/avx512.h +++ b/vespalib/src/vespa/vespalib/hwaccelrated/avx512.h @@ -18,8 +18,8 @@ public: double squaredEuclideanDistance(const int8_t * a, const int8_t * b, size_t sz) const noexcept override; double squaredEuclideanDistance(const float * a, const float * b, size_t sz) const noexcept override; double squaredEuclideanDistance(const double * a, const double * b, size_t sz) const noexcept override; - void and64(size_t offset, const std::vector> &src, void *dest) const noexcept override; - void or64(size_t offset, const std::vector> &src, void *dest) const noexcept override; + void and128(size_t offset, const std::vector> &src, void *dest) const noexcept override; + void or128(size_t offset, const std::vector> &src, void *dest) const noexcept override; }; } diff --git a/vespalib/src/vespa/vespalib/hwaccelrated/generic.cpp b/vespalib/src/vespa/vespalib/hwaccelrated/generic.cpp index a8e5535cc21..f0112aaddf7 100644 --- a/vespalib/src/vespa/vespalib/hwaccelrated/generic.cpp +++ b/vespalib/src/vespa/vespalib/hwaccelrated/generic.cpp @@ -173,13 +173,13 @@ GenericAccelrator::squaredEuclideanDistance(const double * a, const double * b, } void -GenericAccelrator::and64(size_t offset, const std::vector> &src, void *dest) const noexcept { - helper::andChunks<16, 4>(offset, src, dest); +GenericAccelrator::and128(size_t offset, const std::vector> &src, void *dest) const noexcept { + helper::andChunks<16, 8>(offset, src, dest); } void -GenericAccelrator::or64(size_t offset, const std::vector> &src, void *dest) const noexcept { - helper::orChunks<16,4>(offset, src, dest); +GenericAccelrator::or128(size_t offset, const std::vector> &src, void *dest) const noexcept { + helper::orChunks<16, 8>(offset, src, dest); } } diff --git a/vespalib/src/vespa/vespalib/hwaccelrated/generic.h b/vespalib/src/vespa/vespalib/hwaccelrated/generic.h index 16c8bab71da..ba986656635 100644 --- a/vespalib/src/vespa/vespalib/hwaccelrated/generic.h +++ b/vespalib/src/vespa/vespalib/hwaccelrated/generic.h @@ -26,8 +26,8 @@ public: double squaredEuclideanDistance(const int8_t * a, const int8_t * b, size_t sz) const noexcept override; double squaredEuclideanDistance(const float * a, const float * b, size_t sz) const noexcept override; double squaredEuclideanDistance(const double * a, const double * b, size_t sz) const noexcept override; - void and64(size_t offset, const std::vector> &src, void *dest) const noexcept override; - void or64(size_t offset, const std::vector> &src, void *dest) const noexcept override; + void and128(size_t offset, const std::vector> &src, void *dest) const noexcept override; + void or128(size_t offset, const std::vector> &src, void *dest) const noexcept override; }; } diff --git a/vespalib/src/vespa/vespalib/hwaccelrated/iaccelrated.cpp b/vespalib/src/vespa/vespalib/hwaccelrated/iaccelrated.cpp index d707553b504..a02e9545765 100644 --- a/vespalib/src/vespa/vespalib/hwaccelrated/iaccelrated.cpp +++ b/vespalib/src/vespa/vespalib/hwaccelrated/iaccelrated.cpp @@ -153,11 +153,11 @@ verifyOr64(const IAccelrated & accel, const std::vector> & simpleOrWith(expected, optionallyInvert(vRefs[j].second, vectors[j])); } - uint64_t dest[8] __attribute((aligned(64))); - accel.or64(offset*sizeof(uint64_t), vRefs, dest); + uint64_t dest[16] __attribute((aligned(64))); + accel.or128(offset * sizeof(uint64_t), vRefs, dest); int diff = memcmp(&expected[offset], dest, sizeof(dest)); if (diff != 0) { - LOG_ABORT("Accelerator fails to compute correct 64 bytes OR"); + LOG_ABORT("Accelerator fails to compute correct 128 bytes OR"); } } @@ -174,11 +174,11 @@ verifyAnd64(const IAccelrated & accel, const std::vector> simpleAndWith(expected, optionallyInvert(vRefs[j].second, vectors[j])); } - uint64_t dest[8] __attribute((aligned(64))); - accel.and64(offset*sizeof(uint64_t), vRefs, dest); + uint64_t dest[16] __attribute((aligned(64))); + accel.and128(offset * sizeof(uint64_t), vRefs, dest); int diff = memcmp(&expected[offset], dest, sizeof(dest)); if (diff != 0) { - LOG_ABORT("Accelerator fails to compute correct 64 bytes AND"); + LOG_ABORT("Accelerator fails to compute correct 128 bytes AND"); } } @@ -186,9 +186,9 @@ void verifyOr64(const IAccelrated & accel) { std::vector> vectors(3) ; for (auto & v : vectors) { - fill(v, 16); + fill(v, 32); } - for (size_t offset = 0; offset < 8; offset++) { + for (size_t offset = 0; offset < 16; offset++) { for (size_t i = 1; i < vectors.size(); i++) { verifyOr64(accel, vectors, offset, i, false); verifyOr64(accel, vectors, offset, i, true); @@ -200,9 +200,9 @@ void verifyAnd64(const IAccelrated & accel) { std::vector> vectors(3); for (auto & v : vectors) { - fill(v, 16); + fill(v, 32); } - for (size_t offset = 0; offset < 8; offset++) { + for (size_t offset = 0; offset < 16; offset++) { for (size_t i = 1; i < vectors.size(); i++) { verifyAnd64(accel, vectors, offset, i, false); verifyAnd64(accel, vectors, offset, i, true); diff --git a/vespalib/src/vespa/vespalib/hwaccelrated/iaccelrated.h b/vespalib/src/vespa/vespalib/hwaccelrated/iaccelrated.h index 806e77caced..f070f206b7e 100644 --- a/vespalib/src/vespa/vespalib/hwaccelrated/iaccelrated.h +++ b/vespalib/src/vespa/vespalib/hwaccelrated/iaccelrated.h @@ -31,10 +31,10 @@ public: virtual double squaredEuclideanDistance(const int8_t * a, const int8_t * b, size_t sz) const noexcept = 0; virtual double squaredEuclideanDistance(const float * a, const float * b, size_t sz) const noexcept = 0; virtual double squaredEuclideanDistance(const double * a, const double * b, size_t sz) const noexcept = 0; - // AND 64 bytes from multiple, optionally inverted sources - virtual void and64(size_t offset, const std::vector> &src, void *dest) const noexcept = 0; - // OR 64 bytes from multiple, optionally inverted sources - virtual void or64(size_t offset, const std::vector> &src, void *dest) const noexcept = 0; + // AND 128 bytes from multiple, optionally inverted sources + virtual void and128(size_t offset, const std::vector> &src, void *dest) const noexcept = 0; + // OR 128 bytes from multiple, optionally inverted sources + virtual void or128(size_t offset, const std::vector> &src, void *dest) const noexcept = 0; static const IAccelrated & getAccelerator() __attribute__((noinline)); }; diff --git a/vespalib/src/vespa/vespalib/hwaccelrated/private_helpers.hpp b/vespalib/src/vespa/vespalib/hwaccelrated/private_helpers.hpp index c884f0d7bb9..6731b449462 100644 --- a/vespalib/src/vespa/vespalib/hwaccelrated/private_helpers.hpp +++ b/vespalib/src/vespa/vespalib/hwaccelrated/private_helpers.hpp @@ -43,7 +43,7 @@ void andChunks(size_t offset, const std::vector> & src, void * dest) { typedef uint64_t Chunk __attribute__ ((vector_size (ChunkSize))); static_assert(sizeof(Chunk) == ChunkSize, "sizeof(Chunk) == ChunkSize"); - static_assert(ChunkSize*Chunks == 64, "ChunkSize*Chunks == 64"); + static_assert(ChunkSize*Chunks == 128, "ChunkSize*Chunks == 128"); Chunk * chunk = static_cast(dest); const Chunk * tmp = cast(src[0].first, offset); for (size_t n=0; n < Chunks; n++) { @@ -62,7 +62,7 @@ void orChunks(size_t offset, const std::vector> & src, void * dest) { typedef uint64_t Chunk __attribute__ ((vector_size (ChunkSize))); static_assert(sizeof(Chunk) == ChunkSize, "sizeof(Chunk) == ChunkSize"); - static_assert(ChunkSize*Chunks == 64, "ChunkSize*Chunks == 64"); + static_assert(ChunkSize*Chunks == 128, "ChunkSize*Chunks == 128"); Chunk * chunk = static_cast(dest); const Chunk * tmp = cast(src[0].first, offset); for (size_t n=0; n < Chunks; n++) { -- cgit v1.2.3 From 70b5538aa7f57782d89e52d4dcb9de755a06b666 Mon Sep 17 00:00:00 2001 From: Harald Musum Date: Tue, 19 Dec 2023 22:08:56 +0100 Subject: Revert "Expose GPU load in nodes API" --- .../hosted/provision/autoscale/ClusterModel.java | 12 ++--- .../autoscale/ClusterNodesTimeseries.java | 3 +- .../vespa/hosted/provision/autoscale/Load.java | 63 +++++++++++----------- .../provision/autoscale/MetricsResponse.java | 45 ++++------------ .../hosted/provision/autoscale/QuestMetricsDb.java | 13 +---- .../persistence/ApplicationSerializer.java | 8 +-- .../provision/restapi/ApplicationSerializer.java | 2 - .../provision/restapi/NodesV2ApiHandler.java | 2 - .../provision/testutils/MockNodeRepository.java | 5 +- .../vespa/hosted/provision/NodeRepoStatsTest.java | 21 ++++---- .../provision/autoscale/AutoscalingTest.java | 52 +++++++++--------- .../vespa/hosted/provision/autoscale/Loader.java | 4 +- .../autoscale/MetricsV2MetricsFetcherTest.java | 2 - .../provision/autoscale/NodeMetricsDbTest.java | 2 +- .../provision/autoscale/QuestMetricsDbTest.java | 6 +-- .../maintenance/AutoscalingMaintainerTester.java | 2 +- .../provision/maintenance/MetricsReporterTest.java | 2 +- .../ScalingSuggestionsMaintainerTest.java | 2 +- .../persistence/ApplicationSerializerTest.java | 4 +- .../provision/restapi/responses/application1.json | 16 ++---- .../provision/restapi/responses/application2.json | 8 +-- .../hosted/provision/restapi/responses/stats.json | 24 +++------ 22 files changed, 111 insertions(+), 187 deletions(-) diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java index 986ab830283..1e4a11fdea2 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java @@ -233,13 +233,11 @@ public class ClusterModel { double queryCpu = queryCpuPerGroup * groupCount() / groups; double writeCpu = (double)groupSize() / groupSize; return new Load(cpu.queryFraction() * queryCpu + (1 - cpu.queryFraction()) * writeCpu, - (1 - memory.fixedFraction()) * (double) groupSize() / groupSize + memory.fixedFraction() * 1, - (double)groupSize() / groupSize, - 1, - 1); + (1 - memory.fixedFraction()) * (double)groupSize() / groupSize + memory.fixedFraction() * 1, + (double)groupSize() / groupSize); } else { - return new Load((double) nodeCount() / nodes, 1, 1, 1, 1); + return new Load((double)nodeCount() / nodes, 1, 1); } } @@ -248,7 +246,7 @@ public class ClusterModel { * if one of the nodes go down. */ public Load idealLoad() { - var ideal = new Load(cpu.idealLoad(), memory.idealLoad(), disk.idealLoad(), cpu.idealLoad(), memory.idealLoad()).divide(redundancyAdjustment()); + var ideal = new Load(cpu.idealLoad(), memory.idealLoad(), disk.idealLoad()).divide(redundancyAdjustment()); if ( !cluster.bcpGroupInfo().isEmpty() && cluster.bcpGroupInfo().queryRate() > 0) { // Since we have little local information, use information about query cost in other groups Load bcpGroupIdeal = adjustQueryDependentIdealLoadByBcpGroupInfo(ideal); @@ -394,7 +392,7 @@ public class ClusterModel { if (averageQueryRate().isEmpty() || averageQueryRate().getAsDouble() == 0.0) return OptionalDouble.empty(); // TODO: Query rate should generally be sampled at the time where we see the peak resource usage int fanOut = clusterSpec.type().isContainer() ? 1 : groupSize(); - return OptionalDouble.of(peakLoad().cpu() * cpu.queryFraction() * fanOut * nodes.not().retired().first().get().resources().vcpu() + return OptionalDouble.of(peakLoad().cpu() * cpu.queryFraction() * fanOut * nodes.not().retired().first().get().resources().vcpu() / averageQueryRate().getAsDouble() / groupCount()); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java index 6978e269c3d..e1ef21ebd13 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java @@ -67,8 +67,7 @@ public class ClusterNodesTimeseries { * the average of the highest reading for that dimension on each node. */ public Load peakLoad() { - return new Load(peakLoad(Load.Dimension.cpu), peakLoad(Load.Dimension.memory), peakLoad(Load.Dimension.disk), - peakLoad(Load.Dimension.gpu), peakLoad(Load.Dimension.gpuMemory)); + return new Load(peakLoad(Load.Dimension.cpu), peakLoad(Load.Dimension.memory), peakLoad(Load.Dimension.disk)); } private double peakLoad(Load.Dimension dimension) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java index 22c13795d18..799ed621807 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java @@ -3,7 +3,9 @@ package com.yahoo.vespa.hosted.provision.autoscale; import com.yahoo.config.provision.NodeResources; +import java.util.Objects; import java.util.function.DoubleBinaryOperator; +import java.util.function.DoubleFunction; import java.util.function.DoubleUnaryOperator; import java.util.function.Predicate; @@ -12,36 +14,32 @@ import java.util.function.Predicate; * * @author bratseth */ -public record Load(double cpu, double memory, double disk, double gpu, double gpuMemory) { +public class Load { - public enum Dimension { cpu, memory, disk, gpu, gpuMemory } + public enum Dimension { cpu, memory, disk } - public Load(double cpu, double memory, double disk, double gpu, double gpuMemory) { + private final double cpu, memory, disk; + + public Load(double cpu, double memory, double disk) { this.cpu = requireNormalized(cpu, "cpu"); this.memory = requireNormalized(memory, "memory"); this.disk = requireNormalized(disk, "disk"); - this.gpu = requireNormalized(gpu, "gpu"); - this.gpuMemory = requireNormalized(gpuMemory, "gpuMemory"); } public double cpu() { return cpu; } public double memory() { return memory; } public double disk() { return disk; } - public double gpu() { return gpu; } - public double gpuMemory() { return gpuMemory; } - public Load withCpu(double cpu) { return new Load(cpu, memory, disk, gpu, gpuMemory); } - public Load withMemory(double memory) { return new Load(cpu, memory, disk, gpu, gpuMemory); } - public Load withDisk(double disk) { return new Load(cpu, memory, disk, gpu, gpuMemory); } - public Load withGpu(double gpu) { return new Load(cpu, memory, disk, gpu, gpuMemory); } - public Load withGpuMemory(double gpuMemory) { return new Load(cpu, memory, disk, gpu, gpuMemory); } + public Load withCpu(double cpu) { return new Load(cpu, memory, disk); } + public Load withMemory(double memory) { return new Load(cpu, memory, disk); } + public Load withDisk(double disk) { return new Load(cpu, memory, disk); } public Load add(Load other) { return join(other, (a, b) -> a + b); } public Load multiply(NodeResources resources) { - return new Load(cpu * resources.vcpu(), memory * resources.memoryGb(), disk * resources.diskGb(), gpu * resources.gpuResources().count(), gpu * resources.gpuResources().memoryGb()); + return new Load(cpu * resources.vcpu(), memory * resources.memoryGb(), disk * resources.diskGb()); } public Load multiply(double factor) { return map(v -> v * factor); @@ -57,25 +55,21 @@ public record Load(double cpu, double memory, double disk, double gpu, double gp return map(v -> divide(v, divisor)); } public Load divide(NodeResources resources) { - return new Load(divide(cpu, resources.vcpu()), divide(memory, resources.memoryGb()), divide(disk, resources.diskGb()), divide(gpu, resources.gpuResources().count()), divide(gpuMemory, resources.gpuResources().memoryGb())); + return new Load(divide(cpu, resources.vcpu()), divide(memory, resources.memoryGb()), divide(disk, resources.diskGb())); } /** Returns the load where the given function is applied to each dimension of this. */ public Load map(DoubleUnaryOperator f) { return new Load(f.applyAsDouble(cpu), f.applyAsDouble(memory), - f.applyAsDouble(disk), - f.applyAsDouble(gpu), - f.applyAsDouble(gpuMemory)); + f.applyAsDouble(disk)); } /** Returns the load where the given function is applied to each dimension of this and the given load. */ public Load join(Load other, DoubleBinaryOperator f) { return new Load(f.applyAsDouble(this.cpu(), other.cpu()), f.applyAsDouble(this.memory(), other.memory()), - f.applyAsDouble(this.disk(), other.disk()), - f.applyAsDouble(this.gpu(), other.gpu()), - f.applyAsDouble(this.gpuMemory(), other.gpuMemory())); + f.applyAsDouble(this.disk(), other.disk())); } /** Returns true if any dimension matches the predicate. */ @@ -94,8 +88,6 @@ public record Load(double cpu, double memory, double disk, double gpu, double gp case cpu -> cpu(); case memory -> memory(); case disk -> disk(); - case gpu -> gpu(); - case gpuMemory -> gpuMemory(); }; } @@ -103,7 +95,7 @@ public record Load(double cpu, double memory, double disk, double gpu, double gp if (Double.isNaN(value)) throw new IllegalArgumentException(name + " must be a number but is NaN"); if (value < 0) - throw new IllegalArgumentException(name + " must be zero or larger, but is " + value); + throw new IllegalArgumentException(name + " must be zero or lager, but is " + value); return value; } @@ -112,20 +104,29 @@ public record Load(double cpu, double memory, double disk, double gpu, double gp return a / b; } + @Override + public boolean equals(Object o) { + if (o == this) return true; + if ( ! (o instanceof Load other)) return false; + if (other.cpu() != this.cpu()) return false; + if (other.memory() != this.memory()) return false; + if (other.disk() != this.disk()) return false; + return true; + } + + @Override + public int hashCode() { return Objects.hash(cpu, memory, disk); } + @Override public String toString() { - return "load: " + cpu + " cpu, " + memory + " memory, " + disk + " disk," + gpu + " gpu," + gpuMemory + " gpuMemory"; + return "load: " + cpu + " cpu, " + memory + " memory, " + disk + " disk"; } - public static Load zero() { return new Load(0, 0, 0, 0, 0); } - public static Load one() { return new Load(1, 1, 1, 1, 1); } + public static Load zero() { return new Load(0, 0, 0); } + public static Load one() { return new Load(1, 1, 1); } public static Load byDividing(NodeResources a, NodeResources b) { - return new Load(divide(a.vcpu(), b.vcpu()), - divide(a.memoryGb(), b.memoryGb()), - divide(a.diskGb(), b.diskGb()), - divide(a.gpuResources().count(), b.gpuResources().count()), - divide(a.gpuResources().memoryGb(), b.gpuResources().memoryGb())); + return new Load(divide(a.vcpu(), b.vcpu()), divide(a.memoryGb(), b.memoryGb()), divide(a.diskGb(), b.diskGb())); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java index f35879d0b24..a6882e49efa 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java @@ -76,10 +76,8 @@ public class MetricsResponse { nodeMetrics.add(new Pair<>(hostname, new NodeMetricSnapshot(at, new Load(Metric.cpu.from(nodeValues), Metric.memory.from(nodeValues), - Metric.disk.from(nodeValues), - Metric.gpu.from(nodeValues), - Metric.gpuMemory.from(nodeValues)), - (long) Metric.generation.from(nodeValues), + Metric.disk.from(nodeValues)), + (long)Metric.generation.from(nodeValues), Metric.inService.from(nodeValues) > 0, clusterIsStable(node.get(), applicationNodes, nodeValues), Metric.queryRate.from(nodeValues)))); @@ -128,7 +126,6 @@ public class MetricsResponse { @Override public List metricResponseNames() { - // TODO(mpolden): Track only CPU util once we support proper GPU scaling return List.of(HostedNodeAdminMetrics.CPU_UTIL.baseName(), HostedNodeAdminMetrics.GPU_UTIL.baseName()); } @@ -142,7 +139,6 @@ public class MetricsResponse { @Override public List metricResponseNames() { - // TODO(mpolden): Track only CPU memory once we support proper GPU scaling return List.of(HostedNodeAdminMetrics.MEM_UTIL.baseName(), SearchNodeMetrics.CONTENT_PROTON_RESOURCE_USAGE_MEMORY.average(), HostedNodeAdminMetrics.GPU_MEM_USED.baseName(), @@ -151,7 +147,7 @@ public class MetricsResponse { @Override double computeFinal(ListMap values) { - return Math.max(cpuMemUtil(values), gpuMemory.computeFinal(values)); + return Math.max(gpuMemUtil(values), cpuMemUtil(values)); } private double cpuMemUtil(ListMap values) { @@ -164,6 +160,12 @@ public class MetricsResponse { return 0; } + private double gpuMemUtil(ListMap values) { + var usedGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_USED.baseName()).stream().mapToDouble(v -> v).sum(); + var totalGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()).stream().mapToDouble(v -> v).sum(); + return totalGpuMemory > 0 ? usedGpuMemory / totalGpuMemory : 0; + } + }, disk { // a node resource @@ -184,35 +186,6 @@ public class MetricsResponse { return 0; } - }, - gpu { // a node resource - - @Override - public List metricResponseNames() { - return List.of(HostedNodeAdminMetrics.GPU_UTIL.baseName()); - } - - @Override - double computeFinal(ListMap values) { - return values.values().stream().flatMap(List::stream).mapToDouble(v -> v).max().orElse(0) / 100; // % to ratio - } - - }, - gpuMemory { // a node resource - - @Override - public List metricResponseNames() { - return List.of(HostedNodeAdminMetrics.GPU_MEM_USED.baseName(), - HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()); - } - - @Override - double computeFinal(ListMap values) { - var usedGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_USED.baseName()).stream().mapToDouble(v -> v).sum(); - var totalGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()).stream().mapToDouble(v -> v).sum(); - return totalGpuMemory > 0 ? usedGpuMemory / totalGpuMemory : 0; - } - }, generation { // application config generation active on the node diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java index c0de9a43f7f..38127fa3093 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java @@ -144,8 +144,6 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { row.putBool(6, snapshot.getSecond().inService()); row.putBool(7, snapshot.getSecond().stable()); row.putFloat(8, (float) snapshot.getSecond().queryRate()); - row.putFloat(9, (float) snapshot.getSecond().load().gpu()); - row.putFloat(10, (float) snapshot.getSecond().load().gpuMemory()); row.append(); } writer.commit(); @@ -245,9 +243,6 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { private void ensureNodeTableIsUpdated() { try { // Example: nodeTable.ensureColumnExists("write_rate", "float"); - // TODO(mpolden): Remove after January 2024 - nodeTable.ensureColumnExists("gpu_util", "float"); - nodeTable.ensureColumnExists("gpu_mem_total_util", "float"); } catch (Exception e) { nodeTable.repair(e); } @@ -267,9 +262,7 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { try { issue("create table " + nodeTable.name + " (hostname string, at timestamp, cpu_util float, mem_total_util float, disk_util float," + - " application_generation long, inService boolean, stable boolean, queries_rate float," + - " gpu_util float, gpu_mem_total_util float" + - " )" + + " application_generation long, inService boolean, stable boolean, queries_rate float)" + " timestamp(at)" + "PARTITION BY DAY;", newContext()); @@ -318,9 +311,7 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { new NodeMetricSnapshot(Instant.ofEpochMilli(record.getTimestamp(1) / 1000), new Load(record.getFloat(2), record.getFloat(3), - record.getFloat(4), - record.getFloat(9), - record.getFloat(10)), + record.getFloat(4)), record.getLong(5), record.getBool(6), record.getBool(7), diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java index 6f325700401..c4e7d3b9acc 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java @@ -76,8 +76,6 @@ public class ApplicationSerializer { private static final String cpuKey = "cpu"; private static final String memoryKey = "memory"; private static final String diskKey = "disk"; - private static final String gpuKey = "gpu"; - private static final String gpuMemory = "gpuMemory"; private static final String fromKey = "from"; private static final String toKey = "to"; private static final String generationKey = "generation"; @@ -203,16 +201,12 @@ public class ApplicationSerializer { loadObject.setDouble(cpuKey, load.cpu()); loadObject.setDouble(memoryKey, load.memory()); loadObject.setDouble(diskKey, load.disk()); - loadObject.setDouble(gpuKey, load.gpu()); - loadObject.setDouble(gpuMemory, load.gpuMemory()); } private static Load loadFromSlime(Inspector loadObject) { return new Load(loadObject.field(cpuKey).asDouble(), loadObject.field(memoryKey).asDouble(), - loadObject.field(diskKey).asDouble(), - loadObject.field(gpuKey).asDouble(), - loadObject.field(gpuMemory).asDouble()); + loadObject.field(diskKey).asDouble()); } private static void toSlime(Autoscaling.Metrics metrics, Cursor metricsObject) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java index 89853896104..225eb3e4e8d 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java @@ -98,8 +98,6 @@ public class ApplicationSerializer { loadObject.setDouble("cpu", load.cpu()); loadObject.setDouble("memory", load.memory()); loadObject.setDouble("disk", load.disk()); - loadObject.setDouble("gpu", load.gpu()); - loadObject.setDouble("gpuMemory", load.gpuMemory()); } private static void toSlime(Autoscaling.Metrics metrics, Cursor metricsObject) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java index 0b157e8635b..9080030f026 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java @@ -502,8 +502,6 @@ public class NodesV2ApiHandler extends ThreadedHttpRequestHandler { object.setDouble("cpu", load.cpu()); object.setDouble("memory", load.memory()); object.setDouble("disk", load.disk()); - object.setDouble("gpu", load.gpu()); - object.setDouble("gpuMemory", load.gpuMemory()); } /** Returns a copy of the given URI with the host and port from the given URI and the path set to the given path */ diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java index d3b88997059..fe6b204ed31 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java @@ -40,6 +40,7 @@ import com.yahoo.vespa.hosted.provision.applications.Cluster; import com.yahoo.vespa.hosted.provision.autoscale.Autoscaling; import com.yahoo.vespa.hosted.provision.autoscale.Load; import com.yahoo.vespa.hosted.provision.autoscale.MemoryMetricsDb; +import com.yahoo.vespa.hosted.provision.lb.LoadBalancerService; import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.node.Status; @@ -238,8 +239,8 @@ public class MockNodeRepository extends NodeRepository { Optional.of(new ClusterResources(4, 1, new NodeResources(3, 16, 100, 1))), clock().instant(), - new Load(0.1, 0.2, 0.3, 0, 0), - new Load(0.4, 0.5, 0.6, 0, 0), + new Load(0.1, 0.2, 0.3), + new Load(0.4, 0.5, 0.6), new Autoscaling.Metrics(0.7, 0.8, 0.9))); try (Mutex lock = applications().lock(app1Id)) { applications().put(app1.with(cluster1), lock); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java index b2e04ba2233..0a26678d37e 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java @@ -15,6 +15,7 @@ import com.yahoo.vespa.hosted.provision.autoscale.NodeMetricSnapshot; import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester; import org.junit.Test; +import java.time.Duration; import java.util.List; import static org.junit.Assert.assertEquals; @@ -98,7 +99,7 @@ public class NodeRepoStatsTest { else { loadFactor = loadApp3; } - var snapshot = new NodeMetricSnapshot(now, new Load(1.0, 0.9, 0.8, 0, 0).multiply(loadFactor), 1, true, true, 1.0 ); + var snapshot = new NodeMetricSnapshot(now, new Load(1.0, 0.9, 0.8).multiply(loadFactor), 1, true, true, 1.0 ); tester.nodeRepository().metricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(), snapshot))); } @@ -107,8 +108,8 @@ public class NodeRepoStatsTest { assertEquals(26, stats.totalCost(), delta); assertEquals(8.319999999999999, stats.totalAllocatedCost(), delta); - assertLoad(new Load(0.6180,0.5562,0.4944, 0, 0), stats.load()); - assertLoad(new Load(0.4682,0.4214,0.3745, 0, 0), stats.activeLoad()); + assertLoad(new Load(0.6180,0.5562,0.4944), stats.load()); + assertLoad(new Load(0.4682,0.4214,0.3745), stats.activeLoad()); var app1Stats = stats.applicationStats().get(0); var app2Stats = stats.applicationStats().get(2); @@ -118,27 +119,25 @@ public class NodeRepoStatsTest { assertEquals(3.6400, app1Stats.cost(), delta); assertEquals(0.8676, app1Stats.utilizedCost(), delta); assertEquals(2.7724, app1Stats.unutilizedCost(), delta); - assertLoad(new Load(0.2571, 0.2314, 0.2057, 0, 0), app1Stats.load()); + assertLoad(new Load(0.2571, 0.2314, 0.2057), app1Stats.load()); assertEquals(app2, app2Stats.id()); assertEquals(2.0799, app2Stats.cost(), delta); assertEquals(0.7712, app2Stats.utilizedCost(), delta); assertEquals(1.3087, app2Stats.unutilizedCost(), delta); - assertLoad(new Load(.40, 0.36, 0.32, 0, 0), app2Stats.load()); + assertLoad(new Load(.40, 0.36, 0.32), app2Stats.load()); assertEquals(app3, app3Stats.id()); assertEquals(2.6000, app3Stats.cost(), delta); assertEquals(1.2049, app3Stats.utilizedCost(), delta); assertEquals(1.3950, app3Stats.unutilizedCost(), delta); - assertLoad(new Load(0.5, 0.45, 0.40, 0, 0), app3Stats.load()); + assertLoad(new Load(0.5, 0.45, 0.40), app3Stats.load()); } private static void assertLoad(Load expected, Load actual) { - assertEquals("cpu", expected.cpu(), actual.cpu(), delta); - assertEquals("memory", expected.memory(), actual.memory(), delta); - assertEquals("disk", expected.disk(), actual.disk(), delta); - assertEquals("gpu", expected.gpu(), actual.gpu(), delta); - assertEquals("gpuMemory", expected.gpuMemory(), actual.gpuMemory(), delta); + assertEquals("cpu", expected.cpu(), actual.cpu(), delta); + assertEquals("memory", expected.memory(), actual.memory(), delta); + assertEquals("disk", expected.disk(), actual.disk(), delta); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java index 4236f7ac968..d4d34ab66e5 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java @@ -44,7 +44,7 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max)) .build(); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12, 0, 0), 1, true, true, 100); + fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12), 1, true, true, 100); var result = fixture.autoscale(); assertTrue(result.resources().isEmpty()); assertEquals(Autoscaling.Status.insufficient, result.status()); @@ -63,13 +63,13 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max)) .build(); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12, 0, 0), 1, true, true, 100); + fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12), 1, true, true, 100); var result = fixture.autoscale(); assertTrue(result.resources().isEmpty()); assertEquals(Autoscaling.Status.insufficient, result.status()); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.08f, 0.17, 0.12, 0, 0), 1, true, true, 100); + fixture.loader().applyLoad(new Load(0.08f, 0.17, 0.12), 1, true, true, 100); fixture.tester().assertResources("Scaling down", 8, 1, 16, 32, 200, fixture.autoscale()); @@ -128,8 +128,8 @@ public class AutoscalingTest { @Test public void test_autoscaling_up_is_fast() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); - fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1, 0, 0), 3); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 1); + fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1), 3); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 1); fixture.tester().assertResources("Scaling up since resource usage is too high", 8, 1, 5.3, 17.0, 75.1, fixture.autoscale()); @@ -148,7 +148,7 @@ public class AutoscalingTest { .build(); fixture.tester().setScalingDuration(fixture.applicationId(), fixture.clusterSpec.id(), Duration.ofMinutes(5)); - fixture.loader().applyLoad(new Load(0.01, 0.38, 0, 0, 0), 5); + fixture.loader().applyLoad(new Load(0.01, 0.38, 0), 5); fixture.tester().assertResources("Scaling down", 2, 1, 4, 8, 50, fixture.autoscale()); @@ -190,7 +190,7 @@ public class AutoscalingTest { public void test_only_autoscaling_up_quickly() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.setScalingDuration(Duration.ofHours(12)); // Fixture sets last completion to be 1 day into the past - fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0, 0, 0), 10); + fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0), 10); fixture.tester().assertResources("Scaling up (only) since resource usage is too high", 5, 1, 11.7, 14.9, 131.5, fixture.autoscale()); @@ -202,7 +202,7 @@ public class AutoscalingTest { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.setScalingDuration(Duration.ofHours(12)); // Fixture sets last completion to be 1 day into the past fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0, 0, 0), 10); + fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0), 10); fixture.tester().assertResources("Scaling cpu and disk up and memory down", 5, 1, 11.7, 4.0, 131.5, fixture.autoscale()); @@ -213,7 +213,7 @@ public class AutoscalingTest { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(false).build(); fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0, 0, 0), 10); + fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0), 10); fixture.tester().assertResources("Scaling cpu and disk up, memory follows", 16, 1, 4, 8.0, 28.3, fixture.autoscale()); @@ -264,7 +264,7 @@ public class AutoscalingTest { .clusterType(ClusterSpec.Type.container) .awsProdSetup(false) .build(); - var duration = fixture.loader().addMeasurements(new Load(0.04, 0.39, 0.01, 0, 0), 20); + var duration = fixture.loader().addMeasurements(new Load(0.04, 0.39, 0.01), 20); fixture.tester().clock().advance(duration.negated()); fixture.loader().zeroTraffic(20, 1); fixture.tester().assertResources("Scaled down", @@ -358,7 +358,7 @@ public class AutoscalingTest { fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester().clock().advance(Duration.ofDays(1)); - fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95, 0, 0), 120); + fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95), 120); fixture.tester().assertResources("Scaling up to limit since resource usage is too high", 6, 1, 2.4, 78.0, 79.0, fixture.autoscale()); @@ -372,7 +372,7 @@ public class AutoscalingTest { // deploy fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.05f, 0.05f, 0.05f, 0, 0), 120); + fixture.loader().applyLoad(new Load(0.05f, 0.05f, 0.05f), 120); fixture.tester().assertResources("Scaling down to limit since resource usage is low", 4, 1, 1.8, 7.4, 23.4, fixture.autoscale()); @@ -395,7 +395,7 @@ public class AutoscalingTest { 2, 1, defaultResources, fixture.nodes().toResources()); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95, 0, 0), 120); + fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95), 120); fixture.tester().assertResources("Scaling up", 5, 1, defaultResources.vcpu(), defaultResources.memoryGb(), defaultResources.diskGb(), @@ -461,7 +461,7 @@ public class AutoscalingTest { .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.01, 0.01, 0.01, 0, 0), 120); + fixture.loader().applyLoad(new Load(0.01, 0.01, 0.01), 120); Autoscaling suggestion = fixture.suggest(); fixture.tester().assertResources("Choosing the remote disk flavor as it has less disk", 2, 1, 3.0, 100.0, 10.0, @@ -498,7 +498,7 @@ public class AutoscalingTest { public void not_using_out_of_service_measurements() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7, 0, 0), 1, false, true, 120); + fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7), 1, false, true, 120); assertTrue("Not scaling up since nodes were measured while cluster was out of service", fixture.autoscale().resources().isEmpty()); } @@ -507,7 +507,7 @@ public class AutoscalingTest { public void not_using_unstable_measurements() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7, 0, 0), 1, true, false, 120); + fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7), 1, true, false, 120); assertTrue("Not scaling up since nodes were measured while cluster was unstable", fixture.autoscale().resources().isEmpty()); } @@ -536,7 +536,7 @@ public class AutoscalingTest { .build(); fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1, 0, 0), 120); + fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1), 120); fixture.tester().assertResources("Suggesting resources where disk is 3x memory (this is a content cluster)", 11, 1, 13.0, 60.0, 179.9, fixture.tester().suggest(fixture.applicationId, fixture.clusterSpec.id(), min, min)); @@ -557,7 +557,7 @@ public class AutoscalingTest { .build(); fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1, 0, 0), 120); + fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1), 120); fixture.tester().assertResources("Suggesting resources where disk is 3x memory (this is a content cluster)", 13, 1, 36.0, 72.0, 900.0, fixture.tester().suggest(fixture.applicationId, fixture.clusterSpec.id(), min, min)); @@ -668,7 +668,7 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max)) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.16, 0.02, 0.5, 0, 0), 120); + fixture.loader().applyLoad(new Load(0.16, 0.02, 0.5), 120); fixture.tester().assertResources("Scaling down memory", 6, 1, 2.1, 4.0, 96.2, fixture.autoscale()); @@ -826,7 +826,7 @@ public class AutoscalingTest { .zone(new Zone(Environment.dev, RegionName.from("us-east"))) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); assertTrue("Not attempting to scale up because policies dictate we'll only get one node", fixture.autoscale().resources().isEmpty()); } @@ -842,7 +842,7 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max, IntRange.of(3, 5), false, true, Optional.empty(), ClusterInfo.empty())) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); assertEquals("Don't autoscale: Autoscaling is disabled in single node clusters", fixture.autoscale().toString()); } @@ -866,7 +866,7 @@ public class AutoscalingTest { .zone(new Zone(Environment.dev, RegionName.from("us-east"))) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); fixture.tester().assertResources("We scale even in dev because resources are 'required'", 3, 1, 1.0, 13.4, 62.5, fixture.autoscale()); @@ -889,7 +889,7 @@ public class AutoscalingTest { .zone(new Zone(Environment.dev, RegionName.from("us-east"))) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); fixture.tester().assertResources("We scale even in dev because resources are required", 3, 1, 1.5, 8, 50, fixture.autoscale()); @@ -927,13 +927,13 @@ public class AutoscalingTest { fixture.currentResources().advertisedResources()); fixture.tester().deploy(fixture.applicationId(), clusterSpec(false), fixture.capacity()); - fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1, 0, 0), 5); + fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1), 5); fixture.tester().assertResources("Exclusive nodes makes no difference here", 2, 1, 4, 8, 100.0, fixture.autoscale()); fixture.tester().deploy(fixture.applicationId(), clusterSpec(true), fixture.capacity()); - fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1, 0, 0), 5); + fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1), 5); fixture.tester().assertResources("Reverts to the initial resources", 2, 1, 4, 8, 100, fixture.currentResources().advertisedResources()); @@ -952,7 +952,7 @@ public class AutoscalingTest { .build(); var initialNodes = fixture.nodes().asList(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.06, 0.52, 0.27, 0, 0), 100); + fixture.loader().applyLoad(new Load(0.06, 0.52, 0.27), 100); var autoscaling = fixture.autoscale(); fixture.tester().assertResources("Scaling down", 7, 1, 2, 15.8, 384.0, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java index 8dc3945223f..2e953a0f67c 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java @@ -49,7 +49,7 @@ public class Loader { var idealLoad = fixture.clusterModel().idealLoad(); NodeList nodes = fixture.nodes(); float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size()); - Load load = new Load(value, idealLoad.memory(), idealLoad.disk(), 0, 0).multiply(oneExtraNodeFactor); + Load load = new Load(value, idealLoad.memory(), idealLoad.disk()).multiply(oneExtraNodeFactor); Instant initialTime = fixture.tester().clock().instant(); for (int i = 0; i < count; i++) { fixture.tester().clock().advance(samplingInterval); @@ -101,7 +101,7 @@ public class Loader { var idealLoad = fixture.clusterModel().idealLoad(); NodeList nodes = fixture.nodes(); float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size()); - Load load = new Load(idealLoad.cpu(), value, idealLoad.disk(), 0, 0).multiply(oneExtraNodeFactor); + Load load = new Load(idealLoad.cpu(), value, idealLoad.disk()).multiply(oneExtraNodeFactor); for (int i = 0; i < count; i++) { fixture.tester().clock().advance(samplingInterval); for (Node node : nodes) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java index a984306b577..4ec4ecd6d84 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java @@ -99,8 +99,6 @@ public class MetricsV2MetricsFetcherTest { assertEquals("host-3.yahoo.com", values.get(0).getFirst()); assertEquals(0.13, values.get(0).getSecond().load().cpu(), delta); assertEquals(0.9375, values.get(0).getSecond().load().memory(), delta); - assertEquals(0.13, values.get(0).getSecond().load().gpu(), delta); - assertEquals(0.9375, values.get(0).getSecond().load().gpuMemory(), delta); assertFalse("Unstable because buckets are being merged", values.get(0).getSecond().stable()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java index 71ed5bafc3d..e8d1368de71 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java @@ -40,7 +40,7 @@ public class NodeMetricsDbTest { Collection> values = new ArrayList<>(); for (int i = 0; i < 40; i++) { values.add(new Pair<>(node0, new NodeMetricSnapshot(clock.instant(), - new Load(0.9, 0.6, 0.6, 0, 0), + new Load(0.9, 0.6, 0.6), 0, true, false, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java index 96588250674..d52ec12d486 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java @@ -57,8 +57,6 @@ public class QuestMetricsDbTest { assertEquals(0.1, snapshot.load().cpu(), delta); assertEquals(0.2, snapshot.load().memory(), delta); assertEquals(0.4, snapshot.load().disk(), delta); - assertEquals(0.5, snapshot.load().gpu(), delta); - assertEquals(0.6, snapshot.load().gpuMemory(), delta); assertEquals(1, snapshot.generation(), delta); assertEquals(30, snapshot.queryRate(), delta); @@ -232,7 +230,7 @@ public class QuestMetricsDbTest { for (int i = 1; i <= countPerHost; i++) { for (String host : hosts) timeseries.add(new Pair<>(host, new NodeMetricSnapshot(clock.instant(), - new Load(i * 0.1, i * 0.2, i * 0.4, i * 0.5, i * 0.6), + new Load(i * 0.1, i * 0.2, i * 0.4), i % 100, true, true, @@ -246,7 +244,7 @@ public class QuestMetricsDbTest { Collection> timeseries = new ArrayList<>(); for (int i = 1; i <= countPerHost; i++) { for (String host : hosts) - timeseries.add(new Pair<>(host, new NodeMetricSnapshot(at, new Load(i * 0.1, i * 0.2, i * 0.4, i * 0.5, i * 0.6), + timeseries.add(new Pair<>(host, new NodeMetricSnapshot(at, new Load(i * 0.1, i * 0.2, i * 0.4), i % 100, true, false, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java index 4f9b2de4da0..e4a712d3898 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java @@ -77,7 +77,7 @@ public class AutoscalingMaintainerTester { for (Node node : nodes) nodeRepository().metricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(), new NodeMetricSnapshot(clock().instant(), - new Load(cpu, mem, disk, 0, 0), + new Load(cpu, mem, disk), generation, true, true, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java index 152f743900b..d4771594569 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java @@ -270,7 +270,7 @@ public class MetricsReporterTest { Optional.empty(), tester.clock().instant(), Load.zero(), - new Load(0.1, 0.2, 0.3, 0, 0), + new Load(0.1, 0.2, 0.3), Autoscaling.Metrics.zero())); tester.nodeRepository().applications().put(application.with(cluster), tester.nodeRepository().applications().lock(applicationId)); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java index f8be27300fe..0a78874405d 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java @@ -139,7 +139,7 @@ public class ScalingSuggestionsMaintainerTest { for (Node node : nodes) nodeRepository.metricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(), new NodeMetricSnapshot(nodeRepository.clock().instant(), - new Load(cpu, memory, disk, 0, 0), + new Load(cpu, memory, disk), generation, true, true, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java index 918a9043c93..7a00c84faf6 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java @@ -57,8 +57,8 @@ public class ApplicationSerializerTest { Optional.of(new ClusterResources(20, 10, new NodeResources(0.5, 4, 14, 16))), Instant.ofEpochMilli(1234L), - new Load(0.1, 0.2, 0.3, 0.4, 0.5), - new Load(0.4, 0.5, 0.6, 0.7, 0.8), + new Load(0.1, 0.2, 0.3), + new Load(0.4, 0.5, 0.6), new Autoscaling.Metrics(0.7, 0.8, 0.9)), new Autoscaling(Autoscaling.Status.insufficient, "Autoscaling status", diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json index 7b2cf1dc8e4..28bde7bd966 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json @@ -63,16 +63,12 @@ "peak" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk" : 0.0 }, "ideal" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk" : 0.0 }, "metrics" : { "queryRate" : 0.0, @@ -100,16 +96,12 @@ "peak" : { "cpu" : 0.1, "memory" : 0.2, - "disk" : 0.3, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk" : 0.3 }, "ideal" : { "cpu" : 0.4, "memory" : 0.5, - "disk" : 0.6, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk" : 0.6 }, "metrics" : { "queryRate" : 0.7, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json index 10173089f75..05a62ff944d 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json @@ -50,16 +50,12 @@ "peak" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk" : 0.0 }, "ideal" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk" : 0.0 }, "metrics" : { "queryRate" : 0.0, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json index b031e0deba0..788eb6d359f 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json @@ -4,16 +4,12 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk": 0.0 }, "activeLoad": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk": 0.0 }, "applications": [ { @@ -21,9 +17,7 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 @@ -33,9 +27,7 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 @@ -45,9 +37,7 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 @@ -57,9 +47,7 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0, - "gpu": 0.0, - "gpuMemory": 0.0 + "disk": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 -- cgit v1.2.3 From 8146bbf2e2b022902bfed1c93d1d084471cb22a9 Mon Sep 17 00:00:00 2001 From: Harald Musum Date: Tue, 19 Dec 2023 22:50:45 +0100 Subject: Store onnx model info after deciding if we need to restart on deploy Need to store (in ZK) so that info is available on all config servers --- config-model-api/abi-spec.json | 6 ++++-- .../src/main/java/com/yahoo/config/model/api/OnnxModelCost.java | 2 ++ .../change/RestartOnDeployForOnnxModelChangesValidator.java | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json index d05360b8d1a..10c5662678e 100644 --- a/config-model-api/abi-spec.json +++ b/config-model-api/abi-spec.json @@ -1465,7 +1465,8 @@ "public abstract void registerModel(java.net.URI, com.yahoo.config.model.api.OnnxModelOptions)", "public abstract java.util.Map models()", "public abstract void setRestartOnDeploy()", - "public abstract boolean restartOnDeploy()" + "public abstract boolean restartOnDeploy()", + "public abstract void store()" ], "fields" : [ ] }, @@ -1488,7 +1489,8 @@ "public void registerModel(java.net.URI, com.yahoo.config.model.api.OnnxModelOptions)", "public java.util.Map models()", "public void setRestartOnDeploy()", - "public boolean restartOnDeploy()" + "public boolean restartOnDeploy()", + "public void store()" ], "fields" : [ ] }, diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/OnnxModelCost.java b/config-model-api/src/main/java/com/yahoo/config/model/api/OnnxModelCost.java index c13ce4def09..d70b751eba0 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/OnnxModelCost.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/OnnxModelCost.java @@ -25,6 +25,7 @@ public interface OnnxModelCost { Map models(); void setRestartOnDeploy(); boolean restartOnDeploy(); + void store(); } record ModelInfo(String modelId, long estimatedCost, long hash, Optional onnxModelOptions) {} @@ -41,6 +42,7 @@ public interface OnnxModelCost { @Override public Map models() { return Map.of(); } @Override public void setRestartOnDeploy() {} @Override public boolean restartOnDeploy() { return false; } + @Override public void store() {} } } diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java index 8da7f34048b..398538d187f 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java @@ -99,6 +99,7 @@ public class RestartOnDeployForOnnxModelChangesValidator implements ChangeValida private static void setRestartOnDeployAndAddRestartAction(List actions, ApplicationContainerCluster cluster, String message) { log.log(INFO, message); cluster.onnxModelCostCalculator().setRestartOnDeploy(); + cluster.onnxModelCostCalculator().store(); actions.add(new VespaRestartAction(cluster.id(), message)); } -- cgit v1.2.3 From 844a00985d96f58120d7b68b150565d025b7d9ad Mon Sep 17 00:00:00 2001 From: Harald Musum Date: Tue, 19 Dec 2023 23:04:55 +0100 Subject: Implement new method --- .../vespa/model/application/validation/JvmHeapSizeValidatorTest.java | 1 + .../change/RestartOnDeployForOnnxModelChangesValidatorTest.java | 3 +++ 2 files changed, 4 insertions(+) diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java index 213cf4bdfcf..0b32194e257 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java @@ -124,6 +124,7 @@ class JvmHeapSizeValidatorTest { @Override public Map models() { return Map.of(); } @Override public void setRestartOnDeploy() {} @Override public boolean restartOnDeploy() { return false;} + @Override public void store() {} @Override public long aggregatedModelCostInBytes() { return totalCost.get(); } @Override public void registerModel(ApplicationFile path) {} @Override public void registerModel(ApplicationFile path, OnnxModelOptions onnxModelOptions) {} diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidatorTest.java index 5873d15bd9a..adcf58785fa 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidatorTest.java @@ -110,6 +110,9 @@ public class RestartOnDeployForOnnxModelChangesValidatorTest { @Override public boolean restartOnDeploy() { return restartOnDeploy; } + + @Override + public void store() {} }; } -- cgit v1.2.3 From a3c938f789d8b2d8474708eff091174b5f210672 Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Thu, 14 Dec 2023 14:14:16 +0100 Subject: Store GPU metrics and load separately --- .../hosted/provision/autoscale/ClusterModel.java | 12 +++-- .../autoscale/ClusterNodesTimeseries.java | 3 +- .../vespa/hosted/provision/autoscale/Load.java | 63 +++++++++++----------- .../provision/autoscale/MetricsResponse.java | 45 ++++++++++++---- .../hosted/provision/autoscale/QuestMetricsDb.java | 13 ++++- .../persistence/ApplicationSerializer.java | 8 ++- .../provision/testutils/MockNodeRepository.java | 5 +- .../vespa/hosted/provision/NodeRepoStatsTest.java | 21 ++++---- .../provision/autoscale/AutoscalingTest.java | 52 +++++++++--------- .../vespa/hosted/provision/autoscale/Loader.java | 4 +- .../autoscale/MetricsV2MetricsFetcherTest.java | 2 + .../provision/autoscale/NodeMetricsDbTest.java | 2 +- .../provision/autoscale/QuestMetricsDbTest.java | 6 ++- .../maintenance/AutoscalingMaintainerTester.java | 2 +- .../provision/maintenance/MetricsReporterTest.java | 2 +- .../ScalingSuggestionsMaintainerTest.java | 2 +- .../persistence/ApplicationSerializerTest.java | 4 +- 17 files changed, 147 insertions(+), 99 deletions(-) diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java index 1e4a11fdea2..986ab830283 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java @@ -233,11 +233,13 @@ public class ClusterModel { double queryCpu = queryCpuPerGroup * groupCount() / groups; double writeCpu = (double)groupSize() / groupSize; return new Load(cpu.queryFraction() * queryCpu + (1 - cpu.queryFraction()) * writeCpu, - (1 - memory.fixedFraction()) * (double)groupSize() / groupSize + memory.fixedFraction() * 1, - (double)groupSize() / groupSize); + (1 - memory.fixedFraction()) * (double) groupSize() / groupSize + memory.fixedFraction() * 1, + (double)groupSize() / groupSize, + 1, + 1); } else { - return new Load((double)nodeCount() / nodes, 1, 1); + return new Load((double) nodeCount() / nodes, 1, 1, 1, 1); } } @@ -246,7 +248,7 @@ public class ClusterModel { * if one of the nodes go down. */ public Load idealLoad() { - var ideal = new Load(cpu.idealLoad(), memory.idealLoad(), disk.idealLoad()).divide(redundancyAdjustment()); + var ideal = new Load(cpu.idealLoad(), memory.idealLoad(), disk.idealLoad(), cpu.idealLoad(), memory.idealLoad()).divide(redundancyAdjustment()); if ( !cluster.bcpGroupInfo().isEmpty() && cluster.bcpGroupInfo().queryRate() > 0) { // Since we have little local information, use information about query cost in other groups Load bcpGroupIdeal = adjustQueryDependentIdealLoadByBcpGroupInfo(ideal); @@ -392,7 +394,7 @@ public class ClusterModel { if (averageQueryRate().isEmpty() || averageQueryRate().getAsDouble() == 0.0) return OptionalDouble.empty(); // TODO: Query rate should generally be sampled at the time where we see the peak resource usage int fanOut = clusterSpec.type().isContainer() ? 1 : groupSize(); - return OptionalDouble.of(peakLoad().cpu() * cpu.queryFraction() * fanOut * nodes.not().retired().first().get().resources().vcpu() + return OptionalDouble.of(peakLoad().cpu() * cpu.queryFraction() * fanOut * nodes.not().retired().first().get().resources().vcpu() / averageQueryRate().getAsDouble() / groupCount()); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java index e1ef21ebd13..6978e269c3d 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterNodesTimeseries.java @@ -67,7 +67,8 @@ public class ClusterNodesTimeseries { * the average of the highest reading for that dimension on each node. */ public Load peakLoad() { - return new Load(peakLoad(Load.Dimension.cpu), peakLoad(Load.Dimension.memory), peakLoad(Load.Dimension.disk)); + return new Load(peakLoad(Load.Dimension.cpu), peakLoad(Load.Dimension.memory), peakLoad(Load.Dimension.disk), + peakLoad(Load.Dimension.gpu), peakLoad(Load.Dimension.gpuMemory)); } private double peakLoad(Load.Dimension dimension) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java index 799ed621807..22c13795d18 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Load.java @@ -3,9 +3,7 @@ package com.yahoo.vespa.hosted.provision.autoscale; import com.yahoo.config.provision.NodeResources; -import java.util.Objects; import java.util.function.DoubleBinaryOperator; -import java.util.function.DoubleFunction; import java.util.function.DoubleUnaryOperator; import java.util.function.Predicate; @@ -14,32 +12,36 @@ import java.util.function.Predicate; * * @author bratseth */ -public class Load { +public record Load(double cpu, double memory, double disk, double gpu, double gpuMemory) { - public enum Dimension { cpu, memory, disk } + public enum Dimension { cpu, memory, disk, gpu, gpuMemory } - private final double cpu, memory, disk; - - public Load(double cpu, double memory, double disk) { + public Load(double cpu, double memory, double disk, double gpu, double gpuMemory) { this.cpu = requireNormalized(cpu, "cpu"); this.memory = requireNormalized(memory, "memory"); this.disk = requireNormalized(disk, "disk"); + this.gpu = requireNormalized(gpu, "gpu"); + this.gpuMemory = requireNormalized(gpuMemory, "gpuMemory"); } public double cpu() { return cpu; } public double memory() { return memory; } public double disk() { return disk; } + public double gpu() { return gpu; } + public double gpuMemory() { return gpuMemory; } - public Load withCpu(double cpu) { return new Load(cpu, memory, disk); } - public Load withMemory(double memory) { return new Load(cpu, memory, disk); } - public Load withDisk(double disk) { return new Load(cpu, memory, disk); } + public Load withCpu(double cpu) { return new Load(cpu, memory, disk, gpu, gpuMemory); } + public Load withMemory(double memory) { return new Load(cpu, memory, disk, gpu, gpuMemory); } + public Load withDisk(double disk) { return new Load(cpu, memory, disk, gpu, gpuMemory); } + public Load withGpu(double gpu) { return new Load(cpu, memory, disk, gpu, gpuMemory); } + public Load withGpuMemory(double gpuMemory) { return new Load(cpu, memory, disk, gpu, gpuMemory); } public Load add(Load other) { return join(other, (a, b) -> a + b); } public Load multiply(NodeResources resources) { - return new Load(cpu * resources.vcpu(), memory * resources.memoryGb(), disk * resources.diskGb()); + return new Load(cpu * resources.vcpu(), memory * resources.memoryGb(), disk * resources.diskGb(), gpu * resources.gpuResources().count(), gpu * resources.gpuResources().memoryGb()); } public Load multiply(double factor) { return map(v -> v * factor); @@ -55,21 +57,25 @@ public class Load { return map(v -> divide(v, divisor)); } public Load divide(NodeResources resources) { - return new Load(divide(cpu, resources.vcpu()), divide(memory, resources.memoryGb()), divide(disk, resources.diskGb())); + return new Load(divide(cpu, resources.vcpu()), divide(memory, resources.memoryGb()), divide(disk, resources.diskGb()), divide(gpu, resources.gpuResources().count()), divide(gpuMemory, resources.gpuResources().memoryGb())); } /** Returns the load where the given function is applied to each dimension of this. */ public Load map(DoubleUnaryOperator f) { return new Load(f.applyAsDouble(cpu), f.applyAsDouble(memory), - f.applyAsDouble(disk)); + f.applyAsDouble(disk), + f.applyAsDouble(gpu), + f.applyAsDouble(gpuMemory)); } /** Returns the load where the given function is applied to each dimension of this and the given load. */ public Load join(Load other, DoubleBinaryOperator f) { return new Load(f.applyAsDouble(this.cpu(), other.cpu()), f.applyAsDouble(this.memory(), other.memory()), - f.applyAsDouble(this.disk(), other.disk())); + f.applyAsDouble(this.disk(), other.disk()), + f.applyAsDouble(this.gpu(), other.gpu()), + f.applyAsDouble(this.gpuMemory(), other.gpuMemory())); } /** Returns true if any dimension matches the predicate. */ @@ -88,6 +94,8 @@ public class Load { case cpu -> cpu(); case memory -> memory(); case disk -> disk(); + case gpu -> gpu(); + case gpuMemory -> gpuMemory(); }; } @@ -95,7 +103,7 @@ public class Load { if (Double.isNaN(value)) throw new IllegalArgumentException(name + " must be a number but is NaN"); if (value < 0) - throw new IllegalArgumentException(name + " must be zero or lager, but is " + value); + throw new IllegalArgumentException(name + " must be zero or larger, but is " + value); return value; } @@ -104,29 +112,20 @@ public class Load { return a / b; } - @Override - public boolean equals(Object o) { - if (o == this) return true; - if ( ! (o instanceof Load other)) return false; - if (other.cpu() != this.cpu()) return false; - if (other.memory() != this.memory()) return false; - if (other.disk() != this.disk()) return false; - return true; - } - - @Override - public int hashCode() { return Objects.hash(cpu, memory, disk); } - @Override public String toString() { - return "load: " + cpu + " cpu, " + memory + " memory, " + disk + " disk"; + return "load: " + cpu + " cpu, " + memory + " memory, " + disk + " disk," + gpu + " gpu," + gpuMemory + " gpuMemory"; } - public static Load zero() { return new Load(0, 0, 0); } - public static Load one() { return new Load(1, 1, 1); } + public static Load zero() { return new Load(0, 0, 0, 0, 0); } + public static Load one() { return new Load(1, 1, 1, 1, 1); } public static Load byDividing(NodeResources a, NodeResources b) { - return new Load(divide(a.vcpu(), b.vcpu()), divide(a.memoryGb(), b.memoryGb()), divide(a.diskGb(), b.diskGb())); + return new Load(divide(a.vcpu(), b.vcpu()), + divide(a.memoryGb(), b.memoryGb()), + divide(a.diskGb(), b.diskGb()), + divide(a.gpuResources().count(), b.gpuResources().count()), + divide(a.gpuResources().memoryGb(), b.gpuResources().memoryGb())); } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java index a6882e49efa..f35879d0b24 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java @@ -76,8 +76,10 @@ public class MetricsResponse { nodeMetrics.add(new Pair<>(hostname, new NodeMetricSnapshot(at, new Load(Metric.cpu.from(nodeValues), Metric.memory.from(nodeValues), - Metric.disk.from(nodeValues)), - (long)Metric.generation.from(nodeValues), + Metric.disk.from(nodeValues), + Metric.gpu.from(nodeValues), + Metric.gpuMemory.from(nodeValues)), + (long) Metric.generation.from(nodeValues), Metric.inService.from(nodeValues) > 0, clusterIsStable(node.get(), applicationNodes, nodeValues), Metric.queryRate.from(nodeValues)))); @@ -126,6 +128,7 @@ public class MetricsResponse { @Override public List metricResponseNames() { + // TODO(mpolden): Track only CPU util once we support proper GPU scaling return List.of(HostedNodeAdminMetrics.CPU_UTIL.baseName(), HostedNodeAdminMetrics.GPU_UTIL.baseName()); } @@ -139,6 +142,7 @@ public class MetricsResponse { @Override public List metricResponseNames() { + // TODO(mpolden): Track only CPU memory once we support proper GPU scaling return List.of(HostedNodeAdminMetrics.MEM_UTIL.baseName(), SearchNodeMetrics.CONTENT_PROTON_RESOURCE_USAGE_MEMORY.average(), HostedNodeAdminMetrics.GPU_MEM_USED.baseName(), @@ -147,7 +151,7 @@ public class MetricsResponse { @Override double computeFinal(ListMap values) { - return Math.max(gpuMemUtil(values), cpuMemUtil(values)); + return Math.max(cpuMemUtil(values), gpuMemory.computeFinal(values)); } private double cpuMemUtil(ListMap values) { @@ -160,12 +164,6 @@ public class MetricsResponse { return 0; } - private double gpuMemUtil(ListMap values) { - var usedGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_USED.baseName()).stream().mapToDouble(v -> v).sum(); - var totalGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()).stream().mapToDouble(v -> v).sum(); - return totalGpuMemory > 0 ? usedGpuMemory / totalGpuMemory : 0; - } - }, disk { // a node resource @@ -186,6 +184,35 @@ public class MetricsResponse { return 0; } + }, + gpu { // a node resource + + @Override + public List metricResponseNames() { + return List.of(HostedNodeAdminMetrics.GPU_UTIL.baseName()); + } + + @Override + double computeFinal(ListMap values) { + return values.values().stream().flatMap(List::stream).mapToDouble(v -> v).max().orElse(0) / 100; // % to ratio + } + + }, + gpuMemory { // a node resource + + @Override + public List metricResponseNames() { + return List.of(HostedNodeAdminMetrics.GPU_MEM_USED.baseName(), + HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()); + } + + @Override + double computeFinal(ListMap values) { + var usedGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_USED.baseName()).stream().mapToDouble(v -> v).sum(); + var totalGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()).stream().mapToDouble(v -> v).sum(); + return totalGpuMemory > 0 ? usedGpuMemory / totalGpuMemory : 0; + } + }, generation { // application config generation active on the node diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java index 38127fa3093..c0de9a43f7f 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java @@ -144,6 +144,8 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { row.putBool(6, snapshot.getSecond().inService()); row.putBool(7, snapshot.getSecond().stable()); row.putFloat(8, (float) snapshot.getSecond().queryRate()); + row.putFloat(9, (float) snapshot.getSecond().load().gpu()); + row.putFloat(10, (float) snapshot.getSecond().load().gpuMemory()); row.append(); } writer.commit(); @@ -243,6 +245,9 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { private void ensureNodeTableIsUpdated() { try { // Example: nodeTable.ensureColumnExists("write_rate", "float"); + // TODO(mpolden): Remove after January 2024 + nodeTable.ensureColumnExists("gpu_util", "float"); + nodeTable.ensureColumnExists("gpu_mem_total_util", "float"); } catch (Exception e) { nodeTable.repair(e); } @@ -262,7 +267,9 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { try { issue("create table " + nodeTable.name + " (hostname string, at timestamp, cpu_util float, mem_total_util float, disk_util float," + - " application_generation long, inService boolean, stable boolean, queries_rate float)" + + " application_generation long, inService boolean, stable boolean, queries_rate float," + + " gpu_util float, gpu_mem_total_util float" + + " )" + " timestamp(at)" + "PARTITION BY DAY;", newContext()); @@ -311,7 +318,9 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { new NodeMetricSnapshot(Instant.ofEpochMilli(record.getTimestamp(1) / 1000), new Load(record.getFloat(2), record.getFloat(3), - record.getFloat(4)), + record.getFloat(4), + record.getFloat(9), + record.getFloat(10)), record.getLong(5), record.getBool(6), record.getBool(7), diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java index c4e7d3b9acc..6f325700401 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializer.java @@ -76,6 +76,8 @@ public class ApplicationSerializer { private static final String cpuKey = "cpu"; private static final String memoryKey = "memory"; private static final String diskKey = "disk"; + private static final String gpuKey = "gpu"; + private static final String gpuMemory = "gpuMemory"; private static final String fromKey = "from"; private static final String toKey = "to"; private static final String generationKey = "generation"; @@ -201,12 +203,16 @@ public class ApplicationSerializer { loadObject.setDouble(cpuKey, load.cpu()); loadObject.setDouble(memoryKey, load.memory()); loadObject.setDouble(diskKey, load.disk()); + loadObject.setDouble(gpuKey, load.gpu()); + loadObject.setDouble(gpuMemory, load.gpuMemory()); } private static Load loadFromSlime(Inspector loadObject) { return new Load(loadObject.field(cpuKey).asDouble(), loadObject.field(memoryKey).asDouble(), - loadObject.field(diskKey).asDouble()); + loadObject.field(diskKey).asDouble(), + loadObject.field(gpuKey).asDouble(), + loadObject.field(gpuMemory).asDouble()); } private static void toSlime(Autoscaling.Metrics metrics, Cursor metricsObject) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java index fe6b204ed31..d3b88997059 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java @@ -40,7 +40,6 @@ import com.yahoo.vespa.hosted.provision.applications.Cluster; import com.yahoo.vespa.hosted.provision.autoscale.Autoscaling; import com.yahoo.vespa.hosted.provision.autoscale.Load; import com.yahoo.vespa.hosted.provision.autoscale.MemoryMetricsDb; -import com.yahoo.vespa.hosted.provision.lb.LoadBalancerService; import com.yahoo.vespa.hosted.provision.node.Agent; import com.yahoo.vespa.hosted.provision.node.IP; import com.yahoo.vespa.hosted.provision.node.Status; @@ -239,8 +238,8 @@ public class MockNodeRepository extends NodeRepository { Optional.of(new ClusterResources(4, 1, new NodeResources(3, 16, 100, 1))), clock().instant(), - new Load(0.1, 0.2, 0.3), - new Load(0.4, 0.5, 0.6), + new Load(0.1, 0.2, 0.3, 0, 0), + new Load(0.4, 0.5, 0.6, 0, 0), new Autoscaling.Metrics(0.7, 0.8, 0.9))); try (Mutex lock = applications().lock(app1Id)) { applications().put(app1.with(cluster1), lock); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java index 0a26678d37e..b2e04ba2233 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepoStatsTest.java @@ -15,7 +15,6 @@ import com.yahoo.vespa.hosted.provision.autoscale.NodeMetricSnapshot; import com.yahoo.vespa.hosted.provision.provisioning.ProvisioningTester; import org.junit.Test; -import java.time.Duration; import java.util.List; import static org.junit.Assert.assertEquals; @@ -99,7 +98,7 @@ public class NodeRepoStatsTest { else { loadFactor = loadApp3; } - var snapshot = new NodeMetricSnapshot(now, new Load(1.0, 0.9, 0.8).multiply(loadFactor), 1, true, true, 1.0 ); + var snapshot = new NodeMetricSnapshot(now, new Load(1.0, 0.9, 0.8, 0, 0).multiply(loadFactor), 1, true, true, 1.0 ); tester.nodeRepository().metricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(), snapshot))); } @@ -108,8 +107,8 @@ public class NodeRepoStatsTest { assertEquals(26, stats.totalCost(), delta); assertEquals(8.319999999999999, stats.totalAllocatedCost(), delta); - assertLoad(new Load(0.6180,0.5562,0.4944), stats.load()); - assertLoad(new Load(0.4682,0.4214,0.3745), stats.activeLoad()); + assertLoad(new Load(0.6180,0.5562,0.4944, 0, 0), stats.load()); + assertLoad(new Load(0.4682,0.4214,0.3745, 0, 0), stats.activeLoad()); var app1Stats = stats.applicationStats().get(0); var app2Stats = stats.applicationStats().get(2); @@ -119,25 +118,27 @@ public class NodeRepoStatsTest { assertEquals(3.6400, app1Stats.cost(), delta); assertEquals(0.8676, app1Stats.utilizedCost(), delta); assertEquals(2.7724, app1Stats.unutilizedCost(), delta); - assertLoad(new Load(0.2571, 0.2314, 0.2057), app1Stats.load()); + assertLoad(new Load(0.2571, 0.2314, 0.2057, 0, 0), app1Stats.load()); assertEquals(app2, app2Stats.id()); assertEquals(2.0799, app2Stats.cost(), delta); assertEquals(0.7712, app2Stats.utilizedCost(), delta); assertEquals(1.3087, app2Stats.unutilizedCost(), delta); - assertLoad(new Load(.40, 0.36, 0.32), app2Stats.load()); + assertLoad(new Load(.40, 0.36, 0.32, 0, 0), app2Stats.load()); assertEquals(app3, app3Stats.id()); assertEquals(2.6000, app3Stats.cost(), delta); assertEquals(1.2049, app3Stats.utilizedCost(), delta); assertEquals(1.3950, app3Stats.unutilizedCost(), delta); - assertLoad(new Load(0.5, 0.45, 0.40), app3Stats.load()); + assertLoad(new Load(0.5, 0.45, 0.40, 0, 0), app3Stats.load()); } private static void assertLoad(Load expected, Load actual) { - assertEquals("cpu", expected.cpu(), actual.cpu(), delta); - assertEquals("memory", expected.memory(), actual.memory(), delta); - assertEquals("disk", expected.disk(), actual.disk(), delta); + assertEquals("cpu", expected.cpu(), actual.cpu(), delta); + assertEquals("memory", expected.memory(), actual.memory(), delta); + assertEquals("disk", expected.disk(), actual.disk(), delta); + assertEquals("gpu", expected.gpu(), actual.gpu(), delta); + assertEquals("gpuMemory", expected.gpuMemory(), actual.gpuMemory(), delta); } } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java index d4d34ab66e5..4236f7ac968 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java @@ -44,7 +44,7 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max)) .build(); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12), 1, true, true, 100); + fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12, 0, 0), 1, true, true, 100); var result = fixture.autoscale(); assertTrue(result.resources().isEmpty()); assertEquals(Autoscaling.Status.insufficient, result.status()); @@ -63,13 +63,13 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max)) .build(); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12), 1, true, true, 100); + fixture.loader().applyLoad(new Load(0.8f, 0.17, 0.12, 0, 0), 1, true, true, 100); var result = fixture.autoscale(); assertTrue(result.resources().isEmpty()); assertEquals(Autoscaling.Status.insufficient, result.status()); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.08f, 0.17, 0.12), 1, true, true, 100); + fixture.loader().applyLoad(new Load(0.08f, 0.17, 0.12, 0, 0), 1, true, true, 100); fixture.tester().assertResources("Scaling down", 8, 1, 16, 32, 200, fixture.autoscale()); @@ -128,8 +128,8 @@ public class AutoscalingTest { @Test public void test_autoscaling_up_is_fast() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); - fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1), 3); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 1); + fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1, 0, 0), 3); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 1); fixture.tester().assertResources("Scaling up since resource usage is too high", 8, 1, 5.3, 17.0, 75.1, fixture.autoscale()); @@ -148,7 +148,7 @@ public class AutoscalingTest { .build(); fixture.tester().setScalingDuration(fixture.applicationId(), fixture.clusterSpec.id(), Duration.ofMinutes(5)); - fixture.loader().applyLoad(new Load(0.01, 0.38, 0), 5); + fixture.loader().applyLoad(new Load(0.01, 0.38, 0, 0, 0), 5); fixture.tester().assertResources("Scaling down", 2, 1, 4, 8, 50, fixture.autoscale()); @@ -190,7 +190,7 @@ public class AutoscalingTest { public void test_only_autoscaling_up_quickly() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.setScalingDuration(Duration.ofHours(12)); // Fixture sets last completion to be 1 day into the past - fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0), 10); + fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0, 0, 0), 10); fixture.tester().assertResources("Scaling up (only) since resource usage is too high", 5, 1, 11.7, 14.9, 131.5, fixture.autoscale()); @@ -202,7 +202,7 @@ public class AutoscalingTest { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.setScalingDuration(Duration.ofHours(12)); // Fixture sets last completion to be 1 day into the past fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0), 10); + fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0, 0, 0), 10); fixture.tester().assertResources("Scaling cpu and disk up and memory down", 5, 1, 11.7, 4.0, 131.5, fixture.autoscale()); @@ -213,7 +213,7 @@ public class AutoscalingTest { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(false).build(); fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester.clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0), 10); + fixture.loader().applyLoad(new Load(1.0, 0.1, 1.0, 0, 0), 10); fixture.tester().assertResources("Scaling cpu and disk up, memory follows", 16, 1, 4, 8.0, 28.3, fixture.autoscale()); @@ -264,7 +264,7 @@ public class AutoscalingTest { .clusterType(ClusterSpec.Type.container) .awsProdSetup(false) .build(); - var duration = fixture.loader().addMeasurements(new Load(0.04, 0.39, 0.01), 20); + var duration = fixture.loader().addMeasurements(new Load(0.04, 0.39, 0.01, 0, 0), 20); fixture.tester().clock().advance(duration.negated()); fixture.loader().zeroTraffic(20, 1); fixture.tester().assertResources("Scaled down", @@ -358,7 +358,7 @@ public class AutoscalingTest { fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester().clock().advance(Duration.ofDays(1)); - fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95), 120); + fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95, 0, 0), 120); fixture.tester().assertResources("Scaling up to limit since resource usage is too high", 6, 1, 2.4, 78.0, 79.0, fixture.autoscale()); @@ -372,7 +372,7 @@ public class AutoscalingTest { // deploy fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.05f, 0.05f, 0.05f), 120); + fixture.loader().applyLoad(new Load(0.05f, 0.05f, 0.05f, 0, 0), 120); fixture.tester().assertResources("Scaling down to limit since resource usage is low", 4, 1, 1.8, 7.4, 23.4, fixture.autoscale()); @@ -395,7 +395,7 @@ public class AutoscalingTest { 2, 1, defaultResources, fixture.nodes().toResources()); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95), 120); + fixture.loader().applyLoad(new Load(0.25, 0.95, 0.95, 0, 0), 120); fixture.tester().assertResources("Scaling up", 5, 1, defaultResources.vcpu(), defaultResources.memoryGb(), defaultResources.diskGb(), @@ -461,7 +461,7 @@ public class AutoscalingTest { .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.01, 0.01, 0.01), 120); + fixture.loader().applyLoad(new Load(0.01, 0.01, 0.01, 0, 0), 120); Autoscaling suggestion = fixture.suggest(); fixture.tester().assertResources("Choosing the remote disk flavor as it has less disk", 2, 1, 3.0, 100.0, 10.0, @@ -498,7 +498,7 @@ public class AutoscalingTest { public void not_using_out_of_service_measurements() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7), 1, false, true, 120); + fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7, 0, 0), 1, false, true, 120); assertTrue("Not scaling up since nodes were measured while cluster was out of service", fixture.autoscale().resources().isEmpty()); } @@ -507,7 +507,7 @@ public class AutoscalingTest { public void not_using_unstable_measurements() { var fixture = DynamicProvisioningTester.fixture().awsProdSetup(true).build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7), 1, true, false, 120); + fixture.loader().applyLoad(new Load(0.9, 0.6, 0.7, 0, 0), 1, true, false, 120); assertTrue("Not scaling up since nodes were measured while cluster was unstable", fixture.autoscale().resources().isEmpty()); } @@ -536,7 +536,7 @@ public class AutoscalingTest { .build(); fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1), 120); + fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1, 0, 0), 120); fixture.tester().assertResources("Suggesting resources where disk is 3x memory (this is a content cluster)", 11, 1, 13.0, 60.0, 179.9, fixture.tester().suggest(fixture.applicationId, fixture.clusterSpec.id(), min, min)); @@ -557,7 +557,7 @@ public class AutoscalingTest { .build(); fixture.setScalingDuration(Duration.ofHours(6)); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1), 120); + fixture.loader().applyLoad(new Load(0.5, 0.8, 0.1, 0, 0), 120); fixture.tester().assertResources("Suggesting resources where disk is 3x memory (this is a content cluster)", 13, 1, 36.0, 72.0, 900.0, fixture.tester().suggest(fixture.applicationId, fixture.clusterSpec.id(), min, min)); @@ -668,7 +668,7 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max)) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.16, 0.02, 0.5), 120); + fixture.loader().applyLoad(new Load(0.16, 0.02, 0.5, 0, 0), 120); fixture.tester().assertResources("Scaling down memory", 6, 1, 2.1, 4.0, 96.2, fixture.autoscale()); @@ -826,7 +826,7 @@ public class AutoscalingTest { .zone(new Zone(Environment.dev, RegionName.from("us-east"))) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); assertTrue("Not attempting to scale up because policies dictate we'll only get one node", fixture.autoscale().resources().isEmpty()); } @@ -842,7 +842,7 @@ public class AutoscalingTest { .capacity(Capacity.from(min, max, IntRange.of(3, 5), false, true, Optional.empty(), ClusterInfo.empty())) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); assertEquals("Don't autoscale: Autoscaling is disabled in single node clusters", fixture.autoscale().toString()); } @@ -866,7 +866,7 @@ public class AutoscalingTest { .zone(new Zone(Environment.dev, RegionName.from("us-east"))) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); fixture.tester().assertResources("We scale even in dev because resources are 'required'", 3, 1, 1.0, 13.4, 62.5, fixture.autoscale()); @@ -889,7 +889,7 @@ public class AutoscalingTest { .zone(new Zone(Environment.dev, RegionName.from("us-east"))) .build(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0), 200); + fixture.loader().applyLoad(new Load(1.0, 1.0, 1.0, 0, 0), 200); fixture.tester().assertResources("We scale even in dev because resources are required", 3, 1, 1.5, 8, 50, fixture.autoscale()); @@ -927,13 +927,13 @@ public class AutoscalingTest { fixture.currentResources().advertisedResources()); fixture.tester().deploy(fixture.applicationId(), clusterSpec(false), fixture.capacity()); - fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1), 5); + fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1, 0, 0), 5); fixture.tester().assertResources("Exclusive nodes makes no difference here", 2, 1, 4, 8, 100.0, fixture.autoscale()); fixture.tester().deploy(fixture.applicationId(), clusterSpec(true), fixture.capacity()); - fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1), 5); + fixture.loader().applyLoad(new Load(0.1, 0.1, 0.1, 0, 0), 5); fixture.tester().assertResources("Reverts to the initial resources", 2, 1, 4, 8, 100, fixture.currentResources().advertisedResources()); @@ -952,7 +952,7 @@ public class AutoscalingTest { .build(); var initialNodes = fixture.nodes().asList(); fixture.tester().clock().advance(Duration.ofDays(2)); - fixture.loader().applyLoad(new Load(0.06, 0.52, 0.27), 100); + fixture.loader().applyLoad(new Load(0.06, 0.52, 0.27, 0, 0), 100); var autoscaling = fixture.autoscale(); fixture.tester().assertResources("Scaling down", 7, 1, 2, 15.8, 384.0, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java index 2e953a0f67c..8dc3945223f 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Loader.java @@ -49,7 +49,7 @@ public class Loader { var idealLoad = fixture.clusterModel().idealLoad(); NodeList nodes = fixture.nodes(); float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size()); - Load load = new Load(value, idealLoad.memory(), idealLoad.disk()).multiply(oneExtraNodeFactor); + Load load = new Load(value, idealLoad.memory(), idealLoad.disk(), 0, 0).multiply(oneExtraNodeFactor); Instant initialTime = fixture.tester().clock().instant(); for (int i = 0; i < count; i++) { fixture.tester().clock().advance(samplingInterval); @@ -101,7 +101,7 @@ public class Loader { var idealLoad = fixture.clusterModel().idealLoad(); NodeList nodes = fixture.nodes(); float oneExtraNodeFactor = (float)(nodes.size() - 1.0) / (nodes.size()); - Load load = new Load(idealLoad.cpu(), value, idealLoad.disk()).multiply(oneExtraNodeFactor); + Load load = new Load(idealLoad.cpu(), value, idealLoad.disk(), 0, 0).multiply(oneExtraNodeFactor); for (int i = 0; i < count; i++) { fixture.tester().clock().advance(samplingInterval); for (Node node : nodes) { diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java index 4ec4ecd6d84..a984306b577 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java @@ -99,6 +99,8 @@ public class MetricsV2MetricsFetcherTest { assertEquals("host-3.yahoo.com", values.get(0).getFirst()); assertEquals(0.13, values.get(0).getSecond().load().cpu(), delta); assertEquals(0.9375, values.get(0).getSecond().load().memory(), delta); + assertEquals(0.13, values.get(0).getSecond().load().gpu(), delta); + assertEquals(0.9375, values.get(0).getSecond().load().gpuMemory(), delta); assertFalse("Unstable because buckets are being merged", values.get(0).getSecond().stable()); } diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java index e8d1368de71..71ed5bafc3d 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/NodeMetricsDbTest.java @@ -40,7 +40,7 @@ public class NodeMetricsDbTest { Collection> values = new ArrayList<>(); for (int i = 0; i < 40; i++) { values.add(new Pair<>(node0, new NodeMetricSnapshot(clock.instant(), - new Load(0.9, 0.6, 0.6), + new Load(0.9, 0.6, 0.6, 0, 0), 0, true, false, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java index d52ec12d486..96588250674 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDbTest.java @@ -57,6 +57,8 @@ public class QuestMetricsDbTest { assertEquals(0.1, snapshot.load().cpu(), delta); assertEquals(0.2, snapshot.load().memory(), delta); assertEquals(0.4, snapshot.load().disk(), delta); + assertEquals(0.5, snapshot.load().gpu(), delta); + assertEquals(0.6, snapshot.load().gpuMemory(), delta); assertEquals(1, snapshot.generation(), delta); assertEquals(30, snapshot.queryRate(), delta); @@ -230,7 +232,7 @@ public class QuestMetricsDbTest { for (int i = 1; i <= countPerHost; i++) { for (String host : hosts) timeseries.add(new Pair<>(host, new NodeMetricSnapshot(clock.instant(), - new Load(i * 0.1, i * 0.2, i * 0.4), + new Load(i * 0.1, i * 0.2, i * 0.4, i * 0.5, i * 0.6), i % 100, true, true, @@ -244,7 +246,7 @@ public class QuestMetricsDbTest { Collection> timeseries = new ArrayList<>(); for (int i = 1; i <= countPerHost; i++) { for (String host : hosts) - timeseries.add(new Pair<>(host, new NodeMetricSnapshot(at, new Load(i * 0.1, i * 0.2, i * 0.4), + timeseries.add(new Pair<>(host, new NodeMetricSnapshot(at, new Load(i * 0.1, i * 0.2, i * 0.4, i * 0.5, i * 0.6), i % 100, true, false, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java index e4a712d3898..4f9b2de4da0 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/AutoscalingMaintainerTester.java @@ -77,7 +77,7 @@ public class AutoscalingMaintainerTester { for (Node node : nodes) nodeRepository().metricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(), new NodeMetricSnapshot(clock().instant(), - new Load(cpu, mem, disk), + new Load(cpu, mem, disk, 0, 0), generation, true, true, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java index d4771594569..152f743900b 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/MetricsReporterTest.java @@ -270,7 +270,7 @@ public class MetricsReporterTest { Optional.empty(), tester.clock().instant(), Load.zero(), - new Load(0.1, 0.2, 0.3), + new Load(0.1, 0.2, 0.3, 0, 0), Autoscaling.Metrics.zero())); tester.nodeRepository().applications().put(application.with(cluster), tester.nodeRepository().applications().lock(applicationId)); diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java index 0a78874405d..f8be27300fe 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/ScalingSuggestionsMaintainerTest.java @@ -139,7 +139,7 @@ public class ScalingSuggestionsMaintainerTest { for (Node node : nodes) nodeRepository.metricsDb().addNodeMetrics(List.of(new Pair<>(node.hostname(), new NodeMetricSnapshot(nodeRepository.clock().instant(), - new Load(cpu, memory, disk), + new Load(cpu, memory, disk, 0, 0), generation, true, true, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java index 7a00c84faf6..918a9043c93 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/ApplicationSerializerTest.java @@ -57,8 +57,8 @@ public class ApplicationSerializerTest { Optional.of(new ClusterResources(20, 10, new NodeResources(0.5, 4, 14, 16))), Instant.ofEpochMilli(1234L), - new Load(0.1, 0.2, 0.3), - new Load(0.4, 0.5, 0.6), + new Load(0.1, 0.2, 0.3, 0.4, 0.5), + new Load(0.4, 0.5, 0.6, 0.7, 0.8), new Autoscaling.Metrics(0.7, 0.8, 0.9)), new Autoscaling(Autoscaling.Status.insufficient, "Autoscaling status", -- cgit v1.2.3 From 7d7daee12ee6813c42af3f63f3467d7868572b66 Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Thu, 14 Dec 2023 14:15:59 +0100 Subject: Expose GPU load in nodes API --- .../provision/restapi/ApplicationSerializer.java | 2 ++ .../provision/restapi/NodesV2ApiHandler.java | 2 ++ .../provision/restapi/responses/application1.json | 16 +++++++++++---- .../provision/restapi/responses/application2.json | 8 ++++++-- .../hosted/provision/restapi/responses/stats.json | 24 ++++++++++++++++------ 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java index 225eb3e4e8d..89853896104 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java @@ -98,6 +98,8 @@ public class ApplicationSerializer { loadObject.setDouble("cpu", load.cpu()); loadObject.setDouble("memory", load.memory()); loadObject.setDouble("disk", load.disk()); + loadObject.setDouble("gpu", load.gpu()); + loadObject.setDouble("gpuMemory", load.gpuMemory()); } private static void toSlime(Autoscaling.Metrics metrics, Cursor metricsObject) { diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java index 9080030f026..0b157e8635b 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/NodesV2ApiHandler.java @@ -502,6 +502,8 @@ public class NodesV2ApiHandler extends ThreadedHttpRequestHandler { object.setDouble("cpu", load.cpu()); object.setDouble("memory", load.memory()); object.setDouble("disk", load.disk()); + object.setDouble("gpu", load.gpu()); + object.setDouble("gpuMemory", load.gpuMemory()); } /** Returns a copy of the given URI with the host and port from the given URI and the path set to the given path */ diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json index 28bde7bd966..7b2cf1dc8e4 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application1.json @@ -63,12 +63,16 @@ "peak" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0 + "disk" : 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "ideal" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0 + "disk" : 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "metrics" : { "queryRate" : 0.0, @@ -96,12 +100,16 @@ "peak" : { "cpu" : 0.1, "memory" : 0.2, - "disk" : 0.3 + "disk" : 0.3, + "gpu": 0.0, + "gpuMemory": 0.0 }, "ideal" : { "cpu" : 0.4, "memory" : 0.5, - "disk" : 0.6 + "disk" : 0.6, + "gpu": 0.0, + "gpuMemory": 0.0 }, "metrics" : { "queryRate" : 0.7, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json index 05a62ff944d..10173089f75 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/application2.json @@ -50,12 +50,16 @@ "peak" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0 + "disk" : 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "ideal" : { "cpu" : 0.0, "memory" : 0.0, - "disk" : 0.0 + "disk" : 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "metrics" : { "queryRate" : 0.0, diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json index 788eb6d359f..b031e0deba0 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/stats.json @@ -4,12 +4,16 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "activeLoad": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "applications": [ { @@ -17,7 +21,9 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 @@ -27,7 +33,9 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 @@ -37,7 +45,9 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 @@ -47,7 +57,9 @@ "load": { "cpu": 0.0, "memory": 0.0, - "disk": 0.0 + "disk": 0.0, + "gpu": 0.0, + "gpuMemory": 0.0 }, "cost": 0.0, "unutilizedCost": 0.0 -- cgit v1.2.3 From 9942838b7e6a671d572644a49c284c06bf685eb6 Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Wed, 20 Dec 2023 10:10:00 +0100 Subject: Handle missing value in new columns --- .../yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java index c0de9a43f7f..4d0bbb4e511 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/QuestMetricsDb.java @@ -319,8 +319,8 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { new Load(record.getFloat(2), record.getFloat(3), record.getFloat(4), - record.getFloat(9), - record.getFloat(10)), + getFloatOrDefault(record, 9, 0), + getFloatOrDefault(record, 10, 0)), record.getLong(5), record.getBool(6), record.getBool(7), @@ -332,6 +332,11 @@ public class QuestMetricsDb extends AbstractComponent implements MetricsDb { } } + private float getFloatOrDefault(Record record, int col, float defaultValue) { + float value = record.getFloat(col); + return Float.isNaN(value) ? defaultValue : value; + } + private ClusterTimeseries getClusterSnapshots(ApplicationId application, ClusterSpec.Id cluster) throws SqlException { String sql = "select * from " + clusterTable.name; var context = newContext(); -- cgit v1.2.3 From a48551952571c8d1fcbe21a73243ed13036a1937 Mon Sep 17 00:00:00 2001 From: Harald Musum Date: Wed, 20 Dec 2023 10:52:37 +0100 Subject: Cosmetic changes to log message --- .../RestartOnDeployForOnnxModelChangesValidator.java | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java index 398538d187f..e118a2940d7 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidator.java @@ -50,7 +50,8 @@ public class RestartOnDeployForOnnxModelChangesValidator implements ChangeValida if (enoughMemoryToAvoidRestart(clusterInCurrentModel, cluster, deployState.getDeployLogger())) continue; - log.log(FINE, "Validating " + cluster + ", current models=" + currentModels + ", next models=" + nextModels); + log.log(FINE, "Validating %s, current Onnx models:%s, next Onnx models:%s" + .formatted(cluster, currentModels, nextModels)); actions.addAll(validateModelChanges(cluster, currentModels, nextModels)); actions.addAll(validateSetOfModels(cluster, currentModels, nextModels)); } @@ -79,7 +80,7 @@ public class RestartOnDeployForOnnxModelChangesValidator implements ChangeValida List actions = new ArrayList<>(); Set currentModelIds = currentModels.keySet(); Set nextModelIds = nextModels.keySet(); - log.log(FINE, "Checking if model set has changed (%s) -> (%s)".formatted(currentModelIds, nextModelIds)); + log.log(FINE, "Checking if Onnx model set has changed (%s) -> (%s)".formatted(currentModelIds, nextModelIds)); if (! currentModelIds.equals(nextModelIds)) { String message = "Onnx model set has changed from %s to %s, need to restart services in %s" .formatted(currentModelIds, nextModelIds, cluster); @@ -116,20 +117,23 @@ public class RestartOnDeployForOnnxModelChangesValidator implements ChangeValida var availableMemoryPercentage = cluster.availableMemoryPercentage(); int memoryPercentage = (int) (availableMemory / totalMemory * availableMemoryPercentage); + var prefix = "Validating Onnx models memory usage for %s".formatted(cluster); if (memoryPercentage < percentLimit) { - deployLogger.log(INFO, "Validating %s, percentage of available memory too low (%d < %d) to avoid restart, consider a flavor with more memory to avoid this" - .formatted(cluster, memoryPercentage, percentLimit)); + deployLogger.log(INFO, ("%s, percentage of available memory " + + "too low (%d < %d) to avoid restart, consider a flavor with more memory to avoid this") + .formatted(prefix, memoryPercentage, percentLimit)); return false; } if (availableMemory < gbLimit) { - deployLogger.log(INFO, "Validating %s, available memory too low (%.2f Gb < %.2f Gb) to avoid restart, consider a flavor with more memory to avoid this" - .formatted(cluster, availableMemory, gbLimit)); + deployLogger.log(INFO, ("%s, available memory too low " + + "(%.2f Gb < %.2f Gb) to avoid restart, consider a flavor with more memory to avoid this") + .formatted(prefix, availableMemory, gbLimit)); return false; } - log.log(FINE, "Validating %s, enough available memory (%.2f Gb) to avoid restart (models use %.2f Gb)" - .formatted(cluster, availableMemory, memoryUsedByModels)); + log.log(FINE, "%s, enough available memory (%.2f Gb) to avoid restart (models use %.2f Gb)" + .formatted(prefix, availableMemory, memoryUsedByModels)); return true; } -- cgit v1.2.3 From 2cf8d8faf2193a57fbe324d5293c5d3ed739b3be Mon Sep 17 00:00:00 2001 From: Henning Baldersheim Date: Wed, 20 Dec 2023 10:31:21 +0000 Subject: - Having expensive asserts during shutdown is not worthwhile. It does not prevent persisting any errors, nor does it provide any information about what went wrong. --- searchcore/src/vespa/searchcore/proton/bucketdb/bucketdb.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/searchcore/src/vespa/searchcore/proton/bucketdb/bucketdb.cpp b/searchcore/src/vespa/searchcore/proton/bucketdb/bucketdb.cpp index ddc6441210a..148877ed6cc 100644 --- a/searchcore/src/vespa/searchcore/proton/bucketdb/bucketdb.cpp +++ b/searchcore/src/vespa/searchcore/proton/bucketdb/bucketdb.cpp @@ -62,7 +62,6 @@ BucketDB::checkActiveCount() const { void BucketDB::unloadBucket(BucketId bucket, const BucketState &delta) { - checkActiveCount(); BucketState *state = getBucketStatePtr(bucket); assert(state); *state -= delta; -- cgit v1.2.3 From 6a186753da0755719430cf8e1928b5c640eb215f Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 10:39:46 +0000 Subject: Update dependency eslint-plugin-prettier to v5.1.0 --- client/js/app/yarn.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/client/js/app/yarn.lock b/client/js/app/yarn.lock index dff60b31ec5..c06265edaa1 100644 --- a/client/js/app/yarn.lock +++ b/client/js/app/yarn.lock @@ -1204,7 +1204,7 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@pkgr/utils@^2.3.1": +"@pkgr/utils@^2.4.2": version "2.4.2" resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc" integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw== @@ -1900,9 +1900,9 @@ base@^0.11.1: pascalcase "^0.1.1" big-integer@^1.6.44: - version "1.6.51" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" - integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + version "1.6.52" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" + integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== bplist-parser@^0.2.0: version "0.2.0" @@ -2564,9 +2564,9 @@ eslint-plugin-import@^2: tsconfig-paths "^3.15.0" eslint-plugin-prettier@^5: - version "5.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz#a3b399f04378f79f066379f544e42d6b73f11515" - integrity sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg== + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.0.tgz#f14bb2b18756ad54f1ad3dc4c989cb73dfa326a3" + integrity sha512-hQc+2zbnMeXcIkg+pKZtVa+3Yqx4WY7SMkn1PLZ4VbBEU7jJIpVn9347P8BBhTbz6ne85aXvQf30kvexcqBeWw== dependencies: prettier-linter-helpers "^1.0.0" synckit "^0.8.5" @@ -2842,9 +2842,9 @@ fast-diff@^1.1.2: integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== fast-glob@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -2863,9 +2863,9 @@ fast-levenshtein@^2.0.6: integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== fastq@^1.6.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" - integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + version "1.16.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.16.0.tgz#83b9a9375692db77a822df081edb6a9cf6839320" + integrity sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA== dependencies: reusify "^1.0.4" @@ -5442,12 +5442,12 @@ supports-preserve-symlinks-flag@^1.0.0: integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== synckit@^0.8.5: - version "0.8.5" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3" - integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q== + version "0.8.6" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.6.tgz#b69b7fbce3917c2673cbdc0d87fb324db4a5b409" + integrity sha512-laHF2savN6sMeHCjLRkheIU4wo3Zg9Ln5YOjOo7sZ5dVQW8yF5pPE5SIw1dsPhq3TRp1jisKRCdPhfs/1WMqDA== dependencies: - "@pkgr/utils" "^2.3.1" - tslib "^2.5.0" + "@pkgr/utils" "^2.4.2" + tslib "^2.6.2" tabbable@^6.0.1: version "6.2.0" @@ -5525,7 +5525,7 @@ tsconfig-paths@^3.15.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.0.0, tslib@^2.5.0, tslib@^2.6.0: +tslib@^2.0.0, tslib@^2.6.0, tslib@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== -- cgit v1.2.3 From 29225f7f44b596c0220dcecc90fa3289d73064b6 Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Wed, 20 Dec 2023 15:05:05 +0100 Subject: Print less severe message for incomplete deployment --- client/go/internal/cli/cmd/root.go | 7 ++++++- client/go/internal/cli/cmd/status.go | 6 +++++- client/go/internal/cli/cmd/status_test.go | 8 ++++---- client/go/internal/vespa/target.go | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/client/go/internal/cli/cmd/root.go b/client/go/internal/cli/cmd/root.go index 383ce7dd28d..8e0f3de4f72 100644 --- a/client/go/internal/cli/cmd/root.go +++ b/client/go/internal/cli/cmd/root.go @@ -69,6 +69,7 @@ type CLI struct { // the error. type ErrCLI struct { Status int + warn bool quiet bool hints []string error @@ -599,7 +600,11 @@ func (c *CLI) Run(args ...string) error { if err != nil { if cliErr, ok := err.(ErrCLI); ok { if !cliErr.quiet { - c.printErr(cliErr, cliErr.hints...) + if cliErr.warn { + c.printWarning(cliErr, cliErr.hints...) + } else { + c.printErr(cliErr, cliErr.hints...) + } } } else { c.printErr(err) diff --git a/client/go/internal/cli/cmd/status.go b/client/go/internal/cli/cmd/status.go index 29a4a5775db..6056ee439b2 100644 --- a/client/go/internal/cli/cmd/status.go +++ b/client/go/internal/cli/cmd/status.go @@ -176,7 +176,11 @@ $ vespa status deployment -t local [session-id] --wait 600 waiter := cli.waiter(time.Duration(waitSecs) * time.Second) id, err := waiter.Deployment(t, wantedID) if err != nil { - return err + var hints []string + if waiter.Timeout == 0 { + hints = []string{"Consider using the --wait flag to wait for completion"} + } + return ErrCLI{Status: 1, warn: true, hints: hints, error: err} } if t.IsCloud() { log.Printf("Deployment run %s has completed", color.CyanString(strconv.FormatInt(id, 10))) diff --git a/client/go/internal/cli/cmd/status_test.go b/client/go/internal/cli/cmd/status_test.go index 3c6277b9050..5ef96c462d8 100644 --- a/client/go/internal/cli/cmd/status_test.go +++ b/client/go/internal/cli/cmd/status_test.go @@ -85,7 +85,7 @@ func TestStatusError(t *testing.T) { cli.httpClient = client assert.NotNil(t, cli.Run("status", "container")) assert.Equal(t, - "Container default at http://127.0.0.1:8080 is not ready: unhealthy container default: status 500 at http://127.0.0.1:8080/status.html: wait timed out\n", + "Container default at http://127.0.0.1:8080 is not ready: unhealthy container default: status 500 at http://127.0.0.1:8080/status.html: giving up\n", stdout.String()) assert.Equal(t, "Error: services not ready: default\n", @@ -122,13 +122,13 @@ func TestStatusLocalDeployment(t *testing.T) { resp.Body = []byte(`{"currentGeneration": 42, "converged": false}`) client.NextResponse(resp) assert.NotNil(t, cli.Run("status", "deployment")) - assert.Equal(t, "Error: deployment not converged on latest generation: wait timed out\n", stderr.String()) + assert.Equal(t, "Warning: deployment not converged on latest generation: giving up\nHint: Consider using the --wait flag to wait for completion\n", stderr.String()) // Explicit generation stderr.Reset() client.NextResponse(resp) assert.NotNil(t, cli.Run("status", "deployment", "41")) - assert.Equal(t, "Error: deployment not converged on generation 41: wait timed out\n", stderr.String()) + assert.Equal(t, "Warning: deployment not converged on generation 41: giving up\nHint: Consider using the --wait flag to wait for completion\n", stderr.String()) } func TestStatusCloudDeployment(t *testing.T) { @@ -164,7 +164,7 @@ func TestStatusCloudDeployment(t *testing.T) { Body: []byte(`{"active": false, "status": "failure"}`), }) assert.NotNil(t, cli.Run("status", "deployment", "42", "-w", "10")) - assert.Equal(t, "Waiting up to 10s for deployment to converge...\nError: deployment run 42 incomplete after waiting up to 10s: aborting wait: run 42 ended with unsuccessful status: failure\n", stderr.String()) + assert.Equal(t, "Waiting up to 10s for deployment to converge...\nWarning: deployment run 42 incomplete after waiting up to 10s: aborting wait: run 42 ended with unsuccessful status: failure\n", stderr.String()) } func isLocalTarget(args []string) bool { diff --git a/client/go/internal/vespa/target.go b/client/go/internal/vespa/target.go index 543ce2f4a29..36f69583b9a 100644 --- a/client/go/internal/vespa/target.go +++ b/client/go/internal/vespa/target.go @@ -36,7 +36,7 @@ const ( AnyDeployment int64 = -2 ) -var errWaitTimeout = errors.New("wait timed out") +var errWaitTimeout = errors.New("giving up") var errAuth = errors.New("auth failed") // Authenticator authenticates the given HTTP request. -- cgit v1.2.3 From 72240d0834661eca88265449bb67dd431c765342 Mon Sep 17 00:00:00 2001 From: Martin Polden Date: Wed, 20 Dec 2023 15:09:56 +0100 Subject: Increase default timeout --- client/go/internal/vespa/target.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/go/internal/vespa/target.go b/client/go/internal/vespa/target.go index 36f69583b9a..90d1e1997da 100644 --- a/client/go/internal/vespa/target.go +++ b/client/go/internal/vespa/target.go @@ -255,7 +255,7 @@ func wait(service *Service, okFn responseFunc, reqFn requestFunc, timeout, retry deadline := time.Now().Add(timeout) loopOnce := timeout == 0 for time.Now().Before(deadline) || loopOnce { - response, err = service.Do(reqFn(), 10*time.Second) + response, err = service.Do(reqFn(), 20*time.Second) if errors.Is(err, errAuth) { return status, fmt.Errorf("aborting wait: %w", err) } else if err == nil { -- cgit v1.2.3 From b845595dc7f07f411a94a4691b388468a5bc3d89 Mon Sep 17 00:00:00 2001 From: HÃ¥vard Pettersen Date: Tue, 19 Dec 2023 17:54:34 +0000 Subject: enable sorting on cost --- .../searchcore/proton/matching/match_tools.cpp | 6 +- .../src/vespa/searchcore/proton/matching/query.cpp | 7 +- .../src/vespa/searchcore/proton/matching/query.h | 3 +- .../tests/queryeval/blueprint/blueprint_test.cpp | 23 ++++-- .../blueprint/intermediate_blueprints_test.cpp | 83 ++++++++++++---------- .../queryeval/filter_search/filter_search_test.cpp | 2 +- .../queryeval/same_element/same_element_test.cpp | 2 +- .../src/vespa/searchlib/queryeval/blueprint.cpp | 20 +++--- .../src/vespa/searchlib/queryeval/blueprint.h | 26 +++++-- .../queryeval/intermediate_blueprints.cpp | 62 +++++++++------- .../searchlib/queryeval/intermediate_blueprints.h | 24 +++---- .../searchlib/queryeval/same_element_blueprint.cpp | 2 +- .../searchlib/queryeval/same_element_blueprint.h | 2 +- 13 files changed, 157 insertions(+), 105 deletions(-) diff --git a/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp b/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp index b5224281724..565604826ee 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp +++ b/searchcore/src/vespa/searchcore/proton/matching/match_tools.cpp @@ -203,7 +203,8 @@ MatchToolsFactory(QueryLimiter & queryLimiter, trace.addEvent(5, "Build query execution plan"); _query.reserveHandles(_requestContext, searchContext, _mdl); trace.addEvent(5, "Optimize query execution plan"); - _query.optimize(SortBlueprintsByCost::check(_queryEnv.getProperties(), rankSetup.sort_blueprints_by_cost())); + bool sort_by_cost = SortBlueprintsByCost::check(_queryEnv.getProperties(), rankSetup.sort_blueprints_by_cost()); + _query.optimize(sort_by_cost); trace.addEvent(4, "Perform dictionary lookups and posting lists initialization"); double hitRate = std::min(1.0, double(maxNumHits)/double(searchContext.getDocIdLimit())); bool create_postinglist_when_non_strict = CreatePostingListWhenNonStrict::check(_queryEnv.getProperties(), rankSetup.create_postinglist_when_non_strict()); @@ -216,7 +217,8 @@ MatchToolsFactory(QueryLimiter & queryLimiter, _query.handle_global_filter(_requestContext, searchContext.getDocIdLimit(), _attribute_blueprint_params.global_filter_lower_limit, _attribute_blueprint_params.global_filter_upper_limit, - trace, create_postinglist_when_non_strict, use_estimate_for_fetch_postings); + trace, create_postinglist_when_non_strict, use_estimate_for_fetch_postings, + sort_by_cost); } _query.freeze(); trace.addEvent(5, "Prepare shared state for multi-threaded rank executors"); diff --git a/searchcore/src/vespa/searchcore/proton/matching/query.cpp b/searchcore/src/vespa/searchcore/proton/matching/query.cpp index 149828b0a91..dfa1bd91157 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/query.cpp +++ b/searchcore/src/vespa/searchcore/proton/matching/query.cpp @@ -201,7 +201,7 @@ void Query::optimize(bool sort_by_cost) { (void) sort_by_cost; - _blueprint = Blueprint::optimize(std::move(_blueprint)); + _blueprint = Blueprint::optimize(std::move(_blueprint), sort_by_cost); LOG(debug, "optimized blueprint:\n%s\n", _blueprint->asString().c_str()); } @@ -215,7 +215,8 @@ void Query::handle_global_filter(const IRequestContext & requestContext, uint32_t docid_limit, double global_filter_lower_limit, double global_filter_upper_limit, search::engine::Trace& trace, - bool create_postinglist_when_non_strict, bool use_estimate_for_fetch_postings) + bool create_postinglist_when_non_strict, bool use_estimate_for_fetch_postings, + bool sort_by_cost) { if (!handle_global_filter(*_blueprint, docid_limit, global_filter_lower_limit, global_filter_upper_limit, requestContext.thread_bundle(), &trace)) @@ -224,7 +225,7 @@ Query::handle_global_filter(const IRequestContext & requestContext, uint32_t doc } // optimized order may change after accounting for global filter: trace.addEvent(5, "Optimize query execution plan to account for global filter"); - _blueprint = Blueprint::optimize(std::move(_blueprint)); + _blueprint = Blueprint::optimize(std::move(_blueprint), sort_by_cost); LOG(debug, "blueprint after handle_global_filter:\n%s\n", _blueprint->asString().c_str()); // strictness may change if optimized order changed: fetchPostings(ExecuteInfo::create(true, 1.0, requestContext.getDoom(), requestContext.thread_bundle(), diff --git a/searchcore/src/vespa/searchcore/proton/matching/query.h b/searchcore/src/vespa/searchcore/proton/matching/query.h index 8062f12b70d..b468b4b8f33 100644 --- a/searchcore/src/vespa/searchcore/proton/matching/query.h +++ b/searchcore/src/vespa/searchcore/proton/matching/query.h @@ -109,7 +109,8 @@ public: void handle_global_filter(const IRequestContext & requestContext, uint32_t docid_limit, double global_filter_lower_limit, double global_filter_upper_limit, search::engine::Trace& trace, - bool create_postinglist_when_non_strict, bool use_estimate_for_fetch_postings); + bool create_postinglist_when_non_strict, bool use_estimate_for_fetch_postings, + bool sort_by_cost); /** * Calculates and handles the global filter if needed by the blueprint tree. diff --git a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp index eefca5c82e9..f800e124bdc 100644 --- a/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp +++ b/searchlib/src/tests/queryeval/blueprint/blueprint_test.cpp @@ -1,6 +1,7 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "mysearch.h" #include +#include #include #include #include @@ -22,8 +23,12 @@ class MyOr : public IntermediateBlueprint { private: public: - double calculate_cost() const final { return 1.0; } - double calculate_relative_estimate() const final { return 0.5; } + double calculate_cost() const final { + return cost_of(get_children(), OrFlow()); + } + double calculate_relative_estimate() const final { + return estimate_of(get_children(), OrFlow()); + } HitEstimate combine(const std::vector &data) const override { return max(data); } @@ -32,7 +37,7 @@ public: return mixChildrenFields(); } - void sort(Children &children) const override { + void sort(Children &children, bool) const override { std::sort(children.begin(), children.end(), TieredGreaterEstimate()); } @@ -440,7 +445,8 @@ TEST_F("testChildAndNotCollapsing", Fixture) ) ); TEST_DO(f.check_not_equal(*sorted, *unsorted)); - unsorted = Blueprint::optimize(std::move(unsorted)); + unsorted->setDocIdLimit(1000); + unsorted = Blueprint::optimize(std::move(unsorted), true); TEST_DO(f.check_equal(*sorted, *unsorted)); } @@ -479,7 +485,8 @@ TEST_F("testChildAndCollapsing", Fixture) ); TEST_DO(f.check_not_equal(*sorted, *unsorted)); - unsorted = Blueprint::optimize(std::move(unsorted)); + unsorted->setDocIdLimit(1000); + unsorted = Blueprint::optimize(std::move(unsorted), true); TEST_DO(f.check_equal(*sorted, *unsorted)); } @@ -517,7 +524,8 @@ TEST_F("testChildOrCollapsing", Fixture) .add(MyLeafSpec(1).addField(2, 42).create()) ); TEST_DO(f.check_not_equal(*sorted, *unsorted)); - unsorted = Blueprint::optimize(std::move(unsorted)); + unsorted->setDocIdLimit(1000); + unsorted = Blueprint::optimize(std::move(unsorted), true); TEST_DO(f.check_equal(*sorted, *unsorted)); } @@ -560,7 +568,8 @@ TEST_F("testChildSorting", Fixture) ); TEST_DO(f.check_not_equal(*sorted, *unsorted)); - unsorted = Blueprint::optimize(std::move(unsorted)); + unsorted->setDocIdLimit(1000); + unsorted = Blueprint::optimize(std::move(unsorted), true); TEST_DO(f.check_equal(*sorted, *unsorted)); } diff --git a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp index 234ff5a9d19..ab1c004c721 100644 --- a/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp +++ b/searchlib/src/tests/queryeval/blueprint/intermediate_blueprints_test.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -75,7 +76,8 @@ void check_sort_order(IntermediateBlueprint &self, BlueprintVector children, std for (const auto & child: children) { unordered.push_back(child.get()); } - self.sort(children); + // TODO: sort by cost (requires both setDocIdLimit and optimize to be called) + self.sort(children, false); for (size_t i = 0; i < children.size(); ++i) { EXPECT_EQUAL(children[i].get(), unordered[order[i]]); } @@ -129,7 +131,7 @@ TEST("test AndNot Blueprint") { template void optimize(std::unique_ptr &ref) { - auto optimized = Blueprint::optimize(std::move(ref)); + auto optimized = Blueprint::optimize(std::move(ref), true); ref.reset(dynamic_cast(optimized.get())); ASSERT_TRUE(ref); optimized.release(); @@ -141,8 +143,8 @@ TEST("test And propagates updated histestimate") { bp->addChild(ap(MyLeafSpec(20).create()->setSourceId(2))); bp->addChild(ap(MyLeafSpec(200).create()->setSourceId(2))); bp->addChild(ap(MyLeafSpec(2000).create()->setSourceId(2))); - optimize(bp); bp->setDocIdLimit(5000); + optimize(bp); bp->fetchPostings(ExecuteInfo::TRUE); EXPECT_EQUAL(3u, bp->childCnt()); for (uint32_t i = 0; i < bp->childCnt(); i++) { @@ -161,8 +163,8 @@ TEST("test Or propagates updated histestimate") { bp->addChild(ap(MyLeafSpec(2000).create()->setSourceId(2))); bp->addChild(ap(MyLeafSpec(800).create()->setSourceId(2))); bp->addChild(ap(MyLeafSpec(20).create()->setSourceId(2))); - optimize(bp); bp->setDocIdLimit(5000); + optimize(bp); bp->fetchPostings(ExecuteInfo::TRUE); EXPECT_EQUAL(4u, bp->childCnt()); for (uint32_t i = 0; i < bp->childCnt(); i++) { @@ -514,36 +516,45 @@ vespalib::string to_str(const Inspector &value) { } void compare(const Blueprint &bp1, const Blueprint &bp2, bool expect_eq) { - auto ignore_cost = [expect_eq](const auto &path, const auto &a, const auto &b) { - if (!path.empty() && std::holds_alternative(path.back())) { - vespalib::stringref field = std::get(path.back()); - if (field == "cost") { - return true; - } - } - if (expect_eq) { - fprintf(stderr, " mismatch at %s: %s vs %s\n", path_to_str(path).c_str(), - to_str(a).c_str(), to_str(b).c_str()); - } - return false; - }; + auto cmp_hook = [expect_eq](const auto &path, const auto &a, const auto &b) { + if (!path.empty() && std::holds_alternative(path.back())) { + vespalib::stringref field = std::get(path.back()); + if (field == "cost") { + return true; + } + if (field == "relative_estimate") { + double a_val = a.asDouble(); + double b_val = b.asDouble(); + if (a_val != 0.0 && b_val != 0.0 && vespalib::approx_equal(a_val, b_val)) { + return true; + } + } + } + if (expect_eq) { + fprintf(stderr, " mismatch at %s: %s vs %s\n", path_to_str(path).c_str(), + to_str(a).c_str(), to_str(b).c_str()); + } + return false; + }; Slime a; Slime b; bp1.asSlime(SlimeInserter(a)); bp2.asSlime(SlimeInserter(b)); if (expect_eq) { - EXPECT_TRUE(vespalib::slime::are_equal(a.get(), b.get(), ignore_cost)); + EXPECT_TRUE(vespalib::slime::are_equal(a.get(), b.get(), cmp_hook)); } else { - EXPECT_FALSE(vespalib::slime::are_equal(a.get(), b.get(), ignore_cost)); + EXPECT_FALSE(vespalib::slime::are_equal(a.get(), b.get(), cmp_hook)); } } void -optimize_and_compare(Blueprint::UP top, Blueprint::UP expect) { +optimize_and_compare(Blueprint::UP top, Blueprint::UP expect, bool sort_by_cost = true) { + top->setDocIdLimit(1000); + expect->setDocIdLimit(1000); TEST_DO(compare(*top, *expect, false)); - top = Blueprint::optimize(std::move(top)); + top = Blueprint::optimize(std::move(top), sort_by_cost); TEST_DO(compare(*top, *expect, true)); - expect = Blueprint::optimize(std::move(expect)); + expect = Blueprint::optimize(std::move(expect), sort_by_cost); TEST_DO(compare(*expect, *top, true)); } @@ -670,11 +681,11 @@ TEST("test empty root node optimization and safeness") { //------------------------------------------------------------------------- auto expect_up = std::make_unique(); - EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top1))->asString()); - EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top2))->asString()); - EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top3))->asString()); - EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top4))->asString()); - EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top5))->asString()); + EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top1), true)->asString()); + EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top2), true)->asString()); + EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top3), true)->asString()); + EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top4), true)->asString()); + EXPECT_EQUAL(expect_up->asString(), Blueprint::optimize(std::move(top5), true)->asString()); } TEST("and with one empty child is optimized away") { @@ -682,7 +693,7 @@ TEST("and with one empty child is optimized away") { Blueprint::UP top = ap((new SourceBlenderBlueprint(*selector))-> addChild(ap(MyLeafSpec(10).create())). addChild(addLeafs(std::make_unique(), {{0, true}, 10, 20}))); - top = Blueprint::optimize(std::move(top)); + top = Blueprint::optimize(std::move(top), true); Blueprint::UP expect_up(ap((new SourceBlenderBlueprint(*selector))-> addChild(ap(MyLeafSpec(10).create())). addChild(std::make_unique()))); @@ -857,8 +868,8 @@ TEST("require that replaced blueprints retain source id") { addChild(ap(MyLeafSpec(30).create()->setSourceId(55))))); Blueprint::UP expect2_up(ap(MyLeafSpec(30).create()->setSourceId(42))); //------------------------------------------------------------------------- - top1_up = Blueprint::optimize(std::move(top1_up)); - top2_up = Blueprint::optimize(std::move(top2_up)); + top1_up = Blueprint::optimize(std::move(top1_up), true); + top2_up = Blueprint::optimize(std::move(top2_up), true); EXPECT_EQUAL(expect1_up->asString(), top1_up->asString()); EXPECT_EQUAL(expect2_up->asString(), top2_up->asString()); EXPECT_EQUAL(13u, top1_up->getSourceId()); @@ -1177,7 +1188,7 @@ TEST("require that children of near are not optimized") { auto expect_up = ap((new NearBlueprint(10))-> addChild(addLeafs(std::make_unique(), {20, {0, true}})). addChild(addLeafs(std::make_unique(), {{0, true}, 30}))); - top_up = Blueprint::optimize(std::move(top_up)); + top_up = Blueprint::optimize(std::move(top_up), true); TEST_DO(compare(*top_up, *expect_up, true)); } @@ -1188,27 +1199,27 @@ TEST("require that children of onear are not optimized") { auto expect_up = ap((new ONearBlueprint(10))-> addChild(addLeafs(std::make_unique(), {20, {0, true}})). addChild(addLeafs(std::make_unique(), {{0, true}, 30}))); - top_up = Blueprint::optimize(std::move(top_up)); + top_up = Blueprint::optimize(std::move(top_up), true); TEST_DO(compare(*top_up, *expect_up, true)); } TEST("require that ANDNOT without children is optimized to empty search") { Blueprint::UP top_up = std::make_unique(); auto expect_up = std::make_unique(); - top_up = Blueprint::optimize(std::move(top_up)); + top_up = Blueprint::optimize(std::move(top_up), true); EXPECT_EQUAL(expect_up->asString(), top_up->asString()); } TEST("require that highest cost tier sorts last for OR") { Blueprint::UP top = addLeafsWithCostTier(std::make_unique(), {{50, 1}, {30, 3}, {20, 2}, {10, 1}}); Blueprint::UP expect = addLeafsWithCostTier(std::make_unique(), {{50, 1}, {10, 1}, {20, 2}, {30, 3}}); - optimize_and_compare(std::move(top), std::move(expect)); + optimize_and_compare(std::move(top), std::move(expect), false); } TEST("require that highest cost tier sorts last for AND") { Blueprint::UP top = addLeafsWithCostTier(std::make_unique(), {{10, 1}, {20, 3}, {30, 2}, {50, 1}}); Blueprint::UP expect = addLeafsWithCostTier(std::make_unique(), {{10, 1}, {50, 1}, {30, 2}, {20, 3}}); - optimize_and_compare(std::move(top), std::move(expect)); + optimize_and_compare(std::move(top), std::move(expect), false); } template @@ -1325,7 +1336,7 @@ void verify_cost(make &&mk, double expect) { .cost(1.2).leaf(300) .cost(1.3).leaf(500); bp->setDocIdLimit(1000); - bp = Blueprint::optimize(std::move(bp)); + bp = Blueprint::optimize(std::move(bp), true); EXPECT_EQUAL(bp->cost(), expect); } diff --git a/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp b/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp index f910ff5be1b..1180206279d 100644 --- a/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp +++ b/searchlib/src/tests/queryeval/filter_search/filter_search_test.cpp @@ -48,7 +48,7 @@ concept ChildCollector = requires(T a, std::unique_ptr bp) { // inherit Blueprint to capture the default filter factory struct DefaultBlueprint : Blueprint { double calculate_relative_estimate() const override { abort(); } - void optimize(Blueprint* &, OptimizePass) override { abort(); } + void optimize(Blueprint* &, OptimizePass, bool) override { abort(); } const State &getState() const override { abort(); } void fetchPostings(const ExecuteInfo &) override { abort(); } void freeze() override { abort(); } diff --git a/searchlib/src/tests/queryeval/same_element/same_element_test.cpp b/searchlib/src/tests/queryeval/same_element/same_element_test.cpp index d05e6c8e4f4..7c535e5d3d5 100644 --- a/searchlib/src/tests/queryeval/same_element/same_element_test.cpp +++ b/searchlib/src/tests/queryeval/same_element/same_element_test.cpp @@ -46,7 +46,7 @@ std::unique_ptr make_blueprint(const std::vectorfetchPostings(ExecuteInfo::createForTest(strict)); result->freeze(); return result; diff --git a/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp index 71d53ade2f7..ee383f18ea4 100644 --- a/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/blueprint.cpp @@ -130,15 +130,15 @@ Blueprint::Blueprint() noexcept Blueprint::~Blueprint() = default; Blueprint::UP -Blueprint::optimize(Blueprint::UP bp) { +Blueprint::optimize(Blueprint::UP bp, bool sort_by_cost) { Blueprint *root = bp.release(); - root->optimize(root, OptimizePass::FIRST); - root->optimize(root, OptimizePass::LAST); + root->optimize(root, OptimizePass::FIRST, sort_by_cost); + root->optimize(root, OptimizePass::LAST, sort_by_cost); return Blueprint::UP(root); } void -Blueprint::optimize_self(OptimizePass) +Blueprint::optimize_self(OptimizePass, bool) { } @@ -549,19 +549,19 @@ IntermediateBlueprint::should_do_termwise_eval(const UnpackInfo &unpack, double } void -IntermediateBlueprint::optimize(Blueprint* &self, OptimizePass pass) +IntermediateBlueprint::optimize(Blueprint* &self, OptimizePass pass, bool sort_by_cost) { assert(self == this); if (should_optimize_children()) { for (auto &child : _children) { auto *child_ptr = child.release(); - child_ptr->optimize(child_ptr, pass); + child_ptr->optimize(child_ptr, pass, sort_by_cost); child.reset(child_ptr); } } - optimize_self(pass); + optimize_self(pass, sort_by_cost); if (pass == OptimizePass::LAST) { - sort(_children); + sort(_children, sort_by_cost); set_cost(calculate_cost()); } maybe_eliminate_self(self, get_replacement()); @@ -759,10 +759,10 @@ LeafBlueprint::getRange(vespalib::string &, vespalib::string &) const { } void -LeafBlueprint::optimize(Blueprint* &self, OptimizePass pass) +LeafBlueprint::optimize(Blueprint* &self, OptimizePass pass, bool sort_by_cost) { assert(self == this); - optimize_self(pass); + optimize_self(pass, sort_by_cost); maybe_eliminate_self(self, get_replacement()); } diff --git a/searchlib/src/vespa/searchlib/queryeval/blueprint.h b/searchlib/src/vespa/searchlib/queryeval/blueprint.h index 66d55015f62..7caeeddd01c 100644 --- a/searchlib/src/vespa/searchlib/queryeval/blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/blueprint.h @@ -172,6 +172,20 @@ public: // lower limit for docid_limit: max child estimate static HitEstimate sat_sum(const std::vector &data, uint32_t docid_limit); + // sort children to minimize total cost of OR flow + struct MinimalOrCost { + bool operator () (const auto &a, const auto &b) const noexcept { + return a->estimate() / a->cost() > b->estimate() / b->cost(); + } + }; + + // sort children to minimize total cost of AND flow + struct MinimalAndCost { + bool operator () (const auto &a, const auto &b) const noexcept { + return (1.0 - a->estimate()) / a->cost() > (1.0 - b->estimate()) / b->cost(); + } + }; + // utility to get the greater estimate to sort first, higher tiers last struct TieredGreaterEstimate { bool operator () (const auto &a, const auto &b) const noexcept { @@ -246,9 +260,9 @@ public: virtual void setDocIdLimit(uint32_t limit) noexcept { _docid_limit = limit; } uint32_t get_docid_limit() const noexcept { return _docid_limit; } - static Blueprint::UP optimize(Blueprint::UP bp); - virtual void optimize(Blueprint* &self, OptimizePass pass) = 0; - virtual void optimize_self(OptimizePass pass); + static Blueprint::UP optimize(Blueprint::UP bp, bool sort_by_cost); + virtual void optimize(Blueprint* &self, OptimizePass pass, bool sort_by_cost) = 0; + virtual void optimize_self(OptimizePass pass, bool sort_by_cost); virtual Blueprint::UP get_replacement(); virtual bool should_optimize_children() const { return true; } @@ -376,7 +390,7 @@ public: void setDocIdLimit(uint32_t limit) noexcept final; - void optimize(Blueprint* &self, OptimizePass pass) final; + void optimize(Blueprint* &self, OptimizePass pass, bool sort_by_cost) final; void set_global_filter(const GlobalFilter &global_filter, double estimated_hit_ratio) override; IndexList find(const IPredicate & check) const; @@ -393,7 +407,7 @@ public: virtual double calculate_cost() const = 0; virtual HitEstimate combine(const std::vector &data) const = 0; virtual FieldSpecBaseList exposeFields() const = 0; - virtual void sort(Children &children) const = 0; + virtual void sort(Children &children, bool sort_by_cost) const = 0; virtual bool inheritStrict(size_t i) const = 0; virtual SearchIteratorUP createIntermediateSearch(MultiSearch::Children subSearches, @@ -413,7 +427,7 @@ class LeafBlueprint : public Blueprint private: State _state; protected: - void optimize(Blueprint* &self, OptimizePass pass) final; + void optimize(Blueprint* &self, OptimizePass pass, bool sort_by_cost) final; void setEstimate(HitEstimate est) { _state.estimate(est); _state.relative_estimate(calculate_relative_estimate()); diff --git a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp index 364602cba03..a3f32c6eb7b 100644 --- a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.cpp @@ -33,7 +33,7 @@ size_t lookup_create_source(std::vector > &sources, } template -void optimize_source_blenders(IntermediateBlueprint &self, size_t begin_idx) { +void optimize_source_blenders(IntermediateBlueprint &self, size_t begin_idx, bool sort_by_cost) { std::vector source_blenders; const SourceBlenderBlueprint * reference = nullptr; for (size_t i = begin_idx; i < self.childCnt(); ++i) { @@ -63,7 +63,7 @@ void optimize_source_blenders(IntermediateBlueprint &self, size_t begin_idx) { top->addChild(std::move(sources.back())); sources.pop_back(); } - blender_up = Blueprint::optimize(std::move(blender_up)); + blender_up = Blueprint::optimize(std::move(blender_up), sort_by_cost); self.addChild(std::move(blender_up)); } } @@ -114,7 +114,7 @@ AndNotBlueprint::exposeFields() const } void -AndNotBlueprint::optimize_self(OptimizePass pass) +AndNotBlueprint::optimize_self(OptimizePass pass, bool sort_by_cost) { if (childCnt() == 0) { return; @@ -152,7 +152,7 @@ AndNotBlueprint::optimize_self(OptimizePass pass) } } if (pass == OptimizePass::LAST) { - optimize_source_blenders(*this, 1); + optimize_source_blenders(*this, 1, sort_by_cost); } } @@ -166,10 +166,14 @@ AndNotBlueprint::get_replacement() } void -AndNotBlueprint::sort(Children &children) const +AndNotBlueprint::sort(Children &children, bool sort_by_cost) const { if (children.size() > 2) { - std::sort(children.begin() + 1, children.end(), TieredGreaterEstimate()); + if (sort_by_cost) { + std::sort(children.begin() + 1, children.end(), MinimalOrCost()); + } else { + std::sort(children.begin() + 1, children.end(), TieredGreaterEstimate()); + } } } @@ -231,7 +235,7 @@ AndBlueprint::exposeFields() const } void -AndBlueprint::optimize_self(OptimizePass pass) +AndBlueprint::optimize_self(OptimizePass pass, bool sort_by_cost) { if (pass == OptimizePass::FIRST) { for (size_t i = 0; i < childCnt(); ++i) { @@ -244,7 +248,7 @@ AndBlueprint::optimize_self(OptimizePass pass) } } if (pass == OptimizePass::LAST) { - optimize_source_blenders(*this, 0); + optimize_source_blenders(*this, 0, sort_by_cost); } } @@ -258,9 +262,13 @@ AndBlueprint::get_replacement() } void -AndBlueprint::sort(Children &children) const +AndBlueprint::sort(Children &children, bool sort_by_cost) const { - std::sort(children.begin(), children.end(), TieredLessEstimate()); + if (sort_by_cost) { + std::sort(children.begin(), children.end(), MinimalAndCost()); + } else { + std::sort(children.begin(), children.end(), TieredLessEstimate()); + } } bool @@ -344,7 +352,7 @@ OrBlueprint::exposeFields() const } void -OrBlueprint::optimize_self(OptimizePass pass) +OrBlueprint::optimize_self(OptimizePass pass, bool sort_by_cost) { if (pass == OptimizePass::FIRST) { for (size_t i = 0; (childCnt() > 1) && (i < childCnt()); ++i) { @@ -359,7 +367,7 @@ OrBlueprint::optimize_self(OptimizePass pass) } } if (pass == OptimizePass::LAST) { - optimize_source_blenders(*this, 0); + optimize_source_blenders(*this, 0, sort_by_cost); } } @@ -373,9 +381,13 @@ OrBlueprint::get_replacement() } void -OrBlueprint::sort(Children &children) const +OrBlueprint::sort(Children &children, bool sort_by_cost) const { - std::sort(children.begin(), children.end(), TieredGreaterEstimate()); + if (sort_by_cost) { + std::sort(children.begin(), children.end(), MinimalOrCost()); + } else { + std::sort(children.begin(), children.end(), TieredGreaterEstimate()); + } } bool @@ -452,7 +464,7 @@ WeakAndBlueprint::exposeFields() const } void -WeakAndBlueprint::sort(Children &) const +WeakAndBlueprint::sort(Children &, bool) const { // order needs to stay the same as _weights } @@ -516,9 +528,13 @@ NearBlueprint::exposeFields() const } void -NearBlueprint::sort(Children &children) const +NearBlueprint::sort(Children &children, bool sort_by_cost) const { - std::sort(children.begin(), children.end(), TieredLessEstimate()); + if (sort_by_cost) { + std::sort(children.begin(), children.end(), MinimalAndCost()); + } else { + std::sort(children.begin(), children.end(), TieredLessEstimate()); + } } bool @@ -579,10 +595,9 @@ ONearBlueprint::exposeFields() const } void -ONearBlueprint::sort(Children &children) const +ONearBlueprint::sort(Children &, bool) const { // ordered near cannot sort children here - (void)children; } bool @@ -648,7 +663,7 @@ RankBlueprint::exposeFields() const } void -RankBlueprint::optimize_self(OptimizePass pass) +RankBlueprint::optimize_self(OptimizePass pass, bool sort_by_cost) { if (pass == OptimizePass::FIRST) { for (size_t i = 1; i < childCnt(); ++i) { @@ -658,7 +673,7 @@ RankBlueprint::optimize_self(OptimizePass pass) } } if (pass == OptimizePass::LAST) { - optimize_source_blenders(*this, 1); + optimize_source_blenders(*this, 1, sort_by_cost); } } @@ -672,9 +687,8 @@ RankBlueprint::get_replacement() } void -RankBlueprint::sort(Children &children) const +RankBlueprint::sort(Children &, bool) const { - (void)children; } bool @@ -751,7 +765,7 @@ SourceBlenderBlueprint::exposeFields() const } void -SourceBlenderBlueprint::sort(Children &) const +SourceBlenderBlueprint::sort(Children &, bool) const { } diff --git a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h index 14672c2a5cd..ff4360c0f15 100644 --- a/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h +++ b/searchlib/src/vespa/searchlib/queryeval/intermediate_blueprints.h @@ -19,10 +19,10 @@ public: double calculate_relative_estimate() const final; HitEstimate combine(const std::vector &data) const override; FieldSpecBaseList exposeFields() const override; - void optimize_self(OptimizePass pass) override; + void optimize_self(OptimizePass pass, bool sort_by_cost) override; AndNotBlueprint * asAndNot() noexcept final { return this; } Blueprint::UP get_replacement() override; - void sort(Children &children) const override; + void sort(Children &children, bool sort_by_cost) const override; bool inheritStrict(size_t i) const override; SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, @@ -47,10 +47,10 @@ public: double calculate_relative_estimate() const final; HitEstimate combine(const std::vector &data) const override; FieldSpecBaseList exposeFields() const override; - void optimize_self(OptimizePass pass) override; + void optimize_self(OptimizePass pass, bool sort_by_cost) override; AndBlueprint * asAnd() noexcept final { return this; } Blueprint::UP get_replacement() override; - void sort(Children &children) const override; + void sort(Children &children, bool sort_by_cost) const override; bool inheritStrict(size_t i) const override; SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, @@ -73,10 +73,10 @@ public: double calculate_relative_estimate() const final; HitEstimate combine(const std::vector &data) const override; FieldSpecBaseList exposeFields() const override; - void optimize_self(OptimizePass pass) override; + void optimize_self(OptimizePass pass, bool sort_by_cost) override; OrBlueprint * asOr() noexcept final { return this; } Blueprint::UP get_replacement() override; - void sort(Children &children) const override; + void sort(Children &children, bool sort_by_cost) const override; bool inheritStrict(size_t i) const override; SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, @@ -101,7 +101,7 @@ public: double calculate_relative_estimate() const final; HitEstimate combine(const std::vector &data) const override; FieldSpecBaseList exposeFields() const override; - void sort(Children &children) const override; + void sort(Children &children, bool sort_by_cost) const override; bool inheritStrict(size_t i) const override; bool always_needs_unpack() const override; WeakAndBlueprint * asWeakAnd() noexcept final { return this; } @@ -133,7 +133,7 @@ public: HitEstimate combine(const std::vector &data) const override; FieldSpecBaseList exposeFields() const override; bool should_optimize_children() const override { return false; } - void sort(Children &children) const override; + void sort(Children &children, bool sort_by_cost) const override; bool inheritStrict(size_t i) const override; SearchIteratorUP createSearch(fef::MatchData &md, bool strict) const override; SearchIterator::UP @@ -157,7 +157,7 @@ public: HitEstimate combine(const std::vector &data) const override; FieldSpecBaseList exposeFields() const override; bool should_optimize_children() const override { return false; } - void sort(Children &children) const override; + void sort(Children &children, bool sort_by_cost) const override; bool inheritStrict(size_t i) const override; SearchIteratorUP createSearch(fef::MatchData &md, bool strict) const override; SearchIterator::UP @@ -177,9 +177,9 @@ public: double calculate_relative_estimate() const final; HitEstimate combine(const std::vector &data) const override; FieldSpecBaseList exposeFields() const override; - void optimize_self(OptimizePass pass) override; + void optimize_self(OptimizePass pass, bool sort_by_cost) override; Blueprint::UP get_replacement() override; - void sort(Children &children) const override; + void sort(Children &children, bool sort_by_cost) const override; bool inheritStrict(size_t i) const override; bool isRank() const noexcept final { return true; } SearchIterator::UP @@ -206,7 +206,7 @@ public: double calculate_relative_estimate() const final; HitEstimate combine(const std::vector &data) const override; FieldSpecBaseList exposeFields() const override; - void sort(Children &children) const override; + void sort(Children &children, bool sort_by_cost) const override; bool inheritStrict(size_t i) const override; SearchIterator::UP createIntermediateSearch(MultiSearch::Children subSearches, diff --git a/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.cpp b/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.cpp index f0c75173671..bd677289218 100644 --- a/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.cpp +++ b/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.cpp @@ -45,7 +45,7 @@ SameElementBlueprint::addTerm(Blueprint::UP term) } void -SameElementBlueprint::optimize_self(OptimizePass pass) +SameElementBlueprint::optimize_self(OptimizePass pass, bool) { if (pass == OptimizePass::LAST) { std::sort(_terms.begin(), _terms.end(), diff --git a/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.h b/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.h index 6a988e67149..06c20339e81 100644 --- a/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.h +++ b/searchlib/src/vespa/searchlib/queryeval/same_element_blueprint.h @@ -34,7 +34,7 @@ public: // used by create visitor void addTerm(Blueprint::UP term); - void optimize_self(OptimizePass pass) override; + void optimize_self(OptimizePass pass, bool sort_by_cost) override; void fetchPostings(const ExecuteInfo &execInfo) override; std::unique_ptr create_same_element_search(search::fef::TermFieldMatchData& tfmd, bool strict) const; -- cgit v1.2.3 From e822ad99db63b95a330cd1e8618941aadadec3ad Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 20 Dec 2023 20:41:38 +0000 Subject: Update dependency org.openrewrite.maven:rewrite-maven-plugin to v5.17.0 --- parent/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parent/pom.xml b/parent/pom.xml index afcde6dd930..0506c87493c 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -317,7 +317,7 @@ --> org.openrewrite.maven rewrite-maven-plugin - 5.16.1 + 5.17.0 org.openrewrite.java.testing.junit5.JUnit5BestPractices -- cgit v1.2.3