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

Commit 3a383104 authored by Josh Gao's avatar Josh Gao Committed by Gerrit Code Review
Browse files

Merge changes I9f36cc26,I06561ad0,I42c2a8d0

* changes:
  adb: add benchmark script.
  adb: add IOVector.
  Revert "Revert "adb: add support for O_CLOEXEC to unique_fd pipe wrapper.""
parents 2ed14f39 fd3fd937
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -122,6 +122,7 @@ libadb_test_srcs = [
    "sysdeps_test.cpp",
    "sysdeps/stat_test.cpp",
    "transport_test.cpp",
    "types_test.cpp",
]

cc_library_host_static {
+28 −1
Original line number Diff line number Diff line
@@ -28,11 +28,38 @@ struct AdbCloser {
using unique_fd = android::base::unique_fd_impl<AdbCloser>;

#if !defined(_WIN32)
inline bool Pipe(unique_fd* read, unique_fd* write) {
inline bool Pipe(unique_fd* read, unique_fd* write, int flags = 0) {
    int pipefd[2];
#if !defined(__APPLE__)
    if (pipe2(pipefd, flags) != 0) {
        return false;
    }
#else
    // Darwin doesn't have pipe2. Implement it ourselves.
    if (flags != 0 && (flags & ~(O_CLOEXEC | O_NONBLOCK)) != 0) {
        errno = EINVAL;
        return false;
    }

    if (pipe(pipefd) != 0) {
        return false;
    }

    if (flags & O_CLOEXEC) {
        if (fcntl(pipefd[0], F_SETFD, FD_CLOEXEC) != 0 ||
            fcntl(pipefd[1], F_SETFD, FD_CLOEXEC) != 0) {
            PLOG(FATAL) << "failed to set FD_CLOEXEC on newly created pipe";
        }
    }

    if (flags & O_NONBLOCK) {
        if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) != 0 ||
            fcntl(pipefd[1], F_SETFL, O_NONBLOCK) != 0) {
            PLOG(FATAL) << "failed to set O_NONBLOCK  on newly created pipe";
        }
    }
#endif

    read->reset(pipefd[0]);
    write->reset(pipefd[1]);
    return true;
+120 −0
Original line number Diff line number Diff line
#!/usr/bin/env python3
#
# 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.
#

import os
import statistics
import time

import adb

def lock_min(device):
    device.shell_nocheck(["""
        for x in /sys/devices/system/cpu/cpu?/cpufreq; do
            echo userspace > $x/scaling_governor
            cat $x/scaling_min_freq > $x/scaling_setspeed
        done
    """])

def lock_max(device):
    device.shell_nocheck(["""
        for x in /sys/devices/system/cpu/cpu?/cpufreq; do
            echo userspace > $x/scaling_governor
            cat $x/scaling_max_freq > $x/scaling_setspeed
        done
    """])

def unlock(device):
    device.shell_nocheck(["""
        for x in /sys/devices/system/cpu/cpu?/cpufreq; do
            echo ondemand > $x/scaling_governor
            echo sched > $x/scaling_governor
            echo schedutil > $x/scaling_governor
        done
    """])

def harmonic_mean(xs):
    return 1.0 / statistics.mean([1.0 / x for x in xs])

def analyze(name, speeds):
    median = statistics.median(speeds)
    mean = harmonic_mean(speeds)
    stddev = statistics.stdev(speeds)
    msg = "%s: %d runs: median %.2f MiB/s, mean %.2f MiB/s, stddev: %.2f MiB/s"
    print(msg % (name, len(speeds), median, mean, stddev))

def benchmark_push(device=None, file_size_mb=100):
    if device == None:
        device = adb.get_device()

    lock_max(device)

    remote_path = "/dev/null"
    local_path = "/tmp/adb_benchmark_temp"

    with open(local_path, "wb") as f:
        f.truncate(file_size_mb * 1024 * 1024)

    speeds = list()
    for _ in range(0, 5):
        begin = time.time()
        device.push(local=local_path, remote=remote_path)
        end = time.time()
        speeds.append(file_size_mb / float(end - begin))

    analyze("push %dMiB" % file_size_mb, speeds)

def benchmark_pull(device=None, file_size_mb=100):
    if device == None:
        device = adb.get_device()

    lock_max(device)

    remote_path = "/data/local/tmp/adb_benchmark_temp"
    local_path = "/tmp/adb_benchmark_temp"

    device.shell(["dd", "if=/dev/zero", "of=" + remote_path, "bs=1m",
                  "count=" + str(file_size_mb)])
    speeds = list()
    for _ in range(0, 5):
        begin = time.time()
        device.pull(remote=remote_path, local=local_path)
        end = time.time()
        speeds.append(file_size_mb / float(end - begin))

    analyze("pull %dMiB" % file_size_mb, speeds)

def benchmark_shell(device=None, file_size_mb=100):
    if device == None:
        device = adb.get_device()

    lock_max(device)

    speeds = list()
    for _ in range(0, 5):
        begin = time.time()
        device.shell(["dd", "if=/dev/zero", "bs=1m",
                      "count=" + str(file_size_mb)])
        end = time.time()
        speeds.append(file_size_mb / float(end - begin))

    analyze("shell %dMiB" % file_size_mb, speeds)

def main():
    benchmark_pull()

if __name__ == "__main__":
    main()
+1 −1
Original line number Diff line number Diff line
@@ -62,7 +62,7 @@ struct asocket {
    int fd = -1;

    // queue of data waiting to be written
    std::deque<Range> packet_queue;
    IOVector packet_queue;

    std::string smart_socket_data;

+9 −11
Original line number Diff line number Diff line
@@ -113,14 +113,14 @@ enum class SocketFlushResult {
};

static SocketFlushResult local_socket_flush_incoming(asocket* s) {
    while (!s->packet_queue.empty()) {
        Range& r = s->packet_queue.front();

        int rc = adb_write(s->fd, r.data(), r.size());
        if (rc == static_cast<int>(r.size())) {
            s->packet_queue.pop_front();
    if (!s->packet_queue.empty()) {
        std::vector<adb_iovec> iov = s->packet_queue.iovecs();
        ssize_t rc = adb_writev(s->fd, iov.data(), iov.size());
        if (rc > 0 && static_cast<size_t>(rc) == s->packet_queue.size()) {
            s->packet_queue.clear();
        } else if (rc > 0) {
            r.drop_front(rc);
            // TODO: Implement a faster drop_front?
            s->packet_queue.take_front(rc);
            fdevent_add(s->fde, FDE_WRITE);
            return SocketFlushResult::TryAgain;
        } else if (rc == -1 && errno == EAGAIN) {
@@ -130,7 +130,6 @@ static SocketFlushResult local_socket_flush_incoming(asocket* s) {
            // We failed to write, but it's possible that we can still read from the socket.
            // Give that a try before giving up.
            s->has_write_error = true;
            break;
        }
    }

@@ -217,8 +216,7 @@ static bool local_socket_flush_outgoing(asocket* s) {
static int local_socket_enqueue(asocket* s, apacket::payload_type data) {
    D("LS(%d): enqueue %zu", s->id, data.size());

    Range r(std::move(data));
    s->packet_queue.push_back(std::move(r));
    s->packet_queue.append(std::move(data));
    switch (local_socket_flush_incoming(s)) {
        case SocketFlushResult::Destroyed:
            return -1;
@@ -622,7 +620,7 @@ static int smart_socket_enqueue(asocket* s, apacket::payload_type data) {
    D("SS(%d): enqueue %zu", s->id, data.size());

    if (s->smart_socket_data.empty()) {
        // TODO: Make this a BlockChain?
        // TODO: Make this an IOVector?
        s->smart_socket_data.assign(data.begin(), data.end());
    } else {
        std::copy(data.begin(), data.end(), std::back_inserter(s->smart_socket_data));
Loading