diff options
author | Andreas Gampe <agampe@google.com> | 2015-04-25 14:44:29 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2015-04-25 17:07:07 -0700 |
commit | e34a42cd37b2b3b6b21280df14fa6f40917b5d6e (patch) | |
tree | b9a9362bdd3db787caffbe9ab72b3b3ad810bff9 | |
parent | 3f4fa70a251443b7e35ee0464120e53daf4ae9c1 (diff) | |
download | art-e34a42cd37b2b3b6b21280df14fa6f40917b5d6e.tar.gz art-e34a42cd37b2b3b6b21280df14fa6f40917b5d6e.tar.bz2 art-e34a42cd37b2b3b6b21280df14fa6f40917b5d6e.zip |
ART: Fix Trace types, check minimum buf size
Also make streaming mode adhere to the given buffer (and fix the
case where the buffer is too small for a packet). This is important
to not lose too much tracing information when the runtime is destroyed
with an unflushed buffer.
Change-Id: I6525fe4326ac5c3d7c9cda41c54a2a911ca889b7
-rw-r--r-- | runtime/base/casts.h | 19 | ||||
-rw-r--r-- | runtime/native/dalvik_system_ZygoteHooks.cc | 3 | ||||
-rw-r--r-- | runtime/trace.cc | 36 | ||||
-rw-r--r-- | runtime/trace.h | 7 |
4 files changed, 50 insertions, 15 deletions
diff --git a/runtime/base/casts.h b/runtime/base/casts.h index c7e39a29f..f8846498d 100644 --- a/runtime/base/casts.h +++ b/runtime/base/casts.h @@ -18,9 +18,11 @@ #define ART_RUNTIME_BASE_CASTS_H_ #include <assert.h> +#include <limits> #include <string.h> #include <type_traits> +#include "base/logging.h" #include "base/macros.h" namespace art { @@ -83,6 +85,23 @@ inline Dest bit_cast(const Source& source) { return dest; } +// A version of static_cast that DCHECKs that the value can be precisely represented +// when converting to Dest. +template <typename Dest, typename Source> +inline Dest dchecked_integral_cast(const Source source) { + DCHECK( + // Check that the value is within the lower limit of Dest. + (static_cast<intmax_t>(std::numeric_limits<Dest>::min()) <= + static_cast<intmax_t>(std::numeric_limits<Source>::min()) || + source >= static_cast<Source>(std::numeric_limits<Dest>::min())) && + // Check that the value is within the upper limit of Dest. + (static_cast<uintmax_t>(std::numeric_limits<Dest>::max()) >= + static_cast<uintmax_t>(std::numeric_limits<Source>::max()) || + source <= static_cast<Source>(std::numeric_limits<Dest>::max()))); + + return static_cast<Dest>(source); +} + } // namespace art #endif // ART_RUNTIME_BASE_CASTS_H_ diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index 852434816..1a7a3e5ba 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -152,6 +152,7 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, ji if (Trace::GetMethodTracingMode() != TracingMode::kTracingInactive) { Trace::TraceOutputMode output_mode = Trace::GetOutputMode(); Trace::TraceMode trace_mode = Trace::GetMode(); + size_t buffer_size = Trace::GetBufferSize(); // Just drop it. Trace::Abort(); @@ -176,7 +177,7 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, ji proc_name.c_str()); Trace::Start(trace_file.c_str(), -1, - -1, // TODO: Expose buffer size. + buffer_size, 0, // TODO: Expose flags. output_mode, trace_mode, diff --git a/runtime/trace.cc b/runtime/trace.cc index 5322f9fc1..9eca517dc 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -22,6 +22,7 @@ #define ATRACE_TAG ATRACE_TAG_DALVIK #include "cutils/trace.h" +#include "base/casts.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" @@ -329,7 +330,7 @@ void* Trace::RunSamplingThread(void* arg) { return nullptr; } -void Trace::Start(const char* trace_filename, int trace_fd, int buffer_size, int flags, +void Trace::Start(const char* trace_filename, int trace_fd, size_t buffer_size, int flags, TraceOutputMode output_mode, TraceMode trace_mode, int interval_us) { Thread* self = Thread::Current(); { @@ -592,19 +593,15 @@ TracingMode Trace::GetMethodTracingMode() { } } -static constexpr size_t kStreamingBufferSize = 16 * KB; +static constexpr size_t kMinBufSize = 18U; // Trace header is up to 18B. -Trace::Trace(File* trace_file, const char* trace_name, int buffer_size, int flags, +Trace::Trace(File* trace_file, const char* trace_name, size_t buffer_size, int flags, TraceOutputMode output_mode, TraceMode trace_mode) : trace_file_(trace_file), - buf_(new uint8_t[output_mode == TraceOutputMode::kStreaming ? - kStreamingBufferSize : - buffer_size]()), + buf_(new uint8_t[std::max(kMinBufSize, buffer_size)]()), flags_(flags), trace_output_mode_(output_mode), trace_mode_(trace_mode), clock_source_(default_clock_source_), - buffer_size_(output_mode == TraceOutputMode::kStreaming ? - kStreamingBufferSize : - buffer_size), + buffer_size_(std::max(kMinBufSize, buffer_size)), start_time_(MicroTime()), clock_overhead_ns_(GetClockOverheadNanoSeconds()), cur_offset_(0), overflow_(false), interval_us_(0), streaming_lock_(nullptr) { uint16_t trace_version = GetTraceVersion(clock_source_); @@ -621,6 +618,7 @@ Trace::Trace(File* trace_file, const char* trace_name, int buffer_size, int flag uint16_t record_size = GetRecordSize(clock_source_); Append2LE(buf_.get() + 16, record_size); } + static_assert(18 <= kMinBufSize, "Minimum buffer size not large enough for trace header"); // Update current offset. cur_offset_.StoreRelaxed(kTraceHeaderLength); @@ -875,11 +873,21 @@ static std::string GetMethodLine(mirror::ArtMethod* method) void Trace::WriteToBuf(const uint8_t* src, size_t src_size) { int32_t old_offset = cur_offset_.LoadRelaxed(); int32_t new_offset = old_offset + static_cast<int32_t>(src_size); - if (new_offset > buffer_size_) { + if (dchecked_integral_cast<size_t>(new_offset) > buffer_size_) { // Flush buffer. if (!trace_file_->WriteFully(buf_.get(), old_offset)) { PLOG(WARNING) << "Failed streaming a tracing event."; } + + // Check whether the data is too large for the buffer, then write immediately. + if (src_size >= buffer_size_) { + if (!trace_file_->WriteFully(src, src_size)) { + PLOG(WARNING) << "Failed streaming a tracing event."; + } + cur_offset_.StoreRelease(0); // Buffer is empty now. + return; + } + old_offset = 0; new_offset = static_cast<int32_t>(src_size); } @@ -900,7 +908,7 @@ void Trace::LogMethodTraceEvent(Thread* thread, mirror::ArtMethod* method, do { old_offset = cur_offset_.LoadRelaxed(); new_offset = old_offset + GetRecordSize(clock_source_); - if (new_offset > buffer_size_) { + if (static_cast<size_t>(new_offset) > buffer_size_) { overflow_ = true; return; } @@ -1034,4 +1042,10 @@ Trace::TraceMode Trace::GetMode() { return the_trace_->trace_mode_; } +size_t Trace::GetBufferSize() { + MutexLock mu(Thread::Current(), *Locks::trace_lock_); + CHECK(the_trace_ != nullptr) << "Trace mode requested, but no trace currently running"; + return the_trace_->buffer_size_; +} + } // namespace art diff --git a/runtime/trace.h b/runtime/trace.h index 1ecd4d8ff..06824b8be 100644 --- a/runtime/trace.h +++ b/runtime/trace.h @@ -72,7 +72,7 @@ class Trace FINAL : public instrumentation::InstrumentationListener { static void SetDefaultClockSource(TraceClockSource clock_source); - static void Start(const char* trace_filename, int trace_fd, int buffer_size, int flags, + static void Start(const char* trace_filename, int trace_fd, size_t buffer_size, int flags, TraceOutputMode output_mode, TraceMode trace_mode, int interval_us) LOCKS_EXCLUDED(Locks::mutator_lock_, Locks::thread_list_lock_, @@ -136,9 +136,10 @@ class Trace FINAL : public instrumentation::InstrumentationListener { static TraceOutputMode GetOutputMode() LOCKS_EXCLUDED(Locks::trace_lock_); static TraceMode GetMode() LOCKS_EXCLUDED(Locks::trace_lock_); + static size_t GetBufferSize() LOCKS_EXCLUDED(Locks::trace_lock_); private: - Trace(File* trace_file, const char* trace_name, int buffer_size, int flags, + Trace(File* trace_file, const char* trace_name, size_t buffer_size, int flags, TraceOutputMode output_mode, TraceMode trace_mode); // The sampling interval in microseconds is passed as an argument. @@ -202,7 +203,7 @@ class Trace FINAL : public instrumentation::InstrumentationListener { const TraceClockSource clock_source_; // Size of buf_. - const int buffer_size_; + const size_t buffer_size_; // Time trace was created. const uint64_t start_time_; |