Home | History | Annotate | Download | only in trace_processor
      1 /*
      2  * Copyright (C) 2019 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "src/trace_processor/ftrace_utils.h"
     18 
     19 #include <stdint.h>
     20 #include <algorithm>
     21 
     22 #include "perfetto/base/logging.h"
     23 #include "perfetto/base/string_writer.h"
     24 
     25 namespace perfetto {
     26 namespace trace_processor {
     27 namespace ftrace_utils {
     28 
     29 namespace {
     30 struct FtraceTime {
     31   FtraceTime(int64_t ns)
     32       : secs(ns / 1000000000LL), micros((ns - secs * 1000000000LL) / 1000) {}
     33 
     34   const int64_t secs;
     35   const int64_t micros;
     36 };
     37 }  // namespace
     38 
     39 TaskState::TaskState(const char* state_str) {
     40   bool invalid_char = false;
     41   bool is_runnable = false;
     42   for (size_t i = 0; state_str[i] != '\0'; i++) {
     43     char c = state_str[i];
     44     if (is_kernel_preempt()) {
     45       // No other character should be encountered after '+'.
     46       invalid_char = true;
     47       break;
     48     } else if (c == '+') {
     49       state_ |= kMaxState;
     50       continue;
     51     }
     52 
     53     if (is_runnable) {
     54       // We should not encounter any character apart from '+' if runnable.
     55       invalid_char = true;
     56       break;
     57     }
     58 
     59     if (c == 'R') {
     60       if (state_ != 0) {
     61         // We should not encounter R if we already have set other atoms.
     62         invalid_char = true;
     63         break;
     64       } else {
     65         is_runnable = true;
     66         continue;
     67       }
     68     }
     69 
     70     if (c == 'S')
     71       state_ |= Atom::kInterruptibleSleep;
     72     else if (c == 'D')
     73       state_ |= Atom::kUninterruptibleSleep;
     74     else if (c == 'T')
     75       state_ |= Atom::kStopped;
     76     else if (c == 't')
     77       state_ |= Atom::kTraced;
     78     else if (c == 'X')
     79       state_ |= Atom::kExitDead;
     80     else if (c == 'Z')
     81       state_ |= Atom::kExitZombie;
     82     else if (c == 'x')
     83       state_ |= Atom::kTaskDead;
     84     else if (c == 'K')
     85       state_ |= Atom::kWakeKill;
     86     else if (c == 'W')
     87       state_ |= Atom::kWaking;
     88     else if (c == 'P')
     89       state_ |= Atom::kParked;
     90     else if (c == 'N')
     91       state_ |= Atom::kNoLoad;
     92     else {
     93       invalid_char = true;
     94       break;
     95     }
     96   }
     97 
     98   bool no_state = !is_runnable && state_ == 0;
     99   if (invalid_char || no_state) {
    100     state_ = 0;
    101   } else {
    102     state_ |= kValid;
    103   }
    104 }
    105 
    106 TaskState::TaskStateStr TaskState::ToString() const {
    107   PERFETTO_CHECK(is_valid());
    108 
    109   char buffer[32];
    110   size_t pos = 0;
    111 
    112   // This mapping is given by the file
    113   // https://android.googlesource.com/kernel/msm.git/+/android-msm-wahoo-4.4-pie-qpr1/include/trace/events/sched.h#155
    114   if (is_runnable()) {
    115     buffer[pos++] = 'R';
    116   } else {
    117     if (state_ & Atom::kInterruptibleSleep)
    118       buffer[pos++] = 'S';
    119     if (state_ & Atom::kUninterruptibleSleep)
    120       buffer[pos++] = 'D';  // D for (D)isk sleep
    121     if (state_ & Atom::kStopped)
    122       buffer[pos++] = 'T';
    123     if (state_ & Atom::kTraced)
    124       buffer[pos++] = 't';
    125     if (state_ & Atom::kExitDead)
    126       buffer[pos++] = 'X';
    127     if (state_ & Atom::kExitZombie)
    128       buffer[pos++] = 'Z';
    129     if (state_ & Atom::kTaskDead)
    130       buffer[pos++] = 'x';
    131     if (state_ & Atom::kWakeKill)
    132       buffer[pos++] = 'K';
    133     if (state_ & Atom::kWaking)
    134       buffer[pos++] = 'W';
    135     if (state_ & Atom::kParked)
    136       buffer[pos++] = 'P';
    137     if (state_ & Atom::kNoLoad)
    138       buffer[pos++] = 'N';
    139   }
    140 
    141   if (is_kernel_preempt())
    142     buffer[pos++] = '+';
    143 
    144   TaskStateStr output{};
    145   memcpy(output.data(), buffer, std::min(pos, output.size() - 1));
    146   return output;
    147 }
    148 
    149 void FormatSystracePrefix(int64_t timestamp,
    150                           uint32_t cpu,
    151                           uint32_t pid,
    152                           uint32_t tgid,
    153                           base::StringView name,
    154                           base::StringWriter* writer) {
    155   FtraceTime ftrace_time(timestamp);
    156   if (pid == 0) {
    157     name = "<idle>";
    158   }
    159 
    160   int64_t padding = 16 - static_cast<int64_t>(name.size());
    161   if (PERFETTO_LIKELY(padding > 0)) {
    162     writer->AppendChar(' ', static_cast<size_t>(padding));
    163   }
    164   writer->AppendString(name);
    165   writer->AppendChar('-');
    166 
    167   size_t pre_pid_pos = writer->pos();
    168   writer->AppendInt(pid);
    169   size_t pid_chars = writer->pos() - pre_pid_pos;
    170   if (PERFETTO_LIKELY(pid_chars < 5)) {
    171     writer->AppendChar(' ', 5 - pid_chars);
    172   }
    173 
    174   writer->AppendLiteral(" (");
    175   if (tgid == 0) {
    176     writer->AppendLiteral("-----");
    177   } else {
    178     writer->AppendPaddedInt<' ', 5>(tgid);
    179   }
    180   writer->AppendLiteral(") [");
    181   writer->AppendPaddedInt<'0', 3>(cpu);
    182   writer->AppendLiteral("] .... ");
    183 
    184   writer->AppendInt(ftrace_time.secs);
    185   writer->AppendChar('.');
    186   writer->AppendPaddedInt<'0', 6>(ftrace_time.micros);
    187   writer->AppendChar(':');
    188 }
    189 
    190 }  // namespace ftrace_utils
    191 }  // namespace trace_processor
    192 }  // namespace perfetto
    193