diff options
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> |