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

Commit 2e9166e6 authored by Daniele Di Proietto's avatar Daniele Di Proietto
Browse files

Support reading vendor categories from file instead of HAL

There are three types of categories in atrace.cpp now:
* The builtin categories (not affected by this change).
* The new vendor categories read from the file. They're discoved at
  runtime, but they behave like the builtin categories (they're enabled
  by writing to tracefs).
* The old HAL categories. They're listed, enabled and disabled by
  calling the HAL. They are not discovered at all now if the vendor file
  is there.

Tested on a device with a vendor file, by listing categories and making
sure that enabling them has the expected effect on tracefs.

Bug: 204935495
Change-Id: I3117c42a005aca0b736c538a274b0d76887cb706
parent f533eb15
Loading
Loading
Loading
Loading

cmds/atrace/README.md

0 → 100644
+48 −0
Original line number Diff line number Diff line
# Atrace categories

The atrace command (and the perfetto configuration) allow listing **categories**
to select subsets of events to be traced.

Each category can include some userspace events and some ftrace events.

## Vendor categories

It's possible to extend exiting categories (or to define new categories) from
the /vendor partition in order to add hardware specific ftrace events.

Since android 14, if the file `/vendor/etc/atrace/atrace_categories.txt`, atrace
and perfetto will consider the categories and ftrace events listed there.

The file contains a list of categories, and for each category (on the following
lines, indented with one or more spaces of time), a list of ftrace events that
should be enabled when the category is enabled.

Each ftrace event should be a subdirectory in `/sys/kernel/tracing/events/` and
should be of the form `group/event`. Listing a whole group is not supported,
each event needs to be listed explicitly.

It is not an error if an ftrace event is listed in the file, but not present on
the tracing file system.

Example:

```
gfx
 mali/gpu_power_state
 mali/mali_pm_status
thermal_tj
 thermal_exynos/thermal_cpu_pressure
 thermal_exynos/thermal_exynos_arm_update
```

The file lists two categories (`gfx` and `thermal_tj`). When the `gfx` category
is enabled, atrace (or perfetto) will enable
`/sys/kernel/tracing/events/mali/gpu_power_state` and
`/sys/kernel/tracing/events/mali/mali_pm_status`. When the `thermal_tj` category
is enabled, atrace (or perfetto) will enable
`/sys/kernel/tracing/events/thermal_exynos/thermal_cpu_pressure` and
`/sys/kernel/tracing/events/thermal_exynos/thermal_exynos_arm_update`.

Since android 14, if the file `/vendor/etc/atrace/atrace_categories.txt` exists
on the file system, perfetto and atrace do not query the android.hardware.atrace
HAL (which is deprecated).
+104 −28
Original line number Diff line number Diff line
@@ -49,6 +49,7 @@
#include <android-base/file.h>
#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/stringprintf.h>

using namespace android;
@@ -73,6 +74,8 @@ const char* k_coreServiceCategory = "core_services";
const char* k_pdxServiceCategory = "pdx";
const char* k_coreServicesProp = "ro.atrace.core.services";

const char* kVendorCategoriesPath = "/vendor/etc/atrace/atrace_categories.txt";

typedef enum { OPT, REQ } requiredness;

struct TracingCategory {
@@ -253,7 +256,20 @@ static const TracingCategory k_categories[] = {
    } },
};

struct TracingVendorCategory {
// A category in the vendor categories file.
struct TracingVendorFileCategory {
    // The name identifying the category.
    std::string name;

    // If the category is enabled through command.
    bool enabled = false;

    // Paths to the ftrace enable files (relative to g_traceFolder).
    std::vector<std::string> ftrace_enable_paths;
};

// A category in the vendor HIDL HAL.
struct TracingVendorHalCategory {
    // The name identifying the category.
    std::string name;

@@ -263,11 +279,8 @@ struct TracingVendorCategory {
    // If the category is enabled through command.
    bool enabled;

    TracingVendorCategory(string &&name, string &&description, bool enabled)
            : name(std::move(name))
            , description(std::move(description))
            , enabled(enabled)
    {}
    TracingVendorHalCategory(string&& name, string&& description, bool enabled)
          : name(std::move(name)), description(std::move(description)), enabled(enabled) {}
};

/* Command line options */
@@ -287,8 +300,9 @@ static bool g_tracePdx = false;
static bool g_traceAborted = false;
static bool g_categoryEnables[arraysize(k_categories)] = {};
static std::string g_traceFolder;
static std::vector<TracingVendorFileCategory> g_vendorFileCategories;
static sp<IAtraceDevice> g_atraceHal;
static std::vector<TracingVendorCategory> g_vendorCategories;
static std::vector<TracingVendorHalCategory> g_vendorHalCategories;

/* Sys file paths */
static const char* k_traceClockPath =
@@ -645,6 +659,13 @@ static bool disableKernelTraceEvents() {
            }
        }
    }
    for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
        for (const std::string& path : c.ftrace_enable_paths) {
            if (fileIsWritable(path.c_str())) {
                ok &= setKernelOptionEnable(path.c_str(), false);
            }
        }
    }
    return ok;
}

@@ -724,7 +745,13 @@ static bool setKernelTraceFuncs(const char* funcs)
static bool setCategoryEnable(const char* name)
{
    bool vendor_found = false;
    for (auto &c : g_vendorCategories) {
    for (auto& c : g_vendorFileCategories) {
        if (strcmp(name, c.name.c_str()) == 0) {
            c.enabled = true;
            vendor_found = true;
        }
    }
    for (auto& c : g_vendorHalCategories) {
        if (strcmp(name, c.name.c_str()) == 0) {
            c.enabled = true;
            vendor_found = true;
@@ -870,6 +897,16 @@ static bool setUpKernelTracing()
        }
    }

    for (const TracingVendorFileCategory& c : g_vendorFileCategories) {
        if (c.enabled) {
            for (const std::string& path : c.ftrace_enable_paths) {
                if (fileIsWritable(path.c_str())) {
                    ok &= setKernelOptionEnable(path.c_str(), true);
                }
            }
        }
    }

    return ok;
}

@@ -1055,7 +1092,10 @@ static void listSupportedCategories()
            printf("  %10s - %s\n", c.name, c.longname);
        }
    }
    for (const auto &c : g_vendorCategories) {
    for (const auto& c : g_vendorFileCategories) {
        printf("  %10s - (VENDOR)\n", c.name.c_str());
    }
    for (const auto& c : g_vendorHalCategories) {
        printf("  %10s - %s (HAL)\n", c.name.c_str(), c.description.c_str());
    }
}
@@ -1114,8 +1154,38 @@ bool findTraceFiles()
    return true;
}

void initVendorCategories()
{
void initVendorCategoriesFromFile() {
    std::ifstream is(kVendorCategoriesPath);
    for (std::string line; std::getline(is, line);) {
        if (line.empty()) {
            continue;
        }
        if (android::base::StartsWith(line, ' ') || android::base::StartsWith(line, '\t')) {
            if (g_vendorFileCategories.empty()) {
                fprintf(stderr, "Malformed vendor categories file\n");
                exit(1);
                return;
            }
            std::string_view path = std::string_view(line).substr(1);
            while (android::base::StartsWith(path, ' ') || android::base::StartsWith(path, '\t')) {
                path.remove_prefix(1);
            }
            if (path.empty()) {
                continue;
            }
            std::string enable_path = "events/";
            enable_path += path;
            enable_path += "/enable";
            g_vendorFileCategories.back().ftrace_enable_paths.push_back(std::move(enable_path));
        } else {
            TracingVendorFileCategory cat;
            cat.name = line;
            g_vendorFileCategories.push_back(std::move(cat));
        }
    }
}

void initVendorCategoriesFromHal() {
    g_atraceHal = IAtraceDevice::getService();

    if (g_atraceHal == nullptr) {
@@ -1123,11 +1193,10 @@ void initVendorCategories()
        return;
    }

    Return<void> ret = g_atraceHal->listCategories(
        [](const auto& list) {
            g_vendorCategories.reserve(list.size());
    Return<void> ret = g_atraceHal->listCategories([](const auto& list) {
        g_vendorHalCategories.reserve(list.size());
        for (const auto& category : list) {
                g_vendorCategories.emplace_back(category.name, category.description, false);
            g_vendorHalCategories.emplace_back(category.name, category.description, false);
        }
    });
    if (!ret.isOk()) {
@@ -1135,15 +1204,23 @@ void initVendorCategories()
    }
}

static bool setUpVendorTracing()
{
void initVendorCategories() {
    // If kVendorCategoriesPath exists on the filesystem, do not use the HAL.
    if (access(kVendorCategoriesPath, F_OK) != -1) {
        initVendorCategoriesFromFile();
    } else {
        initVendorCategoriesFromHal();
    }
}

static bool setUpVendorTracingWithHal() {
    if (g_atraceHal == nullptr) {
        // No atrace HAL
        return true;
    }

    std::vector<hidl_string> categories;
    for (const auto &c : g_vendorCategories) {
    for (const auto& c : g_vendorHalCategories) {
        if (c.enabled) {
            categories.emplace_back(c.name);
        }
@@ -1164,15 +1241,14 @@ static bool setUpVendorTracing()
    return true;
}

static bool cleanUpVendorTracing()
{
static bool cleanUpVendorTracingWithHal() {
    if (g_atraceHal == nullptr) {
        // No atrace HAL
        return true;
    }

    if (!g_vendorCategories.size()) {
        // No vendor categories
    if (!g_vendorHalCategories.size()) {
        // No vendor HAL categories
        return true;
    }

@@ -1326,7 +1402,7 @@ int main(int argc, char **argv)

    if (ok && traceStart && !onlyUserspace) {
        ok &= setUpKernelTracing();
        ok &= setUpVendorTracing();
        ok &= setUpVendorTracingWithHal();
        ok &= startTrace();
    }

@@ -1397,7 +1473,7 @@ int main(int argc, char **argv)
    if (traceStop) {
        cleanUpUserspaceTracing();
        if (!onlyUserspace) {
            cleanUpVendorTracing();
            cleanUpVendorTracingWithHal();
            cleanUpKernelTracing();
        }
    }