summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--searchcore/CMakeLists.txt1
-rw-r--r--searchcore/src/tests/proton/common/hw_info_sampler/CMakeLists.txt9
-rw-r--r--searchcore/src/tests/proton/common/hw_info_sampler/DESC2
-rw-r--r--searchcore/src/tests/proton/common/hw_info_sampler/FILES1
-rw-r--r--searchcore/src/tests/proton/common/hw_info_sampler/hw_info_sampler_test.cpp83
-rw-r--r--searchcore/src/vespa/searchcore/config/CMakeLists.txt1
-rw-r--r--searchcore/src/vespa/searchcore/config/hwinfo.def8
-rw-r--r--searchcore/src/vespa/searchcore/config/proton.def12
-rw-r--r--searchcore/src/vespa/searchcore/proton/common/hw_info_sampler.cpp112
-rw-r--r--searchcore/src/vespa/searchcore/proton/common/hw_info_sampler.h29
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/proton.cpp7
11 files changed, 260 insertions, 5 deletions
diff --git a/searchcore/CMakeLists.txt b/searchcore/CMakeLists.txt
index e93bd74880c..66db223d7ec 100644
--- a/searchcore/CMakeLists.txt
+++ b/searchcore/CMakeLists.txt
@@ -69,6 +69,7 @@ vespa_define_module(
src/tests/proton/bucketdb/bucketdb
src/tests/proton/common
src/tests/proton/common/document_type_inspector
+ src/tests/proton/common/hw_info_sampler
src/tests/proton/common/state_reporter_utils
src/tests/proton/config
src/tests/proton/docsummary
diff --git a/searchcore/src/tests/proton/common/hw_info_sampler/CMakeLists.txt b/searchcore/src/tests/proton/common/hw_info_sampler/CMakeLists.txt
new file mode 100644
index 00000000000..72e932bd996
--- /dev/null
+++ b/searchcore/src/tests/proton/common/hw_info_sampler/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(searchcore_hw_info_sampler_test_app TEST
+ SOURCES
+ hw_info_sampler_test.cpp
+ DEPENDS
+ searchcore_pcommon
+ searchcore_fconfig
+)
+vespa_add_test(NAME searchcore_hw_info_sampler_test_app COMMAND searchcore_hw_info_sampler_test_app)
diff --git a/searchcore/src/tests/proton/common/hw_info_sampler/DESC b/searchcore/src/tests/proton/common/hw_info_sampler/DESC
new file mode 100644
index 00000000000..82461c9b864
--- /dev/null
+++ b/searchcore/src/tests/proton/common/hw_info_sampler/DESC
@@ -0,0 +1,2 @@
+Test for hw_info_sampler. Take a look at hw_info_sampler_test.cpp for details.
+
diff --git a/searchcore/src/tests/proton/common/hw_info_sampler/FILES b/searchcore/src/tests/proton/common/hw_info_sampler/FILES
new file mode 100644
index 00000000000..164cdc82bce
--- /dev/null
+++ b/searchcore/src/tests/proton/common/hw_info_sampler/FILES
@@ -0,0 +1 @@
+hw_info_sampler_test.cpp
diff --git a/searchcore/src/tests/proton/common/hw_info_sampler/hw_info_sampler_test.cpp b/searchcore/src/tests/proton/common/hw_info_sampler/hw_info_sampler_test.cpp
new file mode 100644
index 00000000000..e9ea623d554
--- /dev/null
+++ b/searchcore/src/tests/proton/common/hw_info_sampler/hw_info_sampler_test.cpp
@@ -0,0 +1,83 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+#include <vespa/fastos/fastos.h>
+
+#include <vespa/searchcore/proton/common/hw_info_sampler.h>
+#include <vespa/searchcore/config/config-hwinfo.h>
+#include <vespa/searchcore/proton/test/directory_handler.h>
+#include <vespa/vespalib/testkit/testapp.h>
+#include <vespa/config/print/fileconfigwriter.h>
+
+using proton::HwInfoSampler;
+using vespa::config::search::core::HwinfoConfig;
+using vespa::config::search::core::HwinfoConfigBuilder;
+
+using Clock = std::chrono::system_clock;
+using Config = HwInfoSampler::Config;
+
+namespace {
+
+const vespalib::string test_dir = "temp";
+constexpr uint64_t sampleLen = 1024 * 1024 * 40;
+
+long time_point_to_long(Clock::time_point tp)
+{
+ return std::chrono::duration_cast<std::chrono::seconds>(tp.time_since_epoch()).count();
+}
+
+}
+
+struct Fixture
+{
+ proton::test::DirectoryHandler _dirHandler;
+
+ Fixture()
+ : _dirHandler(test_dir)
+ {
+ }
+
+ void writeConfig(const HwinfoConfig &config) {
+ config::FileConfigWriter writer(test_dir + "/hwinfo.cfg");
+ ASSERT_TRUE(writer.write(config));
+ }
+
+};
+
+TEST_F("Test that hw_info_sampler uses override info", Fixture)
+{
+ Config samplerCfg(75.0, 100.0, sampleLen);
+ HwInfoSampler sampler(test_dir, samplerCfg);
+ EXPECT_EQUAL(75.0, sampler.diskWriteSpeed());
+ EXPECT_NOT_EQUAL(0, time_point_to_long(sampler.sampleTime()));
+ EXPECT_TRUE(sampler.hwInfo().slowDisk());
+}
+
+TEST_F("Test that hw_info_sampler uses saved info", Fixture)
+{
+ HwinfoConfigBuilder builder;
+ builder.disk.writespeed = 72.0;
+ builder.disk.sampletime = time_point_to_long(Clock::now());
+ f.writeConfig(builder);
+ Config samplerCfg(0.0, 70.0, sampleLen);
+ HwInfoSampler sampler(test_dir, samplerCfg);
+ EXPECT_EQUAL(builder.disk.writespeed, sampler.diskWriteSpeed());
+ EXPECT_EQUAL(builder.disk.sampletime, time_point_to_long(sampler.sampleTime()));
+ EXPECT_FALSE(sampler.hwInfo().slowDisk());
+}
+
+TEST_F("Test that hw_info_sampler can sample disk write speed", Fixture)
+{
+ Config samplerCfg(0.0, 100.0, sampleLen);
+ HwInfoSampler sampler(test_dir, samplerCfg);
+ ASSERT_NOT_EQUAL(0.0, sampler.diskWriteSpeed());
+ ASSERT_NOT_EQUAL(0, time_point_to_long(sampler.sampleTime()));
+ HwInfoSampler sampler2(test_dir, samplerCfg);
+ EXPECT_APPROX(sampler.diskWriteSpeed(), sampler2.diskWriteSpeed(), 0.1);
+ EXPECT_EQUAL(time_point_to_long(sampler.sampleTime()),
+ time_point_to_long(sampler2.sampleTime()));
+}
+
+TEST_MAIN()
+{
+ vespalib::rmdir(test_dir, true);
+ TEST_RUN_ALL();
+}
diff --git a/searchcore/src/vespa/searchcore/config/CMakeLists.txt b/searchcore/src/vespa/searchcore/config/CMakeLists.txt
index df24e854023..12771eee425 100644
--- a/searchcore/src/vespa/searchcore/config/CMakeLists.txt
+++ b/searchcore/src/vespa/searchcore/config/CMakeLists.txt
@@ -11,3 +11,4 @@ vespa_generate_config(searchcore_fconfig proton.def)
install(FILES proton.def DESTINATION var/db/vespa/config_server/serverdb/classes)
vespa_generate_config(searchcore_fconfig ranking-constants.def)
install(FILES ranking-constants.def DESTINATION var/db/vespa/config_server/serverdb/classes)
+vespa_generate_config(searchcore_fconfig hwinfo.def)
diff --git a/searchcore/src/vespa/searchcore/config/hwinfo.def b/searchcore/src/vespa/searchcore/config/hwinfo.def
new file mode 100644
index 00000000000..ae816f6110a
--- /dev/null
+++ b/searchcore/src/vespa/searchcore/config/hwinfo.def
@@ -0,0 +1,8 @@
+# Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+namespace=vespa.config.search.core
+
+## Write speed, MiB/s, typically measured by writing 1 GiB data to disk.
+disk.writespeed double default = 0.0
+
+## Sample time, in seconds since epoch
+disk.sampletime long default = 0
diff --git a/searchcore/src/vespa/searchcore/config/proton.def b/searchcore/src/vespa/searchcore/config/proton.def
index 1aec6df7a17..cd56d4fc403 100644
--- a/searchcore/src/vespa/searchcore/config/proton.def
+++ b/searchcore/src/vespa/searchcore/config/proton.def
@@ -386,3 +386,15 @@ writefilter.disklimit double default = 0.9
## Interval between sampling of disk and memory usage. Default is 60 seconds.
writefilter.sampleinterval double default = 60.0
+
+## Override for disk write speed, measured in MiB/s. When zero, the
+## actual disk write speed is sampled by writing data to a temporary file.
+hwinfo.disk.writespeed double default = 200.0
+
+## Amount of data to write to temporary file when sampling disk write speed.
+## Default is 1 GiB.
+hwinfo.disk.samplewritesize long default = 1073741824
+
+## Minimun write speed needed to avoid disk being considered slow.
+## Unit is MiB/s, default is 100.0 MiB/s.
+hwinfo.disk.slowwritespeedlimit double default = 100.0
diff --git a/searchcore/src/vespa/searchcore/proton/common/hw_info_sampler.cpp b/searchcore/src/vespa/searchcore/proton/common/hw_info_sampler.cpp
index ca6efa347cd..2c820b8e733 100644
--- a/searchcore/src/vespa/searchcore/proton/common/hw_info_sampler.cpp
+++ b/searchcore/src/vespa/searchcore/proton/common/hw_info_sampler.cpp
@@ -1,13 +1,119 @@
// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "hw_info_sampler.h"
+#include <vespa/config/config.h>
+#include <vespa/config/common/configholder.h>
+#include <vespa/config/file/filesource.h>
+#include <vespa/searchcore/config/config-hwinfo.h>
+#include <vespa/config/print/fileconfigwriter.h>
+#include <vespa/vespalib/io/fileutil.h>
+
+using config::ConfigHandle;
+using config::ConfigSubscriber;
+using config::FileSpec;
+using vespa::config::search::core::HwinfoConfig;
+using vespa::config::search::core::HwinfoConfigBuilder;
+using vespalib::alloc::Alloc;
+
+using Clock = std::chrono::system_clock;
namespace proton {
-HwInfoSampler::HwInfoSampler(const vespalib::string &path)
- : _hwInfo()
+namespace {
+
+std::unique_ptr<HwinfoConfig> readConfig(const vespalib::string &path) {
+ FileSpec spec(path + "/" + "hwinfo.cfg");
+ ConfigSubscriber s(spec);
+ std::unique_ptr<ConfigHandle<HwinfoConfig>> handle = s.subscribe<HwinfoConfig>("hwinfo");
+ s.nextConfig(0);
+ return std::move(handle->getConfig());
+}
+
+
+void writeConfig(const vespalib::string &path,
+ double diskWriteSpeed, Clock::time_point sampleTime)
+{
+ HwinfoConfigBuilder builder;
+ builder.disk.writespeed = diskWriteSpeed;
+ builder.disk.sampletime = std::chrono::duration_cast<std::chrono::seconds>(sampleTime.time_since_epoch()).count();
+ config::FileConfigWriter writer(path + "/hwinfo.cfg");
+ if (!writer.write(builder)) {
+ abort();
+ }
+}
+
+double measureDiskWriteSpeed(const vespalib::string &path,
+ size_t diskWriteLen)
+{
+ FastOS_File testFile;
+ vespalib::string fileName = path + "/hwinfo-writespeed";
+ size_t bufferLen = 1024 * 1024;
+ Alloc buffer(Alloc::allocMMap(bufferLen));
+ memset(buffer.get(), 0, buffer.size());
+ testFile.EnableDirectIO();
+ testFile.OpenWriteOnlyTruncate(fileName.c_str());
+ sync();
+ sleep(1);
+ sync();
+ sleep(1);
+ Clock::time_point before = Clock::now();
+ size_t residue = diskWriteLen;
+ while (residue > 0) {
+ size_t writeNow = std::min(residue, bufferLen);
+ testFile.WriteBuf(buffer.get(), writeNow);
+ residue -= writeNow;
+ }
+ Clock::time_point after = Clock::now();
+ testFile.Close();
+ vespalib::unlink(fileName);
+ double elapsed = std::chrono::duration<double>(after - before).count();
+ double diskWriteSpeed = diskWriteLen / elapsed / 1024 / 1024;
+ return diskWriteSpeed;
+}
+
+}
+
+HwInfoSampler::HwInfoSampler(const vespalib::string &path,
+ const Config &config)
+ : _hwInfo(),
+ _sampleTime(),
+ _diskWriteSpeed(0.0)
+{
+ if (config._diskWriteSpeedOverride != 0) {
+ _diskWriteSpeed = config._diskWriteSpeedOverride;
+ _sampleTime = Clock::now();
+ } else {
+ auto cfg = readConfig(path);
+ if (cfg && cfg->disk.sampletime != 0.0) {
+ _sampleTime = std::chrono::time_point<Clock>(std::chrono::seconds(cfg->disk.sampletime));
+ _diskWriteSpeed = cfg->disk.writespeed;
+ } else {
+ sample(path, config);
+ }
+ }
+ setup(config);
+}
+
+HwInfoSampler::~HwInfoSampler()
+{
+}
+
+void
+HwInfoSampler::setup(const Config &config)
+{
+ bool slowDisk = _diskWriteSpeed < config._slowWriteSpeedLimit;
+ _hwInfo = HwInfo(slowDisk);
+}
+
+void
+HwInfoSampler::sample(const vespalib::string &path, const Config &config)
{
- (void) path;
+ size_t minDiskWriteLen = 1024u * 1024u;
+ size_t diskWriteLen = config._diskSampleWriteSize;
+ diskWriteLen = std::max(diskWriteLen, minDiskWriteLen);
+ _sampleTime = Clock::now();
+ _diskWriteSpeed = measureDiskWriteSpeed(path, diskWriteLen);
+ writeConfig(path, _diskWriteSpeed, _sampleTime);
}
}
diff --git a/searchcore/src/vespa/searchcore/proton/common/hw_info_sampler.h b/searchcore/src/vespa/searchcore/proton/common/hw_info_sampler.h
index 32772f2d41e..0a96043572d 100644
--- a/searchcore/src/vespa/searchcore/proton/common/hw_info_sampler.h
+++ b/searchcore/src/vespa/searchcore/proton/common/hw_info_sampler.h
@@ -4,6 +4,7 @@
#include "hw_info.h"
#include <vespa/vespalib/stllike/string.h>
+#include <chrono>
namespace proton {
@@ -13,11 +14,37 @@ namespace proton {
*/
class HwInfoSampler
{
+public:
+ struct Config {
+ double _diskWriteSpeedOverride;
+ double _slowWriteSpeedLimit;
+ uint64_t _diskSampleWriteSize;
+
+ Config(double diskWriteSpeedOverride,
+ double slowWriteSpeedLimit,
+ double diskSampleWriteSize)
+ : _diskWriteSpeedOverride(diskWriteSpeedOverride),
+ _slowWriteSpeedLimit(slowWriteSpeedLimit),
+ _diskSampleWriteSize(diskSampleWriteSize)
+ {
+ }
+ };
+
+private:
HwInfo _hwInfo;
+ using Clock = std::chrono::system_clock;
+ Clock::time_point _sampleTime;
+ double _diskWriteSpeed;
+
+ void setup(const Config &config);
+ void sample(const vespalib::string &path, const Config &config);
public:
- HwInfoSampler(const vespalib::string &path);
+ HwInfoSampler(const vespalib::string &path, const Config &config);
+ ~HwInfoSampler();
const HwInfo &hwInfo() const { return _hwInfo; }
+ std::chrono::time_point<Clock> sampleTime() const { return _sampleTime; }
+ double diskWriteSpeed() const { return _diskWriteSpeed; }
};
}
diff --git a/searchcore/src/vespa/searchcore/proton/server/proton.cpp b/searchcore/src/vespa/searchcore/proton/server/proton.cpp
index 942d90a728f..388aa83a44f 100644
--- a/searchcore/src/vespa/searchcore/proton/server/proton.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/proton.cpp
@@ -241,7 +241,12 @@ Proton::init(const BootstrapConfig::SP & configSnapshot)
{
assert( _initStarted && ! _initComplete );
const ProtonConfig &protonConfig = configSnapshot->getProtonConfig();
- _hwInfoSampler = std::make_unique<HwInfoSampler>(protonConfig.basedir);
+ const auto &samplerCfgArgs = protonConfig.hwinfo.disk;
+ HwInfoSampler::Config samplerCfg(samplerCfgArgs.writespeed,
+ samplerCfgArgs.slowwritespeedlimit,
+ samplerCfgArgs.samplewritesize);
+ _hwInfoSampler = std::make_unique<HwInfoSampler>(protonConfig.basedir,
+ samplerCfg);
_hwInfo = _hwInfoSampler->hwInfo();
setFS4Compression(protonConfig);
_diskMemUsageSampler = std::make_unique<DiskMemUsageSampler>