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

Commit a6f51b89 authored by Archisha Baranwal's avatar Archisha Baranwal Committed by Android (Google) Code Review
Browse files

Merge "Define the metric definition for GrAlloc allocation per process metric." into main

parents 3d55e090 8b57947e
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