Open mottosso opened 8 years ago
Initial results, using Python for both server and client, xmlrpclib for IPC.
# ...
proxy = xmlrpclib.ServerProxy("http://127.0.0.1:7070")
positions = proxy.compute(positions, {
"envelope": envelope.asFloat(),
"amplitude": amplitude.asDouble(),
"offset": offset.asDouble(),
})
# ...
def compute(positions, data):
for pos in positions:
value = math.sin(pos[0] * data["amplitude"] + data["offset"])
value *= data["envelope"]
pos[1] += value # modify Y-coordinate
return positions
server = SimpleXMLRPCServer(("127.0.0.1", 7070))
server.register_function(compute)
print("Listening on 127.0.0.1:7070")
server.serve_forever()
First of all, xmlrpc is doing implicit serialisation to XML and by the looks of it, that serialisation is not fast. Unsure of what else could be the bottleneck in this scenario. How can I find out?|
Initial results with ZeroMQ, same algorithm. Notice the performance difference!
# ...
self.socket.send(json.dumps({
"positions": positions,
"data": {
"envelope": envelope.asFloat(),
"amplitude": amplitude.asDouble(),
"offset": offset.asDouble(),
}
}))
# ...
while True:
# Wait for next request from client
data = json.loads(socket.recv())
# Send reply back to client
socket.send(json.dumps(compute(**data)))
ZeroMQ is obviously built for speed, but we are still doing JSON serialisation/deserialisation through Python and it's still passing through TCP. It may be compiled on both ends, but so is xmlrpclib(?).
We could likely increase performance further by serialising via something like msgpack, protobuf or cap'n'proto.
But the primary bottleneck is (likely) Python itself.
Once we have a C++ implementation, we can have a look at rigid performance comparisons!
Initial results with C++11 deformer and Python plug-in.
Using the cppzmq bindings and nlohmann/json library.
void compute(json &j)
{
auto data = j["data"];
for (auto &pos: j["positions"])
{
auto frequency = data["frequency"].get<double>();
auto offset = data["offset"].get<double>();
auto amplitude = data["amplitude"].get<double>();
auto envelope = data["envelope"].get<double>();
auto x = pos[0].get<float>();
auto y = pos[1].get<float>();
float value = sin(x * frequency + offset) * amplitude * envelope;
pos[1] = y + value;
}
}
Quite remarkable performance penalty; slower than Python-to-Python! The JSON library was admittedly excluding performance from his list of requirements, but I wouldn't have thought it'd be that affected. Could it be the ZeroMQ library? How? It's the same library as the one used through Python, but without marshalling its way through an inferior interpreter.
Motivation
The act of developing plug-ins for Maya can be improved.
Today, developing a plug-in involves:
This MVP will explore the possibility of a server/client implementation of high-performance computation to combat these disadvantages, with the goal of reaching a performance level of "good enough".
To some extent, performance may very well be outperform a native plug-in via simplified maintenance, testing and better library and language support (e.g. C++11, 14, 17).
If successful, it will allow you to:
Goal
This MVP should provide an externally running process with raw vertex POSITIONS, modify this data in some way and subsequently feed it back into Maya.
Implementation
A node acting as a TCP endpoint from within Maya takes as input the
.outMesh
of another node of typemesh
and provides subsequent node with an.inMesh
.The endpoint transmits the information to an externally running process within which it is somehow being modified and later returned. The endpoint node then outputs the result of this transformation, like any other deformer would.
Todo
vec3
, suitable for GLM.Measure
With the three IPC libraries, (1) xmlrpc, (2) pyzmq and (3) zmq, measure the following.
Conclusion
The end result is a compiled application of high-performance, communicating with a ZeroMQ server running within Maya. The default implementation within Maya will be a Python plug-in, with an optional compiled component for higher performance. Estimating a 5% cost for IPC compared with natively developed plug-ins, excluding potential performance gain mentioned in Motivation above.
If successful, the technique may then also apply to other applications, including standalone use.