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

Commit f5204922 authored by Yangster-mac's avatar Yangster-mac
Browse files

Avoid creating temporary objects in FiterValue().

It reduces the cpu time from 1000ns to 750ns

Test: statsd test.
Change-Id: Ifa7e98e3368f8d55f85c7b09d05a6c416482981d
parent 5d108838
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -239,7 +239,8 @@ LOCAL_SRC_FILES := $(statsd_common_src) \
                   benchmark/main.cpp \
                   benchmark/hello_world_benchmark.cpp \
                   benchmark/log_event_benchmark.cpp \
                   benchmark/stats_write_benchmark.cpp
                   benchmark/stats_write_benchmark.cpp \
                   benchmark/filter_value_benchmark.cpp

LOCAL_C_INCLUDES := $(statsd_common_c_includes)

+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.
 */
#include <vector>
#include "benchmark/benchmark.h"
#include "FieldValue.h"
#include "HashableDimensionKey.h"
#include "logd/LogEvent.h"

namespace android {
namespace os {
namespace statsd {

using std::vector;

static void BM_FilterValue(benchmark::State& state) {
    LogEvent event(1, 100000);
    event.write(3.2f);
    event.write("LOCATION");
    event.write((int64_t)990);
    event.init();

    FieldMatcher field_matcher;
    field_matcher.set_field(1);
    field_matcher.add_child()->set_field(2);
    field_matcher.add_child()->set_field(3);

    std::vector<Matcher> matchers;
    translateFieldMatcher(field_matcher, &matchers);

    while (state.KeepRunning()) {
        vector<HashableDimensionKey> output;
        filterValues(matchers, event.getValues(), &output);
    }
}

BENCHMARK(BM_FilterValue);

}  //  namespace statsd
}  //  namespace os
}  //  namespace android
+8 −0
Original line number Diff line number Diff line
@@ -135,6 +135,8 @@ Value::Value(const Value& from) {
        case STRING:
            str_value = from.str_value;
            break;
        default:
            break;
    }
}

@@ -148,6 +150,8 @@ std::string Value::toString() const {
            return std::to_string(float_value) + "[F]";
        case STRING:
            return str_value + "[S]";
        default:
            return "[UNKNOWN]";
    }
}

@@ -163,6 +167,8 @@ bool Value::operator==(const Value& that) const {
            return float_value == that.float_value;
        case STRING:
            return str_value == that.str_value;
        default:
            return false;
    }
}

@@ -177,6 +183,8 @@ bool Value::operator!=(const Value& that) const {
            return float_value != that.float_value;
        case STRING:
            return str_value != that.str_value;
        default:
            return false;
    }
}

+6 −4
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ const int32_t kMaxLogDepth = 2;
const int32_t kLastBitMask = 0x80;
const int32_t kClearLastBitDeco = 0x7f;

enum Type { INT, LONG, FLOAT, STRING };
enum Type { UNKNOWN, INT, LONG, FLOAT, STRING };

int32_t getEncodedField(int32_t pos[], int32_t depth, bool includeDepth);

@@ -82,6 +82,8 @@ private:
    int32_t mField;

public:
    Field() {}

    Field(int32_t tag, int32_t pos[], int32_t depth) : mTag(tag) {
        mField = getEncodedField(pos, depth, true);
    }
@@ -229,6 +231,8 @@ struct Matcher {
 *
 */
struct Value {
    Value() : type(UNKNOWN) {}

    Value(int32_t v) {
        int_value = v;
        type = INT;
@@ -280,15 +284,13 @@ struct Value {
    bool operator!=(const Value& that) const;

    bool operator<(const Value& that) const;

private:
    Value(){};
};

/**
 * Represents a log item, or a dimension item (They are essentially the same).
 */
struct FieldValue {
    FieldValue() {}
    FieldValue(const Field& field, const Value& value) : mField(field), mValue(value) {
    }
    bool operator==(const FieldValue& that) const {
+20 −10
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
#define DEBUG false  // STOPSHIP if true
#include "Log.h"

#include <mutex>

#include "HashableDimensionKey.h"
#include "FieldValue.h"

@@ -48,6 +50,8 @@ android::hash_t hashDimension(const HashableDimensionKey& value) {
                hash = android::JenkinsHashMixBytes(hash, (uint8_t*)&floatVal, sizeof(float));
                break;
            }
            default:
                break;
        }
    }
    return JenkinsHashWhiten(hash);
@@ -62,26 +66,32 @@ bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>
    int prevAnyMatcherPrefix = 0;
    size_t prevPrevFanout = 0;
    size_t prevFanout = 0;

    // For each matcher get matched results.
    vector<FieldValue> matchedResults(2);
    for (const auto& matcher : matcherFields) {
        vector<FieldValue> matchedResults;
        size_t num_matches = 0;
        for (const auto& value : values) {
            // TODO: potential optimization here to break early because all fields are naturally
            // sorted.
            if (value.mField.matches(matcher)) {
                matchedResults.push_back(FieldValue(
                        Field(value.mField.getTag(), (value.mField.getField() & matcher.mMask)),
                        value.mValue));
                if (num_matches >= matchedResults.size()) {
                    matchedResults.resize(num_matches * 2);
                }
                matchedResults[num_matches].mField.setTag(value.mField.getTag());
                matchedResults[num_matches].mField.setField(value.mField.getField() & matcher.mMask);
                matchedResults[num_matches].mValue = value.mValue;
                num_matches++;
            }
        }

        if (matchedResults.size() == 0) {
        if (num_matches == 0) {
            VLOG("We can't find a dimension value for matcher (%d)%#x.", matcher.mMatcher.getTag(),
                   matcher.mMatcher.getField());
            continue;
        }

        if (matchedResults.size() == 1) {
        if (num_matches == 1) {
            for (auto& dimension : *output) {
                dimension.addValue(matchedResults[0]);
            }
@@ -117,23 +127,23 @@ bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>
            // First create fanout (fanout size is matchedResults.Size which could be one,
            // which means we do nothing here)
            oldSize = output->size();
            for (size_t i = 1; i < matchedResults.size(); i++) {
            for (size_t i = 1; i < num_matches; i++) {
                output->insert(output->end(), output->begin(), output->begin() + oldSize);
            }
            prevPrevFanout = oldSize;
            prevFanout = matchedResults.size();
            prevFanout = num_matches;
        } else {
            // If we should not create fanout, e.g., uid tag from same position should be remain
            // together.
            oldSize = prevPrevFanout;
            if (prevFanout != matchedResults.size()) {
            if (prevFanout != num_matches) {
                // sanity check.
                ALOGE("2 Any matcher result in different output");
                return false;
            }
        }
        // now add the matched field value to output
        for (size_t i = 0; i < matchedResults.size(); i++) {
        for (size_t i = 0; i < num_matches; i++) {
            for (int j = 0; j < oldSize; j++) {
                (*output)[i * oldSize + j].addValue(matchedResults[i]);
            }
Loading