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

Commit 2ca5d860 authored by Adrian Roos's avatar Adrian Roos
Browse files

ProtoLog: Cache the result of ProtoLogImpl.isEnabled(ProtoLogGroup)

We introduce a generated class ProtoLog$Cache, which contains a field
for each ProtoLogGroup to cache whether it is enabled or not.

This both makes lookup faster, and reduces code size.

Test: make droid
Change-Id: I581c87849c875918b182eff85996b6d19a6755ec
parent cd45b2ab
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ genrule {
    cmd: "$(location protologtool) transform-protolog-calls " +
      "--protolog-class com.android.server.protolog.common.ProtoLog " +
      "--protolog-impl-class com.android.server.protolog.ProtoLogImpl " +
      "--protolog-cache-class 'com.android.server.protolog.ProtoLog$$Cache' " +
      "--loggroups-class com.android.server.wm.ProtoLogGroup " +
      "--loggroups-jar $(location :services.core.wm.protologgroups) " +
      "--output-srcjar $(out) " +
+14 −2
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@ import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.IllegalFormatConversionException;
import java.util.TreeMap;
import java.util.stream.Collectors;
@@ -57,8 +56,18 @@ import java.util.stream.Collectors;
public class ProtoLogImpl {
    private static final TreeMap<String, IProtoLogGroup> LOG_GROUPS = new TreeMap<>();

    /**
     * A runnable to update the cached output of {@link #isEnabled}.
     *
     * Must be invoked after every action that could change the result of {@link #isEnabled}, eg.
     * starting / stopping proto log, or enabling / disabling log groups.
     */
    static Runnable sCacheUpdater = () -> { };

    private static void addLogGroupEnum(IProtoLogGroup[] config) {
        Arrays.stream(config).forEach(group -> LOG_GROUPS.put(group.name(), group));
        for (IProtoLogGroup group : config) {
            LOG_GROUPS.put(group.name(), group);
        }
    }

    static {
@@ -303,6 +312,7 @@ public class ProtoLogImpl {
            mProtoLogEnabled = true;
            mProtoLogEnabledLockFree = true;
        }
        sCacheUpdater.run();
    }

    /**
@@ -327,6 +337,7 @@ public class ProtoLogImpl {
                throw new IllegalStateException("logging enabled while waiting for flush.");
            }
        }
        sCacheUpdater.run();
    }

    /**
@@ -351,6 +362,7 @@ public class ProtoLogImpl {
                return -1;
            }
        }
        sCacheUpdater.run();
        return 0;
    }

+10 −3
Original line number Diff line number Diff line
@@ -27,19 +27,21 @@ class CommandOptions(args: Array<String>) {

        private const val PROTOLOG_CLASS_PARAM = "--protolog-class"
        private const val PROTOLOGIMPL_CLASS_PARAM = "--protolog-impl-class"
        private const val PROTOLOGCACHE_CLASS_PARAM = "--protolog-cache-class"
        private const val PROTOLOGGROUP_CLASS_PARAM = "--loggroups-class"
        private const val PROTOLOGGROUP_JAR_PARAM = "--loggroups-jar"
        private const val VIEWER_CONFIG_JSON_PARAM = "--viewer-conf"
        private const val OUTPUT_SOURCE_JAR_PARAM = "--output-srcjar"
        private val parameters = setOf(PROTOLOG_CLASS_PARAM, PROTOLOGIMPL_CLASS_PARAM,
                PROTOLOGGROUP_CLASS_PARAM, PROTOLOGGROUP_JAR_PARAM, VIEWER_CONFIG_JSON_PARAM,
                OUTPUT_SOURCE_JAR_PARAM)
                PROTOLOGCACHE_CLASS_PARAM, PROTOLOGGROUP_CLASS_PARAM, PROTOLOGGROUP_JAR_PARAM,
                VIEWER_CONFIG_JSON_PARAM, OUTPUT_SOURCE_JAR_PARAM)

        val USAGE = """
            Usage: ${Constants.NAME} <command> [<args>]
            Available commands:

            $TRANSFORM_CALLS_CMD $PROTOLOG_CLASS_PARAM <class name> $PROTOLOGIMPL_CLASS_PARAM
                <class name> $PROTOLOGCACHE_CLASS_PARAM
                <class name> $PROTOLOGGROUP_CLASS_PARAM <class name> $PROTOLOGGROUP_JAR_PARAM
                <config.jar> $OUTPUT_SOURCE_JAR_PARAM <output.srcjar> [<input.java>]
            - processes java files replacing stub calls with logging code.
@@ -54,7 +56,7 @@ class CommandOptions(args: Array<String>) {
        """.trimIndent()

        private fun validateClassName(name: String): String {
            if (!Pattern.matches("^([a-z]+[A-Za-z0-9]*\\.)+([A-Za-z0-9]+)$", name)) {
            if (!Pattern.matches("^([a-z]+[A-Za-z0-9]*\\.)+([A-Za-z0-9$]+)$", name)) {
                throw InvalidCommandException("Invalid class name $name")
            }
            return name
@@ -121,6 +123,7 @@ class CommandOptions(args: Array<String>) {
    val protoLogClassNameArg: String
    val protoLogGroupsClassNameArg: String
    val protoLogImplClassNameArg: String
    val protoLogCacheClassNameArg: String
    val protoLogGroupsJarArg: String
    val viewerConfigJsonArg: String
    val outputSourceJarArg: String
@@ -170,6 +173,8 @@ class CommandOptions(args: Array<String>) {
                        params))
                protoLogImplClassNameArg = validateClassName(getParam(PROTOLOGIMPL_CLASS_PARAM,
                        params))
                protoLogCacheClassNameArg = validateClassName(getParam(PROTOLOGCACHE_CLASS_PARAM,
                        params))
                protoLogGroupsJarArg = validateJarName(getParam(PROTOLOGGROUP_JAR_PARAM, params))
                viewerConfigJsonArg = validateNotSpecified(VIEWER_CONFIG_JSON_PARAM, params)
                outputSourceJarArg = validateSrcJarName(getParam(OUTPUT_SOURCE_JAR_PARAM, params))
@@ -181,6 +186,7 @@ class CommandOptions(args: Array<String>) {
                protoLogGroupsClassNameArg = validateClassName(getParam(PROTOLOGGROUP_CLASS_PARAM,
                        params))
                protoLogImplClassNameArg = validateNotSpecified(PROTOLOGIMPL_CLASS_PARAM, params)
                protoLogCacheClassNameArg = validateNotSpecified(PROTOLOGCACHE_CLASS_PARAM, params)
                protoLogGroupsJarArg = validateJarName(getParam(PROTOLOGGROUP_JAR_PARAM, params))
                viewerConfigJsonArg = validateJSONName(getParam(VIEWER_CONFIG_JSON_PARAM, params))
                outputSourceJarArg = validateNotSpecified(OUTPUT_SOURCE_JAR_PARAM, params)
@@ -191,6 +197,7 @@ class CommandOptions(args: Array<String>) {
                protoLogClassNameArg = validateNotSpecified(PROTOLOG_CLASS_PARAM, params)
                protoLogGroupsClassNameArg = validateNotSpecified(PROTOLOGGROUP_CLASS_PARAM, params)
                protoLogImplClassNameArg = validateNotSpecified(PROTOLOGIMPL_CLASS_PARAM, params)
                protoLogCacheClassNameArg = validateNotSpecified(PROTOLOGCACHE_CLASS_PARAM, params)
                protoLogGroupsJarArg = validateNotSpecified(PROTOLOGGROUP_JAR_PARAM, params)
                viewerConfigJsonArg = validateJSONName(getParam(VIEWER_CONFIG_JSON_PARAM, params))
                outputSourceJarArg = validateNotSpecified(OUTPUT_SOURCE_JAR_PARAM, params)
+45 −1
Original line number Diff line number Diff line
@@ -53,7 +53,8 @@ object ProtoLogTool {

        command.javaSourceArgs.map { path ->
            executor.submitCallable {
                val transformer = SourceTransformer(command.protoLogImplClassNameArg, processor)
                val transformer = SourceTransformer(command.protoLogImplClassNameArg,
                        command.protoLogCacheClassNameArg, processor)
                val file = File(path)
                val text = file.readText()
                val outSrc = try {
@@ -80,10 +81,53 @@ object ProtoLogTool {

        executor.shutdown()

        val cacheSplit = command.protoLogCacheClassNameArg.split(".")
        val cacheName = cacheSplit.last()
        val cachePackage = cacheSplit.dropLast(1).joinToString(".")
        val cachePath = "gen/${cacheSplit.joinToString("/")}.java"

        outJar.putNextEntry(ZipEntry(cachePath))
        outJar.write(generateLogGroupCache(cachePackage, cacheName, groups,
                command.protoLogImplClassNameArg, command.protoLogGroupsClassNameArg).toByteArray())

        outJar.close()
        out.close()
    }

    fun generateLogGroupCache(
        cachePackage: String,
        cacheName: String,
        groups: Map<String, LogGroup>,
        protoLogImplClassName: String,
        protoLogGroupsClassName: String
    ): String {
        val fields = groups.values.map {
            "public static boolean ${it.name}_enabled = false;"
        }.joinToString("\n")

        val updates = groups.values.map {
            "${it.name}_enabled = " +
                    "$protoLogImplClassName.isEnabled($protoLogGroupsClassName.${it.name});"
        }.joinToString("\n")

        return """
            package $cachePackage;

            public class $cacheName {
${fields.replaceIndent("                ")}

                static {
                    $protoLogImplClassName.sCacheUpdater = $cacheName::update;
                    update();
                }

                static void update() {
${updates.replaceIndent("                    ")}
                }
            }
        """.trimIndent()
    }

    private fun tryParse(code: String, fileName: String): CompilationUnit {
        try {
            return StaticJavaParser.parse(code)
+6 −5
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.protolog.tool

import com.android.protolog.tool.Constants.IS_ENABLED_METHOD
import com.android.server.protolog.common.LogDataType
import com.github.javaparser.StaticJavaParser
import com.github.javaparser.ast.CompilationUnit
@@ -45,6 +44,7 @@ import com.github.javaparser.printer.PrettyPrinterConfiguration

class SourceTransformer(
    protoLogImplClassName: String,
    protoLogCacheClassName: String,
    private val protoLogCallProcessor: ProtoLogCallProcessor
) : ProtoLogCallVisitor {
    override fun processCall(
@@ -91,10 +91,9 @@ class SourceTransformer(
            // Replace call to a stub method with an actual implementation.
            // Out: com.android.server.protolog.ProtoLogImpl.e(GROUP, 1234, null, arg)
            newCall.setScope(protoLogImplClassNode)
            // Create a call to ProtoLogImpl.isEnabled(GROUP)
            // Out: com.android.server.protolog.ProtoLogImpl.isEnabled(GROUP)
            val isLogEnabled = MethodCallExpr(protoLogImplClassNode, IS_ENABLED_METHOD,
                NodeList<Expression>(newCall.arguments[0].clone()))
            // Create a call to ProtoLog$Cache.GROUP_enabled
            // Out: com.android.server.protolog.ProtoLog$Cache.GROUP_enabled
            val isLogEnabled = FieldAccessExpr(protoLogCacheClassNode, "${group.name}_enabled")
            if (argTypes.size != call.arguments.size - 2) {
                throw InvalidProtoLogCallException(
                        "Number of arguments (${argTypes.size} does not mach format" +
@@ -211,6 +210,8 @@ class SourceTransformer(

    private val protoLogImplClassNode =
            StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogImplClassName)
    private val protoLogCacheClassNode =
            StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogCacheClassName)
    private var processedCode: MutableList<String> = mutableListOf()
    private var offsets: IntArray = IntArray(0)
    private var fileName: String = ""
Loading