• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
getElapsedTime()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 
SpecWriter(std::string filename,std::string testname)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.
dump(const std::vector<RandomOperation> & operations,const std::vector<std::shared_ptr<RandomOperand>> & operands)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.
dump(test_wrapper::Type type,const uint8_t * buffer,uint32_t length)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.
dump(const std::vector<RandomVariable> & dimensions)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])
dump(const std::shared_ptr<RandomOperand> & op)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)
dump(const RandomOperation & op)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