blob: 8251ebc0f53aad65f934a50ec7651fefef30ccdd [file]
/*
* Copyright (C) 2019 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 "RandomGraphGeneratorUtils.h"
#include <algorithm>
#include <iomanip>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "RandomGraphGenerator.h"
#include "RandomVariable.h"
namespace android {
namespace nn {
namespace fuzzing_test {
std::mt19937 RandomNumberGenerator::generator;
std::string Logger::getElapsedTime() {
auto end = std::chrono::high_resolution_clock::now();
int ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - mStart).count();
int hour = ms / 3600000;
int minutes = (ms % 3600000) / 60000;
int seconds = (ms % 60000) / 1000;
int milli = ms % 1000;
std::ostringstream oss;
oss << std::setfill('0') << std::setw(2) << hour << ":" << std::setw(2) << minutes << ":"
<< std::setw(2) << seconds << "." << std::setw(3) << milli << " ";
return oss.str();
}
SpecWriter::SpecWriter(std::string filename, std::string testname) : os(filename) {
if (os.is_open() && testname != "") {
os << "# Generated from " << testname << ". Do not edit.\n\n";
}
}
// Main entrance of dumping the spec file.
// Check nn/tools/test_generator/README.md for guide on spec file syntax.
void SpecWriter::dump(const std::vector<RandomOperation>& operations,
const std::vector<std::shared_ptr<RandomOperand>>& operands) {
// Dump model operands.
os << "# Model operands\n";
for (auto& operand : operands) dump(operand);
// Dump model operations.
os << "\n# Model operations\nmodel = Model()\n";
for (const auto& operation : operations) dump(operation);
// Dump input/output buffers.
os << "\n# Example\n";
os << "Example({\n";
for (auto& operand : operands) {
if (operand->type == RandomOperandType::CONST ||
operand->type == RandomOperandType::INTERNAL) {
continue;
}
os << " op" << operand->opIndex << ": [";
dump(operand->dataType, reinterpret_cast<uint8_t*>(operand->buffer.data()),
operand->getNumberOfElements());
os << "],\n";
}
os << "}).DisableDynamicOutputShapeVariation().DisableLifeTimeVariation()\n";
}
// Dump an operand buffer.
void SpecWriter::dump(test_wrapper::Type type, const uint8_t* buffer, uint32_t length) {
if (buffer == nullptr) return;
switch (type) {
case test_wrapper::Type::FLOAT32:
case test_wrapper::Type::TENSOR_FLOAT32:
dump(reinterpret_cast<const float*>(buffer), length);
break;
case test_wrapper::Type::INT32:
case test_wrapper::Type::TENSOR_INT32:
dump(reinterpret_cast<const int32_t*>(buffer), length);
break;
case test_wrapper::Type::TENSOR_QUANT8_ASYMM:
dump(reinterpret_cast<const uint8_t*>(buffer), length);
break;
case test_wrapper::Type::TENSOR_QUANT8_SYMM:
dump(reinterpret_cast<const int8_t*>(buffer), length);
break;
case test_wrapper::Type::TENSOR_QUANT16_ASYMM:
dump(reinterpret_cast<const uint16_t*>(buffer), length);
break;
case test_wrapper::Type::TENSOR_QUANT16_SYMM:
dump(reinterpret_cast<const int16_t*>(buffer), length);
break;
case test_wrapper::Type::BOOL:
case test_wrapper::Type::TENSOR_BOOL8:
dump(reinterpret_cast<const bool8*>(buffer), length);
break;
case test_wrapper::Type::FLOAT16:
case test_wrapper::Type::TENSOR_FLOAT16:
dump(reinterpret_cast<const _Float16*>(buffer), length);
break;
default:
NN_FUZZER_CHECK(false) << "Unknown type when dumping the buffer";
}
}
// Dump dimensions with curly braces.
void SpecWriter::dump(const std::vector<RandomVariable>& dimensions) {
os << "{" << joinStr(", ", dimensions, [](const RandomVariable& var) {
return std::to_string(var.getValue());
}) << "}";
}
// Dump a model operand.
// e.g. op0 = Input("op0", "TENSOR_FLOAT32", "{1, 2, 6, 1}")
// e.g. op1 = Parameter("op1", "INT32", "{}", [2])
void SpecWriter::dump(const std::shared_ptr<RandomOperand>& op) {
os << "op" << op->opIndex << " = " << toString(op->type) << "(\"op" << op->opIndex << "\", \""
<< toString(op->dataType) << "\", \"";
dump(op->dimensions);
if (op->scale != 0.0f || op->zeroPoint != 0) {
os << ", " << op->scale << "f, " << op->zeroPoint;
}
os << "\"";
if (op->type == RandomOperandType::CONST) {
os << ", [";
dump(op->dataType, reinterpret_cast<uint8_t*>(op->buffer.data()),
op->getNumberOfElements());
os << "]";
}
os << ")\n";
}
// Dump a model operation.
// e.g. model = model.Operation("CONV_2D", op0, op1, op2, op3, op4, op5, op6).To(op7)
void SpecWriter::dump(const RandomOperation& op) {
auto getOperandStr = [](std::shared_ptr<RandomOperand> op) {
return "op" + std::to_string(op->opIndex);
};
os << "model = model.Operation(\"" << kOperationNames[op.opType] << "\", "
<< joinStr(", ", op.inputs, getOperandStr) << ").To("
<< joinStr(", ", op.outputs, getOperandStr) << ")\n";
}
} // namespace fuzzing_test
} // namespace nn
} // namespace android