blob: 908340f0cb035dc9ee9902b71e4ea3f627fd9f83 [file] [log] [blame]
/*
* Copyright (C) 2022 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 "src/trace_processor/importers/common/clock_converter.h"
#include <time.h>
#include <algorithm>
#include <atomic>
#include <cinttypes>
#include <queue>
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/hash.h"
#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "protos/perfetto/common/builtin_clock.pbzero.h"
#include "protos/perfetto/trace/clock_snapshot.pbzero.h"
namespace perfetto {
namespace trace_processor {
ClockConverter::ClockConverter(TraceProcessorContext* context)
: context_(context) {}
void ClockConverter::MaybeInitialize() {
if (is_initialized)
return;
is_initialized = true;
timelines_.Insert(kRealClock, {});
timelines_.Insert(kMonoClock, {});
for (auto it = context_->storage->clock_snapshot_table().IterateRows(); it;
++it) {
if (it.clock_id() == kRealClock || it.clock_id() == kMonoClock)
timelines_.Find(it.clock_id())->emplace(it.ts(), it.clock_value());
}
}
base::StatusOr<ClockConverter::Timestamp> ClockConverter::FromTraceTime(
ClockId clock_id,
Timestamp ts) {
MaybeInitialize();
Timeline* timeline = timelines_.Find(clock_id);
if (!timeline) {
return base::ErrStatus(
"Provided clock has not been found in the converter "
"clocks.");
}
if (timeline->empty()) {
return base::ErrStatus("Target clock is not in the trace.");
}
auto next_snapshot = timeline->lower_bound(ts);
// If lower bound was not found, it means that the ts was higher then the last
// one. If that's the case we look for thhe last element and return clock
// value for this + offset.
if (next_snapshot == timeline->end()) {
next_snapshot--;
return next_snapshot->second + ts - next_snapshot->first;
}
// If there is a snapshot with this ts or lower bound is the first snapshot,
// we have no other option then to return the clock value for this snapshot.
if (next_snapshot == timeline->begin() || next_snapshot->first == ts)
return next_snapshot->second;
auto prev_snapshot = next_snapshot;
prev_snapshot--;
// The most truthful way to calculate the clock value is to use this formula,
// as there is no reason to assume that the clock is monotonistic. This
// prevents us from going back in time.
return std::min(prev_snapshot->second + ts - prev_snapshot->first,
next_snapshot->second);
}
std::string ClockConverter::TimeToStr(Timestamp ts) {
constexpr int64_t one_second_in_ns = 1LL * 1000LL * 1000LL * 1000LL;
int64_t s = ts / one_second_in_ns;
int64_t ns = ts % one_second_in_ns;
time_t time_s = static_cast<time_t>(s);
struct tm* time_tm = gmtime(&time_s);
int seconds = time_tm->tm_sec;
int minutes = time_tm->tm_min;
int hours = time_tm->tm_hour;
int day = time_tm->tm_mday;
int month = time_tm->tm_mon + 1;
int year = time_tm->tm_year + 1900;
base::StackString<64> buf("%04d-%02d-%02dT%02d:%02d:%02d.%09" PRId64, year,
month, day, hours, minutes, seconds, ns);
return buf.ToStdString();
}
} // namespace trace_processor
} // namespace perfetto