[autotest] Monitor the latency of heartbeat serialize/deserialize

Measure the latency for serializing/deserializing objects in heartbeat
between master and shards, and send the data to statsd server.

Serializing/deserializing Host object could become an overhead in the
future due to its dependency on other objects (epecially, AclGroup and
User), therefore, we should keep an eye on it.

BUG=chromium:448608
TEST=puppylab
DEPLOY=apache

Change-Id: Ic81233de3489d66e1f8287614c09d8b8db944982
Reviewed-on: https://chromium-review.googlesource.com/244849
Reviewed-by: Mungyung Ryu <mkryu@google.com>
Commit-Queue: Mungyung Ryu <mkryu@google.com>
Tested-by: Mungyung Ryu <mkryu@google.com>
diff --git a/frontend/afe/model_logic.py b/frontend/afe/model_logic.py
index a0923ba..c48fcf8 100644
--- a/frontend/afe/model_logic.py
+++ b/frontend/afe/model_logic.py
@@ -11,6 +11,7 @@
 from django.db.models.sql import query
 import django.db.models.sql.where
 from django.utils import datastructures
+from autotest_lib.client.common_lib.cros.graphite import autotest_stats
 from autotest_lib.frontend.afe import rdb_model_extensions
 
 
@@ -941,19 +942,23 @@
         @returns: Dictionary representation of the object.
         """
         serialized = {}
-        for field in self._meta.concrete_model._meta.local_fields:
-            if field.rel is None:
-                serialized[field.name] = field._get_val_from_obj(self)
-            elif (include_dependencies and
-                  field.name in self.SERIALIZATION_LINKS_TO_KEEP):
-                # attname will contain "_id" suffix for foreign keys,
-                # e.g. HostAttribute.host will be serialized as 'host_id'.
-                # Use it for easy deserialization.
-                serialized[field.attname] = field._get_val_from_obj(self)
+        timer = autotest_stats.Timer('serialize_latency.%s' % (
+                type(self).__name__))
+        with timer.get_client('local'):
+            for field in self._meta.concrete_model._meta.local_fields:
+                if field.rel is None:
+                    serialized[field.name] = field._get_val_from_obj(self)
+                elif (include_dependencies and
+                      field.name in self.SERIALIZATION_LINKS_TO_KEEP):
+                    # attname will contain "_id" suffix for foreign keys,
+                    # e.g. HostAttribute.host will be serialized as 'host_id'.
+                    # Use it for easy deserialization.
+                    serialized[field.attname] = field._get_val_from_obj(self)
 
         if include_dependencies:
-            for link in self.SERIALIZATION_LINKS_TO_FOLLOW:
-                serialized[link] = self._serialize_relation(link)
+            with timer.get_client('related'):
+                for link in self.SERIALIZATION_LINKS_TO_FOLLOW:
+                    serialized[link] = self._serialize_relation(link)
 
         return serialized
 
@@ -1123,8 +1128,12 @@
         except cls.DoesNotExist:
             instance = cls()
 
-        instance._deserialize_local(local)
-        instance._deserialize_relations(related)
+        timer = autotest_stats.Timer('deserialize_latency.%s' % (
+                type(instance).__name__))
+        with timer.get_client('local'):
+            instance._deserialize_local(local)
+        with timer.get_client('related'):
+            instance._deserialize_relations(related)
 
         return instance