Home | History | Annotate | Download | only in performance
      1 /*
      2  * Copyright (C) 2016 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 "PerfTest.h"
     18 #include <fstream>
     19 #include <iomanip>
     20 #include <iostream>
     21 #include <string>
     22 
     23 #ifdef ASSERT
     24 #undef ASSERT
     25 #endif
     26 #define ASSERT(cond)                                                                              \
     27     do {                                                                                          \
     28         if (!(cond)) {                                                                            \
     29             cerr << __func__ << ":" << __LINE__ << " condition:" << #cond << " failed\n" << endl; \
     30             exit(EXIT_FAILURE);                                                                   \
     31         }                                                                                         \
     32     } while (0)
     33 
     34 // the ratio that the service is synced on the same cpu beyond
     35 // GOOD_SYNC_MIN is considered as good
     36 #define GOOD_SYNC_MIN (0.6)
     37 
     38 // the precision used for cout to dump float
     39 #define DUMP_PRICISION 2
     40 
     41 using std::cerr;
     42 using std::cout;
     43 using std::endl;
     44 using std::left;
     45 using std::ios;
     46 using std::min;
     47 using std::max;
     48 using std::to_string;
     49 using std::setprecision;
     50 using std::setw;
     51 using std::ofstream;
     52 using std::make_tuple;
     53 
     54 tuple<Pipe, Pipe> Pipe::createPipePair() {
     55     int a[2];
     56     int b[2];
     57 
     58     int error1 = pipe(a);
     59     int error2 = pipe(b);
     60     ASSERT(error1 >= 0);
     61     ASSERT(error2 >= 0);
     62 
     63     return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
     64 }
     65 
     66 Pipe::Pipe(Pipe&& rval) noexcept {
     67     fd_read_ = rval.fd_read_;
     68     fd_write_ = rval.fd_write_;
     69     rval.fd_read_ = 0;
     70     rval.fd_write_ = 0;
     71 }
     72 
     73 Pipe::~Pipe() {
     74     if (fd_read_) {
     75         close(fd_read_);
     76     }
     77     if (fd_write_) {
     78         close(fd_write_);
     79     }
     80 }
     81 
     82 Results Results::combine(const Results& a, const Results& b) {
     83     Results ret;
     84     for (uint32_t i = 0; i < kNumBuckets; i++) {
     85         ret.buckets_[i] = a.buckets_[i] + b.buckets_[i];
     86     }
     87     ret.worst_ = max(a.worst_, b.worst_);
     88     ret.best_ = min(a.best_, b.best_);
     89     ret.transactions_ = a.transactions_ + b.transactions_;
     90     ret.miss_ = a.miss_ + b.miss_;
     91     ret.total_time_ = a.total_time_ + b.total_time_;
     92     return ret;
     93 }
     94 
     95 static void traceStop() {
     96     ofstream file;
     97     file.open(TRACE_PATH "/tracing_on", ios::out | ios::trunc);
     98     file << '0' << endl;
     99     file.close();
    100 }
    101 
    102 void Results::addTime(uint64_t nano) {
    103     buckets_[min(nano, kMaxTimeBucket - 1) / kTimePerBucket] += 1;
    104     best_ = min(nano, best_);
    105     worst_ = max(nano, worst_);
    106     if (raw_dump_) {
    107         raw_data_->push_back(nano);
    108     }
    109     transactions_ += 1;
    110     total_time_ += nano;
    111     if (missDeadline(nano)) {
    112         miss_++;
    113         if (tracing_) {
    114             // There might be multiple process pair running the test concurrently
    115             // each may execute following statements and only the first one actually
    116             // stop the trace and any traceStop() after then has no effect.
    117             traceStop();
    118             cerr << endl;
    119             cerr << "deadline triggered: halt & stop trace" << endl;
    120             cerr << "log:" TRACE_PATH "/trace" << endl;
    121             cerr << endl;
    122             exit(EXIT_FAILURE);
    123         }
    124     }
    125 }
    126 
    127 void Results::setupRawData() {
    128     raw_dump_ = true;
    129     if (raw_data_ == nullptr) {
    130         raw_data_ = new list<uint64_t>;
    131     } else {
    132         raw_data_->clear();
    133     }
    134 }
    135 
    136 void Results::flushRawData() {
    137     if (raw_dump_) {
    138         bool first = true;
    139         cout << "[";
    140         for (auto nano : *raw_data_) {
    141             cout << (first ? "" : ",") << to_string(nano);
    142             first = false;
    143         }
    144         cout << "]," << endl;
    145         delete raw_data_;
    146         raw_data_ = nullptr;
    147     }
    148 }
    149 
    150 void Results::dump() const {
    151     double best = (double)best_ / 1.0E6;
    152     double worst = (double)worst_ / 1.0E6;
    153     double average = (double)total_time_ / transactions_ / 1.0E6;
    154     int W = DUMP_PRICISION + 2;
    155     cout << std::setprecision(DUMP_PRICISION) << "{ \"avg\":" << setw(W) << left << average
    156          << ", \"wst\":" << setw(W) << left << worst << ", \"bst\":" << setw(W) << left << best
    157          << ", \"miss\":" << left << miss_ << ", \"meetR\":" << setprecision(DUMP_PRICISION + 3)
    158          << left << (1.0 - (double)miss_ / transactions_) << "}";
    159 }
    160 
    161 void Results::dumpDistribution() const {
    162     uint64_t cur_total = 0;
    163     cout << "{ ";
    164     cout << std::setprecision(DUMP_PRICISION + 3);
    165     for (uint32_t i = 0; i < kNumBuckets; i++) {
    166         float cur_time = kTimePerBucketMS * i + 0.5f * kTimePerBucketMS;
    167         float accumulation = cur_total + buckets_[i];
    168         if ((cur_total < 0.5f * transactions_) && (accumulation >= 0.5f * transactions_)) {
    169             cout << "\"p50\":" << cur_time << ", ";
    170         }
    171         if ((cur_total < 0.9f * transactions_) && (accumulation >= 0.9f * transactions_)) {
    172             cout << "\"p90\":" << cur_time << ", ";
    173         }
    174         if ((cur_total < 0.95f * transactions_) && (accumulation >= 0.95f * transactions_)) {
    175             cout << "\"p95\":" << cur_time << ", ";
    176         }
    177         if ((cur_total < 0.99f * transactions_) && (accumulation >= 0.99f * transactions_)) {
    178             cout << "\"p99\": " << cur_time;
    179         }
    180         cur_total += buckets_[i];
    181     }
    182     cout << "}";
    183 }
    184 
    185 PResults PResults::combine(const PResults& a, const PResults& b) {
    186     PResults ret;
    187     ret.nNotInherent = a.nNotInherent + b.nNotInherent;
    188     ret.nNotSync = a.nNotSync + b.nNotSync;
    189     ret.other = Results::combine(a.other, b.other);
    190     ret.fifo = Results::combine(a.fifo, b.fifo);
    191     return ret;
    192 }
    193 
    194 void PResults::dump() const {
    195     int no_trans = other.getTransactions() + fifo.getTransactions();
    196     double sync_ratio = (1.0 - (double)nNotSync / no_trans);
    197     cout << "{\"SYNC\":\"" << ((sync_ratio > GOOD_SYNC_MIN) ? "GOOD" : "POOR") << "\","
    198          << "\"S\":" << (no_trans - nNotSync) << ",\"I\":" << no_trans << ","
    199          << "\"R\":" << sync_ratio << "," << endl;
    200     cout << "  \"other_ms\":";
    201     other.dump();
    202     cout << "," << endl;
    203     cout << "  \"fifo_ms\": ";
    204     fifo.dump();
    205     cout << "," << endl;
    206     cout << "  \"otherdis\":";
    207     other.dumpDistribution();
    208     cout << "," << endl;
    209     cout << "  \"fifodis\": ";
    210     fifo.dumpDistribution();
    211     cout << endl;
    212     cout << "}," << endl;
    213 }
    214