Home | History | Annotate | Download | only in fuzzing
      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 "RandomGraphGeneratorUtils.h"
     18 
     19 #include <algorithm>
     20 #include <iomanip>
     21 #include <memory>
     22 #include <sstream>
     23 #include <string>
     24 
     25 #include "RandomGraphGenerator.h"
     26 #include "RandomVariable.h"
     27 
     28 namespace android {
     29 namespace nn {
     30 namespace fuzzing_test {
     31 
     32 std::mt19937 RandomNumberGenerator::generator;
     33 
     34 std::string Logger::getElapsedTime() {
     35     auto end = std::chrono::high_resolution_clock::now();
     36     int ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - mStart).count();
     37     int hour = ms / 3600000;
     38     int minutes = (ms % 3600000) / 60000;
     39     int seconds = (ms % 60000) / 1000;
     40     int milli = ms % 1000;
     41     std::ostringstream oss;
     42     oss << std::setfill('0') << std::setw(2) << hour << ":" << std::setw(2) << minutes << ":"
     43         << std::setw(2) << seconds << "." << std::setw(3) << milli << " ";
     44     return oss.str();
     45 }
     46 
     47 SpecWriter::SpecWriter(std::string filename, std::string testname) : os(filename) {
     48     if (os.is_open() && testname != "") {
     49         os << "# Generated from " << testname << ". Do not edit.\n\n";
     50     }
     51 }
     52 
     53 // Main entrance of dumping the spec file.
     54 // Check nn/tools/test_generator/README.md for guide on spec file syntax.
     55 void SpecWriter::dump(const std::vector<RandomOperation>& operations,
     56                       const std::vector<std::shared_ptr<RandomOperand>>& operands) {
     57     // RandomGraphGenerator does not support dynamic output shape.
     58     os << "Configuration.test_dynamic_output_shape = False\n\n";
     59 
     60     // Dump model operands.
     61     os << "# Model operands\n";
     62     for (auto& operand : operands) dump(operand);
     63 
     64     // Dump model operations.
     65     os << "\n# Model operations\nmodel = Model()\n";
     66     for (const auto& operation : operations) dump(operation);
     67 
     68     // Dump input/output buffers.
     69     os << "\n# Example\n";
     70     os << "Example({\n";
     71     for (auto& operand : operands) {
     72         if (operand->type == RandomOperandType::CONST ||
     73             operand->type == RandomOperandType::INTERNAL) {
     74             continue;
     75         }
     76         os << "    op" << operand->opIndex << ": [";
     77         dump(operand->dataType, reinterpret_cast<uint8_t*>(operand->buffer.data()),
     78              operand->getNumberOfElements());
     79         os << "],\n";
     80     }
     81     os << "})\n";
     82 }
     83 
     84 // Dump an operand buffer.
     85 void SpecWriter::dump(test_wrapper::Type type, const uint8_t* buffer, uint32_t length) {
     86     if (buffer == nullptr) return;
     87     switch (type) {
     88         case test_wrapper::Type::FLOAT32:
     89         case test_wrapper::Type::TENSOR_FLOAT32:
     90             dump(reinterpret_cast<const float*>(buffer), length);
     91             break;
     92         case test_wrapper::Type::INT32:
     93         case test_wrapper::Type::TENSOR_INT32:
     94             dump(reinterpret_cast<const int32_t*>(buffer), length);
     95             break;
     96         case test_wrapper::Type::TENSOR_QUANT8_ASYMM:
     97             dump(reinterpret_cast<const uint8_t*>(buffer), length);
     98             break;
     99         case test_wrapper::Type::TENSOR_QUANT8_SYMM:
    100             dump(reinterpret_cast<const int8_t*>(buffer), length);
    101             break;
    102         case test_wrapper::Type::TENSOR_QUANT16_ASYMM:
    103             dump(reinterpret_cast<const uint16_t*>(buffer), length);
    104             break;
    105         case test_wrapper::Type::TENSOR_QUANT16_SYMM:
    106             dump(reinterpret_cast<const int16_t*>(buffer), length);
    107             break;
    108         case test_wrapper::Type::BOOL:
    109         case test_wrapper::Type::TENSOR_BOOL8:
    110             dump(reinterpret_cast<const bool8*>(buffer), length);
    111             break;
    112         case test_wrapper::Type::FLOAT16:
    113         case test_wrapper::Type::TENSOR_FLOAT16:
    114             dump(reinterpret_cast<const _Float16*>(buffer), length);
    115             break;
    116         default:
    117             NN_FUZZER_CHECK(false) << "Unknown type when dumping the buffer";
    118     }
    119 }
    120 
    121 // Dump dimensions with curly braces.
    122 void SpecWriter::dump(const std::vector<RandomVariable>& dimensions) {
    123     os << "{" << joinStr(", ", dimensions, [](const RandomVariable& var) {
    124         return std::to_string(var.getValue());
    125     }) << "}";
    126 }
    127 
    128 // Dump a model operand.
    129 // e.g. op0 = Input("op0", "TENSOR_FLOAT32", "{1, 2, 6, 1}")
    130 // e.g. op1 = Parameter("op1", "INT32", "{}", [2])
    131 void SpecWriter::dump(const std::shared_ptr<RandomOperand>& op) {
    132     os << "op" << op->opIndex << " = " << toString(op->type) << "(\"op" << op->opIndex << "\", \""
    133        << toString(op->dataType) << "\", \"";
    134     dump(op->dimensions);
    135     if (op->scale != 0.0f || op->zeroPoint != 0) {
    136         os << ", " << op->scale << "f, " << op->zeroPoint;
    137     }
    138     os << "\"";
    139     if (op->type == RandomOperandType::CONST) {
    140         os << ", [";
    141         dump(op->dataType, reinterpret_cast<uint8_t*>(op->buffer.data()),
    142              op->getNumberOfElements());
    143         os << "]";
    144     }
    145     os << ")\n";
    146 }
    147 
    148 // Dump a model operation.
    149 // e.g. model = model.Operation("CONV_2D", op0, op1, op2, op3, op4, op5, op6).To(op7)
    150 void SpecWriter::dump(const RandomOperation& op) {
    151     auto getOperandStr = [](std::shared_ptr<RandomOperand> op) {
    152         return "op" + std::to_string(op->opIndex);
    153     };
    154     os << "model = model.Operation(\"" << kOperationNames[op.opType] << "\", "
    155        << joinStr(", ", op.inputs, getOperandStr) << ").To("
    156        << joinStr(", ", op.outputs, getOperandStr) << ")\n";
    157 }
    158 
    159 }  // namespace fuzzing_test
    160 }  // namespace nn
    161 }  // namespace android
    162