> On Nov. 19, 2019, 6:12 p.m., Andrei Sekretenko wrote:
> > src/master/http.cpp
> > Lines 2242 (patched)
> > <https://reviews.apache.org/r/71750/diff/1/?file=2172061#file2172061line2242>
> >
> >     Did you consider allocating the `agent` temporaries outside of the 
> > loops? In my experience, protobuf construction used to be much more 
> > expensive than modification.
> >     
> >     (Tried this, observed a ~10% speedup for `v1 'master::call::GetState' 
> > application/x-protobuf` in my setup.)
> 
> Benjamin Mahler wrote:
>     Hm.. that's interesting, could certainly look into this for the GetAgents 
> and GetFrameworks code which both use temporaries. The temporaries aren't 
> necessary though, we could eliminate the need to copy entirely, but 
> allocating them outside the loops seems like an easier win.
>     
>     Unfortunately the most expensive part in practice (non-pending tasks) are 
> not using temporaries like this. I'll look into a patch at the end of this 
> chain to allocate outside the loops.
> 
> Benjamin Mahler wrote:
>     > (Tried this, observed a ~10% speedup for v1 'master::call::GetState' 
> application/x-protobuf in my setup.)
>     
>     Curious to see your setup (did you just use a lot of agents instead of a 
> lot of tasks?) and your diff.

Also did you run with optimizations on? How many runs did you do? Because 
there's quite a high variance. Just did 10 runs of 
AgentFrameworkTaskCountContentType/MasterStateQuery_BENCHMARK_Test.GetState/3:

before: median 5.29 from [4.41, 4.51, 5.07, 5.10, 5.27, 5.32, 5.49, 5.51, 5.70, 
6.46]
after:  median 5.11 from [4.68, 4.79, 4.80, 4.84, 5.01, 5.21, 5.25, 5.42, 6.42, 
7.43]

So based on medians it's 96.6% of the time without the loop change?

With the following diff applied to this chain to produce 'after':

```
diff --git a/src/master/http.cpp b/src/master/http.cpp
index 0ca25b6d7..c77788cdf 100644
--- a/src/master/http.cpp
+++ b/src/master/http.cpp
@@ -1480,6 +1480,7 @@ string Master::Http::serializeGetFrameworks(
   // expect a large number of pending tasks, we currently don't
   // bother with the more efficient approach.
 
+  mesos::master::Response::GetFrameworks::Framework f;
   foreachvalue (const Framework* framework,
                 master->frameworks.registered) {
     // Skip unauthorized frameworks.
@@ -1487,7 +1488,7 @@ string Master::Http::serializeGetFrameworks(
       continue;
     }
 
-    mesos::master::Response::GetFrameworks::Framework f = model(*framework);
+    f = model(*framework);
     writer.WriteTag(
         WireFormatLite::MakeTag(
             mesos::master::Response::GetFrameworks
@@ -1504,7 +1505,7 @@ string Master::Http::serializeGetFrameworks(
       continue;
     }
 
-    mesos::master::Response::GetFrameworks::Framework f = model(*framework);
+    f = model(*framework);
     writer.WriteTag(
         WireFormatLite::MakeTag(
             mesos::master::Response::GetFrameworks
@@ -2970,15 +2971,15 @@ string Master::Http::serializeGetAgents(
   google::protobuf::io::StringOutputStream stream(&output);
   google::protobuf::io::CodedOutputStream writer(&stream);
 
+  mesos::master::Response::GetAgents::Agent agent;
   foreachvalue (const Slave* slave, master->slaves.registered) {
     // TODO(bmahler): Consider not constructing the temporary
     // agent object and instead serialize directly.
-    mesos::master::Response::GetAgents::Agent agent =
-      protobuf::master::event::createAgentResponse(
-          *slave,
-          master->slaves.draining.get(slave->id),
-          master->slaves.deactivated.contains(slave->id),
-          approvers);
+    agent = protobuf::master::event::createAgentResponse(
+        *slave,
+        master->slaves.draining.get(slave->id),
+        master->slaves.deactivated.contains(slave->id),
+        approvers);
 
     writer.WriteTag(
         WireFormatLite::MakeTag(
@@ -2988,14 +2989,15 @@ string Master::Http::serializeGetAgents(
     agent.SerializeToCodedStream(&writer);
   }
 
+  SlaveInfo recoveredAgent;
   foreachvalue (const SlaveInfo& slaveInfo, master->slaves.recovered) {
     // TODO(bmahler): Consider not constructing the temporary
     // SlaveInfo object and instead serialize directly.
-    SlaveInfo agent = slaveInfo;
-    agent.clear_resources();
+    recoveredAgent = slaveInfo;
+    recoveredAgent.clear_resources();
     foreach (const Resource& resource, slaveInfo.resources()) {
       if (approvers->approved<VIEW_ROLE>(resource)) {
-        *agent.add_resources() = resource;
+        *recoveredAgent.add_resources() = resource;
       }
     }
 
@@ -3003,8 +3005,8 @@ string Master::Http::serializeGetAgents(
         WireFormatLite::MakeTag(
             mesos::master::Response::GetAgents::kRecoveredAgentsFieldNumber,
             WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
-    writer.WriteVarint32(agent.ByteSizeLong());
-    agent.SerializeToCodedStream(&writer);
+    writer.WriteVarint32(recoveredAgent.ByteSizeLong());
+    recoveredAgent.SerializeToCodedStream(&writer);
   }
 
   // While an explicit Trim() isn't necessary (since the coded

```


- Benjamin


-----------------------------------------------------------
This is an automatically generated e-mail. To reply, visit:
https://reviews.apache.org/r/71750/#review218678
-----------------------------------------------------------


On Nov. 12, 2019, 12:03 a.m., Benjamin Mahler wrote:
> 
> -----------------------------------------------------------
> This is an automatically generated e-mail. To reply, visit:
> https://reviews.apache.org/r/71750/
> -----------------------------------------------------------
> 
> (Updated Nov. 12, 2019, 12:03 a.m.)
> 
> 
> Review request for mesos, Andrei Sekretenko, Greg Mann, and Meng Zhu.
> 
> 
> Bugs: MESOS-10026
>     https://issues.apache.org/jira/browse/MESOS-10026
> 
> 
> Repository: mesos
> 
> 
> Description
> -------
> 
> This updates the handling to serialize directly to protobuf or json
> from the in-memory v0 state, bypassing expensive intermediate
> serialization / de-serialization / object construction / object
> destruction.
> 
> This initial patch shows the approach that will be used for the
> other expensive calls. Note that this type of manual writing is
> more brittle and complex, but it can be mostly eliminated if we
> keep an up-to-date v1 GetState in memory in the future.
> 
> When this approach is applied fully to GetState, it leads to the
> following improvement:
> 
> Before:
> v0 '/state' response took 6.55 secs
> v1 'GetState' application/x-protobuf response took 24.08 secs
> v1 'GetState' application/json response took 22.76 secs
> 
> After:
> v0 '/state' response took 8.00 secs
> v1 'GetState' application/x-protobuf response took 5.73 secs
> v1 'GetState' application/json response took 9.62 secs
> 
> 
> Diffs
> -----
> 
>   src/master/http.cpp 60765c9b9d6903f6ed94fa8c614055698caad0da 
>   src/master/master.hpp dc45028d2ecfb61bf9ea82d90d2393af648a6023 
> 
> 
> Diff: https://reviews.apache.org/r/71750/diff/1/
> 
> 
> Testing
> -------
> 
> make check
> 
> 
> Thanks,
> 
> Benjamin Mahler
> 
>

Reply via email to