Merge "simpleperf: handle monitored processes correctly when a cpu is up."
diff --git a/simpleperf/Android.mk b/simpleperf/Android.mk
index 56ea8ff..c9108be 100644
--- a/simpleperf/Android.mk
+++ b/simpleperf/Android.mk
@@ -25,6 +25,7 @@
simpleperf_cppflags_host := $(simpleperf_common_cppflags) \
-DUSE_BIONIC_UAPI_HEADERS -I bionic/libc/kernel \
+ -fvisibility=hidden \
simpleperf_cppflags_host_darwin := -I $(LOCAL_PATH)/nonlinux_support/include
simpleperf_cppflags_host_windows := -I $(LOCAL_PATH)/nonlinux_support/include
@@ -211,6 +212,29 @@
$(call dist-for-goals,sdk,$(ALL_MODULES.simpleperf_report.BUILT))
+
+# libsimpleperf_report.so
+# It is the shared library used on host by python scripts
+# to report samples in different ways.
+# =========================================================
+include $(CLEAR_VARS)
+LOCAL_MODULE := libsimpleperf_report
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_host)
+LOCAL_CPPFLAGS := $(simpleperf_cppflags_host)
+LOCAL_CPPFLAGS_darwin := $(simpleperf_cppflags_host_darwin)
+LOCAL_CPPFLAGS_linux := $(simpleperf_cppflags_host_linux)
+LOCAL_CPPFLAGS_windows := $(simpleperf_cppflags_host_windows)
+LOCAL_SRC_FILES := report_lib_interface.cpp
+LOCAL_STATIC_LIBRARIES := libsimpleperf $(simpleperf_static_libraries_host)
+LOCAL_STATIC_LIBRARIES_linux := $(simpleperf_static_libraries_host_linux)
+LOCAL_LDLIBS_linux := $(simpleperf_ldlibs_host_linux) -Wl,--exclude-libs,ALL
+LOCAL_MULTILIB := first
+LOCAL_CXX_STL := libc++_static
+include $(LLVM_HOST_BUILD_MK)
+include $(BUILD_HOST_SHARED_LIBRARY)
+
+
# simpleperf_unit_test
# =========================================================
simpleperf_unit_test_src_files := \
diff --git a/simpleperf/cmd_dumprecord_test.cpp b/simpleperf/cmd_dumprecord_test.cpp
index 441851f..b61942b 100644
--- a/simpleperf/cmd_dumprecord_test.cpp
+++ b/simpleperf/cmd_dumprecord_test.cpp
@@ -26,3 +26,7 @@
TEST(cmd_dump, record_file_option) {
ASSERT_TRUE(DumpCmd()->Run({GetTestData("perf.data")}));
}
+
+TEST(cmd_dump, dump_data_generated_by_linux_perf) {
+ ASSERT_TRUE(DumpCmd()->Run({GetTestData(PERF_DATA_GENERATED_BY_LINUX_PERF)}));
+}
diff --git a/simpleperf/cmd_report.cpp b/simpleperf/cmd_report.cpp
index b855a6a..fe93dbc 100644
--- a/simpleperf/cmd_report.cpp
+++ b/simpleperf/cmd_report.cpp
@@ -657,7 +657,6 @@
}
bool ReportCommand::ReadSampleTreeFromRecordFile() {
- thread_tree_.AddThread(0, 0, "swapper");
sample_tree_builder_->SetBranchSampleOption(use_branch_address_);
// Normally do strict arch check when unwinding stack. But allow unwinding
// 32-bit processes on 64-bit devices for system wide profiling.
diff --git a/simpleperf/cmd_report_sample.cpp b/simpleperf/cmd_report_sample.cpp
index 5a7599a..a58595a 100644
--- a/simpleperf/cmd_report_sample.cpp
+++ b/simpleperf/cmd_report_sample.cpp
@@ -300,7 +300,7 @@
callchain->set_symbol(symbol->DemangledName());
callchain->set_file(map->dso->Path());
- if (show_callchain_) {
+ if (show_callchain_ && (r.sample_type & PERF_SAMPLE_CALLCHAIN)) {
bool first_ip = true;
for (uint64_t i = 0; i < r.callchain_data.ip_nr; ++i) {
uint64_t ip = r.callchain_data.ips[i];
@@ -368,7 +368,7 @@
FprintIndented(report_fp_, 1, "dso: %s\n", map->dso->Path().c_str());
FprintIndented(report_fp_, 1, "symbol: %s\n", symbol->DemangledName());
- if (show_callchain_) {
+ if (show_callchain_ && (r.sample_type & PERF_SAMPLE_CALLCHAIN)) {
FprintIndented(report_fp_, 1, "callchain:\n");
bool first_ip = true;
for (uint64_t i = 0; i < r.callchain_data.ip_nr; ++i) {
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index a64ee18..a889775 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -411,6 +411,11 @@
testing::ExitedWithCode(0), "elf: Read failed");
}
+TEST_F(ReportCommandTest, report_data_generated_by_linux_perf) {
+ Report(PERF_DATA_GENERATED_BY_LINUX_PERF);
+ ASSERT_TRUE(success);
+}
+
#if defined(__linux__)
static std::unique_ptr<Command> RecordCmd() {
diff --git a/simpleperf/get_test_data.h b/simpleperf/get_test_data.h
index 88e7e91..339871e 100644
--- a/simpleperf/get_test_data.h
+++ b/simpleperf/get_test_data.h
@@ -95,4 +95,8 @@
static const std::string SYMFS_FOR_NO_SYMBOL_TABLE_WARNING = "data/symfs_for_no_symbol_table_warning";
static const std::string SYMFS_FOR_READ_ELF_FILE_WARNING = "data/symfs_for_read_elf_file_warning";
+
+// generated_by_linux_perf.data is generated by `perf record -F 1 -a -g -- sleep 0.1`.
+static const std::string PERF_DATA_GENERATED_BY_LINUX_PERF = "generated_by_linux_perf.data";
+
#endif // SIMPLE_PERF_GET_TEST_DATA_H_
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp
index 2cb68a5..2bcba4d 100644
--- a/simpleperf/record.cpp
+++ b/simpleperf/record.cpp
@@ -273,7 +273,8 @@
: Record(p) {
const char* end = p + size();
p += header_size();
- MoveFromBinaryFormat(data, p);
+ data = reinterpret_cast<const Mmap2RecordDataType*>(p);
+ p += sizeof(*data);
filename = p;
p += Align(strlen(filename) + 1, 8);
CHECK_LE(p, end);
diff --git a/simpleperf/record_file.h b/simpleperf/record_file.h
index 1b3191a..9277570 100644
--- a/simpleperf/record_file.h
+++ b/simpleperf/record_file.h
@@ -116,9 +116,22 @@
return feature_section_descriptors_.find(feature) != feature_section_descriptors_.end();
}
bool ReadFeatureSection(int feature, std::vector<char>* data);
+
+ // There are two ways to read records in data section: one is by calling
+ // ReadDataSection(), and [callback] is called for each Record. the other
+ // is by calling ReadRecord() in a loop.
+
// If sorted is true, sort records before passing them to callback function.
bool ReadDataSection(const std::function<bool(std::unique_ptr<Record>)>& callback,
bool sorted = true);
+
+ // Read next record. If read successfully, set [record] and return true.
+ // If there is no more records, set [record] to nullptr and return true.
+ // Otherwise return false.
+ bool ReadRecord(std::unique_ptr<Record>& record, bool sorted = true);
+
+ size_t GetAttrIndexOfRecord(const SampleRecord& record);
+
std::vector<std::string> ReadCmdlineFeature();
std::vector<BuildIdRecord> ReadBuildIdFeature();
std::string ReadFeatureString(int feature);
@@ -133,7 +146,7 @@
bool ReadAttrSection();
bool ReadIdsForAttr(const PerfFileFormat::FileAttr& attr, std::vector<uint64_t>* ids);
bool ReadFeatureSectionDescriptors();
- std::unique_ptr<Record> ReadRecord(size_t* nbytes_read);
+ std::unique_ptr<Record> ReadRecord(uint64_t* nbytes_read);
bool Read(void* buf, size_t len);
void ProcessEventIdRecord(const EventIdRecord& r);
@@ -143,12 +156,15 @@
PerfFileFormat::FileHeader header_;
std::vector<PerfFileFormat::FileAttr> file_attrs_;
std::vector<std::vector<uint64_t>> event_ids_for_file_attrs_;
- std::unordered_map<uint64_t, perf_event_attr*> event_id_to_attr_map_;
+ std::unordered_map<uint64_t, size_t> event_id_to_attr_map_;
std::map<int, PerfFileFormat::SectionDesc> feature_section_descriptors_;
size_t event_id_pos_in_sample_records_;
size_t event_id_reverse_pos_in_non_sample_records_;
+ std::unique_ptr<RecordCache> record_cache_;
+ uint64_t read_record_size_;
+
DISALLOW_COPY_AND_ASSIGN(RecordFileReader);
};
diff --git a/simpleperf/record_file_reader.cpp b/simpleperf/record_file_reader.cpp
index ac74d24..68fcc4c 100644
--- a/simpleperf/record_file_reader.cpp
+++ b/simpleperf/record_file_reader.cpp
@@ -46,7 +46,7 @@
RecordFileReader::RecordFileReader(const std::string& filename, FILE* fp)
: filename_(filename), record_fp_(fp), event_id_pos_in_sample_records_(0),
- event_id_reverse_pos_in_non_sample_records_(0) {
+ event_id_reverse_pos_in_non_sample_records_(0), read_record_size_(0) {
}
RecordFileReader::~RecordFileReader() {
@@ -115,7 +115,7 @@
}
event_ids_for_file_attrs_.push_back(ids);
for (auto id : ids) {
- event_id_to_attr_map_[id] = &file_attrs_[i].attr;
+ event_id_to_attr_map_[id] = i;
}
}
return true;
@@ -160,20 +160,37 @@
bool RecordFileReader::ReadDataSection(
const std::function<bool(std::unique_ptr<Record>)>& callback, bool sorted) {
- if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) {
- PLOG(ERROR) << "fseek() failed";
- return false;
- }
- bool has_timestamp = true;
- for (const auto& attr : file_attrs_) {
- if (!IsTimestampSupported(attr.attr)) {
- has_timestamp = false;
- break;
+ std::unique_ptr<Record> record;
+ while (ReadRecord(record, sorted)) {
+ if (record == nullptr) {
+ return true;
+ }
+ if (!callback(std::move(record))) {
+ return false;
}
}
- RecordCache cache(has_timestamp);
- for (size_t nbytes_read = 0; nbytes_read < header_.data.size;) {
- std::unique_ptr<Record> record = ReadRecord(&nbytes_read);
+ return false;
+}
+
+bool RecordFileReader::ReadRecord(std::unique_ptr<Record>& record,
+ bool sorted) {
+ if (read_record_size_ == 0) {
+ if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) {
+ PLOG(ERROR) << "fseek() failed";
+ return false;
+ }
+ bool has_timestamp = true;
+ for (const auto& attr : file_attrs_) {
+ if (!IsTimestampSupported(attr.attr)) {
+ has_timestamp = false;
+ break;
+ }
+ }
+ record_cache_.reset(new RecordCache(has_timestamp));
+ }
+ record = nullptr;
+ while (read_record_size_ < header_.data.size && record == nullptr) {
+ record = ReadRecord(&read_record_size_);
if (record == nullptr) {
return false;
}
@@ -181,29 +198,17 @@
ProcessEventIdRecord(*static_cast<EventIdRecord*>(record.get()));
}
if (sorted) {
- cache.Push(std::move(record));
- record = cache.Pop();
- if (record != nullptr) {
- if (!callback(std::move(record))) {
- return false;
- }
- }
- } else {
- if (!callback(std::move(record))) {
- return false;
- }
+ record_cache_->Push(std::move(record));
+ record = record_cache_->Pop();
}
}
- std::vector<std::unique_ptr<Record>> records = cache.PopAll();
- for (auto& record : records) {
- if (!callback(std::move(record))) {
- return false;
- }
+ if (record == nullptr) {
+ record = record_cache_->ForcedPop();
}
return true;
}
-std::unique_ptr<Record> RecordFileReader::ReadRecord(size_t* nbytes_read) {
+std::unique_ptr<Record> RecordFileReader::ReadRecord(uint64_t* nbytes_read) {
char header_buf[Record::header_size()];
if (!Read(header_buf, Record::header_size())) {
return nullptr;
@@ -265,7 +270,7 @@
if (has_event_id) {
auto it = event_id_to_attr_map_.find(event_id);
if (it != event_id_to_attr_map_.end()) {
- attr = it->second;
+ attr = &file_attrs_[it->second].attr;
}
}
}
@@ -273,7 +278,7 @@
}
bool RecordFileReader::Read(void* buf, size_t len) {
- if (fread(buf, len, 1, record_fp_) != 1) {
+ if (len != 0 && fread(buf, len, 1, record_fp_) != 1) {
PLOG(FATAL) << "failed to read file " << filename_;
return false;
}
@@ -283,11 +288,18 @@
void RecordFileReader::ProcessEventIdRecord(const EventIdRecord& r) {
for (size_t i = 0; i < r.count; ++i) {
event_ids_for_file_attrs_[r.data[i].attr_id].push_back(r.data[i].event_id);
- event_id_to_attr_map_[r.data[i].event_id] =
- &file_attrs_[r.data[i].attr_id].attr;
+ event_id_to_attr_map_[r.data[i].event_id] = r.data[i].attr_id;
}
}
+size_t RecordFileReader::GetAttrIndexOfRecord(const SampleRecord& record) {
+ auto it = event_id_to_attr_map_.find(record.id_data.id);
+ if (it != event_id_to_attr_map_.end()) {
+ return it->second;
+ }
+ return 0;
+}
+
bool RecordFileReader::ReadFeatureSection(int feature, std::vector<char>* data) {
const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
auto it = section_map.find(feature);
diff --git a/simpleperf/report_lib_interface.cpp b/simpleperf/report_lib_interface.cpp
new file mode 100644
index 0000000..096cf49
--- /dev/null
+++ b/simpleperf/report_lib_interface.cpp
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2016 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 <memory>
+
+#include <android-base/logging.h>
+
+#include "dso.h"
+#include "event_attr.h"
+#include "record_file.h"
+#include "thread_tree.h"
+#include "utils.h"
+
+extern "C" {
+
+#define EXPORT __attribute__((visibility("default")))
+
+struct Sample {
+ uint64_t ip;
+ uint32_t pid;
+ uint32_t tid;
+ const char* thread_comm;
+ uint64_t time;
+ uint32_t in_kernel;
+ uint32_t cpu;
+ uint64_t period;
+};
+
+struct Event {
+ const char* name;
+};
+
+struct SymbolEntry {
+ const char* dso_name;
+ uint64_t vaddr_in_file;
+ const char* symbol_name;
+};
+
+struct CallChainEntry {
+ uint64_t ip;
+ SymbolEntry symbol;
+};
+
+struct CallChain {
+ uint32_t nr;
+ CallChainEntry* entries;
+};
+
+// Set log severity, different levels are:
+// verbose, debug, info, warning, error, fatal.
+bool SetLogSeverity(const char* log_level) EXPORT;
+bool SetSymfs(const char* symfs_dir) EXPORT;
+bool SetRecordFile(const char* record_file) EXPORT;
+void ShowIpForUnknownSymbol() EXPORT;
+
+Sample* GetNextSample() EXPORT;
+Event* GetEventOfCurrentSample() EXPORT;
+SymbolEntry* GetSymbolOfCurrentSample() EXPORT;
+CallChain* GetCallChainOfCurrentSample() EXPORT;
+}
+
+struct EventAttrWithName {
+ perf_event_attr attr;
+ std::string name;
+};
+
+enum {
+ UPDATE_FLAG_OF_SAMPLE = 1 << 0,
+ UPDATE_FLAG_OF_EVENT = 1 << 1,
+ UPDATE_FLAG_OF_SYMBOL = 1 << 2,
+ UPDATE_FLAG_OF_CALLCHAIN = 1 << 3,
+};
+
+class ReportLib {
+ public:
+ ReportLib()
+ : log_severity_(
+ new android::base::ScopedLogSeverity(android::base::INFO)),
+ record_filename_("perf.data"),
+ update_flag_(0) {}
+
+ static ReportLib& GetInstance() {
+ static ReportLib lib;
+ return lib;
+ }
+
+ bool SetLogSeverity(const char* log_level);
+
+ bool SetSymfs(const char* symfs_dir) { return Dso::SetSymFsDir(symfs_dir); }
+
+ bool SetRecordFile(const char* record_file) {
+ record_filename_ = record_file;
+ return true;
+ }
+
+ void ShowIpForUnknownSymbol() { thread_tree_.ShowIpForUnknownSymbol(); }
+
+ Sample* GetNextSample();
+ Event* GetEventOfCurrentSample();
+ SymbolEntry* GetSymbolOfCurrentSample();
+ CallChain* GetCallChainOfCurrentSample();
+
+ private:
+ Sample* GetCurrentSample();
+
+ std::unique_ptr<android::base::ScopedLogSeverity> log_severity_;
+ std::string record_filename_;
+ std::unique_ptr<RecordFileReader> record_file_reader_;
+ ThreadTree thread_tree_;
+ std::unique_ptr<SampleRecord> current_record_;
+ const ThreadEntry* current_thread_;
+ Sample current_sample_;
+ Event current_event_;
+ SymbolEntry current_symbol_;
+ CallChain current_callchain_;
+ std::vector<CallChainEntry> callchain_entries_;
+ int update_flag_;
+ std::vector<EventAttrWithName> event_attrs_;
+};
+
+bool ReportLib::SetLogSeverity(const char* log_level) {
+ android::base::LogSeverity severity;
+ if (!GetLogSeverity(log_level, &severity)) {
+ LOG(ERROR) << "Unknown log severity: " << log_level;
+ return false;
+ }
+ log_severity_ = nullptr;
+ log_severity_.reset(new android::base::ScopedLogSeverity(severity));
+ return true;
+}
+
+Sample* ReportLib::GetNextSample() {
+ if (record_file_reader_ == nullptr) {
+ record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
+ if (record_file_reader_ == nullptr) {
+ return nullptr;
+ }
+ }
+ while (true) {
+ std::unique_ptr<Record> record;
+ if (!record_file_reader_->ReadRecord(record)) {
+ return nullptr;
+ }
+ if (record == nullptr) {
+ return nullptr;
+ }
+ thread_tree_.Update(*record);
+ if (record->type() == PERF_RECORD_SAMPLE) {
+ current_record_.reset(static_cast<SampleRecord*>(record.release()));
+ break;
+ }
+ }
+ update_flag_ = 0;
+ return GetCurrentSample();
+}
+
+Sample* ReportLib::GetCurrentSample() {
+ if (!(update_flag_ & UPDATE_FLAG_OF_SAMPLE)) {
+ SampleRecord& r = *current_record_;
+ current_sample_.ip = r.ip_data.ip;
+ current_sample_.pid = r.tid_data.pid;
+ current_sample_.tid = r.tid_data.tid;
+ current_thread_ =
+ thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
+ current_sample_.thread_comm = current_thread_->comm;
+ current_sample_.time = r.time_data.time;
+ current_sample_.in_kernel = r.InKernel();
+ current_sample_.cpu = r.cpu_data.cpu;
+ current_sample_.period = r.period_data.period;
+ update_flag_ |= UPDATE_FLAG_OF_SAMPLE;
+ }
+ return ¤t_sample_;
+}
+
+Event* ReportLib::GetEventOfCurrentSample() {
+ if (!(update_flag_ & UPDATE_FLAG_OF_EVENT)) {
+ if (event_attrs_.empty()) {
+ std::vector<AttrWithId> attrs = record_file_reader_->AttrSection();
+ for (const auto& attr_with_id : attrs) {
+ EventAttrWithName attr;
+ attr.attr = *attr_with_id.attr;
+ attr.name = GetEventNameByAttr(attr.attr);
+ event_attrs_.push_back(attr);
+ }
+ }
+ size_t attr_index =
+ record_file_reader_->GetAttrIndexOfRecord(*current_record_);
+ current_event_.name = event_attrs_[attr_index].name.c_str();
+ update_flag_ |= UPDATE_FLAG_OF_EVENT;
+ }
+ return ¤t_event_;
+}
+
+SymbolEntry* ReportLib::GetSymbolOfCurrentSample() {
+ if (!(update_flag_ & UPDATE_FLAG_OF_SYMBOL)) {
+ SampleRecord& r = *current_record_;
+ const MapEntry* map =
+ thread_tree_.FindMap(current_thread_, r.ip_data.ip, r.InKernel());
+ uint64_t vaddr_in_file;
+ const Symbol* symbol =
+ thread_tree_.FindSymbol(map, r.ip_data.ip, &vaddr_in_file);
+ current_symbol_.dso_name = map->dso->Path().c_str();
+ current_symbol_.vaddr_in_file = vaddr_in_file;
+ current_symbol_.symbol_name = symbol->DemangledName();
+ update_flag_ |= UPDATE_FLAG_OF_SYMBOL;
+ }
+ return ¤t_symbol_;
+}
+
+CallChain* ReportLib::GetCallChainOfCurrentSample() {
+ if (!(update_flag_ & UPDATE_FLAG_OF_CALLCHAIN)) {
+ SampleRecord& r = *current_record_;
+ callchain_entries_.clear();
+
+ if (r.sample_type & PERF_SAMPLE_CALLCHAIN) {
+ bool first_ip = true;
+ bool in_kernel = r.InKernel();
+ for (uint64_t i = 0; i < r.callchain_data.ip_nr; ++i) {
+ uint64_t ip = r.callchain_data.ips[i];
+ if (ip >= PERF_CONTEXT_MAX) {
+ switch (ip) {
+ case PERF_CONTEXT_KERNEL:
+ in_kernel = true;
+ break;
+ case PERF_CONTEXT_USER:
+ in_kernel = false;
+ break;
+ default:
+ LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex
+ << ip;
+ }
+ } else {
+ if (first_ip) {
+ first_ip = false;
+ // Remove duplication with sample ip.
+ if (ip == r.ip_data.ip) {
+ continue;
+ }
+ }
+ const MapEntry* map =
+ thread_tree_.FindMap(current_thread_, ip, in_kernel);
+ uint64_t vaddr_in_file;
+ const Symbol* symbol =
+ thread_tree_.FindSymbol(map, ip, &vaddr_in_file);
+ CallChainEntry entry;
+ entry.ip = ip;
+ entry.symbol.dso_name = map->dso->Path().c_str();
+ entry.symbol.vaddr_in_file = vaddr_in_file;
+ entry.symbol.symbol_name = symbol->DemangledName();
+ callchain_entries_.push_back(entry);
+ }
+ }
+ }
+ current_callchain_.nr = callchain_entries_.size();
+ current_callchain_.entries = callchain_entries_.data();
+ update_flag_ |= UPDATE_FLAG_OF_CALLCHAIN;
+ }
+ return ¤t_callchain_;
+}
+
+bool SetLogSeverity(const char* log_level) {
+ return ReportLib::GetInstance().SetLogSeverity(log_level);
+}
+
+bool SetSymfs(const char* symfs_dir) {
+ return ReportLib::GetInstance().SetSymfs(symfs_dir);
+}
+
+bool SetRecordFile(const char* record_file) {
+ return ReportLib::GetInstance().SetRecordFile(record_file);
+}
+
+void ShowIpForUnknownSymbol() {
+ return ReportLib::GetInstance().ShowIpForUnknownSymbol();
+}
+
+Sample* GetNextSample() { return ReportLib::GetInstance().GetNextSample(); }
+
+Event* GetEventOfCurrentSample() {
+ return ReportLib::GetInstance().GetEventOfCurrentSample();
+}
+
+SymbolEntry* GetSymbolOfCurrentSample() {
+ return ReportLib::GetInstance().GetSymbolOfCurrentSample();
+}
+
+CallChain* GetCallChainOfCurrentSample() {
+ return ReportLib::GetInstance().GetCallChainOfCurrentSample();
+}
diff --git a/simpleperf/scripts/libsimpleperf_report.so b/simpleperf/scripts/libsimpleperf_report.so
new file mode 100755
index 0000000..6e16376
--- /dev/null
+++ b/simpleperf/scripts/libsimpleperf_report.so
Binary files differ
diff --git a/simpleperf/scripts/report_sample.py b/simpleperf/scripts/report_sample.py
new file mode 100644
index 0000000..d0605cd
--- /dev/null
+++ b/simpleperf/scripts/report_sample.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 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.
+#
+
+"""report_sample.py: report samples in the same format as `perf script`.
+"""
+
+import sys
+from simpleperf_report_lib import *
+
+
+def usage():
+ print 'python report_sample.py [options] <record_file>'
+ print '-h/--help print this help message'
+ print '--symfs <symfs_dir> Set the path to looking for symbols'
+ print 'If record file is not given, use default file perf.data.'
+
+
+def report_sample(record_file, symfs_dir):
+ """ read record_file, and print each sample"""
+ lib = ReportLib()
+ lib.ShowIpForUnknownSymbol()
+ if symfs_dir is not None:
+ lib.SetSymfs(symfs_dir)
+ if record_file is not None:
+ lib.SetRecordFile(record_file)
+
+ while True:
+ sample = lib.GetNextSample()
+ if sample is None:
+ break
+ event = lib.GetEventOfCurrentSample()
+ symbol = lib.GetSymbolOfCurrentSample()
+ callchain = lib.GetCallChainOfCurrentSample()
+
+ sec = sample[0].time / 1000000000
+ usec = (sample[0].time - sec * 1000000000) / 1000
+ print '%s\t%d [%03d] %d.%d:\t\t%d %s:' % (sample[0].thread_comm, sample[0].tid, sample[0].cpu, sec, usec, sample[0].period, event[0].name)
+ print '%16x\t%s (%s)' % (sample[0].ip, symbol[0].symbol_name, symbol[0].dso_name)
+ for i in range(callchain[0].nr):
+ entry = callchain[0].entries[i]
+ print '%16x\t%s (%s)' % (entry.ip, entry.symbol.symbol_name, entry.symbol.dso_name)
+ print
+
+
+if __name__ == '__main__':
+ record_file = 'perf.data'
+ symfs_dir = None
+ i = 1
+ while i < len(sys.argv):
+ if sys.argv[i] == '-h' or sys.argv[i] == '--help':
+ usage()
+ sys.exit(0)
+ elif sys.argv[i] == '--symfs':
+ if i + 1 < len(sys.argv):
+ symfs_dir = sys.argv[i + 1]
+ i += 1
+ else:
+ print 'argument for --symfs is missing'
+ sys.exit(1)
+ else:
+ record_file = sys.argv[i]
+ i += 1
+
+ report_sample(record_file, symfs_dir)
diff --git a/simpleperf/scripts/simpleperf_report_lib.py b/simpleperf/scripts/simpleperf_report_lib.py
new file mode 100644
index 0000000..d4724b9
--- /dev/null
+++ b/simpleperf/scripts/simpleperf_report_lib.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 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.
+#
+
+"""simpleperf_report_lib.py: a python wrapper of libsimpleperf_report.so.
+ Used to access samples in perf.data.
+"""
+
+import ctypes as ct
+import os
+
+
+def _get_script_path():
+ return os.path.dirname(os.path.realpath(__file__))
+
+
+def _is_null(p):
+ return ct.cast(p, ct.c_void_p).value is None
+
+
+class SampleStruct(ct.Structure):
+ _fields_ = [('ip', ct.c_uint64),
+ ('pid', ct.c_uint32),
+ ('tid', ct.c_uint32),
+ ('thread_comm', ct.c_char_p),
+ ('time', ct.c_uint64),
+ ('in_kernel', ct.c_uint32),
+ ('cpu', ct.c_uint32),
+ ('period', ct.c_uint64)]
+
+
+class EventStruct(ct.Structure):
+ _fields_ = [('name', ct.c_char_p)]
+
+
+class SymbolStruct(ct.Structure):
+ _fields_ = [('dso_name', ct.c_char_p),
+ ('vaddr_in_file', ct.c_uint64),
+ ('symbol_name', ct.c_char_p)]
+
+
+class CallChainEntryStructure(ct.Structure):
+ _fields_ = [('ip', ct.c_uint64),
+ ('symbol', SymbolStruct)]
+
+
+class CallChainStructure(ct.Structure):
+ _fields_ = [('nr', ct.c_uint32),
+ ('entries', ct.POINTER(CallChainEntryStructure))]
+
+
+class ReportLib(object):
+
+ def __init__(self, native_lib_path=None):
+ if native_lib_path is None:
+ native_lib_path = _get_script_path() + "/libsimpleperf_report.so"
+ self._lib = ct.CDLL(native_lib_path)
+ self._SetLogSeverityFunc = self._lib.SetLogSeverity
+ self._SetSymfsFunc = self._lib.SetSymfs
+ self._SetRecordFileFunc = self._lib.SetRecordFile
+ self._ShowIpForUnknownSymbolFunc = self._lib.ShowIpForUnknownSymbol
+ self._GetNextSampleFunc = self._lib.GetNextSample
+ self._GetNextSampleFunc.restype = ct.POINTER(SampleStruct)
+ self._GetEventOfCurrentSampleFunc = self._lib.GetEventOfCurrentSample
+ self._GetEventOfCurrentSampleFunc.restype = ct.POINTER(EventStruct)
+ self._GetSymbolOfCurrentSampleFunc = self._lib.GetSymbolOfCurrentSample
+ self._GetSymbolOfCurrentSampleFunc.restype = ct.POINTER(SymbolStruct)
+ self._GetCallChainOfCurrentSampleFunc = self._lib.GetCallChainOfCurrentSample
+ self._GetCallChainOfCurrentSampleFunc.restype = ct.POINTER(
+ CallChainStructure)
+
+ def SetLogSeverity(self, log_level='info'):
+ """ Set log severity of native lib, can be verbose,debug,info,error,fatal."""
+ assert(self._SetLogSeverityFunc(log_level))
+
+ def SetSymfs(self, symfs_dir):
+ """ Set directory used to find symbols."""
+ assert(self._SetSymfsFunc(symfs_dir))
+
+ def SetRecordFile(self, record_file):
+ """ Set the path of record file, like perf.data."""
+ assert(self._SetRecordFileFunc(record_file))
+
+ def ShowIpForUnknownSymbol(self):
+ self._ShowIpForUnknownSymbolFunc()
+
+ def GetNextSample(self):
+ sample = self._GetNextSampleFunc()
+ if _is_null(sample):
+ return None
+ return sample
+
+ def GetEventOfCurrentSample(self):
+ event = self._GetEventOfCurrentSampleFunc()
+ assert(not _is_null(event))
+ return event
+
+ def GetSymbolOfCurrentSample(self):
+ symbol = self._GetSymbolOfCurrentSampleFunc()
+ assert(not _is_null(symbol))
+ return symbol
+
+ def GetCallChainOfCurrentSample(self):
+ callchain = self._GetCallChainOfCurrentSampleFunc()
+ assert(not _is_null(callchain))
+ return callchain
diff --git a/simpleperf/testdata/generated_by_linux_perf.data b/simpleperf/testdata/generated_by_linux_perf.data
new file mode 100644
index 0000000..da62584
--- /dev/null
+++ b/simpleperf/testdata/generated_by_linux_perf.data
Binary files differ
diff --git a/simpleperf/thread_tree.h b/simpleperf/thread_tree.h
index 5498df5..da32da1 100644
--- a/simpleperf/thread_tree.h
+++ b/simpleperf/thread_tree.h
@@ -76,6 +76,8 @@
unknown_map_ = MapEntry(0, std::numeric_limits<unsigned long long>::max(),
0, 0, unknown_dso_.get(), false);
kernel_dso_ = Dso::CreateDso(DSO_KERNEL, DEFAULT_KERNEL_MMAP_NAME);
+ // We can't dump comm for pid 0 from /proc, so add it's name here.
+ AddThread(0, 0, "swapper");
}
void AddThread(int pid, int tid, const std::string& comm);
diff --git a/tests/bootloader/bootloadertest.py b/tests/bootloader/bootloadertest.py
new file mode 100644
index 0000000..5923343
--- /dev/null
+++ b/tests/bootloader/bootloadertest.py
@@ -0,0 +1,198 @@
+# Copyright (C) 2016 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 adb
+import os
+import unittest
+import fastboot
+import subprocess
+
+class ShellTest(unittest.TestCase):
+ def __init__(self, *args, **kwargs):
+ super(ShellTest, self).__init__(*args, **kwargs)
+ self.fastboot = fastboot.FastbootDevice()
+
+ def exists_validvals(self, varname, varlist, validlist):
+ self.assertIn(varname, varlist)
+ self.assertIn(varlist[varname], validlist)
+ return varlist[varname]
+
+ def exists_yes_no(self, varname, varlist):
+ return self.exists_validvals(varname, varlist, ["yes", "no"])
+
+ def exists_nonempty(self, varname, varlist):
+ self.assertIn(varname, varlist)
+ self.assertGreater(len(varlist[varname]), 0)
+ return varlist[varname]
+
+ def exists_integer(self, varname, varlist, base=10):
+ val = 0
+ self.assertIn(varname, varlist)
+ try:
+ val = int(varlist[varname], base)
+ except ValueError:
+ self.fail("%s (%s) is not an integer" % (varname, varlist[varname]))
+ return val
+
+ def get_exists(self, varname):
+ val = self.fastboot.getvar(varname)
+ self.assertIsNotNone(val)
+ return val
+
+ def get_exists_validvals(self, varname, validlist):
+ val = self.get_exists(varname)
+ self.assertIn(val, validlist)
+ return val
+
+ def get_exists_yes_no(self, varname):
+ return self.get_exists_validvals(varname, ["yes", "no"])
+
+ def get_exists_nonempty(self, varname):
+ val = self.get_exists(varname)
+ self.assertGreater(len(val), 0)
+ return val
+
+ def get_exists_integer(self, varname, base=10):
+ val = self.get_exists(varname)
+ try:
+ num = int(val, base)
+ except ValueError:
+ self.fail("%s (%s) is not an integer" % (varname, val))
+ return num
+
+ def test_getvarall(self):
+ """Tests that required variables are reported by getvar all"""
+
+ var_all = self.fastboot.getvar_all()
+ self.exists_nonempty("version-baseband", var_all)
+ self.exists_nonempty("version-bootloader", var_all)
+ self.exists_nonempty("product", var_all)
+ self.exists_yes_no("secure", var_all)
+ self.exists_yes_no("unlocked", var_all)
+ self.exists_validvals("off-mode-charge", var_all, ["0", "1"])
+ self.assertIn("variant", var_all)
+ voltage = self.exists_nonempty("battery-voltage", var_all)
+ if voltage[-2:].lower() == "mv":
+ voltage = voltage[:-2]
+ try:
+ voltnum = float(voltage)
+ except ValueError:
+ self.fail("battery-voltage (%s) is not a number" % (varname, voltage))
+ self.exists_yes_no("battery-soc-ok", var_all)
+ maxdl = self.exists_integer("max-download-size", var_all, 16)
+ self.assertGreater(maxdl, 0)
+
+ if "slot-count" in var_all:
+ try:
+ slotcount = int(var_all["slot-count"])
+ except ValueError:
+ self.fail("slot-count (%s) is not an integer" % var_all["slot-count"])
+ if slotcount > 1:
+ # test for A/B variables
+ slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
+ self.exists_validvals("current-slot", var_all, slots)
+
+ # test for slot metadata
+ for slot in slots:
+ self.exists_yes_no("slot-unbootable:"+slot, var_all)
+ self.exists_yes_no("slot-unbootable:"+slot, var_all)
+ self.exists_integer("slot-retry-count:"+slot, var_all)
+ else:
+ print "This does not appear to be an A/B device."
+
+ def test_getvar_nonexistent(self):
+ """Tests behaviour of nonexistent variables."""
+
+ self.assertIsNone(self.fastboot.getvar("fhqwhgads"))
+
+ def test_getvar(self):
+ """Tests all variables separately"""
+
+ self.get_exists_nonempty("version-baseband")
+ self.get_exists_nonempty("version-bootloader")
+ self.get_exists_nonempty("product")
+ self.get_exists_yes_no("secure")
+ self.get_exists_yes_no("unlocked")
+ self.get_exists_validvals("off-mode-charge", ["0", "1"])
+ self.get_exists("variant")
+ voltage = self.get_exists_nonempty("battery-voltage")
+ if voltage[-2:].lower() == "mv":
+ voltage = voltage[:-2]
+ try:
+ voltnum = float(voltage)
+ except ValueError:
+ self.fail("battery-voltage (%s) is not a number" % voltage)
+ self.get_exists_yes_no("battery-soc-ok")
+ maxdl = self.get_exists_integer("max-download-size", 16)
+ self.assertGreater(maxdl, 0)
+
+ slotcount = 0
+ try:
+ slotcountString = self.fastboot.getvar("slot-count")
+ if slotcountString != None:
+ slotcount = int(slotcountString)
+ except ValueError:
+ self.fail("slot-count (%s) is not an integer" % slotcountString)
+ if slotcount > 1:
+ # test for A/B variables
+ slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
+ self.get_exists_validvals("current-slot", slots)
+
+ # test for slot metadata
+ for slot in slots:
+ self.get_exists_yes_no("slot-unbootable:"+slot)
+ self.get_exists_yes_no("slot-successful:"+slot)
+ self.get_exists_integer("slot-retry-count:"+slot)
+ else:
+ print "This does not appear to be an A/B device."
+
+ def test_setactive(self):
+ """Tests that A/B devices can switch to each slot, and the change persists over a reboot."""
+
+ slotcount = 0
+ try:
+ val = self.fastboot.getvar("slot-count")
+ if val != None:
+ slotcount = int(val)
+ except ValueError:
+ self.fail("slot-count (%s) is not an integer" % val)
+ except subprocess.CalledProcessError:
+ print "Does not appear to be an A/B device."
+ maxtries = 0
+ if slotcount > 1:
+ slots = [chr(slotnum+ord('a')) for slotnum in range(slotcount)]
+ for slot in slots:
+ self.fastboot.set_active(slot)
+ self.assertEqual(slot, self.fastboot.getvar("current-slot"))
+ self.assertEqual("no", self.fastboot.getvar("slot-unbootable:"+slot))
+ self.assertEqual("no", self.fastboot.getvar("slot-successful:"+slot))
+ retry = self.get_exists_integer("slot-retry-count:"+slot)
+ if maxtries == 0:
+ maxtries = retry
+ else:
+ self.assertEqual(maxtries, retry)
+ self.fastboot.reboot(True)
+ self.assertEqual(slot, self.fastboot.getvar("current-slot"))
+ self.assertEqual("no", self.fastboot.getvar("slot-unbootable:"+slot))
+ self.assertEqual("no", self.fastboot.getvar("slot-successful:"+slot))
+ retry = self.get_exists_integer("slot-retry-count:"+slot)
+ if maxtries == 0:
+ maxtries = retry
+ else:
+ self.assertEqual(maxtries, retry)
+ else:
+ print "Does not appear to be an A/B device."
+
+if __name__ == '__main__':
+ unittest.main(verbosity=3)
diff --git a/tests/wifi/Android.mk b/tests/wifi/Android.mk
deleted file mode 100644
index 4343259..0000000
--- a/tests/wifi/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Copyright (C) 2010 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 $(call all-subdir-makefiles)
diff --git a/tests/wifi/stress/Android.mk b/tests/wifi/stress/Android.mk
deleted file mode 100644
index 2361483..0000000
--- a/tests/wifi/stress/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Copyright (C) 2010 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.
-# Copyright The Android Open Source Project
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE := wifiLoadScanAssoc
-LOCAL_SRC_FILES := wifiLoadScanAssoc.c
-LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libhardware_legacy
-LOCAL_STATIC_LIBRARIES += libtestUtil
-LOCAL_C_INCLUDES += system/extras/tests/include \
- hardware/libhardware_legacy/include
-
-include $(BUILD_NATIVE_TEST)
diff --git a/tests/wifi/stress/wifiLoadScanAssoc.c b/tests/wifi/stress/wifiLoadScanAssoc.c
deleted file mode 100644
index 5dc2692..0000000
--- a/tests/wifi/stress/wifiLoadScanAssoc.c
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- * Copyright (C) 2010 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.
- *
- */
-
-/*
- * WiFi load, scan, associate, unload stress test
- *
- * Repeatedly executes the following sequence:
- *
- * 1. Load WiFi driver
- * 2. Start supplicant
- * 3. Random delay
- * 4. Obtain supplicant status (optional)
- * 5. Stop supplicant
- * 6. Unload WiFi driver
- *
- * The "Obtain supplicant status" step is optional and is pseudo
- * randomly performed 50% of the time. The default range of
- * delay after start supplicant is intentionally selected such
- * that the obtain supplicant status and stop supplicant steps
- * may be performed while the WiFi driver is still performing a scan
- * or associate. The default values are given by DEFAULT_DELAY_MIN
- * and DEFAULT_DELAY_MAX. Other values can be specified through the
- * use of the -d and -D command-line options.
- *
- * Each sequence is refered to as a pass and by default an unlimited
- * number of passes are performed. An override of the range of passes
- * to be executed is available through the use of the -s (start) and
- * -e (end) command-line options. Can also specify a single specific
- * pass via the -p option. There is also a default time in which the
- * test executes, which is given by DEFAULT_DURATION and can be overriden
- * through the use of the -t command-line option.
- */
-
-#define _GNU_SOURCE
-
-#include <assert.h>
-#include <errno.h>
-#include <libgen.h>
-#include <math.h>
-#include <sched.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-#include <unistd.h>
-
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <hardware_legacy/wifi.h>
-
-#define LOG_TAG "wifiLoadScanAssocTest"
-#include <utils/Log.h>
-#include <testUtil.h>
-
-#define DEFAULT_START_PASS 0
-#define DEFAULT_END_PASS 999
-#define DEFAULT_DURATION FLT_MAX // A fairly long time, so that
- // range of passes will have
- // precedence
-#define DEFAULT_DELAY_MIN 0.0 // Min delay after start supplicant
-#define DEFAULT_DELAY_MAX 20.0 // Max delay after start supplicant
-#define DELAY_EXP 150.0 // Exponent which determines the
- // amount by which values closer
- // to DELAY_MIN are favored.
-
-#define CMD_STATUS "wpa_cli status 2>&1"
-#define CMD_STOP_FRAMEWORK "stop 2>&1"
-#define CMD_START_FRAMEWORK "start 2>&1"
-
-#define MAXSTR 100
-#define MAXCMD 500
-
-typedef unsigned int bool_t;
-#define true (0 == 0)
-#define false (!true)
-
-// File scope variables
-cpu_set_t availCPU;
-unsigned int numAvailCPU;
-float delayMin = DEFAULT_DELAY_MIN;
-float delayMax = DEFAULT_DELAY_MAX;
-bool_t driverLoadedAtStart;
-
-// Command-line mutual exclusion detection flags.
-// Corresponding flag set true once an option is used.
-bool_t eFlag, sFlag, pFlag;
-
-// File scope prototypes
-static void init(void);
-static void randDelay(void);
-static void randBind(const cpu_set_t *availSet, int *chosenCPU);
-
-/*
- * Main
- *
- * Performs the following high-level sequence of operations:
- *
- * 1. Command-line parsing
- *
- * 2. Initialization
- *
- * 3. Execute passes that repeatedly perform the WiFi load, scan,
- * associate, unload sequence.
- *
- * 4. Restore state of WiFi driver to state it was at the
- * start of the test.
- *
- * 5. Restart framework
- */
-int
-main(int argc, char *argv[])
-{
- FILE *fp;
- int rv, opt;
- int cpu;
- char *chptr;
- unsigned int pass;
- char cmd[MAXCMD];
- float duration = DEFAULT_DURATION;
- unsigned int startPass = DEFAULT_START_PASS, endPass = DEFAULT_END_PASS;
- struct timeval startTime, currentTime, delta;
-
- testSetLogCatTag(LOG_TAG);
-
- // Parse command line arguments
- while ((opt = getopt(argc, argv, "d:D:s:e:p:t:?")) != -1) {
- switch (opt) {
- case 'd': // Minimum Delay
- delayMin = strtod(optarg, &chptr);
- if ((*chptr != '\0') || (delayMin < 0.0)) {
- testPrintE("Invalid command-line specified minimum delay "
- "of: %s", optarg);
- exit(1);
- }
- break;
-
- case 'D': // Maximum Delay
- delayMax = strtod(optarg, &chptr);
- if ((*chptr != '\0') || (delayMax < 0.0)) {
- testPrintE("Invalid command-line specified maximum delay "
- "of: %s", optarg);
- exit(2);
- }
- break;
-
- case 't': // Duration
- duration = strtod(optarg, &chptr);
- if ((*chptr != '\0') || (duration < 0.0)) {
- testPrintE("Invalid command-line specified duration of: %s",
- optarg);
- exit(3);
- }
- break;
-
- case 's': // Starting Pass
- if (sFlag || pFlag) {
- testPrintE("Invalid combination of command-line options,");
- if (sFlag) {
- testPrintE(" -s flag specified multiple times.");
- } else {
- testPrintE(" -s and -p flags are mutually exclusive.");
- }
- exit(10);
- }
- sFlag = true;
- startPass = strtoul(optarg, &chptr, 10);
- if (*chptr != '\0') {
- testPrintE("Invalid command-line specified starting pass "
- "of: %s", optarg);
- exit(4);
- }
- break;
-
- case 'e': // Ending Pass
- if (eFlag || pFlag) {
- testPrintE("Invalid combination of command-line options,");
- if (sFlag) {
- testPrintE(" -e flag specified multiple times.");
- } else {
- testPrintE(" -e and -p flags are mutually exclusive.");
- }
- exit(11);
- }
- eFlag = true;
- endPass = strtoul(optarg, &chptr, 10);
- if (*chptr != '\0') {
- testPrintE("Invalid command-line specified ending pass "
- "of: %s", optarg);
- exit(5);
- }
- break;
-
- case 'p': // Single Specific Pass
- if (pFlag || sFlag || eFlag) {
- testPrintE("Invalid combination of command-line options,");
- if (pFlag) {
- testPrintE(" -p flag specified multiple times.");
- } else {
- testPrintE(" -p and -%c flags are mutually exclusive.",
- (sFlag) ? 's' : 'e');
- }
- exit(12);
- }
- pFlag = true;
- endPass = startPass = strtoul(optarg, &chptr, 10);
- if (*chptr != '\0') {
- testPrintE("Invalid command-line specified pass "
- "of: %s", optarg);
- exit(13);
- }
- break;
-
- case '?':
- default:
- testPrintE(" %s [options]", basename(argv[0]));
- testPrintE(" options:");
- testPrintE(" -s Starting pass");
- testPrintE(" -e Ending pass");
- testPrintE(" -p Specific single pass");
- testPrintE(" -t Duration");
- testPrintE(" -d Delay min");
- testPrintE(" -D Delay max");
- exit(((optopt == 0) || (optopt == '?')) ? 0 : 6);
- }
- }
- if (delayMax < delayMin) {
- testPrintE("Unexpected maximum delay less than minimum delay");
- testPrintE(" delayMin: %f delayMax: %f", delayMin, delayMax);
- exit(7);
- }
- if (endPass < startPass) {
- testPrintE("Unexpected ending pass before starting pass");
- testPrintE(" startPass: %u endPass: %u", startPass, endPass);
- exit(8);
- }
- if (argc != optind) {
- testPrintE("Unexpected command-line postional argument");
- testPrintE(" %s [-s start_pass] [-e end_pass] [-d duration]",
- basename(argv[0]));
- exit(9);
- }
- testPrintI("duration: %g", duration);
- testPrintI("startPass: %u", startPass);
- testPrintI("endPass: %u", endPass);
- testPrintI("delayMin: %f", delayMin);
- testPrintI("delayMax: %f", delayMax);
-
- init();
-
- // For each pass
- gettimeofday(&startTime, NULL);
- for (pass = startPass; pass <= endPass; pass++) {
- // Stop if duration of work has already been performed
- gettimeofday(¤tTime, NULL);
- delta = tvDelta(&startTime, ¤tTime);
- if (tv2double(&delta) > duration) { break; }
-
- testPrintI("==== Starting pass: %u", pass);
-
- // Use a pass dependent sequence of random numbers
- srand48(pass);
-
- // Load WiFi Driver
- randBind(&availCPU, &cpu);
- if ((rv = wifi_load_driver()) != 0) {
- testPrintE("CPU: %i wifi_load_driver() failed, rv: %i\n",
- cpu, rv);
- exit(20);
- }
- testPrintI("CPU: %i wifi_load_driver succeeded", cpu);
-
- // Start Supplicant
- randBind(&availCPU, &cpu);
- if ((rv = wifi_start_supplicant(false)) != 0) {
- testPrintE("CPU: %i wifi_start_supplicant() failed, rv: %i\n",
- cpu, rv);
- exit(21);
- }
- testPrintI("CPU: %i wifi_start_supplicant succeeded", cpu);
-
- // Sleep a random amount of time
- randDelay();
-
- /*
- * Obtain WiFi Status
- * Half the time skip this step, which helps increase the
- * level of randomization.
- */
- if (testRandBool()) {
- rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STATUS);
- if (rv >= (signed) sizeof(cmd) - 1) {
- testPrintE("Command too long for: %s\n", CMD_STATUS);
- exit(22);
- }
- testExecCmd(cmd);
- }
-
- // Stop Supplicant
- randBind(&availCPU, &cpu);
- if ((rv = wifi_stop_supplicant(false)) != 0) {
- testPrintE("CPU: %i wifi_stop_supplicant() failed, rv: %i\n",
- cpu, rv);
- exit(23);
- }
- testPrintI("CPU: %i wifi_stop_supplicant succeeded", cpu);
-
- // Unload WiFi Module
- randBind(&availCPU, &cpu);
- if ((rv = wifi_unload_driver()) != 0) {
- testPrintE("CPU: %i wifi_unload_driver() failed, rv: %i\n",
- cpu, rv);
- exit(24);
- }
- testPrintI("CPU: %i wifi_unload_driver succeeded", cpu);
-
- testPrintI("==== Completed pass: %u", pass);
- }
-
- // If needed restore WiFi driver to state it was in at the
- // start of the test. It is assumed that it the driver
- // was loaded, then the wpa_supplicant was also running.
- if (driverLoadedAtStart) {
- // Load driver
- if ((rv = wifi_load_driver()) != 0) {
- testPrintE("main load driver failed, rv: %i", rv);
- exit(25);
- }
-
- // Start supplicant
- if ((rv = wifi_start_supplicant(false)) != 0) {
- testPrintE("main start supplicant failed, rv: %i", rv);
- exit(26);
- }
-
- // Obtain WiFi Status
- rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STATUS);
- if (rv >= (signed) sizeof(cmd) - 1) {
- testPrintE("Command too long for: %s\n", CMD_STATUS);
- exit(22);
- }
- testExecCmd(cmd);
- }
-
- // Start framework
- rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
- if (rv >= (signed) sizeof(cmd) - 1) {
- testPrintE("Command too long for: %s\n", CMD_START_FRAMEWORK);
- exit(27);
- }
- testExecCmd(cmd);
-
- testPrintI("Successfully completed %u passes", pass - startPass);
-
- return 0;
-}
-
-/*
- * Initialize
- *
- * Perform testcase initialization, which includes:
- *
- * 1. Determine which CPUs are available for use
- *
- * 2. Determine total number of available CPUs
- *
- * 3. Stop framework
- *
- * 4. Determine whether WiFi driver is loaded and if so
- * stop wpa_supplicant and unload WiFi driver.
- */
-void
-init(void)
-{
- int rv;
- unsigned int n1;
- char cmd[MAXCMD];
-
- // Use whichever CPUs are available at start of test
- rv = sched_getaffinity(0, sizeof(availCPU), &availCPU);
- if (rv != 0) {
- testPrintE("init sched_getaffinity failed, rv: %i errno: %i",
- rv, errno);
- exit(40);
- }
-
- // How many CPUs are available
- numAvailCPU = 0;
- for (n1 = 0; n1 < CPU_SETSIZE; n1++) {
- if (CPU_ISSET(n1, &availCPU)) { numAvailCPU++; }
- }
- testPrintI("numAvailCPU: %u", numAvailCPU);
-
- // Stop framework
- rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
- if (rv >= (signed) sizeof(cmd) - 1) {
- testPrintE("Command too long for: %s\n", CMD_STOP_FRAMEWORK);
- exit(41);
- }
- testExecCmd(cmd);
-
- // Is WiFi driver loaded?
- // If so stop the wpa_supplicant and unload the driver.
- driverLoadedAtStart = is_wifi_driver_loaded();
- testPrintI("driverLoadedAtStart: %u", driverLoadedAtStart);
- if (driverLoadedAtStart) {
- // Stop wpa_supplicant
- // Might already be stopped, in which case request should
- // return immediately with success.
- if ((rv = wifi_stop_supplicant(false)) != 0) {
- testPrintE("init stop supplicant failed, rv: %i", rv);
- exit(42);
- }
- testPrintI("Stopped wpa_supplicant");
-
- if ((rv = wifi_unload_driver()) != 0) {
- testPrintE("init unload driver failed, rv: %i", rv);
- exit(43);
- }
- testPrintI("WiFi driver unloaded");
- }
-
-}
-
-/*
- * Random Delay
- *
- * Delays for a random amount of time within the range given
- * by the file scope variables delayMin and delayMax. The
- * selected amount of delay can come from any part of the
- * range, with a bias towards values closer to delayMin.
- * The amount of bias is determined by the setting of DELAY_EXP.
- * The setting of DELAY_EXP should always be > 1.0, with higher
- * values causing a more significant bias toward the value
- * of delayMin.
- */
-void randDelay(void)
-{
- const unsigned long nanosecspersec = 1000000000;
- float fract, biasedFract, amt;
- struct timeval startTime, endTime;
-
- // Obtain start time
- gettimeofday(&startTime, NULL);
-
- // Determine random amount to sleep.
- // Values closer to delayMin are prefered by an amount
- // determined by the value of DELAY_EXP.
- fract = testRandFract();
- biasedFract = pow(DELAY_EXP, fract) / pow(DELAY_EXP, 1.0);
- amt = delayMin + ((delayMax - delayMin) * biasedFract);
-
- // Delay
- testDelay(amt);
-
- // Obtain end time and display delta
- gettimeofday(&endTime, NULL);
- testPrintI("delay: %.2f",
- (float) (tv2double(&endTime) - tv2double(&startTime)));
-}
-
-static void
-randBind(const cpu_set_t *availSet, int *chosenCPU)
-{
- int rv;
- cpu_set_t cpuset;
- int chosenAvail, avail, cpu, currentCPU;
-
- // Randomly bind to a CPU
- // Lower 16 bits from random number generator thrown away,
- // because the low-order bits tend to have the same sequence for
- // different seed values.
- chosenAvail = testRandMod(numAvailCPU);
- CPU_ZERO(&cpuset);
- avail = 0;
- for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
- if (CPU_ISSET(cpu, availSet)) {
- if (chosenAvail == avail) {
- CPU_SET(cpu, &cpuset);
- break;
- }
- avail++;
- }
- }
- assert(cpu < CPU_SETSIZE);
- sched_setaffinity(0, sizeof(cpuset), &cpuset);
-
- // Confirm executing on requested CPU
- if ((currentCPU = sched_getcpu()) < 0) {
- testPrintE("randBind sched_getcpu() failed, rv: %i errno: %i",
- currentCPU, errno);
- exit(80);
-
- }
- if (currentCPU != cpu) {
- testPrintE("randBind executing on unexpected CPU %i, expected %i",
- currentCPU, cpu);
- exit(81);
- }
-
- // Let the caller know which CPU was chosen
- *chosenCPU = cpu;
-}
diff --git a/verity/fec/Android.mk b/verity/fec/Android.mk
index 33ef8b5..8527e0b 100644
--- a/verity/fec/Android.mk
+++ b/verity/fec/Android.mk
@@ -21,23 +21,3 @@
LOCAL_CFLAGS += -Wall -Werror -O3
LOCAL_C_INCLUDES += external/fec
include $(BUILD_HOST_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-LOCAL_MODULE := fec
-LOCAL_FORCE_STATIC_EXECUTABLE := true
-LOCAL_SRC_FILES := main.cpp image.cpp
-LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_LIBRARIES := \
- libcrypto_utils \
- libcrypto \
- libfec \
- libfec_rs \
- libbase \
- libext4_utils_static \
- libsquashfs_utils \
- libcutils
-LOCAL_CFLAGS += -Wall -Werror -O3 -DIMAGE_NO_SPARSE=1
-LOCAL_C_INCLUDES += external/fec
-include $(BUILD_EXECUTABLE)
diff --git a/verity/fec/image.cpp b/verity/fec/image.cpp
index 610a462..5c3eb8b 100644
--- a/verity/fec/image.cpp
+++ b/verity/fec/image.cpp
@@ -33,9 +33,7 @@
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
-#ifndef IMAGE_NO_SPARSE
#include <sparse/sparse.h>
-#endif
#include "image.h"
#if defined(__linux__)
@@ -51,24 +49,7 @@
memset(ctx, 0, sizeof(*ctx));
}
-static void mmap_image_free(image *ctx)
-{
- if (ctx->input) {
- munmap(ctx->input, (size_t)ctx->inp_size);
- close(ctx->inp_fd);
- }
-
- if (ctx->fec_mmap_addr) {
- munmap(ctx->fec_mmap_addr, FEC_BLOCKSIZE + ctx->fec_size);
- close(ctx->fec_fd);
- }
-
- if (!ctx->inplace && ctx->output) {
- delete[] ctx->output;
- }
-}
-
-static void file_image_free(image *ctx)
+void image_free(image *ctx)
{
assert(ctx->input == ctx->output);
@@ -79,42 +60,10 @@
if (ctx->fec) {
delete[] ctx->fec;
}
-}
-
-void image_free(image *ctx)
-{
- if (ctx->mmap) {
- mmap_image_free(ctx);
- } else {
- file_image_free(ctx);
- }
image_init(ctx);
}
-static uint64_t get_size(int fd)
-{
- struct stat st;
-
- if (fstat(fd, &st) == -1) {
- FATAL("failed to fstat: %s\n", strerror(errno));
- }
-
- uint64_t size = 0;
-
- if (S_ISBLK(st.st_mode)) {
- if (ioctl(fd, BLKGETSIZE64, &size) == -1) {
- FATAL("failed to ioctl(BLKGETSIZE64): %s\n", strerror(errno));
- }
- } else if (S_ISREG(st.st_mode)) {
- size = st.st_size;
- } else {
- FATAL("unknown file mode: %d\n", (int)st.st_mode);
- }
-
- return size;
-}
-
static void calculate_rounds(uint64_t size, image *ctx)
{
if (!size) {
@@ -129,64 +78,6 @@
ctx->rounds = fec_div_round_up(ctx->blocks, ctx->rs_n);
}
-static void mmap_image_load(const std::vector<int>& fds, image *ctx,
- bool output_needed)
-{
- if (fds.size() != 1) {
- FATAL("multiple input files not supported with mmap\n");
- }
-
- int fd = fds.front();
-
- calculate_rounds(get_size(fd), ctx);
-
- /* check that we can memory map the file; on 32-bit platforms we are
- limited to encoding at most 4 GiB files */
- if (ctx->inp_size > SIZE_MAX) {
- FATAL("cannot mmap %" PRIu64 " bytes\n", ctx->inp_size);
- }
-
- if (ctx->verbose) {
- INFO("memory mapping '%s' (size %" PRIu64 ")\n", ctx->fec_filename,
- ctx->inp_size);
- }
-
- int flags = PROT_READ;
-
- if (ctx->inplace) {
- flags |= PROT_WRITE;
- }
-
- void *p = mmap(NULL, (size_t)ctx->inp_size, flags, MAP_SHARED, fd, 0);
-
- if (p == MAP_FAILED) {
- FATAL("failed to mmap '%s' (size %" PRIu64 "): %s\n",
- ctx->fec_filename, ctx->inp_size, strerror(errno));
- }
-
- ctx->inp_fd = fd;
- ctx->input = (uint8_t *)p;
-
- if (ctx->inplace) {
- ctx->output = ctx->input;
- } else if (output_needed) {
- if (ctx->verbose) {
- INFO("allocating %" PRIu64 " bytes of memory\n", ctx->inp_size);
- }
-
- ctx->output = new uint8_t[ctx->inp_size];
-
- if (!ctx->output) {
- FATAL("failed to allocate memory\n");
- }
-
- memcpy(ctx->output, ctx->input, ctx->inp_size);
- }
-
- /* fd is closed in mmap_image_free */
-}
-
-#ifndef IMAGE_NO_SPARSE
static int process_chunk(void *priv, const void *data, int len)
{
image *ctx = (image *)priv;
@@ -199,25 +90,14 @@
ctx->pos += len;
return 0;
}
-#endif
static void file_image_load(const std::vector<int>& fds, image *ctx)
{
uint64_t size = 0;
-#ifndef IMAGE_NO_SPARSE
std::vector<struct sparse_file *> files;
-#endif
for (auto fd : fds) {
uint64_t len = 0;
-
-#ifdef IMAGE_NO_SPARSE
- if (ctx->sparse) {
- FATAL("sparse files not supported\n");
- }
-
- len = get_size(fd);
-#else
struct sparse_file *file;
if (ctx->sparse) {
@@ -232,7 +112,6 @@
len = sparse_file_len(file, false, false);
files.push_back(file);
-#endif /* IMAGE_NO_SPARSE */
size += len;
}
@@ -253,18 +132,6 @@
ctx->output = ctx->input;
ctx->pos = 0;
-#ifdef IMAGE_NO_SPARSE
- for (auto fd : fds) {
- uint64_t len = get_size(fd);
-
- if (!android::base::ReadFully(fd, &ctx->input[ctx->pos], len)) {
- FATAL("failed to read: %s\n", strerror(errno));
- }
-
- ctx->pos += len;
- close(fd);
- }
-#else
for (auto file : files) {
sparse_file_callback(file, false, false, process_chunk, ctx);
sparse_file_destroy(file);
@@ -273,11 +140,9 @@
for (auto fd : fds) {
close(fd);
}
-#endif
}
-bool image_load(const std::vector<std::string>& filenames, image *ctx,
- bool output_needed)
+bool image_load(const std::vector<std::string>& filenames, image *ctx)
{
assert(ctx->roots > 0 && ctx->roots < FEC_RSM);
ctx->rs_n = FEC_RSM - ctx->roots;
@@ -300,21 +165,13 @@
fds.push_back(fd);
}
- if (ctx->mmap) {
- mmap_image_load(fds, ctx, output_needed);
- } else {
- file_image_load(fds, ctx);
- }
+ file_image_load(fds, ctx);
return true;
}
bool image_save(const std::string& filename, image *ctx)
{
- if (ctx->inplace && ctx->mmap) {
- return true; /* nothing to do */
- }
-
/* TODO: support saving as a sparse file */
int fd = TEMP_FAILURE_RETRY(open(filename.c_str(),
O_WRONLY | O_CREAT | O_TRUNC, 0666));
@@ -332,46 +189,13 @@
return true;
}
-static void mmap_image_ecc_new(image *ctx)
+bool image_ecc_new(const std::string& filename, image *ctx)
{
- if (ctx->verbose) {
- INFO("mmaping '%s' (size %u)\n", ctx->fec_filename, ctx->fec_size);
- }
+ assert(ctx->rounds > 0); /* image_load should be called first */
- int fd = TEMP_FAILURE_RETRY(open(ctx->fec_filename,
- O_RDWR | O_CREAT, 0666));
+ ctx->fec_filename = filename.c_str();
+ ctx->fec_size = ctx->rounds * ctx->roots * FEC_BLOCKSIZE;
- if (fd < 0) {
- FATAL("failed to open file '%s': %s\n", ctx->fec_filename,
- strerror(errno));
- }
-
- assert(sizeof(fec_header) <= FEC_BLOCKSIZE);
- size_t fec_size = FEC_BLOCKSIZE + ctx->fec_size;
-
- if (ftruncate(fd, fec_size) == -1) {
- FATAL("failed to ftruncate file '%s': %s\n", ctx->fec_filename,
- strerror(errno));
- }
-
- if (ctx->verbose) {
- INFO("memory mapping '%s' (size %zu)\n", ctx->fec_filename, fec_size);
- }
-
- void *p = mmap(NULL, fec_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-
- if (p == MAP_FAILED) {
- FATAL("failed to mmap '%s' (size %zu): %s\n", ctx->fec_filename,
- fec_size, strerror(errno));
- }
-
- ctx->fec_fd = fd;
- ctx->fec_mmap_addr = (uint8_t *)p;
- ctx->fec = ctx->fec_mmap_addr;
-}
-
-static void file_image_ecc_new(image *ctx)
-{
if (ctx->verbose) {
INFO("allocating %u bytes of memory\n", ctx->fec_size);
}
@@ -381,20 +205,6 @@
if (!ctx->fec) {
FATAL("failed to allocate %u bytes\n", ctx->fec_size);
}
-}
-
-bool image_ecc_new(const std::string& filename, image *ctx)
-{
- assert(ctx->rounds > 0); /* image_load should be called first */
-
- ctx->fec_filename = filename.c_str();
- ctx->fec_size = ctx->rounds * ctx->roots * FEC_BLOCKSIZE;
-
- if (ctx->mmap) {
- mmap_image_ecc_new(ctx);
- } else {
- file_image_ecc_new(ctx);
- }
return true;
}
@@ -462,7 +272,7 @@
FATAL("failed to rewind '%s': %s", filename.c_str(), strerror(errno));
}
- if (!ctx->mmap && !android::base::ReadFully(fd, ctx->fec, ctx->fec_size)) {
+ if (!android::base::ReadFully(fd, ctx->fec, ctx->fec_size)) {
FATAL("failed to read %u bytes from '%s': %s\n", ctx->fec_size,
filename.c_str(), strerror(errno));
}
@@ -486,10 +296,6 @@
uint8_t header[FEC_BLOCKSIZE];
uint8_t *p = header;
- if (ctx->mmap) {
- p = (uint8_t *)&ctx->fec_mmap_addr[ctx->fec_size];
- }
-
memset(p, 0, FEC_BLOCKSIZE);
fec_header *f = (fec_header *)p;
@@ -506,25 +312,23 @@
/* store a copy of the fec_header at the end of the header block */
memcpy(&p[sizeof(header) - sizeof(fec_header)], p, sizeof(fec_header));
- if (!ctx->mmap) {
- assert(ctx->fec_filename);
+ assert(ctx->fec_filename);
- int fd = TEMP_FAILURE_RETRY(open(ctx->fec_filename,
- O_WRONLY | O_CREAT | O_TRUNC, 0666));
+ int fd = TEMP_FAILURE_RETRY(open(ctx->fec_filename,
+ O_WRONLY | O_CREAT | O_TRUNC, 0666));
- if (fd < 0) {
- FATAL("failed to open file '%s': %s\n", ctx->fec_filename,
- strerror(errno));
- }
-
- if (!android::base::WriteFully(fd, ctx->fec, ctx->fec_size) ||
- !android::base::WriteFully(fd, header, sizeof(header))) {
- FATAL("failed to write to output: %s\n", strerror(errno));
- }
-
- close(fd);
+ if (fd < 0) {
+ FATAL("failed to open file '%s': %s\n", ctx->fec_filename,
+ strerror(errno));
}
+ if (!android::base::WriteFully(fd, ctx->fec, ctx->fec_size) ||
+ !android::base::WriteFully(fd, header, sizeof(header))) {
+ FATAL("failed to write to output: %s\n", strerror(errno));
+ }
+
+ close(fd);
+
return true;
}
diff --git a/verity/fec/image.h b/verity/fec/image.h
index f0211fd..72048c6 100644
--- a/verity/fec/image.h
+++ b/verity/fec/image.h
@@ -38,8 +38,6 @@
struct image {
/* if true, decode file in place instead of creating a new output file */
bool inplace;
- /* if true, use memory mapping instead of copying all input into memory */
- bool mmap;
/* if true, assume input is a sparse file */
bool sparse;
/* if true, print more verbose information to stderr */
@@ -60,7 +58,6 @@
uint64_t rounds;
uint64_t rv;
uint8_t *fec;
- uint8_t *fec_mmap_addr;
uint8_t *input;
uint8_t *output;
};
@@ -79,8 +76,7 @@
void *rs;
};
-extern bool image_load(const std::vector<std::string>& filename, image *ctx,
- bool output_needed);
+extern bool image_load(const std::vector<std::string>& filename, image *ctx);
extern bool image_save(const std::string& filename, image *ctx);
extern bool image_ecc_new(const std::string& filename, image *ctx);
diff --git a/verity/fec/main.cpp b/verity/fec/main.cpp
index 0675fd6..6245f07 100644
--- a/verity/fec/main.cpp
+++ b/verity/fec/main.cpp
@@ -105,7 +105,6 @@
" -h show this help\n"
" -v enable verbose logging\n"
" -r, --roots=<bytes> number of parity bytes\n"
- " -m, --mmap use memory mapping\n"
" -j, --threads=<threads> number of threads to use\n"
" -S treat data as a sparse file\n"
"decoding options:\n"
@@ -176,7 +175,7 @@
FATAL("invalid parameters: inplace can only used when decoding\n");
}
- if (!image_load(inp_filenames, &ctx, false)) {
+ if (!image_load(inp_filenames, &ctx)) {
FATAL("failed to read input\n");
}
@@ -222,7 +221,7 @@
}
if (!image_ecc_load(fec_filename, &ctx) ||
- !image_load(inp_filenames, &ctx, !out_filename.empty())) {
+ !image_load(inp_filenames, &ctx)) {
FATAL("failed to read input\n");
}
@@ -281,7 +280,6 @@
{"sparse", no_argument, 0, 'S'},
{"roots", required_argument, 0, 'r'},
{"inplace", no_argument, 0, 'i'},
- {"mmap", no_argument, 0, 'm'},
{"threads", required_argument, 0, 'j'},
{"print-fec-size", required_argument, 0, 's'},
{"get-ecc-start", required_argument, 0, 'E'},
@@ -317,9 +315,6 @@
case 'i':
ctx.inplace = true;
break;
- case 'm':
- ctx.mmap = true;
- break;
case 'j':
ctx.threads = (int)parse_arg(optarg, "threads", IMAGE_MAX_THREADS);
break;