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
diff --git a/types.h b/types.h
new file mode 100644
index 0000000..dd3e063
--- /dev/null
+++ b/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;
+};