From 2f231b5ce54a8b6239a58b89e189a90836c1470b Mon Sep 17 00:00:00 2001
From: Sergei Trofimov <sergei.trofimov@arm.com>
Date: Thu, 12 Sep 2019 09:13:20 +0100
Subject: [PATCH] fw/target: detect module variations in TargetInfo

- Add modules entry to TargetInfo
- When retrieving TargetInfo from cache, make sure info modules match
  those for the current target, otherwise mark info as stale and
  re-generate.
---
 doc/source/api/output.rst                              |  6 ++++++
 wa/commands/postgres_schemas/postgres_schema.sql       |  3 ++-
 .../postgres_schemas/postgres_schema_update_v1.4.sql   |  2 ++
 wa/framework/output.py                                 |  2 +-
 wa/framework/target/info.py                            | 10 +++++++++-
 wa/framework/target/manager.py                         |  9 +++++++++
 wa/output_processors/postgresql.py                     |  5 +++--
 7 files changed, 32 insertions(+), 5 deletions(-)
 create mode 100644 wa/commands/postgres_schemas/postgres_schema_update_v1.4.sql

diff --git a/doc/source/api/output.rst b/doc/source/api/output.rst
index 63eec3bc..c656b5de 100644
--- a/doc/source/api/output.rst
+++ b/doc/source/api/output.rst
@@ -608,6 +608,12 @@ The available attributes of the class are as follows:
     The name of the target class that was uised ot interact with the device
     during the run E.g.  ``"AndroidTarget"``, ``"LinuxTarget"`` etc.
 
+``modules``
+    A list of names of modules that have been loaded by the target. Modules
+    provide additional functionality, such as access to ``cpufreq`` and which
+    modules are installed may impact how much of the ``TargetInfo`` has been
+    populated.
+
 ``cpus``
     A list of :class:`CpuInfo` objects describing the capabilities of each CPU.
 
diff --git a/wa/commands/postgres_schemas/postgres_schema.sql b/wa/commands/postgres_schemas/postgres_schema.sql
index 19daa85e..658bb01b 100644
--- a/wa/commands/postgres_schemas/postgres_schema.sql
+++ b/wa/commands/postgres_schemas/postgres_schema.sql
@@ -1,4 +1,4 @@
---!VERSION!1.3!ENDVERSION!
+--!VERSION!1.4!ENDVERSION!
 CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
 CREATE EXTENSION IF NOT EXISTS "lo";
 
@@ -78,6 +78,7 @@ CREATE TABLE Targets (
     oid uuid NOT NULL,
     run_oid uuid NOT NULL references Runs(oid),
     target text,
+    modules text[],
     cpus text[],
     os text,
     os_version jsonb,
diff --git a/wa/commands/postgres_schemas/postgres_schema_update_v1.4.sql b/wa/commands/postgres_schemas/postgres_schema_update_v1.4.sql
new file mode 100644
index 00000000..09cae085
--- /dev/null
+++ b/wa/commands/postgres_schemas/postgres_schema_update_v1.4.sql
@@ -0,0 +1,2 @@
+ALTER TABLE targets ADD COLUMN modules text[];
+
diff --git a/wa/framework/output.py b/wa/framework/output.py
index 41e7c8e7..66b90a1d 100644
--- a/wa/framework/output.py
+++ b/wa/framework/output.py
@@ -984,7 +984,7 @@ class RunDatabaseOutput(DatabaseOutput, RunOutputCommon):
 
     @property
     def _db_targetfile(self):
-        columns = ['os', 'is_rooted', 'target', 'abi', 'cpus', 'os_version',
+        columns = ['os', 'is_rooted', 'target', 'modules', 'abi', 'cpus', 'os_version',
                    'hostid', 'hostname', 'kernel_version', 'kernel_release',
                    'kernel_sha1', 'kernel_config', 'sched_features', 'page_size_kb',
                    'system_id', 'screen_resolution', 'prop', 'android_id',
diff --git a/wa/framework/target/info.py b/wa/framework/target/info.py
index 4baab132..9a320026 100644
--- a/wa/framework/target/info.py
+++ b/wa/framework/target/info.py
@@ -221,6 +221,7 @@ class CpuInfo(Podable):
 def get_target_info(target):
     info = TargetInfo()
     info.target = target.__class__.__name__
+    info.modules = target.modules
     info.os = target.os
     info.os_version = target.os_version
     info.system_id = target.system_id
@@ -313,12 +314,13 @@ def cache_target_info(target_info, overwrite=False):
 
 class TargetInfo(Podable):
 
-    _pod_serialization_version = 4
+    _pod_serialization_version = 5
 
     @staticmethod
     def from_pod(pod):
         instance = super(TargetInfo, TargetInfo).from_pod(pod)
         instance.target = pod['target']
+        instance.modules = pod['modules']
         instance.abi = pod['abi']
         instance.cpus = [CpuInfo.from_pod(c) for c in pod['cpus']]
         instance.os = pod['os']
@@ -343,6 +345,7 @@ class TargetInfo(Podable):
     def __init__(self):
         super(TargetInfo, self).__init__()
         self.target = None
+        self.modules = []
         self.cpus = []
         self.os = None
         self.os_version = None
@@ -362,6 +365,7 @@ class TargetInfo(Podable):
     def to_pod(self):
         pod = super(TargetInfo, self).to_pod()
         pod['target'] = self.target
+        pod['modules'] = self.modules
         pod['abi'] = self.abi
         pod['cpus'] = [c.to_pod() for c in self.cpus]
         pod['os'] = self.os
@@ -413,3 +417,7 @@ class TargetInfo(Podable):
     @staticmethod
     def _pod_upgrade_v4(pod):
         return TargetInfo._pod_upgrade_v3(pod)
+
+    @staticmethod
+    def _pod_upgrade_v5(pod):
+        pod['modules'] = pod.get('modules') or []
diff --git a/wa/framework/target/manager.py b/wa/framework/target/manager.py
index 79dec6ca..18280c83 100644
--- a/wa/framework/target/manager.py
+++ b/wa/framework/target/manager.py
@@ -92,9 +92,18 @@ class TargetManager(object):
     @memoized
     def get_target_info(self):
         info = get_target_info_from_cache(self.target.system_id)
+
         if info is None:
             info = get_target_info(self.target)
             cache_target_info(info)
+        else:
+            # If module configuration has changed form when the target info
+            # was previously cached, it is possible additional info will be
+            # available, so should re-generate the cache.
+            if set(info.modules) != set(self.target.modules):
+                info = get_target_info(self.target)
+                cache_target_info(info, overwrite=True)
+
         return info
 
     def reboot(self, context, hard=False):
diff --git a/wa/output_processors/postgresql.py b/wa/output_processors/postgresql.py
index ab48ea87..24d94936 100644
--- a/wa/output_processors/postgresql.py
+++ b/wa/output_processors/postgresql.py
@@ -90,8 +90,8 @@ class PostgresqlResultProcessor(OutputProcessor):
                       "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
         "update_run": "UPDATE Runs SET event_summary=%s, status=%s, timestamp=%s, end_time=%s, duration=%s, state=%s WHERE oid=%s;",
         "create_job": "INSERT INTO Jobs (oid, run_oid, status, retry, label, job_id, iterations, workload_name, metadata, _pod_version, _pod_serialization_version) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s);",
-        "create_target": "INSERT INTO Targets (oid, run_oid, target, cpus, os, os_version, hostid, hostname, abi, is_rooted, kernel_version, kernel_release, kernel_sha1, kernel_config, sched_features, page_size_kb, system_id, screen_resolution, prop, android_id, _pod_version, _pod_serialization_version) "
-                         "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
+        "create_target": "INSERT INTO Targets (oid, run_oid, target, modules, cpus, os, os_version, hostid, hostname, abi, is_rooted, kernel_version, kernel_release, kernel_sha1, kernel_config, sched_features, page_size_kb, system_id, screen_resolution, prop, android_id, _pod_version, _pod_serialization_version) "
+                         "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
         "create_event": "INSERT INTO Events (oid, run_oid, job_oid, timestamp, message, _pod_version, _pod_serialization_version) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s",
         "create_artifact": "INSERT INTO Artifacts (oid, run_oid, job_oid, name, large_object_uuid, description, kind, is_dir, _pod_version, _pod_serialization_version) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
         "create_metric": "INSERT INTO Metrics (oid, run_oid, job_oid, name, value, units, lower_is_better, _pod_version, _pod_serialization_version) VALUES (%s, %s, %s, %s, %s, %s , %s, %s, %s)",
@@ -190,6 +190,7 @@ class PostgresqlResultProcessor(OutputProcessor):
                 self.target_uuid,
                 self.run_uuid,
                 target_pod['target'],
+                target_pod['modules'],
                 target_pod['cpus'],
                 target_pod['os'],
                 target_pod['os_version'],