Enable cpuQuota options, fix cpuQuota logic 64/35964/2
authorPiotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
Thu, 26 Feb 2015 15:30:11 +0000 (16:30 +0100)
committerPiotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
Fri, 27 Feb 2015 12:22:01 +0000 (13:22 +0100)
[Bug/Feature]   Options were disabled after migration from libvirt
[Cause]         N/A
[Solution]      N/A
[Verification]  Run tests, run two containers use 100% cpu on first and
                switch to second and check total cpu usage in host.

Change-Id: I6c79f639f7cf0def3ad0ea73550940d8f5edba9e

common/lxc/cgroup.cpp
common/lxc/cgroup.hpp
common/utils/fs.cpp
common/utils/fs.hpp
server/zone-admin.cpp
server/zone.cpp
server/zones-manager.cpp
tests/unit_tests/server/ut-zone-admin.cpp

index 62f3184..0ec6da2 100644 (file)
@@ -27,6 +27,7 @@
 #include "lxc/cgroup.hpp"
 #include "logger/logger.hpp"
 #include "utils/fs.hpp"
+#include "utils/paths.hpp"
 
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -54,17 +55,38 @@ std::string flagsToPermissions(bool grant, uint32_t flags)
     }
 }
 
+std::string getCgroupPath(const std::string& zoneName,
+                          const std::string& cgroupController,
+                          const std::string& cgroupName)
+{
+    return utils::createFilePath("/sys/fs/cgroup",
+                                 cgroupController,
+                                 "lxc",
+                                 zoneName,
+                                 cgroupName);
+}
+
 } // namespace
 
 bool setCgroup(const std::string& zoneName,
+               const std::string& cgroupController,
                const std::string& cgroupName,
                const std::string& value)
 {
-    const std::string path = "/sys/fs/cgroup/devices/lxc/" + zoneName + "/" + cgroupName;
+    const std::string path = getCgroupPath(zoneName, cgroupController, cgroupName);
     LOGD("Set '" << value << "' to " << path);
     return utils::saveFileContent(path, value);
 }
 
+bool getCgroup(const std::string& zoneName,
+               const std::string& cgroupController,
+               const std::string& cgroupName,
+               std::string& value)
+{
+    const std::string path = getCgroupPath(zoneName, cgroupController, cgroupName);
+    return utils::readFirstLineOfFile(path, value);
+}
+
 bool isDevice(const std::string& device)
 {
     struct stat devStat;
@@ -113,7 +135,7 @@ bool setDeviceAccess(const std::string& zoneName,
     snprintf(value, sizeof(value), "%c %u:%u %s", type, major, minor, perm.c_str());
 
     std::string name = grant ? "devices.allow" : "devices.deny";
-    return setCgroup(zoneName, name, value);
+    return setCgroup(zoneName, "devices", name, value);
 }
 
 
index 2592054..23f0e9b 100644 (file)
@@ -31,9 +31,15 @@ namespace vasum {
 namespace lxc {
 
 bool setCgroup(const std::string& zoneName,
+               const std::string& cgroupController,
                const std::string& cgroupName,
                const std::string& value);
 
+bool getCgroup(const std::string& zoneName,
+               const std::string& cgroupController,
+               const std::string& cgroupName,
+               std::string& value);
+
 bool isDevice(const std::string& device);
 
 bool setDeviceAccess(const std::string& zoneName,
index d7ae2dd..e3a59b3 100644 (file)
@@ -101,6 +101,22 @@ bool saveFileContent(const std::string& path, const std::string& content)
     return true;
 }
 
+bool readFirstLineOfFile(const std::string& path, std::string& ret)
+{
+    std::ifstream file(path);
+    if (!file) {
+        LOGD(path << ": could not open for reading");
+        return false;
+    }
+
+    std::getline(file, ret);
+    if (!file) {
+        LOGD(path << ": read error");
+        return false;
+    }
+    return true;
+}
+
 bool removeFile(const std::string& path)
 {
     LOGD(path << ": exists, removing.");
index b00f95a..b2e05b6 100644 (file)
@@ -50,6 +50,12 @@ bool readFileContent(const std::string& path, std::string& content);
 bool saveFileContent(const std::string& path, const std::string& content);
 
 /**
+ * Read a line from file
+ * Its goal is to read a kernel config files (eg. from /proc, /sys/)
+ */
+bool readFirstLineOfFile(const std::string& path, std::string& ret);
+
+/**
  * Remove file
  */
 bool removeFile(const std::string& path);
index fa465bc..c5e994d 100644 (file)
 #include "logger/logger.hpp"
 #include "utils/paths.hpp"
 #include "utils/c-array.hpp"
+#include "lxc/cgroup.hpp"
 
 #include <cassert>
+#include <climits>
 
 
 namespace vasum {
@@ -210,6 +212,8 @@ bool ZoneAdmin::isPaused()
 
 void ZoneAdmin::setSchedulerLevel(SchedulerLevel sched)
 {
+    assert(isRunning());
+
     switch (sched) {
     case SchedulerLevel::FOREGROUND:
         LOGD(mId << ": Setting SchedulerLevel::FOREGROUND");
@@ -229,27 +233,21 @@ void ZoneAdmin::setSchedulerLevel(SchedulerLevel sched)
 }
 
 
-void ZoneAdmin::setSchedulerParams(std::uint64_t, std::uint64_t, std::int64_t)
-//void ZoneAdmin::setSchedulerParams(std::uint64_t cpuShares, std::uint64_t vcpuPeriod, std::int64_t vcpuQuota)
+void ZoneAdmin::setSchedulerParams(std::uint64_t cpuShares,
+                                   std::uint64_t vcpuPeriod,
+                                   std::int64_t vcpuQuota)
 {
-//    assert(mZone);
-//
-//    int maxParams = 3;
-//    int numParamsBuff = 0;
-//
-//    std::unique_ptr<virTypedParameter[]> params(new virTypedParameter[maxParams]);
-//
-//    virTypedParameterPtr paramsTmp = params.get();
-//
-//    virTypedParamsAddULLong(&paramsTmp, &numParamsBuff, &maxParams, VIR_DOMAIN_SCHEDULER_CPU_SHARES, cpuShares);
-//    virTypedParamsAddULLong(&paramsTmp, &numParamsBuff, &maxParams, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD, vcpuPeriod);
-//    virTypedParamsAddLLong(&paramsTmp, &numParamsBuff, &maxParams, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA, vcpuQuota);
-//
-//    if (virDomainSetSchedulerParameters(mZone.get(), params.get(), numParamsBuff) < 0) {
-//        LOGE(mId << ": Error while setting the zone's scheduler params:\n"
-//             << libvirt::libvirtFormatError());
-//        throw ZoneOperationException();
-//    }
+    assert(vcpuPeriod >= 1000 && vcpuPeriod <= 1000000);
+    assert(vcpuQuota == -1 ||
+           (vcpuQuota >= 1000 && vcpuQuota <= static_cast<std::int64_t>(ULLONG_MAX / 1000)));
+
+    if (!lxc::setCgroup(mId, "cpu", "cpu.shares", std::to_string(cpuShares)) ||
+        !lxc::setCgroup(mId, "cpu", "cpu.cfs_period_us", std::to_string(vcpuPeriod)) ||
+        !lxc::setCgroup(mId, "cpu", "cpu.cfs_quota_us", std::to_string(vcpuQuota))) {
+
+        LOGE(mId << ": Error while setting the zone's scheduler params");
+        throw ZoneOperationException("Could not set scheduler params");
+    }
 }
 
 void ZoneAdmin::setDetachOnExit()
@@ -264,37 +262,12 @@ void ZoneAdmin::setDestroyOnExit()
 
 std::int64_t ZoneAdmin::getSchedulerQuota()
 {
-//    assert(mZone);
-//
-//    int numParamsBuff;
-//    std::unique_ptr<char, void(*)(void*)> type(virDomainGetSchedulerType(mZone.get(), &numParamsBuff), free);
-//
-//    if (type == NULL || numParamsBuff <= 0 || strcmp(type.get(), "posix") != 0) {
-//        LOGE(mId << ": Error while getting the zone's scheduler type:\n"
-//             << libvirt::libvirtFormatError());
-//        throw ZoneOperationException();
-//    }
-//
-//    std::unique_ptr<virTypedParameter[]> params(new virTypedParameter[numParamsBuff]);
-//
-//    if (virDomainGetSchedulerParameters(mZone.get(), params.get(), &numParamsBuff) < 0) {
-//        LOGE(mId << ": Error while getting the zone's scheduler params:\n"
-//             << libvirt::libvirtFormatError());
-//        throw ZoneOperationException();
-//    }
-//
-//    long long quota;
-//    if (virTypedParamsGetLLong(params.get(),
-//                               numParamsBuff,
-//                               VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
-//                               &quota) <= 0) {
-//        LOGE(mId << ": Error while getting the zone's scheduler quota param:\n"
-//             << libvirt::libvirtFormatError());
-//        throw ZoneOperationException();
-//    }
-//
-//    return quota;
-    return 0;
+    std::string ret;
+    if (!lxc::getCgroup(mId, "cpu", "cpu.cfs_quota_us", ret)) {
+        LOGE(mId << ": Error while getting the zone's scheduler quota param");
+        throw ZoneOperationException("Could not get scheduler quota param");
+    }
+    return std::stoll(ret);
 }
 
 void ZoneAdmin::createNetdevVeth(const std::string& /* zoneDev */,
index 5c15f21..0607fda 100644 (file)
@@ -125,19 +125,23 @@ void Zone::start()
     if (mConfig.enableDbusIntegration) {
         mConnectionTransport.reset(new ZoneConnectionTransport(mRunMountPoint));
     }
+
     mAdmin->start();
     if (mConfig.enableDbusIntegration) {
+        // Increase cpu quota before connect, otherwise it'd take ages.
+        goForeground();
         connect();
     }
-
-    // Send to the background only after we're connected, otherwise it'd take ages.
-    LOGD(getId() << ": sending to the background");
-    goBackground();
+    // refocus in ZonesManager will adjust cpu quota after all
 }
 
 void Zone::stop()
 {
     Lock lock(mReconnectMutex);
+    if (mAdmin->isRunning()) {
+        // boost stopping
+        goForeground();
+    }
     disconnect();
     mAdmin->stop();
     mConnectionTransport.reset();
index fd8501f..5f0dca4 100644 (file)
@@ -392,13 +392,15 @@ void ZonesManager::focusInternal(Zones::iterator iter)
     }
 
     for (auto& zone : mZones) {
-        std::string id = zone->getId();
-        if (id == idToFocus) {
-            LOGD(id << ": being sent to foreground");
-            zone->goForeground();
-        } else {
-            LOGD(id << ": being sent to background");
-            zone->goBackground();
+        if (zone->isRunning()) {
+            std::string id = zone->getId();
+            if (id == idToFocus) {
+                LOGD(id << ": being sent to foreground");
+                zone->goForeground();
+            } else {
+                LOGD(id << ": being sent to background");
+                zone->goBackground();
+            }
         }
     }
     mActiveZoneId = idToFocus;
@@ -1245,6 +1247,7 @@ void ZonesManager::handleLockZoneCall(const std::string& id,
 
     LOGT("Lock zone");
     try {
+        zone.goBackground();// make sure it will be in background after unlock
         zone.suspend();
         refocus();
     } catch (ZoneOperationException& e) {
index 255e75e..4dd08db 100644 (file)
@@ -156,16 +156,20 @@ BOOST_AUTO_TEST_CASE(SuspendResumeTest)
     BOOST_CHECK(admin->isRunning());
 }
 
-//BOOST_AUTO_TEST_CASE(SchedulerLevelTest)
-//{
-//    auto admin = create(TEST_CONFIG_PATH);
-//
-//    admin->start();
-//    ensureStarted();
-//    admin->setSchedulerLevel(SchedulerLevel::FOREGROUND);
-//    BOOST_REQUIRE(admin->getSchedulerQuota() == config.cpuQuotaForeground);
-//    admin->setSchedulerLevel(SchedulerLevel::BACKGROUND);
-//    BOOST_REQUIRE(admin->getSchedulerQuota() == config.cpuQuotaBackground);
-//}
+BOOST_AUTO_TEST_CASE(SchedulerLevelTest)
+{
+    BOOST_REQUIRE(mConfig.cpuQuotaForeground != mConfig.cpuQuotaBackground);
+
+    auto admin = create(TEST_CONFIG_PATH);
+
+    admin->start();
+    ensureStarted();
+
+    admin->setSchedulerLevel(SchedulerLevel::FOREGROUND);
+    BOOST_CHECK_EQUAL(admin->getSchedulerQuota(), mConfig.cpuQuotaForeground);
+
+    admin->setSchedulerLevel(SchedulerLevel::BACKGROUND);
+    BOOST_CHECK_EQUAL(admin->getSchedulerQuota(), mConfig.cpuQuotaBackground);
+}
 
 BOOST_AUTO_TEST_SUITE_END()