Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b57947e authored by Archisha Baranwal's avatar Archisha Baranwal
Browse files

Define the metric definition for GrAlloc allocation per process metric.

Add a new metric to track the per-process GrAlloc allocs Perfetto Counter
Track which tracks the per process graphic buffer allocations/deallocations.

Bug: 442355906
Test: atest SysUiMetricsV2Test
Flag: EXEMPT added new perfetto metric for sysui
Change-Id: Ia91214ee0ed844fe4bb0810bcfe92a0a5292a569
parent d5437349
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ filegroup {
        "android_sf_critical_work_main_thread.textproto",
        "android_dmabuf_per_process_metric.textproto",
        "android_sf_critical_work_region_sampling.textproto",
        "android_gralloc_buffers_per_process_metric.textproto",
    ],
}

@@ -48,6 +49,11 @@ prebuilt_etc {
    src: "android_sf_critical_work_region_sampling.textproto",
}

prebuilt_etc {
    name: "android_gralloc_buffers_per_process_metric.textproto",
    src: "android_gralloc_buffers_per_process_metric.textproto",
}

python_library_host {
    name: "metrics-tests-utils",
    srcs: ["tests/utils/*.py"],
+76 −0
Original line number Diff line number Diff line
# Copyright (C) 2025 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.


# There is a specific counter added to Perfetto trace of each process that tracks individual GrAlloc
# allocations for each process. This metric monitors said counter.

# We compute the duration of the current counter value by subtracting the current timestamp
# from the timestamp of the next counter value.
# The LEAD function is used to get the next timestamp. If there is no next timestamp, it uses the
# end of the trace as the next timestamp.
query: {
  id: "gralloc_buffers_counter_span"
  sql: {
    sql: "SELECT
        p.name as process_name,
        pct.name AS counter_name,
        value AS metric_val,
          LEAD(ts, 1, (
            SELECT IFNULL(
              end_ts,
              trace_end()
            ) FROM process p WHERE p.upid = pct.upid)
          ) OVER(PARTITION BY track_id ORDER BY ts) - ts AS dur
        FROM counter c JOIN process_counter_track pct ON pct.id = c.track_id
        JOIN process p ON pct.upid = p.upid
        WHERE pct.name = 'mem.gralloc.buffers' AND pct.upid IS NOT NULL
        "
  column_names: "process_name"
  column_names: "counter_name"
  column_names: "metric_val"
  column_names: "dur"
    }
}

metric_template_spec: {
  id_prefix: "android_gralloc_buffers_per_process_metric"
  dimensions: "process_name"
  dimensions: "counter_name"
  value_columns: "min_val"
  value_columns: "max_val"
  value_columns: "avg_val"
  query: {
    inner_query_id: "gralloc_buffers_counter_span"
    group_by: {
      column_names: "process_name"
      column_names: "counter_name"
      aggregates: {
        column_name: "metric_val"
        op: MIN
        result_column_name: "min_val"
      }
      aggregates: {
        column_name: "metric_val"
        op: MAX
        result_column_name: "max_val"
      }
      aggregates: {
        column_name: "metric_val"
        op: DURATION_WEIGHTED_MEAN
        result_column_name: "avg_val"
      }
    }
  }
}
+123 −0
Original line number Diff line number Diff line
metric_bundles {
  row {
    values {
      double_value: 10.0
    }
    values {
      double_value: 20.0
    }
    values {
      double_value: 13.333333333333334
    }
    dimension {
      string_value: "com.android.systemui"
    }
    dimension {
      string_value: "mem.gralloc.buffers"
    }
  }
  row {
    values {
      double_value: 15.0
    }
    values {
      double_value: 25.0
    }
    values {
      double_value: 15.0
    }
    dimension {
      string_value: "com.google.android.apps.nexuslauncher"
    }
    dimension {
      string_value: "mem.gralloc.buffers"
    }
  }
  specs {
    id: "android_gralloc_buffers_per_process_metric_min_val"
    dimensions: "process_name"
    dimensions: "counter_name"
    value: "min_val"
    query {
      inner_query_id: "gralloc_buffers_counter_span"
      group_by {
        column_names: "process_name"
        column_names: "counter_name"
        aggregates {
          column_name: "metric_val"
          op: MIN
          result_column_name: "min_val"
        }
        aggregates {
          column_name: "metric_val"
          op: MAX
          result_column_name: "max_val"
        }
        aggregates {
          column_name: "metric_val"
          op: DURATION_WEIGHTED_MEAN
          result_column_name: "avg_val"
        }
      }
    }
    bundle_id: "android_gralloc_buffers_per_process_metric"
  }
  specs {
    id: "android_gralloc_buffers_per_process_metric_max_val"
    dimensions: "process_name"
    dimensions: "counter_name"
    value: "max_val"
    query {
      inner_query_id: "gralloc_buffers_counter_span"
      group_by {
        column_names: "process_name"
        column_names: "counter_name"
        aggregates {
          column_name: "metric_val"
          op: MIN
          result_column_name: "min_val"
        }
        aggregates {
          column_name: "metric_val"
          op: MAX
          result_column_name: "max_val"
        }
        aggregates {
          column_name: "metric_val"
          op: DURATION_WEIGHTED_MEAN
          result_column_name: "avg_val"
        }
      }
    }
    bundle_id: "android_gralloc_buffers_per_process_metric"
  }
  specs {
    id: "android_gralloc_buffers_per_process_metric_avg_val"
    dimensions: "process_name"
    dimensions: "counter_name"
    value: "avg_val"
    query {
      inner_query_id: "gralloc_buffers_counter_span"
      group_by {
        column_names: "process_name"
        column_names: "counter_name"
        aggregates {
          column_name: "metric_val"
          op: MIN
          result_column_name: "min_val"
        }
        aggregates {
          column_name: "metric_val"
          op: MAX
          result_column_name: "max_val"
        }
        aggregates {
          column_name: "metric_val"
          op: DURATION_WEIGHTED_MEAN
          result_column_name: "avg_val"
        }
      }
    }
    bundle_id: "android_gralloc_buffers_per_process_metric"
  }
}
+13 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ from metrics_specs.tests.utils import android_bitmap_metric_trace
from metrics_specs.tests.utils import android_sf_critical_work_main_thread_trace
from metrics_specs.tests.utils import android_dmabuf_per_process_metric_trace
from metrics_specs.tests.utils import android_sf_critical_work_region_sampling_trace
from metrics_specs.tests.utils import android_gralloc_buffers_per_process_metric_trace
from metrics_specs.tests.utils import test_helper
import unittest

@@ -73,5 +74,17 @@ class MetricsV2Test(unittest.TestCase):
             ]
        )

    def test_android_gralloc_buffers_per_process_metric(self):
        self.helper.verify_metric(
            spec_file="android_gralloc_buffers_per_process_metric.textproto",
            trace_proto_bytes = android_gralloc_buffers_per_process_metric_trace.get_proto(),
            expected_output_file = "android_gralloc_buffers_per_process_metric_output.txt",
            metric_ids = [
                "android_gralloc_buffers_per_process_metric_min_val",
                "android_gralloc_buffers_per_process_metric_max_val",
                "android_gralloc_buffers_per_process_metric_avg_val",
            ]
        )

if __name__ == '__main__':
    unittest.main()
+48 −0
Original line number Diff line number Diff line
#!/usr/bin/env python3
# Copyright (C) 2025 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from metrics_specs.tests.utils import trace_proto_builder
from perfetto.protos.perfetto.trace.perfetto_trace_pb2 import Trace

def get_proto():
    SYSUI_PID = 1000
    SYSUI_PROCESS_NAME = "com.android.systemui"

    LAUNCHER_PID = 2000
    LAUNCHER_PROCESS_NAME = "com.google.android.apps.nexuslauncher"

    trace = Trace()
    builder = trace_proto_builder.TraceProtoBuilder(trace)

    # Add all processes
    builder.add_packet()
    builder.add_process(pid=SYSUI_PID, ppid=SYSUI_PID, cmdline=SYSUI_PROCESS_NAME, uid=10001)
    builder.add_process(pid=LAUNCHER_PID, ppid=LAUNCHER_PID, cmdline=LAUNCHER_PROCESS_NAME, uid=20001)

    # Add counters in the com.android.systemui process
    builder.add_ftrace_packet(cpu=0)
    builder.add_atrace_counter(ts=1000, pid=SYSUI_PID, tid=SYSUI_PID, buf="mem.gralloc.buffers", cnt=10)
    builder.add_ftrace_packet(cpu=0)
    builder.add_atrace_counter(ts=2000, pid=SYSUI_PID, tid=SYSUI_PID, buf="mem.gralloc.buffers", cnt=20)
    builder.add_ftrace_packet(cpu=0)
    builder.add_atrace_counter(ts=1000, pid=SYSUI_PID, tid=SYSUI_PID, buf="Random Counter", cnt=111)

    # Add counters in the com.google.android.apps.nexuslauncher process
    builder.add_ftrace_packet(cpu=0)
    builder.add_atrace_counter(ts=1500, pid=LAUNCHER_PID, tid=LAUNCHER_PID, buf="mem.gralloc.buffers", cnt=15)
    builder.add_ftrace_packet(cpu=0)
    builder.add_atrace_counter(ts=2500, pid=LAUNCHER_PID, tid=LAUNCHER_PID, buf="mem.gralloc.buffers", cnt=25)

    return builder.trace.SerializeToString()
 No newline at end of file