diff options
author | Josh Gao <jmgao@google.com> | 2018-03-07 16:52:28 -0800 |
---|---|---|
committer | Josh Gao <jmgao@google.com> | 2018-04-11 12:54:07 -0700 |
commit | 1ce99576f0cf76a9cfe4176c0a4a2cb018568a52 (patch) | |
tree | fc09fde6787026ac89c046b86803065a702ad08b | |
parent | 1b86d41c7844729768b2ffd096e1cded3c145a93 (diff) | |
download | system_core-1ce99576f0cf76a9cfe4176c0a4a2cb018568a52.tar.gz system_core-1ce99576f0cf76a9cfe4176c0a4a2cb018568a52.tar.bz2 system_core-1ce99576f0cf76a9cfe4176c0a4a2cb018568a52.zip |
adb: switch apacket payload to a type that doesn't initialize its contents.
Switch from using std::string as the type we use to hold our payload in
apacket to a custom reimplementation that doesn't zero initialize. This
improves bulk transfer throughput in the adb_benchmark microbenchmark
on walleye by ~20%.
Test: adb shell taskset f0 /data/benchmarktest64/adb_benchmark/adb_benchmark
Change-Id: Ibad797701eb1460c9321b0400c5b167b89b2b4d0
-rw-r--r-- | adb/adb.cpp | 16 | ||||
-rw-r--r-- | adb/adb.h | 15 | ||||
-rw-r--r-- | adb/client/auth.cpp | 6 | ||||
-rw-r--r-- | adb/daemon/jdwp_service.cpp | 11 | ||||
-rw-r--r-- | adb/range.h | 65 | ||||
-rw-r--r-- | adb/socket.h | 5 | ||||
-rw-r--r-- | adb/socket_test.cpp | 2 | ||||
-rw-r--r-- | adb/sockets.cpp | 16 | ||||
-rw-r--r-- | adb/transport.cpp | 4 | ||||
-rw-r--r-- | adb/types.h | 163 |
10 files changed, 196 insertions, 107 deletions
diff --git a/adb/adb.cpp b/adb/adb.cpp index 65fa2e795..702a5a2fb 100644 --- a/adb/adb.cpp +++ b/adb/adb.cpp @@ -257,7 +257,7 @@ void send_connect(atransport* t) { << connection_str.length() << ")"; } - cp->payload = std::move(connection_str); + cp->payload.assign(connection_str.begin(), connection_str.end()); cp->msg.data_length = cp->payload.size(); send_packet(cp, t); @@ -329,7 +329,8 @@ static void handle_new_connection(atransport* t, apacket* p) { handle_offline(t); t->update_version(p->msg.arg0, p->msg.arg1); - parse_banner(p->payload, t); + std::string banner(p->payload.begin(), p->payload.end()); + parse_banner(banner, t); #if ADB_HOST handle_online(t); @@ -369,8 +370,10 @@ void handle_packet(apacket *p, atransport *t) send_auth_response(p->payload.data(), p->msg.data_length, t); break; #else - case ADB_AUTH_SIGNATURE: - if (adbd_auth_verify(t->token, sizeof(t->token), p->payload)) { + case ADB_AUTH_SIGNATURE: { + // TODO: Switch to string_view. + std::string signature(p->payload.begin(), p->payload.end()); + if (adbd_auth_verify(t->token, sizeof(t->token), signature)) { adbd_auth_verified(t); t->failed_auth_attempts = 0; } else { @@ -378,6 +381,7 @@ void handle_packet(apacket *p, atransport *t) send_auth_request(t); } break; + } case ADB_AUTH_RSAPUBLICKEY: adbd_auth_confirm_key(p->payload.data(), p->msg.data_length, t); @@ -392,7 +396,9 @@ void handle_packet(apacket *p, atransport *t) case A_OPEN: /* OPEN(local-id, 0, "destination") */ if (t->online && p->msg.arg0 != 0 && p->msg.arg1 == 0) { - asocket* s = create_local_service_socket(p->payload.c_str(), t); + // TODO: Switch to string_view. + std::string address(p->payload.begin(), p->payload.end()); + asocket* s = create_local_service_socket(address.c_str(), t); if (s == nullptr) { send_close(0, p->msg.arg0, t); } else { @@ -28,6 +28,7 @@ #include "adb_trace.h" #include "fdevent.h" #include "socket.h" +#include "types.h" #include "usb.h" constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024; @@ -63,20 +64,6 @@ std::string adb_version(); using TransportId = uint64_t; class atransport; -struct amessage { - uint32_t command; /* command identifier constant */ - uint32_t arg0; /* first argument */ - uint32_t arg1; /* second argument */ - uint32_t data_length; /* length of payload (0 is allowed) */ - uint32_t data_check; /* checksum of data payload */ - uint32_t magic; /* command ^ 0xffffffff */ -}; - -struct apacket { - amessage msg; - std::string payload; -}; - uint32_t calculate_apacket_checksum(const apacket* packet); /* the adisconnect structure is used to record a callback that diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp index c3aef16d4..ade2623b8 100644 --- a/adb/client/auth.cpp +++ b/adb/client/auth.cpp @@ -454,10 +454,8 @@ static void send_auth_publickey(atransport* t) { p->msg.command = A_AUTH; p->msg.arg0 = ADB_AUTH_RSAPUBLICKEY; - p->payload = std::move(key); - // adbd expects a null-terminated string. - p->payload.push_back('\0'); + p->payload.assign(key.data(), key.data() + key.size() + 1); p->msg.data_length = p->payload.size(); send_packet(p, t); } @@ -482,7 +480,7 @@ void send_auth_response(const char* token, size_t token_size, atransport* t) { p->msg.command = A_AUTH; p->msg.arg0 = ADB_AUTH_SIGNATURE; - p->payload = std::move(result); + p->payload.assign(result.begin(), result.end()); p->msg.data_length = p->payload.size(); send_packet(p, t); } diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp index 976155884..89577cb7c 100644 --- a/adb/daemon/jdwp_service.cpp +++ b/adb/daemon/jdwp_service.cpp @@ -459,7 +459,7 @@ static void jdwp_socket_close(asocket* s) { delete s; } -static int jdwp_socket_enqueue(asocket* s, std::string) { +static int jdwp_socket_enqueue(asocket* s, apacket::payload_type) { /* you can't write to this asocket */ D("LS(%d): JDWP socket received data?", s->id); s->peer->close(s->peer); @@ -474,7 +474,7 @@ static void jdwp_socket_ready(asocket* s) { * on the second one, close the connection */ if (!jdwp->pass) { - std::string data; + apacket::payload_type data; data.resize(s->get_max_payload()); size_t len = jdwp_process_list(&data[0], data.size()); data.resize(len); @@ -521,7 +521,8 @@ static void jdwp_process_list_updated(void) { for (auto& t : _jdwp_trackers) { if (t->peer) { // The tracker might not have been connected yet. - t->peer->enqueue(t->peer, data); + apacket::payload_type payload(data.begin(), data.end()); + t->peer->enqueue(t->peer, std::move(payload)); } } } @@ -547,7 +548,7 @@ static void jdwp_tracker_ready(asocket* s) { JdwpTracker* t = (JdwpTracker*)s; if (t->need_initial) { - std::string data; + apacket::payload_type data; data.resize(s->get_max_payload()); data.resize(jdwp_process_list_msg(&data[0], data.size())); t->need_initial = false; @@ -555,7 +556,7 @@ static void jdwp_tracker_ready(asocket* s) { } } -static int jdwp_tracker_enqueue(asocket* s, std::string) { +static int jdwp_tracker_enqueue(asocket* s, apacket::payload_type) { /* you can't write to this socket */ D("LS(%d): JDWP tracker received data?", s->id); s->peer->close(s->peer); diff --git a/adb/range.h b/adb/range.h deleted file mode 100644 index 7a0b8221d..000000000 --- a/adb/range.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -/* - * 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 <string> - -#include <android-base/logging.h> - -struct Range { - explicit Range(std::string data) : data_(std::move(data)) {} - - Range(const Range& copy) = delete; - Range& operator=(const Range& copy) = delete; - - Range(Range&& move) = default; - Range& operator=(Range&& move) = default; - - bool empty() const { - return size() == 0; - } - - size_t size() const { - return data_.size() - begin_offset_ - end_offset_; - }; - - void drop_front(size_t n) { - CHECK_GE(size(), n); - begin_offset_ += n; - } - - void drop_end(size_t n) { - CHECK_GE(size(), n); - end_offset_ += n; - } - - char* data() { - return &data_[0] + begin_offset_; - } - - std::string::iterator begin() { - return data_.begin() + begin_offset_; - } - - std::string::iterator end() { - return data_.end() - end_offset_; - } - - std::string data_; - size_t begin_offset_ = 0; - size_t end_offset_ = 0; -}; diff --git a/adb/socket.h b/adb/socket.h index 2f0908050..e8cb58bd7 100644 --- a/adb/socket.h +++ b/adb/socket.h @@ -24,9 +24,8 @@ #include <string> #include "fdevent.h" -#include "range.h" +#include "types.h" -struct apacket; class atransport; /* An asocket represents one half of a connection between a local and @@ -73,7 +72,7 @@ struct asocket { * peer->ready() when we once again are ready to * receive data. */ - int (*enqueue)(asocket* s, std::string data) = nullptr; + int (*enqueue)(asocket* s, apacket::payload_type data) = nullptr; /* ready is called by the peer when it is ready for * us to send data via enqueue again diff --git a/adb/socket_test.cpp b/adb/socket_test.cpp index 6c4a8b2c1..04214a20b 100644 --- a/adb/socket_test.cpp +++ b/adb/socket_test.cpp @@ -118,7 +118,7 @@ static void CreateCloser(CloseWithPacketArg* arg) { // each write to give the underlying implementation time to flush. bool socket_filled = false; for (int i = 0; i < 128; ++i) { - std::string data; + apacket::payload_type data; data.resize(MAX_PAYLOAD); arg->bytes_written += data.size(); int ret = s->enqueue(s, std::move(data)); diff --git a/adb/sockets.cpp b/adb/sockets.cpp index 0887e6f01..f3fce27a1 100644 --- a/adb/sockets.cpp +++ b/adb/sockets.cpp @@ -37,8 +37,8 @@ #include "adb.h" #include "adb_io.h" -#include "range.h" #include "transport.h" +#include "types.h" static std::recursive_mutex& local_socket_list_lock = *new std::recursive_mutex(); static unsigned local_socket_next_id = 1; @@ -147,7 +147,7 @@ static SocketFlushResult local_socket_flush_incoming(asocket* s) { // Returns false if the socket has been closed and destroyed as a side-effect of this function. static bool local_socket_flush_outgoing(asocket* s) { const size_t max_payload = s->get_max_payload(); - std::string data; + apacket::payload_type data; data.resize(max_payload); char* x = &data[0]; size_t avail = max_payload; @@ -214,7 +214,7 @@ static bool local_socket_flush_outgoing(asocket* s) { return true; } -static int local_socket_enqueue(asocket* s, std::string data) { +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)); @@ -394,7 +394,7 @@ static asocket* create_host_service_socket(const char* name, const char* serial, } #endif /* ADB_HOST */ -static int remote_socket_enqueue(asocket* s, std::string data) { +static int remote_socket_enqueue(asocket* s, apacket::payload_type data) { D("entered remote_socket_enqueue RS(%d) WRITE fd=%d peer.fd=%d", s->id, s->fd, s->peer->fd); apacket* p = get_apacket(); @@ -476,8 +476,7 @@ void connect_to_remote(asocket* s, const char* destination) { p->msg.arg0 = s->id; // adbd expects a null-terminated string. - p->payload = destination; - p->payload.push_back('\0'); + p->payload.assign(destination, destination + strlen(destination) + 1); p->msg.data_length = p->payload.size(); if (p->msg.data_length > s->get_max_payload()) { @@ -612,7 +611,7 @@ char* skip_host_serial(char* service) { #endif // ADB_HOST -static int smart_socket_enqueue(asocket* s, std::string data) { +static int smart_socket_enqueue(asocket* s, apacket::payload_type data) { #if ADB_HOST char* service = nullptr; char* serial = nullptr; @@ -623,7 +622,8 @@ static int smart_socket_enqueue(asocket* s, std::string data) { D("SS(%d): enqueue %zu", s->id, data.size()); if (s->smart_socket_data.empty()) { - s->smart_socket_data = std::move(data); + // TODO: Make this a BlockChain? + s->smart_socket_data.assign(data.begin(), data.end()); } else { std::copy(data.begin(), data.end(), std::back_inserter(s->smart_socket_data)); } diff --git a/adb/transport.cpp b/adb/transport.cpp index 2867d3837..92c52e23c 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp @@ -335,7 +335,7 @@ static void device_tracker_close(asocket* socket) { delete tracker; } -static int device_tracker_enqueue(asocket* socket, std::string) { +static int device_tracker_enqueue(asocket* socket, apacket::payload_type) { /* you can't read from a device tracker, close immediately */ device_tracker_close(socket); return -1; @@ -344,7 +344,7 @@ static int device_tracker_enqueue(asocket* socket, std::string) { static int device_tracker_send(device_tracker* tracker, const std::string& string) { asocket* peer = tracker->socket.peer; - std::string data; + apacket::payload_type data; data.resize(4 + string.size()); char buf[5]; snprintf(buf, sizeof(buf), "%04x", static_cast<int>(string.size())); diff --git a/adb/types.h b/adb/types.h new file mode 100644 index 000000000..dd3e06390 --- /dev/null +++ b/adb/types.h @@ -0,0 +1,163 @@ +/* + * 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. + */ + +#pragma once + +#include <algorithm> +#include <utility> + +#include <android-base/logging.h> + +#include "sysdeps/memory.h" + +// Essentially std::vector<char>, except without zero initialization or reallocation. +struct Block { + using iterator = char*; + + Block() {} + + explicit Block(size_t size) { allocate(size); } + + template <typename Iterator> + Block(Iterator begin, Iterator end) : Block(end - begin) { + std::copy(begin, end, data_); + } + + Block(const Block& copy) = delete; + Block(Block&& move) { + std::swap(data_, move.data_); + std::swap(capacity_, move.capacity_); + std::swap(size_, move.size_); + } + + Block& operator=(const Block& copy) = delete; + Block& operator=(Block&& move) { + clear(); + + std::swap(data_, move.data_); + std::swap(capacity_, move.capacity_); + std::swap(size_, move.size_); + + return *this; + } + + ~Block() { clear(); } + + void resize(size_t new_size) { + if (!data_) { + allocate(new_size); + } else { + CHECK_GE(capacity_, new_size); + size_ = new_size; + } + } + + template <typename InputIt> + void assign(InputIt begin, InputIt end) { + clear(); + allocate(end - begin); + std::copy(begin, end, data_); + } + + void clear() { + free(data_); + capacity_ = 0; + size_ = 0; + } + + size_t capacity() const { return capacity_; } + size_t size() const { return size_; } + bool empty() const { return size() == 0; } + + char* data() { return data_; } + const char* data() const { return data_; } + + char* begin() { return data_; } + const char* begin() const { return data_; } + + char* end() { return data() + size_; } + const char* end() const { return data() + size_; } + + char& operator[](size_t idx) { return data()[idx]; } + const char& operator[](size_t idx) const { return data()[idx]; } + + bool operator==(const Block& rhs) const { + return size() == rhs.size() && memcmp(data(), rhs.data(), size()) == 0; + } + + private: + void allocate(size_t size) { + CHECK(data_ == nullptr); + CHECK_EQ(0ULL, capacity_); + CHECK_EQ(0ULL, size_); + if (size != 0) { + data_ = static_cast<char*>(malloc(size)); + capacity_ = size; + size_ = size; + } + } + + char* data_ = nullptr; + size_t capacity_ = 0; + size_t size_ = 0; +}; + +struct amessage { + uint32_t command; /* command identifier constant */ + uint32_t arg0; /* first argument */ + uint32_t arg1; /* second argument */ + uint32_t data_length; /* length of payload (0 is allowed) */ + uint32_t data_check; /* checksum of data payload */ + uint32_t magic; /* command ^ 0xffffffff */ +}; + +struct apacket { + using payload_type = Block; + amessage msg; + payload_type payload; +}; + +struct Range { + explicit Range(apacket::payload_type data) : data_(std::move(data)) {} + + Range(const Range& copy) = delete; + Range& operator=(const Range& copy) = delete; + + Range(Range&& move) = default; + Range& operator=(Range&& move) = default; + + size_t size() const { return data_.size() - begin_offset_ - end_offset_; }; + bool empty() const { return size() == 0; } + + void drop_front(size_t n) { + CHECK_GE(size(), n); + begin_offset_ += n; + } + + void drop_end(size_t n) { + CHECK_GE(size(), n); + end_offset_ += n; + } + + char* data() { return &data_[0] + begin_offset_; } + + apacket::payload_type::iterator begin() { return data_.begin() + begin_offset_; } + apacket::payload_type::iterator end() { return data_.end() - end_offset_; } + + apacket::payload_type data_; + size_t begin_offset_ = 0; + size_t end_offset_ = 0; +}; |