[Libreoffice-commits] online.git: loolwsd/LOOLForKit.cpp loolwsd/LOOLKit.cpp loolwsd/LOOLWSD.cpp loolwsd/test loolwsd/Unit.hpp

Michael Meeks michael.meeks at collabora.com
Tue Apr 12 20:58:48 UTC 2016


 loolwsd/LOOLForKit.cpp       |    2 
 loolwsd/LOOLKit.cpp          |    3 -
 loolwsd/LOOLWSD.cpp          |   12 +++-
 loolwsd/Unit.hpp             |   21 ++++++-
 loolwsd/test/UnitPrefork.cpp |  121 +++++++++++++++++++++++++++++++++++++++----
 5 files changed, 144 insertions(+), 15 deletions(-)

New commits:
commit 25a092d7de440b5b284f451c26812145fd743521
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Tue Apr 12 21:30:06 2016 +0100

    Add memory accounting metric to UnitPrefork.
    
    Also add hooks to allow custom LOK <-> WSD message for this test.

diff --git a/loolwsd/LOOLForKit.cpp b/loolwsd/LOOLForKit.cpp
index 4ad66b3..e3e8046 100644
--- a/loolwsd/LOOLForKit.cpp
+++ b/loolwsd/LOOLForKit.cpp
@@ -120,6 +120,8 @@ static int createLibreOfficeKit(const std::string& childRoot,
     }
     else
     {
+        UnitKit::get().launchedKit(pid);
+
         // parent
         if (pid < 0)
             Log::syserror("Fork failed.");
diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp
index 9efa6d4..12e652e 100644
--- a/loolwsd/LOOLKit.cpp
+++ b/loolwsd/LOOLKit.cpp
@@ -1021,7 +1021,8 @@ void lokit_main(const std::string& childRoot,
                 {
                     std::string message(data.data(), data.size());
 
-                    UnitKit::get().kitMessage(message);
+                    if (UnitKit::get().filterKitMessage(ws, message))
+                        return true;
 
                     Log::debug(socketName + ": recv [" + LOOLProtocol::getAbbreviatedMessage(message) + "].");
                     StringTokenizer tokens(message, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index c48baad..ace66b1 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -667,6 +667,11 @@ public:
 
     void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) override
     {
+        if (UnitWSD::get().filterHandleRequest(
+                UnitWSD::TestRequest::TEST_REQ_CLIENT,
+                request, response))
+            return;
+
         handleClientRequest(request,response);
     }
 
@@ -721,6 +726,11 @@ public:
 
     void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) override
     {
+        if (UnitWSD::get().filterHandleRequest(
+                UnitWSD::TestRequest::TEST_REQ_PRISONER,
+                request, response))
+            return;
+
         handlePrisonerRequest(request, response);
     }
 
@@ -756,7 +766,7 @@ public:
             newChildren.emplace_back(std::make_shared<ChildProcess>(pid, ws));
             Log::info("Have " + std::to_string(newChildren.size()) + " " + (newChildren.size() == 1 ? "child" : "children") + ".");
             newChildrenCV.notify_one();
-            UnitWSD::get().newChild();
+            UnitWSD::get().newChild(ws);
             return;
         }
 
diff --git a/loolwsd/Unit.hpp b/loolwsd/Unit.hpp
index 658184d..ac925f2 100644
--- a/loolwsd/Unit.hpp
+++ b/loolwsd/Unit.hpp
@@ -21,6 +21,11 @@ class UnitTimeout;
 class UnitHTTPServerRequest;
 class UnitHTTPServerResponse;
 
+namespace Poco { namespace Net {
+        class HTTPServerRequest;
+        class HTTPServerResponse;
+} }
+
 class StorageBase;
 
 typedef UnitBase *(CreateUnitHooksFunction)();
@@ -103,13 +108,20 @@ public:
     /// Tweak the count of pre-spawned kits.
 	virtual void preSpawnCount(int & /* numPrefork */) {}
     /// When a new child kit process reports
-    virtual void newChild() {}
+    virtual void newChild(const std::shared_ptr<Poco::Net::WebSocket> & /* socket */) {}
     /// Intercept createStorage
     virtual bool createStorage(const std::string& /* jailRoot */,
                                const std::string& /* jailPath */,
                                const Poco::URI& /* uri */,
                                std::unique_ptr<StorageBase> & /*rStorage */)
         { return false; }
+    /// Intercept incoming requests, so unit tests can silently communicate
+    virtual bool filterHandleRequest(
+                     TestRequest /* type */,
+                     Poco::Net::HTTPServerRequest& /* request */,
+                     Poco::Net::HTTPServerResponse& /* response */)
+        { return false; }
+
 };
 
 /// Derive your Kit unit test / hooks from me.
@@ -129,13 +141,18 @@ public:
     /// main-loop reached, time for testing
     virtual void invokeForKitTest() {}
 
+    /// Post fork hook - just after we fork to init the child kit
+    virtual void launchedKit(int /* pid */) {}
+
     // ---------------- Kit hooks ----------------
 
     /// Post fork hook - just before we init the child kit
     virtual void postFork() {}
 
     /// Kit got a message
-    virtual void kitMessage(std::string &/* message */) {}
+    virtual bool filterKitMessage(const std::shared_ptr<Poco::Net::WebSocket> & /* ws */,
+                                  std::string &/* message */)
+        { return false; }
 };
 
 #endif
diff --git a/loolwsd/test/UnitPrefork.cpp b/loolwsd/test/UnitPrefork.cpp
index b9239f7..c56e2fc 100644
--- a/loolwsd/test/UnitPrefork.cpp
+++ b/loolwsd/test/UnitPrefork.cpp
@@ -14,50 +14,149 @@
 
 #include "Util.hpp"
 #include "Unit.hpp"
+#include "LOOLProtocol.hpp"
 
 #include <Poco/Timestamp.h>
-using Poco::Timestamp;
+#include <Poco/StringTokenizer.h>
+
+const int NumToPrefork = 20;
 
 // Inside the WSD process
 class UnitPrefork : public UnitWSD
 {
     int _numStarted;
-    const int _numToPrefork;
-    Timestamp _startTime;
+    Poco::Timestamp _startTime;
+    std::vector< std::shared_ptr<Poco::Net::WebSocket> > _childSockets;
 
 public:
     UnitPrefork()
-        : _numStarted(0),
-          _numToPrefork(20)
+        : _numStarted(0)
     {
         setHasKitHooks();
     }
 
     virtual void preSpawnCount(int &numPrefork) override
     {
-        numPrefork = _numToPrefork;
+        numPrefork = NumToPrefork;
+    }
+
+    std::string getMemory(const std::shared_ptr<Poco::Net::WebSocket> &socket)
+    {
+        /// Fetch memory usage data from the last process ...
+        socket->sendFrame("unit-memdump: \n", sizeof("unit-memdump: \n")-1);
+        int flags;
+        char buffer[4096];
+        std::cout << "Waiting for memory stats" << std::endl;
+
+        int length = socket->receiveFrame(buffer, sizeof (buffer), flags);
+        std::string memory = LOOLProtocol::getFirstLine(buffer, length);
+
+        return memory;
     }
 
-    virtual void newChild() override
+    virtual void newChild(const std::shared_ptr<Poco::Net::WebSocket> &socket) override
     {
         ++_numStarted;
-        if (_numStarted >= _numToPrefork)
+        _childSockets.push_back(socket);
+        if (_numStarted >= NumToPrefork)
         {
-            exitTest(TestResult::TEST_OK);
-
             Poco::Timestamp::TimeDiff elapsed = _startTime.elapsed();
 
             std::cout << "Launched " << _numStarted << " in "
                       << (1.0 * elapsed)/Poco::Timestamp::resolution() << std::endl;
+            int num = 0;
+            for (auto child : _childSockets)
+                std::cout << "Memory of " << ++num << " : " <<
+                             getMemory(child) << std::endl;
+
+            exitTest(TestResult::TEST_OK);
         }
     }
 };
 
+namespace {
+    std::vector<int> pids;
+
+    const char *startsWith(const char *line, const char *tag)
+    {
+        int len = strlen(tag);
+        if (!strncmp(line, tag, len))
+        {
+            while (!isdigit(line[len]) && line[len] != '\0')
+                len++;
+//            fprintf(stdout, "does start with %s: '%s'\n", tag, line + len);
+            return line + len;
+        }
+        else
+            return 0;
+    }
+
+    std::string readMemorySizes(FILE *inStream)
+    {
+        size_t numPSSKb = 0;
+        size_t numDirtyKb = 0;
+
+        char line[4096];
+        while (fgets(line, sizeof (line), inStream))
+        {
+            const char *value;
+            if ((value = startsWith(line, "Private_Dirty:")) ||
+                (value = startsWith(line, "Shared_Dirty:")))
+                numDirtyKb += atoi(value);
+            else if ((value = startsWith(line, "Pss:")))
+                numPSSKb += atoi(value);
+        }
+        std::ostringstream oss;
+        oss << numPSSKb << "k pss " << numDirtyKb << "k dirty";
+        return oss.str();
+    }
+}
+
 // Inside the forkit & kit processes
 class UnitKitPrefork : public UnitKit
 {
+    FILE *_procSMaps;
+
 public:
-    UnitKitPrefork() {}
+    UnitKitPrefork()
+        : _procSMaps(NULL)
+    {
+        std::cerr << "UnitKit Prefork init !\n";
+    }
+    ~UnitKitPrefork()
+    {
+        fclose(_procSMaps);
+    }
+
+    virtual void launchedKit(int pid) override
+    {
+        // by the magic of forking - this should appear
+        // in the last kit child nearly fully formed.
+        pids.push_back(pid);
+    }
+
+    virtual void postFork() override
+    {
+        // before we drop the caps we can even open our /proc files !
+        std::string procName = std::string("/proc/") +
+                               std::to_string(getpid()) +
+                               std::string("/smaps");
+        _procSMaps = fopen(procName.c_str(), "r");
+    }
+
+    virtual bool filterKitMessage(const std::shared_ptr<Poco::Net::WebSocket> &ws,
+                                  std::string &message) override
+    {
+        std::string token = LOOLProtocol::getFirstToken(message.c_str(), message.length());
+        if (token == "unit-memdump:")
+        {
+            std::string memory = readMemorySizes(_procSMaps) + "\n";
+            ws->sendFrame(memory.c_str(), memory.length());
+            return true;
+        }
+
+        return false;
+    }
 };
 
 UnitBase *unit_create_wsd(void)


More information about the Libreoffice-commits mailing list