Merge "f2fs_utils: update f2fs utils to match 1.8.0"
diff --git a/simpleperf/README.md b/simpleperf/README.md
index 74b7fb7..b6dc9d7 100644
--- a/simpleperf/README.md
+++ b/simpleperf/README.md
@@ -523,6 +523,8 @@
# Open SimpleperfExamplesPureJava project with Android studio,
# and build this project sucessfully, otherwise the `./gradlew` command below will fail.
$cd SimpleperfExamplePureJava
+
+ # On windows, use "gradlew" instead.
$./gradlew clean assemble
$adb install -r app/build/outputs/apk/app-profiling.apk
@@ -618,6 +620,7 @@
$adb shell run-as com.example.simpleperf.simpleperfexamplepurejava cat perf.data >perf.data
# Report samples using corresponding simpleperf executable on host.
+ # On windows, use "bin\windows\x86_64\simpleperf" instead.
$bin/linux/x86_64/simpleperf report
...
Overhead Command Pid Tid Shared Object Symbol
diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp
index 191d641..2ce5295 100644
--- a/simpleperf/cmd_dumprecord.cpp
+++ b/simpleperf/cmd_dumprecord.cpp
@@ -49,7 +49,7 @@
void DumpFileHeader();
void DumpAttrSection();
void DumpDataSection();
- void DumpFeatureSection();
+ bool DumpFeatureSection();
std::string record_filename_;
std::unique_ptr<RecordFileReader> record_file_reader_;
@@ -75,7 +75,9 @@
DumpFileHeader();
DumpAttrSection();
DumpDataSection();
- DumpFeatureSection();
+ if (!DumpFeatureSection()) {
+ return false;
+ }
return true;
}
@@ -180,7 +182,7 @@
}, false);
}
-void DumpRecordCommand::DumpFeatureSection() {
+bool DumpRecordCommand::DumpFeatureSection() {
std::map<int, SectionDesc> section_map = record_file_reader_->FeatureSectionDescriptors();
for (const auto& pair : section_map) {
int feature = pair.first;
@@ -220,8 +222,18 @@
symbol.addr, symbol.addr + symbol.len);
}
}
+ } else if (feature == FEAT_META_INFO) {
+ std::unordered_map<std::string, std::string> info_map;
+ if (!record_file_reader_->ReadMetaInfoFeature(&info_map)) {
+ return false;
+ }
+ PrintIndented(1, "meta_info:\n");
+ for (auto& pair : info_map) {
+ PrintIndented(2, "%s = %s\n", pair.first.c_str(), pair.second.c_str());
+ }
}
}
+ return true;
}
void RegisterDumpRecordCommand() {
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 3376af0..78e0a95 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -941,7 +941,7 @@
return false;
}
- size_t feature_count = 4;
+ size_t feature_count = 5;
if (branch_sampling_) {
feature_count++;
}
@@ -984,6 +984,13 @@
!record_file_writer_->WriteBranchStackFeature()) {
return false;
}
+
+ std::unordered_map<std::string, std::string> info_map;
+ info_map["simpleperf_version"] = GetSimpleperfVersion();
+ if (!record_file_writer_->WriteMetaInfoFeature(info_map)) {
+ return false;
+ }
+
if (!record_file_writer_->EndWriteFeatures()) {
return false;
}
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index 85bbe34..ec0605a 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -428,3 +428,13 @@
close(read_fd);
ASSERT_EQ("STARTED", s);
}
+
+TEST(record_cmd, record_meta_info_feature) {
+ TemporaryFile tmpfile;
+ ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
+ std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
+ ASSERT_TRUE(reader != nullptr);
+ std::unordered_map<std::string, std::string> info_map;
+ ASSERT_TRUE(reader->ReadMetaInfoFeature(&info_map));
+ ASSERT_NE(info_map.find("simpleperf_version"), info_map.end());
+}
diff --git a/simpleperf/demo/README.md b/simpleperf/demo/README.md
index 2376e94..3737416 100644
--- a/simpleperf/demo/README.md
+++ b/simpleperf/demo/README.md
@@ -35,6 +35,8 @@
# Open SimpleperfExamplesPureJava project with Android Studio,
# and build this project sucessfully, otherwise the `./gradlew` command below will fail.
$cd SimpleperfExamplePureJava
+
+ # On windows, use "gradlew" instead.
$./gradlew clean assemble
$adb install -r app/build/outputs/apk/app-profiling.apk
@@ -49,6 +51,7 @@
3. Show profiling data:
a. show call graph in txt mode
+ # On windows, use "bin\windows\x86\simpleperf" instead.
$bin/linux/x86_64/simpleperf report -g --brief-callgraph | more
If on other hosts, use corresponding simpleperf binary.
b. show call graph in gui mode
@@ -72,6 +75,8 @@
# Open SimpleperfExamplesPureJava project with Android Studio,
# and build this project sucessfully, otherwise the `./gradlew` command below will fail.
$cd SimpleperfExampleWithNative
+
+ # On windows, use "gradlew" instead.
$./gradlew clean assemble
$adb install -r app/build/outputs/apk/app-profiling.apk
@@ -86,6 +91,7 @@
3. Show profiling data:
a. show call graph in txt mode
+ # On windows, use "bin\windows\x86\simpleperf" instead.
$bin/linux/x86_64/simpleperf report -g --brief-callgraph | more
If on other hosts, use corresponding simpleperf binary.
b. show call graph in gui mode
diff --git a/simpleperf/event_fd.cpp b/simpleperf/event_fd.cpp
index 18eff2d..c6edb24 100644
--- a/simpleperf/event_fd.cpp
+++ b/simpleperf/event_fd.cpp
@@ -103,7 +103,7 @@
uint64_t EventFd::Id() const {
if (id_ == 0) {
PerfCounter counter;
- if (ReadCounter(&counter)) {
+ if (InnerReadCounter(&counter)) {
id_ = counter.id;
}
}
@@ -119,23 +119,30 @@
return true;
}
-bool EventFd::ReadCounter(PerfCounter* counter) const {
+bool EventFd::InnerReadCounter(PerfCounter* counter) const {
CHECK(counter != nullptr);
- uint64_t pre_counter = counter->value;
if (!android::base::ReadFully(perf_event_fd_, counter, sizeof(*counter))) {
PLOG(ERROR) << "ReadCounter from " << Name() << " failed";
return false;
}
+ return true;
+}
+
+bool EventFd::ReadCounter(PerfCounter* counter) {
+ if (!InnerReadCounter(counter)) {
+ return false;
+ }
// Trace is always available to systrace if enabled
if (tid_ > 0) {
ATRACE_INT64(android::base::StringPrintf(
"%s_tid%d_cpu%d", event_name_.c_str(), tid_,
- cpu_).c_str(), counter->value - pre_counter);
+ cpu_).c_str(), counter->value - last_counter_value_);
} else {
ATRACE_INT64(android::base::StringPrintf(
"%s_cpu%d", event_name_.c_str(),
- cpu_).c_str(), counter->value - pre_counter);
+ cpu_).c_str(), counter->value - last_counter_value_);
}
+ last_counter_value_ = counter->value;
return true;
}
diff --git a/simpleperf/event_fd.h b/simpleperf/event_fd.h
index f1ddb55..ab47cc5 100644
--- a/simpleperf/event_fd.h
+++ b/simpleperf/event_fd.h
@@ -60,7 +60,7 @@
// this file.
bool EnableEvent();
- bool ReadCounter(PerfCounter* counter) const;
+ bool ReadCounter(PerfCounter* counter);
// Create mapped buffer used to receive records sent by the kernel.
// mmap_pages should be power of 2.
@@ -96,8 +96,10 @@
mmap_metadata_page_(nullptr),
mmap_data_buffer_(nullptr),
mmap_data_buffer_size_(0),
- ioevent_ref_(nullptr) {}
+ ioevent_ref_(nullptr),
+ last_counter_value_(0) {}
+ bool InnerReadCounter(PerfCounter* counter) const;
// Discard how much data we have read, so the kernel can reuse this part of
// mapped area to store new data.
void DiscardMmapData(size_t discard_size);
@@ -123,6 +125,9 @@
IOEventRef ioevent_ref_;
+ // Used by atrace to generate value difference between two ReadCounter() calls.
+ uint64_t last_counter_value_;
+
DISALLOW_COPY_AND_ASSIGN(EventFd);
};
diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp
index b966273..86f57b9 100644
--- a/simpleperf/event_selection_set.cpp
+++ b/simpleperf/event_selection_set.cpp
@@ -450,7 +450,7 @@
return true;
}
-static bool ReadCounter(const EventFd* event_fd, CounterInfo* counter) {
+static bool ReadCounter(EventFd* event_fd, CounterInfo* counter) {
if (!event_fd->ReadCounter(&counter->counter)) {
return false;
}
diff --git a/simpleperf/main.cpp b/simpleperf/main.cpp
index 07b0e4b..ae3e629 100644
--- a/simpleperf/main.cpp
+++ b/simpleperf/main.cpp
@@ -24,8 +24,6 @@
#include "command.h"
#include "utils.h"
-constexpr int SIMPLEPERF_VERSION = 1;
-
int main(int argc, char** argv) {
android::base::InitLogging(argv, android::base::StderrLogger);
std::vector<std::string> args;
@@ -46,8 +44,7 @@
return 1;
}
} else if (strcmp(argv[i], "--version") == 0) {
- LOG(INFO) << "Simpleperf version " << SIMPLEPERF_VERSION << ", revision "
- << SIMPLEPERF_REVISION;
+ LOG(INFO) << "Simpleperf version " << GetSimpleperfVersion();
return 0;
} else {
args.push_back(argv[i]);
diff --git a/simpleperf/record_file.h b/simpleperf/record_file.h
index 51d4f43..32c91fa 100644
--- a/simpleperf/record_file.h
+++ b/simpleperf/record_file.h
@@ -56,6 +56,7 @@
uint32_t file_type,
uint64_t min_vaddr,
const std::vector<const Symbol*>& symbols);
+ bool WriteMetaInfoFeature(const std::unordered_map<std::string, std::string>& info_map);
bool EndWriteFeatures();
// Normally, Close() should be called after writing. But if something
@@ -148,6 +149,7 @@
bool ReadFileFeature(size_t& read_pos, std::string* file_path,
uint32_t* file_type, uint64_t* min_vaddr,
std::vector<Symbol>* symbols);
+ bool ReadMetaInfoFeature(std::unordered_map<std::string, std::string>* info_map);
void LoadBuildIdAndFileFeatures(ThreadTree& thread_tree);
diff --git a/simpleperf/record_file_format.h b/simpleperf/record_file_format.h
index efa000c..f9ed6f3 100644
--- a/simpleperf/record_file_format.h
+++ b/simpleperf/record_file_format.h
@@ -19,34 +19,47 @@
#include "perf_event.h"
-// The file structure of perf.data:
-// file_header
-// id_section
-// attr section
-// data section
-// feature section
-//
-// The feature section has the following structure:
-// a section descriptor array, each element contains the section information of one add_feature.
-// data section of feature 1
-// data section of feature 2
-// ....
+/*
+The file structure of perf.data:
+ file_header
+ id_section
+ attr section
+ data section
+ feature section
-// file feature section:
-// file_struct files[];
-//
-// struct file_struct {
-// uint32_t size; // size of rest fields in file_struct
-// char file_path[];
-// uint32_t file_type;
-// uint64_t min_vaddr;
-// uint32_t symbol_count;
-// struct {
-// uint64_t start_vaddr;
-// uint32_t len;
-// char symbol_name[];
-// } symbol_table;
-// };
+The feature section has the following structure:
+ a section descriptor array, each element contains the section information of one add_feature.
+ data section of feature 1
+ data section of feature 2
+ ....
+
+file feature section:
+ file_struct files[];
+
+ struct file_struct {
+ uint32_t size; // size of rest fields in file_struct
+ char file_path[];
+ uint32_t file_type;
+ uint64_t min_vaddr;
+ uint32_t symbol_count;
+ struct {
+ uint64_t start_vaddr;
+ uint32_t len;
+ char symbol_name[];
+ } symbol_table;
+ };
+
+meta_info feature section:
+ meta_info infos[];
+
+ struct meta_info {
+ char key[];
+ char value[];
+ };
+ keys in meta_info feature section include:
+ simpleperf_version,
+
+*/
namespace PerfFileFormat {
@@ -74,6 +87,7 @@
FEAT_SIMPLEPERF_START = 128,
FEAT_FILE = FEAT_SIMPLEPERF_START,
+ FEAT_META_INFO,
FEAT_MAX_NUM = 256,
};
diff --git a/simpleperf/record_file_reader.cpp b/simpleperf/record_file_reader.cpp
index 0fdb6dd..67f35be 100644
--- a/simpleperf/record_file_reader.cpp
+++ b/simpleperf/record_file_reader.cpp
@@ -434,6 +434,23 @@
return true;
}
+bool RecordFileReader::ReadMetaInfoFeature(std::unordered_map<std::string, std::string>* info_map) {
+ std::vector<char> buf;
+ if (!ReadFeatureSection(FEAT_META_INFO, &buf)) {
+ return false;
+ }
+ const char* p = buf.data();
+ const char* end = buf.data() + buf.size();
+ while (p < end) {
+ const char* key = p;
+ const char* value = key + strlen(key) + 1;
+ CHECK(value < end);
+ (*info_map)[p] = value;
+ p = value + strlen(value) + 1;
+ }
+ return true;
+}
+
void RecordFileReader::LoadBuildIdAndFileFeatures(ThreadTree& thread_tree) {
std::vector<BuildIdRecord> records = ReadBuildIdFeature();
std::vector<std::pair<std::string, BuildId>> build_ids;
diff --git a/simpleperf/record_file_test.cpp b/simpleperf/record_file_test.cpp
index 4fe725b..530611e 100644
--- a/simpleperf/record_file_test.cpp
+++ b/simpleperf/record_file_test.cpp
@@ -157,3 +157,29 @@
ASSERT_EQ(attrs[i].ids, attr_ids_[i].ids);
}
}
+
+TEST_F(RecordFileTest, write_meta_info_feature_section) {
+ // Write to a record file.
+ std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(tmpfile_.path);
+ ASSERT_TRUE(writer != nullptr);
+ AddEventType("cpu-cycles");
+ ASSERT_TRUE(writer->WriteAttrSection(attr_ids_));
+
+ // Write meta_info feature section.
+ ASSERT_TRUE(writer->BeginWriteFeatures(1));
+ std::unordered_map<std::string, std::string> info_map;
+ for (int i = 0; i < 100; ++i) {
+ std::string s = std::to_string(i);
+ info_map[s] = s + s;
+ }
+ ASSERT_TRUE(writer->WriteMetaInfoFeature(info_map));
+ ASSERT_TRUE(writer->EndWriteFeatures());
+ ASSERT_TRUE(writer->Close());
+
+ // Read from a record file.
+ std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile_.path);
+ ASSERT_TRUE(reader != nullptr);
+ std::unordered_map<std::string, std::string> read_info_map;
+ ASSERT_TRUE(reader->ReadMetaInfoFeature(&read_info_map));
+ ASSERT_EQ(read_info_map, info_map);
+}
diff --git a/simpleperf/record_file_writer.cpp b/simpleperf/record_file_writer.cpp
index fe62ab5..083a746 100644
--- a/simpleperf/record_file_writer.cpp
+++ b/simpleperf/record_file_writer.cpp
@@ -328,6 +328,28 @@
return WriteFeatureEnd(FEAT_FILE);
}
+bool RecordFileWriter::WriteMetaInfoFeature(
+ const std::unordered_map<std::string, std::string>& info_map) {
+ uint32_t size = 0u;
+ for (auto& pair : info_map) {
+ size += pair.first.size() + 1;
+ size += pair.second.size() + 1;
+ }
+ std::vector<char> buf(size);
+ char* p = buf.data();
+ for (auto& pair : info_map) {
+ MoveToBinaryFormat(pair.first.c_str(), pair.first.size() + 1, p);
+ MoveToBinaryFormat(pair.second.c_str(), pair.second.size() + 1, p);
+ }
+ if (!WriteFeatureBegin(FEAT_META_INFO)) {
+ return false;
+ }
+ if (!Write(buf.data(), buf.size())) {
+ return false;
+ }
+ return WriteFeatureEnd(FEAT_META_INFO);
+}
+
bool RecordFileWriter::WriteFeatureBegin(int feature) {
auto it = features_.find(feature);
if (it == features_.end()) {
diff --git a/simpleperf/scripts/annotate.py b/simpleperf/scripts/annotate.py
index 1f3a2ef..d88a916 100644
--- a/simpleperf/scripts/annotate.py
+++ b/simpleperf/scripts/annotate.py
@@ -111,7 +111,11 @@
function = stdoutdata[out_pos]
out_pos += 1
assert out_pos < len(stdoutdata)
- file, line = stdoutdata[out_pos].split(':')
+ # Handle lines like "C:\Users\...\file:32".
+ items = stdoutdata[out_pos].rsplit(':', 1)
+ if len(items) != 2:
+ continue
+ (file, line) = items
line = line.split()[0] # Remove comments after line number
out_pos += 1
if file.find('?') != -1:
@@ -123,8 +127,8 @@
else:
line = int(line)
source_lines.append(SourceLine(file, function, line))
- dso[addrs[addr_pos]] = source_lines
- addr_pos += 1
+ dso[addrs[addr_pos]] = source_lines
+ addr_pos += 1
assert addr_pos == len(addrs)
@@ -557,6 +561,9 @@
path = key
from_path = path
to_path = os.path.join(dest_dir, path[1:])
+ elif is_windows() and key.find(':\\') != -1 and os.path.isfile(key):
+ from_path = key
+ to_path = os.path.join(dest_dir, key.replace(':\\', '\\'))
else:
path = key[1:] if key.startswith('/') else key
# Change path on device to path on host
@@ -626,3 +633,4 @@
config = load_config(args.config)
annotator = SourceFileAnnotator(config)
annotator.annotate()
+ log_info('annotate finish successfully, please check result in annotated_files/.')
\ No newline at end of file
diff --git a/simpleperf/scripts/simpleperf_report_lib.py b/simpleperf/scripts/simpleperf_report_lib.py
index 27ce08a..de90466 100644
--- a/simpleperf/scripts/simpleperf_report_lib.py
+++ b/simpleperf/scripts/simpleperf_report_lib.py
@@ -167,14 +167,9 @@
self.convert_to_str = (sys.version_info >= (3, 0))
def _load_dependent_lib(self):
- # As the windows dll is built with mingw we need to also find "libwinpthread-1.dll".
- # Load it before libsimpleperf_report.dll if it does exist in the same folder as this script.
+ # As the windows dll is built with mingw we need to load "libwinpthread-1.dll".
if is_windows():
- libwinpthread_path = os.path.join(get_script_dir(), "libwinpthread-1.dll")
- if os.path.exists(libwinpthread_path):
- self._libwinpthread = ct.CDLL(libwinpthread_path)
- else:
- log_fatal('%s is missing' % libwinpthread_path)
+ self._libwinpthread = ct.CDLL(get_host_binary_path('libwinpthread-1.dll'))
def Close(self):
if self._instance is None:
diff --git a/simpleperf/scripts/update.py b/simpleperf/scripts/update.py
index 7065ef0..fbdc404 100644
--- a/simpleperf/scripts/update.py
+++ b/simpleperf/scripts/update.py
@@ -46,7 +46,8 @@
InstallEntry('sdk_arm64-sdk', 'simpleperf_host32', 'linux/x86/simpleperf', True),
InstallEntry('sdk_mac', 'simpleperf_host', 'darwin/x86_64/simpleperf'),
InstallEntry('sdk_mac', 'simpleperf_host32', 'darwin/x86/simpleperf'),
- InstallEntry('sdk', 'simpleperf.exe', 'windows/x86_64/simpleperf.exe', True),
+ # simpleperf.exe on x86_64 windows doesn't work, use simpleperf32.exe instead.
+ InstallEntry('sdk', 'simpleperf32.exe', 'windows/x86_64/simpleperf.exe', True),
InstallEntry('sdk', 'simpleperf32.exe', 'windows/x86/simpleperf.exe', True),
# libsimpleperf_report.so on host
@@ -56,6 +57,12 @@
InstallEntry('sdk_mac', 'libsimpleperf_report32.so', 'darwin/x86/libsimpleperf_report.dylib'),
InstallEntry('sdk', 'libsimpleperf_report.dll', 'windows/x86_64/libsimpleperf_report.dll', True),
InstallEntry('sdk', 'libsimpleperf_report32.dll', 'windows/x86/libsimpleperf_report.dll', True),
+
+ # libwinpthread-1.dll on windows host
+ InstallEntry('local', '../../../../prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/x86_64-w64-mingw32/bin/libwinpthread-1.dll',
+ 'windows/x86_64/libwinpthread-1.dll', False),
+ InstallEntry('local', '../../../../prebuilts/gcc/linux-x86/host/x86_64-w64-mingw32-4.8/x86_64-w64-mingw32/lib32/libwinpthread-1.dll',
+ 'windows/x86/libwinpthread-1.dll', False),
]
@@ -73,6 +80,8 @@
def fetch_artifact(branch, build, target, pattern):
"""Fetches and artifact from the build server."""
+ if target == 'local':
+ return
logger().info('Fetching %s from %s %s (artifacts matching %s)', build,
target, branch, pattern)
fetch_artifact_path = '/google/data/ro/projects/android/fetch_artifact'
diff --git a/simpleperf/scripts/utils.py b/simpleperf/scripts/utils.py
index ab76c3f..d5515ba 100644
--- a/simpleperf/scripts/utils.py
+++ b/simpleperf/scripts/utils.py
@@ -65,6 +65,8 @@
if is_windows():
if binary_name.endswith('.so'):
binary_name = binary_name[0:-3] + '.dll'
+ elif binary_name.find('.') == -1:
+ binary_name += '.exe'
dir = os.path.join(dir, 'windows')
elif sys.platform == 'darwin': # OSX
if binary_name.endswith('.so'):
diff --git a/simpleperf/utils.cpp b/simpleperf/utils.cpp
index 62a8b63..1dbe078 100644
--- a/simpleperf/utils.cpp
+++ b/simpleperf/utils.cpp
@@ -31,6 +31,7 @@
#include <android-base/file.h>
#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
#include <7zCrc.h>
#include <Xz.h>
@@ -337,3 +338,9 @@
tv.tv_usec = static_cast<int>((time_in_sec - tv.tv_sec) * 1000000);
return tv;
}
+
+constexpr int SIMPLEPERF_VERSION = 1;
+
+std::string GetSimpleperfVersion() {
+ return android::base::StringPrintf("%d.%s", SIMPLEPERF_VERSION, SIMPLEPERF_REVISION);
+}
diff --git a/simpleperf/utils.h b/simpleperf/utils.h
index fc21a99..775fd5c 100644
--- a/simpleperf/utils.h
+++ b/simpleperf/utils.h
@@ -169,4 +169,6 @@
timeval SecondToTimeval(double time_in_sec);
+std::string GetSimpleperfVersion();
+
#endif // SIMPLE_PERF_UTILS_H_